File indexing completed on 2024-05-12 05:22:37
0001 /* 0002 autotests/newkeyapprovaldialogtest.cpp 0003 0004 This file is part of libkleopatra's test suite. 0005 SPDX-FileCopyrightText: 2021 g10 Code GmbH 0006 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include <Libkleo/Compliance> 0012 #include <Libkleo/Formatting> 0013 #include <Libkleo/KeyCache> 0014 #include <Libkleo/KeySelectionCombo> 0015 #include <Libkleo/NewKeyApprovalDialog> 0016 #include <Libkleo/Predicates> 0017 #include <Libkleo/Test> 0018 0019 #include <QCheckBox> 0020 #include <QGroupBox> 0021 #include <QLabel> 0022 #include <QObject> 0023 #include <QPushButton> 0024 #include <QRadioButton> 0025 #include <QSignalSpy> 0026 #include <QTest> 0027 0028 #include <gpgme++/key.h> 0029 0030 #include <gpgme.h> 0031 0032 #include <memory> 0033 #include <set> 0034 0035 #include <gpgme++/gpgmepp_version.h> 0036 #if GPGMEPP_VERSION >= 0x11700 // 1.23.0 0037 #define GPGMEPP_KEY_HAS_HASCERTIFY_SIGN_ENCRYPT_AUTHENTICATE 1 0038 #else 0039 #define GPGMEPP_KEY_HAS_HASCERTIFY_SIGN_ENCRYPT_AUTHENTICATE 0 0040 #endif 0041 0042 using namespace Kleo; 0043 0044 namespace QTest 0045 { 0046 template<> 0047 inline char *toString(const bool &t) 0048 { 0049 return t ? qstrdup("true") : qstrdup("false"); 0050 } 0051 0052 template<> 0053 inline bool qCompare(bool const &t1, bool const &t2, const char *actual, const char *expected, const char *file, int line) 0054 { 0055 return compare_helper(t1 == t2, "Compared values are not the same", toString(t1), toString(t2), actual, expected, file, line); 0056 } 0057 0058 template<> 0059 inline char *toString(const GpgME::Protocol &t) 0060 { 0061 return qstrdup(Formatting::displayName(t).toLocal8Bit().constData()); 0062 } 0063 0064 template<> 0065 inline bool qCompare(GpgME::Protocol const &t1, GpgME::Protocol const &t2, const char *actual, const char *expected, const char *file, int line) 0066 { 0067 return compare_helper(t1 == t2, "Compared values are not the same", toString(t1), toString(t2), actual, expected, file, line); 0068 } 0069 } 0070 0071 namespace 0072 { 0073 0074 // copied from NewKeyApprovalDialog::Private 0075 enum Action { 0076 Unset, 0077 GenerateKey, 0078 IgnoreKey, 0079 }; 0080 0081 auto mapValidity(GpgME::UserID::Validity validity) 0082 { 0083 switch (validity) { 0084 default: 0085 case GpgME::UserID::Unknown: 0086 return GPGME_VALIDITY_UNKNOWN; 0087 case GpgME::UserID::Undefined: 0088 return GPGME_VALIDITY_UNDEFINED; 0089 case GpgME::UserID::Never: 0090 return GPGME_VALIDITY_NEVER; 0091 case GpgME::UserID::Marginal: 0092 return GPGME_VALIDITY_MARGINAL; 0093 case GpgME::UserID::Full: 0094 return GPGME_VALIDITY_FULL; 0095 case GpgME::UserID::Ultimate: 0096 return GPGME_VALIDITY_ULTIMATE; 0097 } 0098 } 0099 0100 // copied from gpgme; slightly modified 0101 void _gpgme_key_add_subkey(gpgme_key_t key, gpgme_subkey_t *r_subkey) 0102 { 0103 gpgme_subkey_t subkey; 0104 0105 subkey = static_cast<gpgme_subkey_t>(calloc(1, sizeof *subkey)); 0106 Q_ASSERT(subkey); 0107 subkey->keyid = subkey->_keyid; 0108 subkey->_keyid[16] = '\0'; 0109 0110 if (!key->subkeys) { 0111 key->subkeys = subkey; 0112 } 0113 if (key->_last_subkey) { 0114 key->_last_subkey->next = subkey; 0115 } 0116 key->_last_subkey = subkey; 0117 0118 *r_subkey = subkey; 0119 } 0120 0121 GpgME::Key createTestKey(const char *uid, 0122 GpgME::Protocol protocol = GpgME::UnknownProtocol, 0123 KeyCache::KeyUsage usage = KeyCache::KeyUsage::AnyUsage, 0124 GpgME::UserID::Validity validity = GpgME::UserID::Full) 0125 { 0126 static int count = 0; 0127 count++; 0128 0129 gpgme_key_t key; 0130 gpgme_key_from_uid(&key, uid); 0131 Q_ASSERT(key); 0132 Q_ASSERT(key->uids); 0133 if (protocol != GpgME::UnknownProtocol) { 0134 key->protocol = protocol == GpgME::OpenPGP ? GPGME_PROTOCOL_OpenPGP : GPGME_PROTOCOL_CMS; 0135 } 0136 const QByteArray fingerprint = QByteArray::number(count, 16).rightJustified(40, '0'); 0137 key->fpr = strdup(fingerprint.constData()); 0138 key->revoked = 0; 0139 key->expired = 0; 0140 key->disabled = 0; 0141 key->can_encrypt = int(usage == KeyCache::KeyUsage::AnyUsage || usage == KeyCache::KeyUsage::Encrypt); 0142 key->can_sign = int(usage == KeyCache::KeyUsage::AnyUsage || usage == KeyCache::KeyUsage::Sign); 0143 #if GPGMEPP_KEY_HAS_HASCERTIFY_SIGN_ENCRYPT_AUTHENTICATE 0144 key->has_encrypt = int(usage == KeyCache::KeyUsage::AnyUsage || usage == KeyCache::KeyUsage::Encrypt); 0145 key->has_sign = int(usage == KeyCache::KeyUsage::AnyUsage || usage == KeyCache::KeyUsage::Sign); 0146 #endif 0147 key->secret = 1; 0148 key->uids->validity = mapValidity(validity); 0149 key->keylist_mode = GPGME_KEYLIST_MODE_VALIDATE; 0150 0151 // add a usable VS-NfD-compliant subkey 0152 gpgme_subkey_t subkey; 0153 _gpgme_key_add_subkey(key, &subkey); 0154 subkey->is_de_vs = 1; 0155 subkey->can_encrypt = key->can_encrypt; 0156 subkey->can_sign = key->can_sign; 0157 0158 return GpgME::Key(key, false); 0159 } 0160 0161 auto testKey(const char *address, GpgME::Protocol protocol = GpgME::UnknownProtocol) 0162 { 0163 const auto email = GpgME::UserID::addrSpecFromString(address); 0164 const auto keys = KeyCache::instance()->findByEMailAddress(email); 0165 for (const auto &key : keys) { 0166 if (protocol == GpgME::UnknownProtocol || key.protocol() == protocol) { 0167 return key; 0168 } 0169 } 0170 return GpgME::Key(); 0171 } 0172 0173 void waitForKeySelectionCombosBeingInitialized(const QDialog *dialog) 0174 { 0175 QVERIFY(dialog); 0176 auto combo = dialog->findChild<KeySelectionCombo *>(); 0177 QVERIFY(combo); 0178 0179 const auto spy = std::make_unique<QSignalSpy>(combo, &KeySelectionCombo::keyListingFinished); 0180 QVERIFY(spy->isValid()); 0181 QVERIFY(spy->wait(10)); 0182 } 0183 0184 template<typename T> 0185 struct Widgets { 0186 std::vector<T *> visible; 0187 std::vector<T *> hidden; 0188 }; 0189 0190 template<typename T> 0191 Widgets<T> visibleAndHiddenWidgets(const QList<T *> &widgets) 0192 { 0193 Widgets<T> result; 0194 std::partition_copy(std::begin(widgets), 0195 std::end(widgets), 0196 std::back_inserter(result.visible), 0197 std::back_inserter(result.hidden), 0198 std::mem_fn(&QWidget::isVisible)); 0199 return result; 0200 } 0201 0202 enum Visibility { 0203 IsHidden, 0204 IsVisible, 0205 }; 0206 0207 enum CheckedState { 0208 IsUnchecked, 0209 IsChecked, 0210 }; 0211 0212 template<typename T> 0213 void verifyProtocolButton(const T *button, Visibility expectedVisibility, CheckedState expectedCheckedState) 0214 { 0215 QVERIFY(button); 0216 QCOMPARE(button->isVisible(), expectedVisibility == IsVisible); 0217 QCOMPARE(button->isChecked(), expectedCheckedState == IsChecked); 0218 } 0219 0220 template<typename T> 0221 void verifyWidgetVisibility(const T *widget, Visibility expectedVisibility) 0222 { 0223 QVERIFY(widget); 0224 QCOMPARE(widget->isVisible(), expectedVisibility == IsVisible); 0225 } 0226 0227 template<typename T> 0228 void verifyWidgetsVisibility(const QList<T> &widgets, Visibility expectedVisibility) 0229 { 0230 for (auto w : widgets) { 0231 verifyWidgetVisibility(w, expectedVisibility); 0232 } 0233 } 0234 0235 void verifyProtocolLabels(const QList<QLabel *> &labels, int expectedNumber, Visibility expectedVisibility) 0236 { 0237 QCOMPARE(labels.size(), expectedNumber); 0238 verifyWidgetsVisibility(labels, expectedVisibility); 0239 } 0240 0241 bool listsOfKeysAreEqual(const std::vector<GpgME::Key> &l1, const std::vector<GpgME::Key> &l2) 0242 { 0243 return std::equal(std::begin(l1), std::end(l1), std::begin(l2), std::end(l2), ByFingerprint<std::equal_to>()); 0244 } 0245 0246 void verifySolution(const KeyResolver::Solution &actual, const KeyResolver::Solution &expected) 0247 { 0248 QCOMPARE(actual.protocol, expected.protocol); 0249 0250 QVERIFY(listsOfKeysAreEqual(actual.signingKeys, expected.signingKeys)); 0251 0252 QVERIFY(std::equal(actual.encryptionKeys.constKeyValueBegin(), 0253 actual.encryptionKeys.constKeyValueEnd(), 0254 expected.encryptionKeys.constKeyValueBegin(), 0255 expected.encryptionKeys.constKeyValueEnd(), 0256 [](const auto &kv1, const auto &kv2) { 0257 return kv1.first == kv2.first && listsOfKeysAreEqual(kv1.second, kv2.second); 0258 })); 0259 } 0260 0261 void switchKeySelectionCombosFromGenerateKeyToIgnoreKey(const QList<KeySelectionCombo *> &combos) 0262 { 0263 for (auto combo : combos) { 0264 if (combo->currentData(Qt::UserRole).toInt() == GenerateKey) { 0265 const auto ignoreIndex = combo->findData(IgnoreKey); 0266 QVERIFY(ignoreIndex != -1); 0267 combo->setCurrentIndex(ignoreIndex); 0268 } 0269 } 0270 } 0271 0272 } 0273 0274 class NewKeyApprovalDialogTest : public QObject 0275 { 0276 Q_OBJECT 0277 0278 private Q_SLOTS: 0279 void init() 0280 { 0281 // hold a reference to the key cache to avoid rebuilding while the test is running 0282 mKeyCache = KeyCache::instance(); 0283 0284 KeyCache::mutableInstance()->setKeys({ 0285 createTestKey("sender@example.net", GpgME::OpenPGP, KeyCache::KeyCache::KeyUsage::AnyUsage), 0286 createTestKey("sender@example.net", GpgME::CMS, KeyCache::KeyCache::KeyUsage::AnyUsage), 0287 createTestKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP, KeyCache::KeyCache::KeyUsage::Encrypt), 0288 createTestKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS, KeyCache::KeyCache::KeyUsage::Encrypt), 0289 createTestKey("Marginal Validity <marginal-openpgp@example.net>", GpgME::OpenPGP, KeyCache::KeyCache::KeyUsage::Encrypt, GpgME::UserID::Marginal), 0290 }); 0291 } 0292 0293 void cleanup() 0294 { 0295 // verify that nobody else holds a reference to the key cache 0296 QVERIFY(mKeyCache.use_count() == 1); 0297 mKeyCache.reset(); 0298 } 0299 0300 void test__verify_test_keys() 0301 { 0302 QVERIFY(!testKey("sender@example.net", GpgME::OpenPGP).isNull()); 0303 QVERIFY(!testKey("sender@example.net", GpgME::CMS).isNull()); 0304 QVERIFY(!testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP).isNull()); 0305 QVERIFY(!testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS).isNull()); 0306 QVERIFY(!testKey("Marginal Validity <marginal-openpgp@example.net>", GpgME::OpenPGP).isNull()); 0307 } 0308 0309 void test__both_protocols_allowed__mixed_not_allowed__openpgp_preferred() 0310 { 0311 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0312 const bool allowMixed = false; 0313 const QString sender = QStringLiteral("sender@example.net"); 0314 const KeyResolver::Solution preferredSolution = { 0315 GpgME::OpenPGP, 0316 {testKey("sender@example.net", GpgME::OpenPGP)}, 0317 { 0318 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 0319 {QStringLiteral("prefer-smime@example.net"), {}}, 0320 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP)}}, 0321 }, 0322 }; 0323 const KeyResolver::Solution alternativeSolution = { 0324 GpgME::CMS, 0325 {testKey("sender@example.net", GpgME::CMS)}, 0326 { 0327 {QStringLiteral("prefer-openpgp@example.net"), {}}, 0328 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 0329 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::CMS)}}, 0330 }, 0331 }; 0332 0333 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0334 dialog->show(); 0335 0336 verifyProtocolButton(dialog->findChild<QRadioButton *>(QStringLiteral("openpgp button")), IsVisible, IsChecked); 0337 verifyProtocolButton(dialog->findChild<QRadioButton *>(QStringLiteral("smime button")), IsVisible, IsUnchecked); 0338 const auto signingKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("signing key"))); 0339 QCOMPARE(signingKeyWidgets.visible.size(), 1); 0340 QCOMPARE(signingKeyWidgets.hidden.size(), 1); 0341 QCOMPARE(signingKeyWidgets.visible[0]->defaultKey(GpgME::OpenPGP), preferredSolution.signingKeys[0].primaryFingerprint()); 0342 QCOMPARE(signingKeyWidgets.hidden[0]->defaultKey(GpgME::CMS), alternativeSolution.signingKeys[0].primaryFingerprint()); 0343 0344 const auto encryptionKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("encryption key"))); 0345 QCOMPARE(encryptionKeyWidgets.visible.size(), 3); 0346 QCOMPARE(encryptionKeyWidgets.hidden.size(), 3); 0347 0348 // encryption key widgets for sender come first (visible for OpenPGP, hidden for S/MIME) 0349 QCOMPARE(encryptionKeyWidgets.visible[0]->property("address").toString(), sender); 0350 QCOMPARE(encryptionKeyWidgets.visible[0]->defaultKey(GpgME::OpenPGP), preferredSolution.encryptionKeys.value(sender)[0].primaryFingerprint()); 0351 QCOMPARE(encryptionKeyWidgets.hidden[0]->property("address").toString(), sender); 0352 QCOMPARE(encryptionKeyWidgets.hidden[0]->defaultKey(GpgME::CMS), alternativeSolution.encryptionKeys.value(sender)[0].primaryFingerprint()); 0353 0354 // encryption key widgets for other recipients follow (visible for OpenPGP, hidden for S/MIME) 0355 QCOMPARE(encryptionKeyWidgets.visible[1]->property("address").toString(), "prefer-openpgp@example.net"); 0356 QCOMPARE(encryptionKeyWidgets.visible[1]->defaultKey(GpgME::OpenPGP), 0357 preferredSolution.encryptionKeys.value("prefer-openpgp@example.net")[0].primaryFingerprint()); 0358 QCOMPARE(encryptionKeyWidgets.hidden[1]->property("address").toString(), "prefer-openpgp@example.net"); 0359 QVERIFY(encryptionKeyWidgets.hidden[1]->defaultKey(GpgME::CMS).isEmpty()); 0360 QCOMPARE(encryptionKeyWidgets.visible[2]->property("address").toString(), "prefer-smime@example.net"); 0361 QVERIFY(encryptionKeyWidgets.visible[2]->defaultKey(GpgME::OpenPGP).isEmpty()); 0362 QCOMPARE(encryptionKeyWidgets.hidden[2]->property("address").toString(), "prefer-smime@example.net"); 0363 QCOMPARE(encryptionKeyWidgets.hidden[2]->defaultKey(GpgME::CMS), 0364 alternativeSolution.encryptionKeys.value("prefer-smime@example.net")[0].primaryFingerprint()); 0365 } 0366 0367 void test__both_protocols_allowed__mixed_not_allowed__smime_preferred() 0368 { 0369 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0370 const bool allowMixed = false; 0371 const QString sender = QStringLiteral("sender@example.net"); 0372 const KeyResolver::Solution preferredSolution = { 0373 GpgME::CMS, 0374 {testKey("sender@example.net", GpgME::CMS)}, 0375 { 0376 {QStringLiteral("prefer-openpgp@example.net"), {}}, 0377 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 0378 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::CMS)}}, 0379 }, 0380 }; 0381 const KeyResolver::Solution alternativeSolution = { 0382 GpgME::OpenPGP, 0383 {testKey("sender@example.net", GpgME::OpenPGP)}, 0384 { 0385 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 0386 {QStringLiteral("prefer-smime@example.net"), {}}, 0387 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP)}}, 0388 }, 0389 }; 0390 0391 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0392 dialog->show(); 0393 0394 verifyProtocolButton(dialog->findChild<QRadioButton *>(QStringLiteral("openpgp button")), IsVisible, IsUnchecked); 0395 verifyProtocolButton(dialog->findChild<QRadioButton *>(QStringLiteral("smime button")), IsVisible, IsChecked); 0396 const auto signingKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("signing key"))); 0397 QCOMPARE(signingKeyWidgets.visible.size(), 1); 0398 QCOMPARE(signingKeyWidgets.hidden.size(), 1); 0399 QCOMPARE(signingKeyWidgets.visible[0]->defaultKey(GpgME::CMS), preferredSolution.signingKeys[0].primaryFingerprint()); 0400 QCOMPARE(signingKeyWidgets.hidden[0]->defaultKey(GpgME::OpenPGP), alternativeSolution.signingKeys[0].primaryFingerprint()); 0401 0402 const auto encryptionKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("encryption key"))); 0403 QCOMPARE(encryptionKeyWidgets.visible.size(), 3); 0404 QCOMPARE(encryptionKeyWidgets.hidden.size(), 3); 0405 0406 // encryption key widgets for sender come first (visible for S/MIME, hidden for OpenPGP) 0407 QCOMPARE(encryptionKeyWidgets.visible[0]->property("address").toString(), sender); 0408 QCOMPARE(encryptionKeyWidgets.visible[0]->defaultKey(GpgME::CMS), preferredSolution.encryptionKeys.value(sender)[0].primaryFingerprint()); 0409 QCOMPARE(encryptionKeyWidgets.hidden[0]->property("address").toString(), sender); 0410 QCOMPARE(encryptionKeyWidgets.hidden[0]->defaultKey(GpgME::OpenPGP), alternativeSolution.encryptionKeys.value(sender)[0].primaryFingerprint()); 0411 0412 // encryption key widgets for other recipients follow (visible for OpenPGP, hidden for S/MIME) 0413 QCOMPARE(encryptionKeyWidgets.visible[1]->property("address").toString(), "prefer-openpgp@example.net"); 0414 QVERIFY(encryptionKeyWidgets.visible[1]->defaultKey(GpgME::CMS).isEmpty()); 0415 QCOMPARE(encryptionKeyWidgets.hidden[1]->property("address").toString(), "prefer-openpgp@example.net"); 0416 QCOMPARE(encryptionKeyWidgets.hidden[1]->defaultKey(GpgME::OpenPGP), 0417 alternativeSolution.encryptionKeys.value("prefer-openpgp@example.net")[0].primaryFingerprint()); 0418 QCOMPARE(encryptionKeyWidgets.visible[2]->property("address").toString(), "prefer-smime@example.net"); 0419 QCOMPARE(encryptionKeyWidgets.visible[2]->defaultKey(GpgME::CMS), 0420 preferredSolution.encryptionKeys.value("prefer-smime@example.net")[0].primaryFingerprint()); 0421 QCOMPARE(encryptionKeyWidgets.hidden[2]->property("address").toString(), "prefer-smime@example.net"); 0422 QVERIFY(encryptionKeyWidgets.hidden[2]->defaultKey(GpgME::OpenPGP).isEmpty()); 0423 } 0424 0425 void test__openpgp_only() 0426 { 0427 const GpgME::Protocol forcedProtocol = GpgME::OpenPGP; 0428 const bool allowMixed = false; 0429 const QString sender = QStringLiteral("sender@example.net"); 0430 const KeyResolver::Solution preferredSolution = { 0431 GpgME::OpenPGP, 0432 {testKey("sender@example.net", GpgME::OpenPGP)}, 0433 { 0434 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 0435 {QStringLiteral("prefer-smime@example.net"), {}}, 0436 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP)}}, 0437 }, 0438 }; 0439 const KeyResolver::Solution alternativeSolution = {}; 0440 0441 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0442 dialog->show(); 0443 0444 verifyProtocolButton(dialog->findChild<QRadioButton *>(QStringLiteral("openpgp button")), IsHidden, IsChecked); 0445 verifyProtocolButton(dialog->findChild<QRadioButton *>(QStringLiteral("smime button")), IsHidden, IsUnchecked); 0446 const auto signingKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("signing key"))); 0447 QCOMPARE(signingKeyWidgets.visible.size(), 1); 0448 QCOMPARE(signingKeyWidgets.hidden.size(), 0); 0449 QCOMPARE(signingKeyWidgets.visible[0]->defaultKey(GpgME::OpenPGP), preferredSolution.signingKeys[0].primaryFingerprint()); 0450 0451 const auto encryptionKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("encryption key"))); 0452 QCOMPARE(encryptionKeyWidgets.visible.size(), 3); 0453 QCOMPARE(encryptionKeyWidgets.hidden.size(), 0); 0454 0455 // encryption key widget for sender comes first 0456 QCOMPARE(encryptionKeyWidgets.visible[0]->property("address").toString(), sender); 0457 QCOMPARE(encryptionKeyWidgets.visible[0]->defaultKey(GpgME::OpenPGP), preferredSolution.encryptionKeys.value(sender)[0].primaryFingerprint()); 0458 0459 // encryption key widgets for other recipients follow 0460 QCOMPARE(encryptionKeyWidgets.visible[1]->property("address").toString(), "prefer-openpgp@example.net"); 0461 QCOMPARE(encryptionKeyWidgets.visible[1]->defaultKey(GpgME::OpenPGP), 0462 preferredSolution.encryptionKeys.value("prefer-openpgp@example.net")[0].primaryFingerprint()); 0463 QCOMPARE(encryptionKeyWidgets.visible[2]->property("address").toString(), "prefer-smime@example.net"); 0464 QVERIFY(encryptionKeyWidgets.visible[2]->defaultKey(GpgME::OpenPGP).isEmpty()); 0465 } 0466 0467 void test__smime_only() 0468 { 0469 const GpgME::Protocol forcedProtocol = GpgME::CMS; 0470 const bool allowMixed = false; 0471 const QString sender = QStringLiteral("sender@example.net"); 0472 const KeyResolver::Solution preferredSolution = { 0473 GpgME::CMS, 0474 {testKey("sender@example.net", GpgME::CMS)}, 0475 { 0476 {QStringLiteral("prefer-openpgp@example.net"), {}}, 0477 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 0478 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::CMS)}}, 0479 }, 0480 }; 0481 const KeyResolver::Solution alternativeSolution = {}; 0482 0483 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0484 dialog->show(); 0485 0486 verifyProtocolButton(dialog->findChild<QRadioButton *>(QStringLiteral("openpgp button")), IsHidden, IsUnchecked); 0487 verifyProtocolButton(dialog->findChild<QRadioButton *>(QStringLiteral("smime button")), IsHidden, IsChecked); 0488 const auto signingKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("signing key"))); 0489 QCOMPARE(signingKeyWidgets.visible.size(), 1); 0490 QCOMPARE(signingKeyWidgets.hidden.size(), 0); 0491 QCOMPARE(signingKeyWidgets.visible[0]->defaultKey(GpgME::CMS), preferredSolution.signingKeys[0].primaryFingerprint()); 0492 0493 const auto encryptionKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("encryption key"))); 0494 QCOMPARE(encryptionKeyWidgets.visible.size(), 3); 0495 QCOMPARE(encryptionKeyWidgets.hidden.size(), 0); 0496 0497 // encryption key widget for sender comes first 0498 QCOMPARE(encryptionKeyWidgets.visible[0]->property("address").toString(), sender); 0499 QCOMPARE(encryptionKeyWidgets.visible[0]->defaultKey(GpgME::CMS), preferredSolution.encryptionKeys.value(sender)[0].primaryFingerprint()); 0500 0501 // encryption key widgets for other recipients follow 0502 QCOMPARE(encryptionKeyWidgets.visible[1]->property("address").toString(), "prefer-openpgp@example.net"); 0503 QVERIFY(encryptionKeyWidgets.visible[1]->defaultKey(GpgME::CMS).isEmpty()); 0504 QCOMPARE(encryptionKeyWidgets.visible[2]->property("address").toString(), "prefer-smime@example.net"); 0505 QCOMPARE(encryptionKeyWidgets.visible[2]->defaultKey(GpgME::CMS), 0506 preferredSolution.encryptionKeys.value("prefer-smime@example.net")[0].primaryFingerprint()); 0507 } 0508 0509 void test__both_protocols_allowed__mixed_allowed() 0510 { 0511 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0512 const bool allowMixed = true; 0513 const QString sender = QStringLiteral("sender@example.net"); 0514 const KeyResolver::Solution preferredSolution = { 0515 GpgME::UnknownProtocol, 0516 {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}, 0517 { 0518 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 0519 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 0520 {QStringLiteral("unknown@example.net"), {}}, 0521 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}}, 0522 }, 0523 }; 0524 const KeyResolver::Solution alternativeSolution = {}; 0525 0526 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0527 dialog->show(); 0528 0529 verifyProtocolButton(dialog->findChild<QCheckBox *>(QStringLiteral("openpgp button")), IsVisible, IsChecked); 0530 verifyProtocolButton(dialog->findChild<QCheckBox *>(QStringLiteral("smime button")), IsVisible, IsChecked); 0531 verifyProtocolLabels(dialog->findChildren<QLabel *>(QStringLiteral("protocol label")), 4, IsVisible); 0532 const auto signingKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("signing key"))); 0533 QCOMPARE(signingKeyWidgets.visible.size(), 2); 0534 QCOMPARE(signingKeyWidgets.hidden.size(), 0); 0535 QCOMPARE(signingKeyWidgets.visible[0]->defaultKey(GpgME::OpenPGP), preferredSolution.signingKeys[0].primaryFingerprint()); 0536 QCOMPARE(signingKeyWidgets.visible[1]->defaultKey(GpgME::CMS), preferredSolution.signingKeys[1].primaryFingerprint()); 0537 0538 const auto encryptionKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("encryption key"))); 0539 QCOMPARE(encryptionKeyWidgets.visible.size(), 5); 0540 QCOMPARE(encryptionKeyWidgets.hidden.size(), 0); 0541 0542 // encryption key widgets for sender come first 0543 QCOMPARE(encryptionKeyWidgets.visible[0]->property("address").toString(), sender); 0544 QCOMPARE(encryptionKeyWidgets.visible[0]->defaultKey(GpgME::OpenPGP), preferredSolution.encryptionKeys.value(sender)[0].primaryFingerprint()); 0545 QCOMPARE(encryptionKeyWidgets.visible[1]->property("address").toString(), sender); 0546 QCOMPARE(encryptionKeyWidgets.visible[1]->defaultKey(GpgME::CMS), preferredSolution.encryptionKeys.value(sender)[1].primaryFingerprint()); 0547 0548 // encryption key widgets for other recipients follow 0549 QCOMPARE(encryptionKeyWidgets.visible[2]->property("address").toString(), "prefer-openpgp@example.net"); 0550 QCOMPARE(encryptionKeyWidgets.visible[2]->defaultKey(GpgME::UnknownProtocol), 0551 preferredSolution.encryptionKeys.value("prefer-openpgp@example.net")[0].primaryFingerprint()); 0552 QCOMPARE(encryptionKeyWidgets.visible[3]->property("address").toString(), "prefer-smime@example.net"); 0553 QCOMPARE(encryptionKeyWidgets.visible[3]->defaultKey(GpgME::UnknownProtocol), 0554 preferredSolution.encryptionKeys.value("prefer-smime@example.net")[0].primaryFingerprint()); 0555 QCOMPARE(encryptionKeyWidgets.visible[4]->property("address").toString(), "unknown@example.net"); 0556 QVERIFY(encryptionKeyWidgets.visible[4]->defaultKey(GpgME::UnknownProtocol).isEmpty()); 0557 } 0558 0559 void test__both_protocols_allowed__mixed_allowed__openpgp_only_preferred_solution() 0560 { 0561 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0562 const bool allowMixed = true; 0563 const QString sender = QStringLiteral("sender@example.net"); 0564 const KeyResolver::Solution preferredSolution = { 0565 GpgME::OpenPGP, 0566 {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}, 0567 { 0568 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 0569 {QStringLiteral("unknown@example.net"), {}}, 0570 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}}, 0571 }, 0572 }; 0573 const KeyResolver::Solution alternativeSolution = {}; 0574 0575 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0576 dialog->show(); 0577 0578 verifyProtocolButton(dialog->findChild<QCheckBox *>(QStringLiteral("openpgp button")), IsVisible, IsChecked); 0579 verifyProtocolButton(dialog->findChild<QCheckBox *>(QStringLiteral("smime button")), IsVisible, IsUnchecked); 0580 verifyProtocolLabels(dialog->findChildren<QLabel *>(QStringLiteral("protocol label")), 4, IsHidden); 0581 const auto signingKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("signing key"))); 0582 QCOMPARE(signingKeyWidgets.visible.size(), 1); 0583 QCOMPARE(signingKeyWidgets.hidden.size(), 1); 0584 QCOMPARE(signingKeyWidgets.visible[0]->defaultKey(GpgME::OpenPGP), preferredSolution.signingKeys[0].primaryFingerprint()); 0585 QCOMPARE(signingKeyWidgets.hidden[0]->defaultKey(GpgME::CMS), preferredSolution.signingKeys[1].primaryFingerprint()); 0586 0587 const auto encryptionKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("encryption key"))); 0588 QCOMPARE(encryptionKeyWidgets.visible.size(), 3); 0589 QCOMPARE(encryptionKeyWidgets.hidden.size(), 1); 0590 0591 // encryption key widgets for sender come first 0592 QCOMPARE(encryptionKeyWidgets.visible[0]->property("address").toString(), sender); 0593 QCOMPARE(encryptionKeyWidgets.visible[0]->defaultKey(GpgME::OpenPGP), preferredSolution.encryptionKeys.value(sender)[0].primaryFingerprint()); 0594 QCOMPARE(encryptionKeyWidgets.hidden[0]->property("address").toString(), sender); 0595 QCOMPARE(encryptionKeyWidgets.hidden[0]->defaultKey(GpgME::CMS), preferredSolution.encryptionKeys.value(sender)[1].primaryFingerprint()); 0596 0597 // encryption key widgets for other recipients follow 0598 QCOMPARE(encryptionKeyWidgets.visible[1]->property("address").toString(), "prefer-openpgp@example.net"); 0599 QCOMPARE(encryptionKeyWidgets.visible[1]->defaultKey(GpgME::UnknownProtocol), 0600 preferredSolution.encryptionKeys.value("prefer-openpgp@example.net")[0].primaryFingerprint()); 0601 QCOMPARE(encryptionKeyWidgets.visible[2]->property("address").toString(), "unknown@example.net"); 0602 QVERIFY(encryptionKeyWidgets.visible[2]->defaultKey(GpgME::UnknownProtocol).isEmpty()); 0603 } 0604 0605 void test__both_protocols_allowed__mixed_allowed__smime_only_preferred_solution() 0606 { 0607 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0608 const bool allowMixed = true; 0609 const QString sender = QStringLiteral("sender@example.net"); 0610 const KeyResolver::Solution preferredSolution = { 0611 GpgME::CMS, 0612 {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}, 0613 { 0614 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 0615 {QStringLiteral("unknown@example.net"), {}}, 0616 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}}, 0617 }, 0618 }; 0619 const KeyResolver::Solution alternativeSolution = {}; 0620 0621 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0622 dialog->show(); 0623 0624 verifyProtocolButton(dialog->findChild<QCheckBox *>(QStringLiteral("openpgp button")), IsVisible, IsUnchecked); 0625 verifyProtocolButton(dialog->findChild<QCheckBox *>(QStringLiteral("smime button")), IsVisible, IsChecked); 0626 verifyProtocolLabels(dialog->findChildren<QLabel *>(QStringLiteral("protocol label")), 4, IsHidden); 0627 const auto signingKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("signing key"))); 0628 QCOMPARE(signingKeyWidgets.visible.size(), 1); 0629 QCOMPARE(signingKeyWidgets.hidden.size(), 1); 0630 QCOMPARE(signingKeyWidgets.visible[0]->defaultKey(GpgME::CMS), preferredSolution.signingKeys[1].primaryFingerprint()); 0631 QCOMPARE(signingKeyWidgets.hidden[0]->defaultKey(GpgME::OpenPGP), preferredSolution.signingKeys[0].primaryFingerprint()); 0632 0633 const auto encryptionKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("encryption key"))); 0634 QCOMPARE(encryptionKeyWidgets.visible.size(), 3); 0635 QCOMPARE(encryptionKeyWidgets.hidden.size(), 1); 0636 0637 // encryption key widgets for sender come first 0638 QCOMPARE(encryptionKeyWidgets.visible[0]->property("address").toString(), sender); 0639 QCOMPARE(encryptionKeyWidgets.visible[0]->defaultKey(GpgME::CMS), preferredSolution.encryptionKeys.value(sender)[1].primaryFingerprint()); 0640 QCOMPARE(encryptionKeyWidgets.hidden[0]->property("address").toString(), sender); 0641 QCOMPARE(encryptionKeyWidgets.hidden[0]->defaultKey(GpgME::OpenPGP), preferredSolution.encryptionKeys.value(sender)[0].primaryFingerprint()); 0642 0643 // encryption key widgets for other recipients follow 0644 QCOMPARE(encryptionKeyWidgets.visible[1]->property("address").toString(), "prefer-smime@example.net"); 0645 QCOMPARE(encryptionKeyWidgets.visible[1]->defaultKey(GpgME::UnknownProtocol), 0646 preferredSolution.encryptionKeys.value("prefer-smime@example.net")[0].primaryFingerprint()); 0647 QCOMPARE(encryptionKeyWidgets.visible[2]->property("address").toString(), "unknown@example.net"); 0648 QVERIFY(encryptionKeyWidgets.visible[2]->defaultKey(GpgME::UnknownProtocol).isEmpty()); 0649 } 0650 0651 void test__both_protocols_allowed__mixed_allowed__no_sender_keys() 0652 { 0653 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0654 const bool allowMixed = true; 0655 const QString sender = QStringLiteral("sender@example.net"); 0656 const KeyResolver::Solution preferredSolution = { 0657 GpgME::UnknownProtocol, 0658 {}, 0659 { 0660 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 0661 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 0662 {QStringLiteral("unknown@example.net"), {}}, 0663 {QStringLiteral("sender@example.net"), {}}, 0664 }, 0665 }; 0666 const KeyResolver::Solution alternativeSolution = {}; 0667 0668 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0669 dialog->show(); 0670 0671 const auto signingKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("signing key"))); 0672 QCOMPARE(signingKeyWidgets.visible.size(), 2); 0673 QCOMPARE(signingKeyWidgets.hidden.size(), 0); 0674 0675 const auto encryptionKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("encryption key"))); 0676 QCOMPARE(encryptionKeyWidgets.visible.size(), 5); 0677 QCOMPARE(encryptionKeyWidgets.hidden.size(), 0); 0678 0679 // encryption key widgets for sender come first 0680 QCOMPARE(encryptionKeyWidgets.visible[0]->property("address").toString(), sender); 0681 QCOMPARE(encryptionKeyWidgets.visible[1]->property("address").toString(), sender); 0682 0683 // encryption key widgets for other recipients follow 0684 QCOMPARE(encryptionKeyWidgets.visible[2]->property("address").toString(), "prefer-openpgp@example.net"); 0685 QCOMPARE(encryptionKeyWidgets.visible[2]->defaultKey(GpgME::UnknownProtocol), 0686 preferredSolution.encryptionKeys.value("prefer-openpgp@example.net")[0].primaryFingerprint()); 0687 QCOMPARE(encryptionKeyWidgets.visible[3]->property("address").toString(), "prefer-smime@example.net"); 0688 QCOMPARE(encryptionKeyWidgets.visible[3]->defaultKey(GpgME::UnknownProtocol), 0689 preferredSolution.encryptionKeys.value("prefer-smime@example.net")[0].primaryFingerprint()); 0690 QCOMPARE(encryptionKeyWidgets.visible[4]->property("address").toString(), "unknown@example.net"); 0691 QVERIFY(encryptionKeyWidgets.visible[4]->defaultKey(GpgME::UnknownProtocol).isEmpty()); 0692 } 0693 0694 void test__both_protocols_allowed__mixed_allowed__encrypt_only() 0695 { 0696 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0697 const bool allowMixed = true; 0698 const QString sender = QStringLiteral("sender@example.net"); 0699 const KeyResolver::Solution preferredSolution = { 0700 GpgME::UnknownProtocol, 0701 {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}, 0702 { 0703 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 0704 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 0705 {QStringLiteral("unknown@example.net"), {}}, 0706 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}}, 0707 }, 0708 }; 0709 const KeyResolver::Solution alternativeSolution = {}; 0710 0711 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, false, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0712 dialog->show(); 0713 0714 const auto signingKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("signing key"))); 0715 QCOMPARE(signingKeyWidgets.visible.size(), 0); 0716 QCOMPARE(signingKeyWidgets.hidden.size(), 0); 0717 0718 const auto encryptionKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("encryption key"))); 0719 QCOMPARE(encryptionKeyWidgets.visible.size(), 5); 0720 QCOMPARE(encryptionKeyWidgets.hidden.size(), 0); 0721 } 0722 0723 void test__ok_button_shows_generate_if_generate_is_selected() 0724 { 0725 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0726 const bool allowMixed = true; 0727 const QString sender = QStringLiteral("sender@example.net"); 0728 const KeyResolver::Solution preferredSolution = { 0729 GpgME::OpenPGP, 0730 {}, // no signing keys to get "Generate key" choice in OpenPGP combo 0731 {{QStringLiteral("sender@example.net"), {}}} // no encryption keys to get "Generate key" choice in OpenPGP combo 0732 }; 0733 const KeyResolver::Solution alternativeSolution = {}; 0734 0735 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0736 dialog->show(); 0737 waitForKeySelectionCombosBeingInitialized(dialog.get()); 0738 0739 const auto okButton = dialog->findChild<QPushButton *>("ok button"); 0740 QVERIFY(okButton); 0741 QVERIFY(okButton->text() != "Generate"); 0742 0743 { 0744 // get the first signing key combo which is the OpenPGP one 0745 const auto signingKeyCombo = dialog->findChild<KeySelectionCombo *>("signing key"); 0746 verifyWidgetVisibility(signingKeyCombo, IsVisible); 0747 const auto originalIndex = signingKeyCombo->currentIndex(); 0748 const auto generateIndex = signingKeyCombo->findData(GenerateKey); 0749 QVERIFY(generateIndex != -1); 0750 signingKeyCombo->setCurrentIndex(generateIndex); 0751 QCOMPARE(okButton->text(), "Generate"); 0752 signingKeyCombo->setCurrentIndex(originalIndex); 0753 QVERIFY(okButton->text() != "Generate"); 0754 } 0755 { 0756 // get the first encryption key combo which is the OpenPGP one for the sender 0757 const auto encryptionKeyCombo = dialog->findChild<KeySelectionCombo *>("encryption key"); 0758 verifyWidgetVisibility(encryptionKeyCombo, IsVisible); 0759 const auto originalIndex = encryptionKeyCombo->currentIndex(); 0760 const auto generateIndex = encryptionKeyCombo->findData(GenerateKey); 0761 QVERIFY(generateIndex != -1); 0762 encryptionKeyCombo->setCurrentIndex(generateIndex); 0763 QCOMPARE(okButton->text(), QStringLiteral("Generate")); 0764 encryptionKeyCombo->setCurrentIndex(originalIndex); 0765 QVERIFY(okButton->text() != QStringLiteral("Generate")); 0766 } 0767 } 0768 0769 void test__ok_button_does_not_show_generate_if_generate_is_selected_in_hidden_combos() 0770 { 0771 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0772 const bool allowMixed = true; 0773 const QString sender = QStringLiteral("sender@example.net"); 0774 const KeyResolver::Solution preferredSolution = { 0775 GpgME::CMS, // enables S/MIME as default protocol, hides OpenPGP combos 0776 {}, // no signing keys to get "Generate key" choice in OpenPGP combo 0777 {{QStringLiteral("sender@example.net"), {}}} // no encryption keys to get "Generate key" choice in OpenPGP combo 0778 }; 0779 const KeyResolver::Solution alternativeSolution = {}; 0780 0781 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0782 dialog->show(); 0783 waitForKeySelectionCombosBeingInitialized(dialog.get()); 0784 0785 const auto okButton = dialog->findChild<QPushButton *>("ok button"); 0786 QVERIFY(okButton); 0787 QVERIFY(okButton->text() != "Generate"); 0788 0789 { 0790 // get the first signing key combo which is the OpenPGP one 0791 const auto signingKeyCombo = dialog->findChild<KeySelectionCombo *>("signing key"); 0792 verifyWidgetVisibility(signingKeyCombo, IsHidden); 0793 const auto originalIndex = signingKeyCombo->currentIndex(); 0794 const auto generateIndex = signingKeyCombo->findData(GenerateKey); 0795 QVERIFY(generateIndex != -1); 0796 signingKeyCombo->setCurrentIndex(generateIndex); 0797 QVERIFY(okButton->text() != QStringLiteral("Generate")); 0798 signingKeyCombo->setCurrentIndex(originalIndex); 0799 QVERIFY(okButton->text() != QStringLiteral("Generate")); 0800 } 0801 { 0802 // get the first encryption key combo which is the OpenPGP one for the sender 0803 const auto encryptionKeyCombo = dialog->findChild<KeySelectionCombo *>("encryption key"); 0804 verifyWidgetVisibility(encryptionKeyCombo, IsHidden); 0805 const auto originalIndex = encryptionKeyCombo->currentIndex(); 0806 const auto generateIndex = encryptionKeyCombo->findData(GenerateKey); 0807 QVERIFY(generateIndex != -1); 0808 encryptionKeyCombo->setCurrentIndex(generateIndex); 0809 QVERIFY(okButton->text() != QStringLiteral("Generate")); 0810 encryptionKeyCombo->setCurrentIndex(originalIndex); 0811 QVERIFY(okButton->text() != QStringLiteral("Generate")); 0812 } 0813 } 0814 0815 void test__ok_button_is_disabled_if_ignore_is_selected_in_all_visible_encryption_combos() 0816 { 0817 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0818 const bool allowMixed = true; 0819 const QString sender = QStringLiteral("sender@example.net"); 0820 const KeyResolver::Solution preferredSolution = { 0821 GpgME::OpenPGP, 0822 {}, // no signing keys to get "Generate key" choice in OpenPGP combo 0823 {{QStringLiteral("sender@example.net"), {}}} // no encryption keys to get "Generate key" choice in OpenPGP combo 0824 }; 0825 const KeyResolver::Solution alternativeSolution = {}; 0826 0827 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0828 dialog->show(); 0829 waitForKeySelectionCombosBeingInitialized(dialog.get()); 0830 0831 const auto okButton = dialog->findChild<QPushButton *>(QStringLiteral("ok button")); 0832 QVERIFY(okButton); 0833 QVERIFY(okButton->isEnabled()); 0834 0835 const auto encryptionKeyWidgets = visibleAndHiddenWidgets(dialog->findChildren<KeySelectionCombo *>(QStringLiteral("encryption key"))); 0836 for (auto combo : encryptionKeyWidgets.visible) { 0837 const auto ignoreIndex = combo->findData(IgnoreKey); 0838 QVERIFY(ignoreIndex != -1); 0839 combo->setCurrentIndex(ignoreIndex); 0840 } 0841 QVERIFY(!okButton->isEnabled()); 0842 } 0843 0844 void test__vs_de_compliance__all_keys_fully_valid() 0845 { 0846 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0847 const bool allowMixed = true; 0848 const QString sender = QStringLiteral("sender@example.net"); 0849 const KeyResolver::Solution preferredSolution = { 0850 GpgME::UnknownProtocol, 0851 {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}, 0852 { 0853 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 0854 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 0855 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}}, 0856 }, 0857 }; 0858 const KeyResolver::Solution alternativeSolution = {}; 0859 0860 Tests::FakeCryptoConfigStringValue fakeCompliance{"gpg", "compliance", QStringLiteral("de-vs")}; 0861 Tests::FakeCryptoConfigIntValue fakeDeVsCompliance{"gpg", "compliance_de_vs", 1}; 0862 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0863 dialog->show(); 0864 waitForKeySelectionCombosBeingInitialized(dialog.get()); 0865 0866 const auto complianceLabel = dialog->findChild<QLabel *>(QStringLiteral("compliance label")); 0867 verifyWidgetVisibility(complianceLabel, IsVisible); 0868 QVERIFY(!complianceLabel->text().contains(DeVSCompliance::name(false))); 0869 } 0870 0871 void test__vs_de_compliance__not_all_keys_fully_valid() 0872 { 0873 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0874 const bool allowMixed = true; 0875 const QString sender = QStringLiteral("sender@example.net"); 0876 const KeyResolver::Solution preferredSolution = { 0877 GpgME::UnknownProtocol, 0878 {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}, 0879 { 0880 {QStringLiteral("marginal-openpgp@example.net"), {testKey("Marginal Validity <marginal-openpgp@example.net>", GpgME::OpenPGP)}}, 0881 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}}, 0882 }, 0883 }; 0884 const KeyResolver::Solution alternativeSolution = {}; 0885 0886 Tests::FakeCryptoConfigStringValue fakeCompliance{"gpg", "compliance", QStringLiteral("de-vs")}; 0887 Tests::FakeCryptoConfigIntValue fakeDeVsCompliance{"gpg", "compliance_de_vs", 1}; 0888 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0889 dialog->show(); 0890 waitForKeySelectionCombosBeingInitialized(dialog.get()); 0891 0892 const auto complianceLabel = dialog->findChild<QLabel *>(QStringLiteral("compliance label")); 0893 verifyWidgetVisibility(complianceLabel, IsVisible); 0894 QVERIFY(complianceLabel->text().contains(DeVSCompliance::name(false))); 0895 } 0896 0897 void test__vs_de_compliance__null_keys_are_ignored() 0898 { 0899 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0900 const bool allowMixed = true; 0901 const QString sender = QStringLiteral("sender@example.net"); 0902 const KeyResolver::Solution preferredSolution = { 0903 GpgME::UnknownProtocol, 0904 {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}, 0905 { 0906 {QStringLiteral("unknown@example.net"), {}}, 0907 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}}, 0908 }, 0909 }; 0910 const KeyResolver::Solution alternativeSolution = {}; 0911 0912 Tests::FakeCryptoConfigStringValue fakeCompliance{"gpg", "compliance", QStringLiteral("de-vs")}; 0913 Tests::FakeCryptoConfigIntValue fakeDeVsCompliance{"gpg", "compliance_de_vs", 1}; 0914 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0915 dialog->show(); 0916 waitForKeySelectionCombosBeingInitialized(dialog.get()); 0917 0918 const auto complianceLabel = dialog->findChild<QLabel *>(QStringLiteral("compliance label")); 0919 verifyWidgetVisibility(complianceLabel, IsVisible); 0920 QVERIFY(!complianceLabel->text().contains(DeVSCompliance::name(false))); 0921 } 0922 0923 void test__sign_and_encrypt_to_self_only() 0924 { 0925 const GpgME::Protocol forcedProtocol = GpgME::OpenPGP; 0926 const bool allowMixed = false; 0927 const QString sender = QStringLiteral("sender@example.net"); 0928 const KeyResolver::Solution preferredSolution = { 0929 GpgME::OpenPGP, 0930 {testKey("sender@example.net", GpgME::OpenPGP)}, 0931 { 0932 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP)}}, 0933 }, 0934 }; 0935 const KeyResolver::Solution alternativeSolution = {}; 0936 0937 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0938 dialog->show(); 0939 0940 QVERIFY(!dialog->findChild<QGroupBox *>(QStringLiteral("encrypt-to-others box"))); 0941 } 0942 0943 void test__sign_and_encrypt_to_self_and_others() 0944 { 0945 const GpgME::Protocol forcedProtocol = GpgME::OpenPGP; 0946 const bool allowMixed = false; 0947 const QString sender = QStringLiteral("sender@example.net"); 0948 const KeyResolver::Solution preferredSolution = { 0949 GpgME::OpenPGP, 0950 {testKey("sender@example.net", GpgME::OpenPGP)}, 0951 { 0952 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 0953 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP)}}, 0954 }, 0955 }; 0956 const KeyResolver::Solution alternativeSolution = {}; 0957 0958 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0959 dialog->show(); 0960 0961 QVERIFY(dialog->findChild<QGroupBox *>(QStringLiteral("encrypt-to-others box"))); 0962 } 0963 0964 void test__result_does_not_include_null_keys() 0965 { 0966 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 0967 const bool allowMixed = true; 0968 const QString sender = QStringLiteral("unknown@example.net"); 0969 const KeyResolver::Solution preferredSolution = { 0970 GpgME::UnknownProtocol, 0971 {}, 0972 { 0973 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 0974 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 0975 {QStringLiteral("unknown@example.net"), {}}, 0976 }, 0977 }; 0978 const KeyResolver::Solution alternativeSolution = {}; 0979 0980 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 0981 dialog->show(); 0982 waitForKeySelectionCombosBeingInitialized(dialog.get()); 0983 switchKeySelectionCombosFromGenerateKeyToIgnoreKey(dialog->findChildren<KeySelectionCombo *>()); 0984 0985 const QSignalSpy dialogAcceptedSpy{dialog.get(), &QDialog::accepted}; 0986 QVERIFY(dialogAcceptedSpy.isValid()); 0987 0988 const auto okButton = dialog->findChild<QPushButton *>(QStringLiteral("ok button")); 0989 QVERIFY(okButton); 0990 QVERIFY(okButton->isEnabled()); 0991 okButton->click(); 0992 0993 QCOMPARE(dialogAcceptedSpy.count(), 1); 0994 verifySolution(dialog->result(), 0995 {GpgME::UnknownProtocol, 0996 {}, 0997 { 0998 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 0999 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 1000 }}); 1001 } 1002 1003 void test__result_has_keys_for_both_protocols_if_both_are_needed() 1004 { 1005 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 1006 const bool allowMixed = true; 1007 const QString sender = QStringLiteral("sender@example.net"); 1008 const KeyResolver::Solution preferredSolution = { 1009 GpgME::UnknownProtocol, 1010 {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}, 1011 { 1012 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 1013 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 1014 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}}, 1015 }, 1016 }; 1017 const KeyResolver::Solution alternativeSolution = {}; 1018 1019 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 1020 dialog->show(); 1021 waitForKeySelectionCombosBeingInitialized(dialog.get()); 1022 switchKeySelectionCombosFromGenerateKeyToIgnoreKey(dialog->findChildren<KeySelectionCombo *>()); 1023 1024 const QSignalSpy dialogAcceptedSpy{dialog.get(), &QDialog::accepted}; 1025 QVERIFY(dialogAcceptedSpy.isValid()); 1026 1027 const auto okButton = dialog->findChild<QPushButton *>(QStringLiteral("ok button")); 1028 QVERIFY(okButton); 1029 QVERIFY(okButton->isEnabled()); 1030 okButton->click(); 1031 1032 QCOMPARE(dialogAcceptedSpy.count(), 1); 1033 verifySolution(dialog->result(), preferredSolution); 1034 } 1035 1036 void test__result_has_only_openpgp_keys_if_openpgp_protocol_selected() 1037 { 1038 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 1039 const bool allowMixed = true; 1040 const QString sender = QStringLiteral("sender@example.net"); 1041 const KeyResolver::Solution preferredSolution = { 1042 GpgME::UnknownProtocol, 1043 {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}, 1044 { 1045 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 1046 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 1047 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}}, 1048 }, 1049 }; 1050 const KeyResolver::Solution alternativeSolution = {}; 1051 1052 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 1053 dialog->show(); 1054 waitForKeySelectionCombosBeingInitialized(dialog.get()); 1055 switchKeySelectionCombosFromGenerateKeyToIgnoreKey(dialog->findChildren<KeySelectionCombo *>()); 1056 1057 const auto smimeButton = dialog->findChild<QCheckBox *>(QStringLiteral("smime button")); 1058 QVERIFY(smimeButton); 1059 smimeButton->click(); 1060 QVERIFY(!smimeButton->isChecked()); 1061 1062 const QSignalSpy dialogAcceptedSpy{dialog.get(), &QDialog::accepted}; 1063 QVERIFY(dialogAcceptedSpy.isValid()); 1064 1065 const auto okButton = dialog->findChild<QPushButton *>(QStringLiteral("ok button")); 1066 QVERIFY(okButton); 1067 QVERIFY(okButton->isEnabled()); 1068 okButton->click(); 1069 1070 QCOMPARE(dialogAcceptedSpy.count(), 1); 1071 verifySolution(dialog->result(), 1072 {GpgME::OpenPGP, 1073 {testKey("sender@example.net", GpgME::OpenPGP)}, 1074 { 1075 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 1076 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP)}}, 1077 }}); 1078 } 1079 1080 void test__result_has_only_smime_keys_if_smime_protocol_selected() 1081 { 1082 const GpgME::Protocol forcedProtocol = GpgME::UnknownProtocol; 1083 const bool allowMixed = true; 1084 const QString sender = QStringLiteral("sender@example.net"); 1085 const KeyResolver::Solution preferredSolution = { 1086 GpgME::UnknownProtocol, 1087 {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}, 1088 { 1089 {QStringLiteral("prefer-openpgp@example.net"), {testKey("Full Trust <prefer-openpgp@example.net>", GpgME::OpenPGP)}}, 1090 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 1091 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::OpenPGP), testKey("sender@example.net", GpgME::CMS)}}, 1092 }, 1093 }; 1094 const KeyResolver::Solution alternativeSolution = {}; 1095 1096 const auto dialog = std::make_unique<NewKeyApprovalDialog>(true, true, sender, preferredSolution, alternativeSolution, allowMixed, forcedProtocol); 1097 dialog->show(); 1098 waitForKeySelectionCombosBeingInitialized(dialog.get()); 1099 switchKeySelectionCombosFromGenerateKeyToIgnoreKey(dialog->findChildren<KeySelectionCombo *>()); 1100 1101 const auto openPGPButton = dialog->findChild<QCheckBox *>(QStringLiteral("openpgp button")); 1102 QVERIFY(openPGPButton); 1103 openPGPButton->click(); 1104 QVERIFY(!openPGPButton->isChecked()); 1105 1106 const QSignalSpy dialogAcceptedSpy{dialog.get(), &QDialog::accepted}; 1107 QVERIFY(dialogAcceptedSpy.isValid()); 1108 1109 const auto okButton = dialog->findChild<QPushButton *>(QStringLiteral("ok button")); 1110 QVERIFY(okButton); 1111 QVERIFY(okButton->isEnabled()); 1112 okButton->click(); 1113 1114 QCOMPARE(dialogAcceptedSpy.count(), 1); 1115 verifySolution(dialog->result(), 1116 {GpgME::CMS, 1117 {testKey("sender@example.net", GpgME::CMS)}, 1118 { 1119 {QStringLiteral("prefer-smime@example.net"), {testKey("Trusted S/MIME <prefer-smime@example.net>", GpgME::CMS)}}, 1120 {QStringLiteral("sender@example.net"), {testKey("sender@example.net", GpgME::CMS)}}, 1121 }}); 1122 } 1123 1124 private: 1125 std::shared_ptr<const KeyCache> mKeyCache; 1126 }; 1127 1128 QTEST_MAIN(NewKeyApprovalDialogTest) 1129 #include "newkeyapprovaldialogtest.moc"