summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnne Jan Brouwer <brouwer@annejan.com>2019-04-17 11:29:57 +0200
committerGitHub <noreply@github.com>2019-04-17 11:29:57 +0200
commit0789259aa59a565ba6c899a8c4e8da88fd5f5637 (patch)
treea62bf49adbdada3ffb40b261b7ae2bcbce243470
parent3698ff096cffec3541253ba1e745c389df0118c2 (diff)
parent57c24f5a7cbcfc52ec3e56be7d04421669f457b8 (diff)
Merge pull request #421 from frawi/master
Display passwords as QR codes
-rw-r--r--icons/qrcode.svg133
-rw-r--r--resources.qrc1
-rw-r--r--src/configdialog.cpp30
-rw-r--r--src/configdialog.h2
-rw-r--r--src/configdialog.ui15
-rw-r--r--src/mainwindow.cpp11
-rw-r--r--src/qpushbuttonasqrcode.cpp48
-rw-r--r--src/qpushbuttonasqrcode.h33
-rw-r--r--src/qtpass.cpp28
-rw-r--r--src/qtpass.h1
-rw-r--r--src/qtpasssettings.cpp8
-rw-r--r--src/qtpasssettings.h3
-rw-r--r--src/settingsconstants.cpp1
-rw-r--r--src/settingsconstants.h1
-rw-r--r--src/src.pro2
15 files changed, 315 insertions, 2 deletions
diff --git a/icons/qrcode.svg b/icons/qrcode.svg
new file mode 100644
index 00000000..81acc872
--- /dev/null
+++ b/icons/qrcode.svg
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="24"
+ height="24"
+ viewBox="0 0 24 24"
+ version="1.1"
+ id="svg6"
+ sodipodi:docname="qrcode.svg"
+ inkscape:version="0.92.3 (2405546, 2018-03-11)">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1280"
+ inkscape:window-height="1370"
+ id="namedview8"
+ showgrid="true"
+ inkscape:zoom="27.812867"
+ inkscape:cx="10.794985"
+ inkscape:cy="11.184682"
+ inkscape:window-x="3200"
+ inkscape:window-y="34"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg6">
+ <inkscape:grid
+ type="xygrid"
+ id="grid14" />
+ </sodipodi:namedview>
+ <title
+ id="title2">Clear</title>
+ <path
+ style="fill:#000000;stroke-width:3.1622777"
+ d="M 1 1 L 1 11 L 11 11 L 11 1 L 1 1 z M 3 3 L 9 3 L 9 9 L 3 9 L 3 3 z "
+ id="rect24-3" />
+ <rect
+ style="fill:#000000;stroke-width:3.1622777"
+ id="rect24-3-6-7"
+ width="2"
+ height="2"
+ x="5"
+ y="5" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#000000;stroke-width:3.1622777"
+ d="M 13,1 V 11 H 23 V 1 Z m 2,2 h 6 v 6 h -6 z"
+ id="rect24-3-5" />
+ <rect
+ style="fill:#000000;stroke-width:3.1622777"
+ id="rect24-3-6-7-3"
+ width="2"
+ height="2"
+ x="17"
+ y="5" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#000000;stroke-width:3.1622777"
+ d="M 1,13 V 23 H 11 V 13 Z m 2,2 h 6 v 6 H 3 Z"
+ id="rect24-3-5-5" />
+ <rect
+ style="fill:#000000;stroke-width:3.1622777"
+ id="rect24-3-6-7-3-6"
+ width="2"
+ height="2"
+ x="5"
+ y="17" />
+ <rect
+ style="fill:#000000;stroke-width:3.1622777"
+ id="rect24-3-6-7-3-2"
+ width="2"
+ height="2"
+ x="13"
+ y="13" />
+ <rect
+ style="fill:#000000;stroke-width:3.1622777"
+ id="rect24-3-6-7-3-9"
+ width="2"
+ height="2"
+ x="21"
+ y="21" />
+ <rect
+ style="fill:#000000;stroke-width:3.1622777"
+ id="rect24-3-6-7-3-1"
+ width="4"
+ height="2"
+ x="17"
+ y="13" />
+ <rect
+ style="fill:#000000;stroke-width:3.1622777"
+ id="rect24-3-6-7-3-1-2"
+ width="4"
+ height="2"
+ x="19"
+ y="15" />
+ <rect
+ style="fill:#000000;stroke-width:3.1622777"
+ id="rect24-3-6-7-3-1-2-7"
+ width="8"
+ height="2"
+ x="13"
+ y="19" />
+ <rect
+ style="fill:#000000;stroke-width:3.1622777"
+ id="rect24-3-6-7-3-1-2-0"
+ width="2"
+ height="4"
+ x="15"
+ y="15" />
+</svg>
diff --git a/resources.qrc b/resources.qrc
index 8043530b..8f4a80e7 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -33,6 +33,7 @@
<file alias="applications-system.svg">icons/applications-system.svg</file>
<file alias="edit-copy.svg">icons/edit-copy.svg</file>
<file alias="edit-clear.svg">icons/edit-clear.svg</file>
+ <file alias="qrcode.svg">icons/qrcode.svg</file>
<file alias="folder-new.svg">icons/folder-new.svg</file>
</qresource>
</RCC>
diff --git a/src/configdialog.cpp b/src/configdialog.cpp
index db72fb08..7ee438e7 100644
--- a/src/configdialog.cpp
+++ b/src/configdialog.cpp
@@ -62,6 +62,7 @@ ConfigDialog::ConfigDialog(MainWindow *parent)
#if defined(Q_OS_WIN) || defined(__APPLE__)
ui->checkBoxUseOtp->hide();
+ ui->checkBoxUseQrencode->hide();
ui->label_10->hide();
#endif
@@ -71,6 +72,12 @@ ConfigDialog::ConfigDialog(MainWindow *parent)
tr("Pass OTP extension needs to be installed"));
}
+ if (!isQrencodeAvailable()) {
+ ui->checkBoxUseQrencode->setEnabled(false);
+ ui->checkBoxUseQrencode->setToolTip(
+ tr("qrencode needs to be installed"));
+ }
+
setProfiles(QtPassSettings::getProfiles(), QtPassSettings::getProfile());
setPwgenPath(QtPassSettings::getPwgenExecutable());
setPasswordConfiguration(QtPassSettings::getPasswordConfiguration());
@@ -82,6 +89,7 @@ ConfigDialog::ConfigDialog(MainWindow *parent)
useGit(QtPassSettings::isUseGit());
useOtp(QtPassSettings::isUseOtp());
+ useQrencode(QtPassSettings::isUseQrencode());
usePwgen(QtPassSettings::isUsePwgen());
useTemplate(QtPassSettings::isUseTemplate());
@@ -206,6 +214,7 @@ void ConfigDialog::on_accepted() {
QtPassSettings::setProfiles(getProfiles());
QtPassSettings::setUseGit(ui->checkBoxUseGit->isChecked());
QtPassSettings::setUseOtp(ui->checkBoxUseOtp->isChecked());
+ QtPassSettings::setUseQrencode(ui->checkBoxUseQrencode->isChecked());
QtPassSettings::setPwgenExecutable(ui->pwgenPath->text());
QtPassSettings::setUsePwgen(ui->checkBoxUsePwgen->isChecked());
QtPassSettings::setAvoidCapitals(ui->checkBoxAvoidCapitals->isChecked());
@@ -540,6 +549,19 @@ void ConfigDialog::criticalMessage(const QString &title, const QString &text) {
QMessageBox::critical(this, title, text, QMessageBox::Ok, QMessageBox::Ok);
}
+bool ConfigDialog::isQrencodeAvailable() {
+#ifdef Q_OS_WIN
+ return false;
+#elif defined(__APPLE__)
+ return false;
+#else
+ QProcess which;
+ which.start("which", QStringList() << "qrencode");
+ which.waitForFinished();
+ return which.exitCode() == 0;
+#endif
+}
+
bool ConfigDialog::isPassOtpAvailable() {
#ifdef Q_OS_WIN
return false;
@@ -703,6 +725,14 @@ void ConfigDialog::useOtp(bool useOtp) {
}
/**
+ * @brief ConfigDialog::useOtp set preference for using otp plugin.
+ * @param useOtp
+ */
+void ConfigDialog::useQrencode(bool useQrencode) {
+ ui->checkBoxUseQrencode->setChecked(useQrencode);
+}
+
+/**
* @brief ConfigDialog::on_checkBoxUseGit_clicked enable or disable related
* checkboxes.
*/
diff --git a/src/configdialog.h b/src/configdialog.h
index b29c617e..24e2f047 100644
--- a/src/configdialog.h
+++ b/src/configdialog.h
@@ -37,6 +37,7 @@ public:
void useTrayIcon(bool useTrayIdon);
void useGit(bool useGit);
void useOtp(bool useOtp);
+ void useQrencode(bool useQrencode);
void setPwgenPath(QString);
void usePwgen(bool usePwgen);
void setPasswordConfiguration(const PasswordConfiguration &config);
@@ -86,6 +87,7 @@ private:
void criticalMessage(const QString &title, const QString &text);
bool isPassOtpAvailable();
+ bool isQrencodeAvailable();
void validate(QTableWidgetItem *item = nullptr);
MainWindow *mainWindow;
diff --git a/src/configdialog.ui b/src/configdialog.ui
index b0887218..93baf53e 100644
--- a/src/configdialog.ui
+++ b/src/configdialog.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>618</width>
- <height>609</height>
+ <width>659</width>
+ <height>650</height>
</rect>
</property>
<property name="sizePolicy">
@@ -518,6 +518,17 @@
</widget>
</item>
<item>
+ <layout class="QHBoxLayout" name="horizontalLayout_16">
+ <item>
+ <widget class="QCheckBox" name="checkBoxUseQrencode">
+ <property name="text">
+ <string>Use qrencode</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
<layout class="QHBoxLayout" name="horizontalLayout_14">
<item>
<widget class="QCheckBox" name="checkBoxUseOtp">
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 86a40aad..79844bd5 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -9,6 +9,7 @@
#include "keygendialog.h"
#include "passworddialog.h"
#include "qpushbuttonwithclipboard.h"
+#include "qpushbuttonasqrcode.h"
#include "qtpass.h"
#include "qtpasssettings.h"
#include "settingsconstants.h"
@@ -1031,6 +1032,16 @@ void MainWindow::addToGridLayout(int position, const QString &field,
frame->layout()->addWidget(fieldLabel);
}
+ if (QtPassSettings::isUseQrencode()) {
+ QPushButtonAsQRCode *qrbutton =
+ new QPushButtonAsQRCode(trimmedValue, this);
+ connect(qrbutton, &QPushButtonAsQRCode::clicked, m_qtPass,
+ &QtPass::showTextAsQRCode);
+ qrbutton->setStyleSheet("border-style: none ; background: transparent;");
+
+ frame->layout()->addWidget(qrbutton);
+ }
+
// set the echo mode to password, if the field is "password"
if (QtPassSettings::isHidePassword() && trimmedField == tr("Password")) {
QLineEdit *line = new QLineEdit();
diff --git a/src/qpushbuttonasqrcode.cpp b/src/qpushbuttonasqrcode.cpp
new file mode 100644
index 00000000..0d063ac5
--- /dev/null
+++ b/src/qpushbuttonasqrcode.cpp
@@ -0,0 +1,48 @@
+#include "qpushbuttonasqrcode.h"
+#include <QTimer>
+
+/**
+ * @brief QPushButtonAsQRCode::QPushButtonAsQRCode
+ * basic constructor
+ * @param textToCopy
+ * the text to display as qrcode
+ * @param parent
+ * the parent window
+ */
+QPushButtonAsQRCode::QPushButtonAsQRCode(const QString &textToCopy,
+ QWidget *parent)
+ : QPushButton(parent), textToCopy(textToCopy),
+ iconEdit(QIcon::fromTheme("qrcode", QIcon(":/icons/qrcode.svg"))) {
+ setIcon(iconEdit);
+ connect(this, SIGNAL(clicked(bool)), this, SLOT(buttonClicked(bool)));
+}
+
+/**
+ * @brief QPushButtonAsQRCode::getTextToCopy returns the text of
+ * associated text field
+ * @return QString textToCopy
+ */
+QString QPushButtonAsQRCode::getTextToCopy() const { return textToCopy; }
+
+/**
+ * @brief QPushButtonAsQRCode::setTextToCopy sets text from associated
+ * text field
+ * @param value QString text to be copied
+ */
+void QPushButtonAsQRCode::setTextToCopy(const QString &value) {
+ textToCopy = value;
+}
+
+/**
+ * @brief QPushButtonAsQRCode::buttonClicked handles clicked event by
+ * emitting clicked(QString) with string provided to constructor
+ */
+void QPushButtonAsQRCode::buttonClicked(bool) {
+ emit clicked(textToCopy);
+}
+
+/**
+ * @brief QPushButtonAsQRCode::changeIconDefault change the icon back to
+ * the default copy icon
+ */
+void QPushButtonAsQRCode::changeIconDefault() { this->setIcon(iconEdit); }
diff --git a/src/qpushbuttonasqrcode.h b/src/qpushbuttonasqrcode.h
new file mode 100644
index 00000000..d0fe5770
--- /dev/null
+++ b/src/qpushbuttonasqrcode.h
@@ -0,0 +1,33 @@
+#ifndef QPUSHBUTTONASQRCODE_H_
+#define QPUSHBUTTONASQRCODE_H_
+
+#include <QPushButton>
+
+/*!
+ \class QPushButtonAsQRCode
+ \brief Stylish widget to display the field as QR Code
+*/
+class QWidget;
+class QPushButtonAsQRCode : public QPushButton {
+ Q_OBJECT
+
+public:
+ explicit QPushButtonAsQRCode(const QString &textToCopy = "",
+ QWidget *parent = nullptr);
+
+ QString getTextToCopy() const;
+ void setTextToCopy(const QString &value);
+
+signals:
+ void clicked(QString);
+
+private slots:
+ void changeIconDefault();
+ void buttonClicked(bool);
+
+private:
+ QString textToCopy;
+ QIcon iconEdit;
+};
+
+#endif // QPUSHBUTTONASQRCODE_H_
diff --git a/src/qtpass.cpp b/src/qtpass.cpp
index 2239e86d..299b7469 100644
--- a/src/qtpass.cpp
+++ b/src/qtpass.cpp
@@ -3,6 +3,8 @@
#include "qtpasssettings.h"
#include <QApplication>
#include <QClipboard>
+#include <QPixmap>
+#include <QLabel>
#ifndef Q_OS_WIN
#include <QInputDialog>
@@ -402,3 +404,29 @@ void QtPass::copyTextToClipboard(const QString &text) {
clearClipboardTimer.start();
}
}
+
+/**
+ * @brief displays the text as qrcode
+ * @param text
+ */
+void QtPass::showTextAsQRCode(const QString &text) {
+ QProcess qrencode;
+ qrencode.start("/usr/bin/qrencode", QStringList() << "-o-" << "-tPNG");
+ qrencode.write(text.toUtf8());
+ qrencode.closeWriteChannel();
+ qrencode.waitForFinished();
+ QByteArray output(qrencode.readAllStandardOutput());
+
+ if (qrencode.exitStatus() || qrencode.exitCode()) {
+ QString error(qrencode.readAllStandardError());
+ m_mainWindow->showStatusMessage(error);
+ } else {
+ QPixmap image;
+ image.loadFromData(output, "PNG");
+
+ QLabel *label = new QLabel();
+ label->setPixmap(image);
+ label->setScaledContents(true);
+ label->show();
+ }
+}
diff --git a/src/qtpass.h b/src/qtpass.h
index f58337b1..05470d83 100644
--- a/src/qtpass.h
+++ b/src/qtpass.h
@@ -39,6 +39,7 @@ signals:
public slots:
void clearClipboard();
void copyTextToClipboard(const QString &text);
+ void showTextAsQRCode(const QString &text);
private slots:
void processError(QProcess::ProcessError);
diff --git a/src/qtpasssettings.cpp b/src/qtpasssettings.cpp
index a38c3159..90405a78 100644
--- a/src/qtpasssettings.cpp
+++ b/src/qtpasssettings.cpp
@@ -395,6 +395,14 @@ void QtPassSettings::setUseOtp(const bool &useOtp) {
getInstance()->setValue(SettingsConstants::useOtp, useOtp);
}
+bool QtPassSettings::isUseQrencode(const bool &defaultValue) {
+ return getInstance()->value(SettingsConstants::useQrencode, defaultValue).toBool();
+}
+
+void QtPassSettings::setUseQrencode(const bool &useQrencode) {
+ getInstance()->setValue(SettingsConstants::useQrencode, useQrencode);
+}
+
bool QtPassSettings::isUsePwgen(const bool &defaultValue) {
return getInstance()
->value(SettingsConstants::usePwgen, defaultValue)
diff --git a/src/qtpasssettings.h b/src/qtpasssettings.h
index aad36da6..3e5ce83d 100644
--- a/src/qtpasssettings.h
+++ b/src/qtpasssettings.h
@@ -144,6 +144,9 @@ public:
static bool isUseOtp(const bool &defaultValue = QVariant().toBool());
static void setUseOtp(const bool &useOtp);
+ static bool isUseQrencode(const bool &defaultValue = QVariant().toBool());
+ static void setUseQrencode(const bool &useQrencode);
+
static bool isUsePwgen(const bool &defaultValue = QVariant().toBool());
static void setUsePwgen(const bool &usePwgen);
diff --git a/src/settingsconstants.cpp b/src/settingsconstants.cpp
index 066931f3..75d5c4c8 100644
--- a/src/settingsconstants.cpp
+++ b/src/settingsconstants.cpp
@@ -44,6 +44,7 @@ const QString SettingsConstants::profile = "profile";
const QString SettingsConstants::groupProfiles = "profiles";
const QString SettingsConstants::useGit = "useGit";
const QString SettingsConstants::useOtp = "useOtp";
+const QString SettingsConstants::useQrencode = "useQrencode";
const QString SettingsConstants::useClipboard = "useClipboard";
const QString SettingsConstants::usePwgen = "usePwgen";
const QString SettingsConstants::avoidCapitals = "avoidCapitals";
diff --git a/src/settingsconstants.h b/src/settingsconstants.h
index 1b719c8e..33ff6e5e 100644
--- a/src/settingsconstants.h
+++ b/src/settingsconstants.h
@@ -41,6 +41,7 @@ public:
const static QString groupProfiles;
const static QString useGit;
const static QString useOtp;
+ const static QString useQrencode;
const static QString useClipboard;
const static QString usePwgen;
const static QString avoidCapitals;
diff --git a/src/src.pro b/src/src.pro
index 18d853ff..3906a0cd 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -17,6 +17,7 @@ SOURCES += mainwindow.cpp \
passworddialog.cpp \
qprogressindicator.cpp \
qpushbuttonwithclipboard.cpp \
+ qpushbuttonasqrcode.cpp \
qtpasssettings.cpp \
settingsconstants.cpp \
pass.cpp \
@@ -38,6 +39,7 @@ HEADERS += mainwindow.h \
qprogressindicator.h \
deselectabletreeview.h \
qpushbuttonwithclipboard.h \
+ qpushbuttonasqrcode.h \
qtpasssettings.h \
enums.h \
settingsconstants.h \