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