1 /*
2     This file is part of the KDE libraries
3     SPDX-FileCopyrightText: 2004 George Staikos <staikos@kde.org>
4 
5     SPDX-License-Identifier: LGPL-2.1-or-later
6 */
7 
8 #include "kwalletwizard.h"
9 
10 #include "ui_kwalletwizardpageexplanation.h"
11 #include "ui_kwalletwizardpageintro.h"
12 #include "ui_kwalletwizardpageoptions.h"
13 #include "ui_kwalletwizardpagepassword.h"
14 #ifdef HAVE_GPGMEPP
15 #include "ui_kwalletwizardpagegpgkey.h"
16 #include "ui_kwalletwizardpagepasswordgpg.h"
17 #endif
18 
19 #include <KLocalizedString>
20 #include <QButtonGroup>
21 #include <QDebug>
22 #include <QIcon>
23 
24 #ifdef HAVE_GPGMEPP
25 #include <KMessageBox>
26 #include <QComboBox>
27 #include <gpgme++/context.h>
28 #include <gpgme++/key.h>
29 #include <gpgme++/keylistresult.h>
30 #endif
31 
32 class PageIntro : public QWizardPage
33 {
34 public:
PageIntro(QWidget * parent)35     explicit PageIntro(QWidget *parent)
36         : QWizardPage(parent)
37     {
38         ui.setupUi(this);
39 
40         ui.ktitlewidget->setText("<h1>" + i18n("KWallet") + "</h1>");
41         ui.ktitlewidget->setIcon(QIcon::fromTheme(QStringLiteral("kwalletmanager")));
42 
43         bg = new QButtonGroup(this);
44         bg->setExclusive(true);
45         bg->addButton(ui._basic, 0);
46         bg->addButton(ui._advanced, 1);
47 
48         // force the "basic" button to be selected
49         ui._basic->setChecked(true);
50     }
51 
52     QButtonGroup *bg;
53 
54 private:
55     Ui::KWalletWizardPageIntro ui;
56 };
57 
58 class PagePassword : public QWizardPage
59 {
60 public:
PagePassword(KWalletWizard * parent)61     explicit PagePassword(KWalletWizard *parent)
62         : QWizardPage(parent)
63     {
64         ui.setupUi(this);
65 
66         registerField(QStringLiteral("useWallet"), ui._useWallet);
67         registerField(QStringLiteral("pass1"), ui._pass1);
68         registerField(QStringLiteral("pass2"), ui._pass2);
69 #ifdef HAVE_GPGMEPP
70         registerField(QStringLiteral("useGPG"), ui._radioGpg);
71         registerField(QStringLiteral("useBlowfish"), ui._radioBlowfish);
72         connect(ui._radioBlowfish, &QRadioButton::toggled, parent, &KWalletWizard::passwordPageUpdate);
73 #endif
74 
75         connect(ui._useWallet, &QCheckBox::clicked, parent, &KWalletWizard::passwordPageUpdate);
76         connect(ui._pass1, &QLineEdit::textChanged, parent, &KWalletWizard::passwordPageUpdate);
77         connect(ui._pass2, &QLineEdit::textChanged, parent, &KWalletWizard::passwordPageUpdate);
78         ui._useWallet->setChecked(true);
79     }
80 
nextId() const81     int nextId() const override
82     {
83 #ifdef HAVE_GPGMEPP
84         int nextId = -1;
85         if (field(QStringLiteral("useWallet")).toBool()) {
86             if (field(QStringLiteral("useBlowfish")).toBool()) {
87                 nextId = static_cast<KWalletWizard *>(wizard())->wizardType() == KWalletWizard::Basic
88                     ? -1
89                     : KWalletWizard::PageOptionsId; // same as non GPGMEPP case
90             } else {
91                 nextId = KWalletWizard::PageGpgKeyId;
92             }
93         }
94 
95         return nextId;
96 #else
97         return static_cast<KWalletWizard *>(wizard())->wizardType() == KWalletWizard::Basic ? -1 : KWalletWizard::PageOptionsId;
98 #endif
99     }
100 
setMatchLabelText(const QString & text)101     void setMatchLabelText(const QString &text)
102     {
103         ui._matchLabel->setText(text);
104     }
105 
106 private:
107 #ifdef HAVE_GPGMEPP
108     Ui::KWalletWizardPagePasswordGpg ui;
109 #else
110     Ui::KWalletWizardPagePassword ui;
111 #endif
112 };
113 
114 #ifdef HAVE_GPGMEPP
115 typedef std::vector<GpgME::Key> KeysVector;
116 Q_DECLARE_METATYPE(GpgME::Key)
117 
118 struct AddKeyToCombo {
119     QComboBox *_list;
AddKeyToComboAddKeyToCombo120     AddKeyToCombo(QComboBox *list)
121         : _list(list)
122     {
123     }
operator ()AddKeyToCombo124     void operator()(const GpgME::Key &k)
125     {
126         QString text = QStringLiteral("%1 (%2)").arg(k.shortKeyID(), k.userID(0).email());
127         QVariant varKey;
128         varKey.setValue(k);
129         _list->addItem(text, varKey);
130     }
131 };
132 
133 class PageGpgKey : public QWizardPage
134 {
135 public:
PageGpgKey(QWidget * parent)136     explicit PageGpgKey(QWidget *parent)
137         : QWizardPage(parent)
138         , userHasGpgKeys(false)
139     {
140         ui.setupUi(this);
141 
142         registerField(QStringLiteral("gpgKey"), ui._gpgKey);
143 
144         KeysVector keys;
145         GpgME::initializeLibrary();
146         GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP);
147         if (err) {
148             qDebug() << "OpenPGP not supported on your system!";
149             KMessageBox::error(
150                 this,
151                 i18n("The GpgME library failed to initialize for the OpenPGP protocol. Please check your system's configuration then try again."));
152         } else {
153             std::shared_ptr<GpgME::Context> ctx(GpgME::Context::createForProtocol(GpgME::OpenPGP));
154             if (nullptr == ctx) {
155                 KMessageBox::error(
156                     this,
157                     i18n("The GpgME library failed to initialize for the OpenPGP protocol. Please check your system's configuration then try again."));
158             } else {
159                 ctx->setKeyListMode(GpgME::KeyListMode::Local);
160                 err = ctx->startKeyListing();
161                 while (!err) {
162                     GpgME::Key k = ctx->nextKey(err);
163                     if (err) {
164                         break;
165                     }
166                     if (!k.isInvalid() && k.canEncrypt() && (k.ownerTrust() == GpgME::Key::Ultimate)) {
167                         keys.push_back(k);
168                     }
169                 }
170                 ctx->endKeyListing();
171             }
172         }
173         std::for_each(keys.begin(), keys.end(), AddKeyToCombo(ui._gpgKey));
174 
175         userHasGpgKeys = keys.size() > 0;
176         if (userHasGpgKeys) {
177             ui.stackedWidget->setCurrentWidget(ui._pageWhenHasKeys);
178         } else {
179             ui.stackedWidget->setCurrentWidget(ui._pageNoKeys);
180             setFinalPage(true);
181         }
182         Q_EMIT completeChanged();
183     }
184 
nextId() const185     int nextId() const override
186     {
187         return static_cast<KWalletWizard *>(wizard())->wizardType() == KWalletWizard::Basic ? -1 : KWalletWizard::PageOptionsId;
188     }
189 
isComplete() const190     bool isComplete() const override
191     {
192         return userHasGpgKeys;
193     }
194 
hasGpgKeys() const195     bool hasGpgKeys() const
196     {
197         return userHasGpgKeys;
198     }
199 
gpgKey() const200     GpgME::Key gpgKey() const
201     {
202         QVariant varKey = ui._gpgKey->itemData(field(QStringLiteral("gpgKey")).toInt());
203         return varKey.value<GpgME::Key>();
204     }
205 
206 private:
207     Ui::KWalletWizardPageGpgKey ui;
208     bool userHasGpgKeys;
209 };
210 #endif
211 
212 class PageOptions : public QWizardPage
213 {
214 public:
PageOptions(QWidget * parent)215     explicit PageOptions(QWidget *parent)
216         : QWizardPage(parent)
217     {
218         ui.setupUi(this);
219 
220         registerField(QStringLiteral("closeWhenIdle"), ui._closeIdle);
221         registerField(QStringLiteral("networkWallet"), ui._networkWallet);
222     }
223 
224 private:
225     Ui::KWalletWizardPageOptions ui;
226 };
227 
228 class PageExplanation : public QWizardPage
229 {
230 public:
PageExplanation(QWidget * parent)231     PageExplanation(QWidget *parent)
232         : QWizardPage(parent)
233     {
234         ui.setupUi(this);
235         setFinalPage(true);
236     }
237 
238 private:
239     Ui::KWalletWizardPageExplanation ui;
240 };
241 
KWalletWizard(QWidget * parent)242 KWalletWizard::KWalletWizard(QWidget *parent)
243     : QWizard(parent)
244 {
245     setOption(HaveFinishButtonOnEarlyPages);
246 
247     m_pageIntro = new PageIntro(this);
248     setPage(PageIntroId, m_pageIntro);
249     m_pagePasswd = new PagePassword(this);
250     setPage(PagePasswordId, m_pagePasswd);
251 #ifdef HAVE_GPGMEPP
252     m_pageGpgKey = new PageGpgKey(this);
253     setPage(PageGpgKeyId, m_pageGpgKey);
254 #endif
255     setPage(PageOptionsId, new PageOptions(this));
256     setPage(PageExplanationId, new PageExplanation(this));
257 
258     resize(500, 420);
259 }
260 
passwordPageUpdate()261 void KWalletWizard::passwordPageUpdate()
262 {
263     bool complete = true;
264     if (field(QStringLiteral("useWallet")).toBool()) {
265 #ifdef HAVE_GPGMEPP
266         if (field(QStringLiteral("useBlowfish")).toBool()) {
267             m_pagePasswd->setFinalPage(wizardType() == Basic);
268             button(NextButton)->setVisible(wizardType() != Basic);
269 #endif
270             if (field(QStringLiteral("pass1")).toString() == field(QStringLiteral("pass2")).toString()) {
271                 if (field(QStringLiteral("pass1")).toString().isEmpty()) {
272                     m_pagePasswd->setMatchLabelText(i18n("<qt>Password is empty.  <b>(WARNING: Insecure)</b></qt>"));
273                 } else {
274                     m_pagePasswd->setMatchLabelText(i18n("Passwords match."));
275                 }
276             } else {
277                 m_pagePasswd->setMatchLabelText(i18n("Passwords do not match."));
278                 complete = false;
279             }
280 #ifdef HAVE_GPGMEPP
281         } else {
282             m_pagePasswd->setFinalPage(false);
283             button(NextButton)->setEnabled(true);
284             return;
285         }
286 #endif
287     } else {
288         m_pagePasswd->setMatchLabelText(QString());
289     }
290     button(wizardType() == Basic ? FinishButton : NextButton)->setEnabled(complete);
291 }
292 
wizardType() const293 KWalletWizard::WizardType KWalletWizard::wizardType() const
294 {
295     return (KWalletWizard::WizardType)m_pageIntro->bg->checkedId();
296 }
297 
initializePage(int id)298 void KWalletWizard::initializePage(int id)
299 {
300     switch (id) {
301     case PagePasswordId: {
302         bool islast = m_pageIntro->bg->checkedId() == 0;
303         m_pagePasswd->setFinalPage(islast);
304         button(NextButton)->setVisible(!islast);
305         break;
306     }
307     }
308 }
309 
310 #ifdef HAVE_GPGMEPP
gpgKey() const311 GpgME::Key KWalletWizard::gpgKey() const
312 {
313     return m_pageGpgKey->gpgKey();
314 }
315 #endif
316