diff options
author | Anne Jan Brouwer <brouwer@annejan.com> | 2019-04-17 11:29:57 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-17 11:29:57 +0200 |
commit | 0789259aa59a565ba6c899a8c4e8da88fd5f5637 (patch) | |
tree | a62bf49adbdada3ffb40b261b7ae2bcbce243470 | |
parent | 3698ff096cffec3541253ba1e745c389df0118c2 (diff) | |
parent | 57c24f5a7cbcfc52ec3e56be7d04421669f457b8 (diff) |
Merge pull request #421 from frawi/master
Display passwords as QR codes
-rw-r--r-- | icons/qrcode.svg | 133 | ||||
-rw-r--r-- | resources.qrc | 1 | ||||
-rw-r--r-- | src/configdialog.cpp | 30 | ||||
-rw-r--r-- | src/configdialog.h | 2 | ||||
-rw-r--r-- | src/configdialog.ui | 15 | ||||
-rw-r--r-- | src/mainwindow.cpp | 11 | ||||
-rw-r--r-- | src/qpushbuttonasqrcode.cpp | 48 | ||||
-rw-r--r-- | src/qpushbuttonasqrcode.h | 33 | ||||
-rw-r--r-- | src/qtpass.cpp | 28 | ||||
-rw-r--r-- | src/qtpass.h | 1 | ||||
-rw-r--r-- | src/qtpasssettings.cpp | 8 | ||||
-rw-r--r-- | src/qtpasssettings.h | 3 | ||||
-rw-r--r-- | src/settingsconstants.cpp | 1 | ||||
-rw-r--r-- | src/settingsconstants.h | 1 | ||||
-rw-r--r-- | src/src.pro | 2 |
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 \ |