1 /*
2  *  Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
3  *
4  *  This program is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 2 or (at your option)
7  *  version 3 of the License.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "TotpExportSettingsDialog.h"
19 
20 #include "core/Config.h"
21 #include "core/Entry.h"
22 #include "gui/Clipboard.h"
23 #include "gui/DatabaseWidget.h"
24 #include "gui/MainWindow.h"
25 #include "gui/SquareSvgWidget.h"
26 #include "qrcode/QrCode.h"
27 #include "totp/totp.h"
28 
29 #include <QBuffer>
30 #include <QDialogButtonBox>
31 #include <QLabel>
32 #include <QMessageBox>
33 #include <QPushButton>
34 #include <QShortcut>
35 #include <QSizePolicy>
36 #include <QVBoxLayout>
37 
TotpExportSettingsDialog(DatabaseWidget * parent,Entry * entry)38 TotpExportSettingsDialog::TotpExportSettingsDialog(DatabaseWidget* parent, Entry* entry)
39     : QDialog(parent)
40     , m_timer(new QTimer(this))
41     , m_verticalLayout(new QVBoxLayout())
42     , m_totpSvgWidget(new SquareSvgWidget())
43     , m_countDown(new QLabel())
44     , m_warningLabel(new QLabel())
45     , m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Close | QDialogButtonBox::Ok))
46 {
47     m_verticalLayout->addWidget(m_warningLabel);
48     m_verticalLayout->addItem(new QSpacerItem(0, 0));
49 
50     m_verticalLayout->addStretch(0);
51     m_verticalLayout->addWidget(m_totpSvgWidget);
52     m_verticalLayout->addStretch(0);
53     m_verticalLayout->addWidget(m_countDown);
54     m_verticalLayout->addWidget(m_buttonBox);
55 
56     setLayout(m_verticalLayout);
57     setAttribute(Qt::WA_DeleteOnClose);
58 
59     connect(m_buttonBox, SIGNAL(rejected()), SLOT(close()));
60     connect(m_buttonBox, SIGNAL(accepted()), SLOT(copyToClipboard()));
61     connect(m_timer, SIGNAL(timeout()), SLOT(autoClose()));
62 
63     new QShortcut(QKeySequence(QKeySequence::Copy), this, SLOT(copyToClipboard()));
64 
65     m_buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Copy"));
66     m_buttonBox->setFocus();
67     m_countDown->setAlignment(Qt::AlignCenter);
68 
69     m_secTillClose = 45;
70     autoClose();
71     m_timer->start(1000);
72 
73     const auto totpSettings = entry->totpSettings();
74     if (totpSettings->custom || !totpSettings->encoder.shortName.isEmpty()) {
75         m_warningLabel->setWordWrap(true);
76         m_warningLabel->setMargin(5);
77         m_warningLabel->setText(tr("NOTE: These TOTP settings are custom and may not work with other authenticators.",
78                                    "TOTP QR code dialog warning"));
79     } else {
80         m_warningLabel->hide();
81     }
82 
83     m_totpUri = Totp::writeSettings(entry->totpSettings(), entry->title(), entry->username(), true);
84     const QrCode qrc(m_totpUri);
85 
86     if (qrc.isValid()) {
87         QBuffer buffer;
88         qrc.writeSvg(&buffer, logicalDpiX());
89         m_totpSvgWidget->load(buffer.data());
90         const int minsize = static_cast<int>(logicalDpiX() * 2.5);
91         m_totpSvgWidget->setMinimumSize(minsize, minsize);
92     } else {
93         auto errorBox = new QMessageBox(parent);
94         errorBox->setAttribute(Qt::WA_DeleteOnClose);
95         errorBox->setIcon(QMessageBox::Warning);
96         errorBox->setText(tr("There was an error creating the QR code."));
97         errorBox->exec();
98         close();
99     }
100 }
101 
copyToClipboard()102 void TotpExportSettingsDialog::copyToClipboard()
103 {
104     clipboard()->setText(m_totpUri);
105     if (config()->get(Config::HideWindowOnCopy).toBool()) {
106         if (config()->get(Config::MinimizeOnCopy).toBool()) {
107             getMainWindow()->minimizeOrHide();
108         } else if (config()->get(Config::DropToBackgroundOnCopy).toBool()) {
109             getMainWindow()->lower();
110             window()->lower();
111         }
112     }
113 }
114 
autoClose()115 void TotpExportSettingsDialog::autoClose()
116 {
117     if (--m_secTillClose > 0) {
118         m_countDown->setText(tr("Closing in %1 seconds.").arg(m_secTillClose));
119     } else {
120         m_timer->stop();
121         close();
122     }
123 }
124 
125 TotpExportSettingsDialog::~TotpExportSettingsDialog() = default;
126