File indexing completed on 2024-11-24 03:41:03
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2021 Slava Aseev <nullptrnine@basealt.ru> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 #include "fdo_secrets_test.h" 0008 #include "mockkwalletd.cpp" 0009 // cannot be in mockkwalletd.cpp, as CMake's automoc does not look there 0010 #include "moc_ktimeout.cpp" 0011 #include "moc_kwalletd.cpp" 0012 #include "static_mock.hpp" 0013 0014 void FdoSecretsTest::initTestCase() 0015 { 0016 static QCA::Initializer init{}; 0017 } 0018 0019 void FdoSecretsTest::serviceStaticFunctions() 0020 { 0021 auto labels = Testset<QString, FdoUniqueLabel>{ 0022 {"label", {"label", -1}}, 0023 {"label__0_", {"label", 0}}, 0024 {"label___1_", {"label_", 1}}, 0025 {"__0_label___200_", {"__0_label_", 200}}, 0026 }; 0027 0028 runTestset(FdoUniqueLabel::fromName, labels); 0029 runRevTestset( 0030 [](const FdoUniqueLabel &l) { 0031 return l.toName(); 0032 }, 0033 labels); 0034 0035 runTestset(KWalletFreedesktopService::wrapToCollectionPath, 0036 Testset<QString, QString>{ 0037 {"/org/freedesktop/secrets/collection/abcd", "/org/freedesktop/secrets/collection/abcd"}, 0038 {"/org/freedesktop/secrets/collection/abcd/2", "/org/freedesktop/secrets/collection/abcd"}, 0039 {"/org/freedesktop/secrets/collection/abcd/2/2/3/4", "/org/freedesktop/secrets/collection/abcd"}, 0040 }); 0041 0042 QCOMPARE(KWalletFreedesktopService::nextPromptPath().path(), "/org/freedesktop/secrets/prompt/p0"); 0043 QCOMPARE(KWalletFreedesktopService::nextPromptPath().path(), "/org/freedesktop/secrets/prompt/p1"); 0044 } 0045 0046 void FdoSecretsTest::collectionStaticFunctions() 0047 { 0048 auto dirNameTestset = Testset<EntryLocation, FdoUniqueLabel>{ 0049 {{FDO_SECRETS_DEFAULT_DIR, "entry1"}, {"entry1", -1}}, 0050 {{FDO_SECRETS_DEFAULT_DIR, "entry__3_"}, {"entry", 3}}, 0051 {{"Passwords", "password__"}, {"Passwords/password__", -1}}, 0052 {{"Passwords__3_", "password__200_"}, {"Passwords__3_/password", 200}}, 0053 {{"", "password"}, {"/password", -1}}, 0054 {{"", "/"}, {"//", -1}}, 0055 {{FDO_SECRETS_DEFAULT_DIR, "/"}, {"/", -1}}, 0056 {{FDO_SECRETS_DEFAULT_DIR, "/__2_"}, {"/", 2}}, 0057 {{"https:", "/foobar.org/"}, {"https://foobar.org/", -1}}, 0058 {{"https:", "/foobar.org/__80_"}, {"https://foobar.org/", 80}}, 0059 }; 0060 0061 runTestset( 0062 [](const EntryLocation &l) { 0063 return l.toUniqueLabel(); 0064 }, 0065 dirNameTestset); 0066 runRevTestset( 0067 [](const FdoUniqueLabel &l) { 0068 return l.toEntryLocation(); 0069 }, 0070 dirNameTestset); 0071 } 0072 0073 void FdoSecretsTest::cleanup() 0074 { 0075 SET_FUNCTION_RESULT(KWalletD::wallets, QStringList()); 0076 } 0077 0078 void FdoSecretsTest::precreatedWallets() 0079 { 0080 const QStringList wallets = {"wallet1", "wallet2", "wallet2__0_", "wallet2__1_"}; 0081 SET_FUNCTION_RESULT(KWalletD::wallets, wallets); 0082 SET_FUNCTION_RESULT_OVERLOADED(KWalletD::isOpen, true, bool(KWalletD::*)(int)); 0083 0084 std::unique_ptr<KWalletD> kwalletd{new KWalletD}; 0085 std::unique_ptr<KWalletFreedesktopService> service{new KWalletFreedesktopService(kwalletd.get())}; 0086 0087 QCOMPARE(wallets.size(), service->collections().size()); 0088 for (const auto &walletName : wallets) { 0089 auto collection = service->getCollectionByWalletName(walletName); 0090 QVERIFY(collection); 0091 QVERIFY(collection->label() == "wallet1" || collection->label() == "wallet2"); 0092 } 0093 0094 auto firstCollection = service->getCollectionByWalletName(wallets.front()); 0095 auto &item1 = firstCollection->pushNewItem(FdoUniqueLabel{"item1", -1}, QDBusObjectPath(firstCollection->fdoObjectPath().path() + "/0")); 0096 QCOMPARE(item1.fdoObjectPath().path(), (firstCollection->fdoObjectPath().path() + "/0")); 0097 QCOMPARE(&item1, service->getItemByObjectPath(item1.fdoObjectPath())); 0098 } 0099 0100 void FdoSecretsTest::aliases() 0101 { 0102 std::unique_ptr<KWalletD> kwalletd{new KWalletD}; 0103 std::unique_ptr<KWalletFreedesktopService> service{new KWalletFreedesktopService(kwalletd.get())}; 0104 0105 service->createCollectionAlias("alias", "walletName"); 0106 service->createCollectionAlias("alias2", "walletName"); 0107 service->createCollectionAlias("alias3", "walletName300"); 0108 service->updateCollectionAlias("alias3", "walletName"); 0109 QSet<QString> checkAliases = {"alias", "alias2", "alias3"}; 0110 const QStringList aliases = service->readAliasesFor("walletName"); 0111 for (const auto &alias : aliases) 0112 checkAliases.remove(alias); 0113 QVERIFY(checkAliases.isEmpty()); 0114 0115 service->removeAlias("alias"); 0116 service->removeAlias("alias2"); 0117 service->removeAlias("alias3"); 0118 QVERIFY(service->readAliasesFor("walletName").isEmpty()); 0119 } 0120 0121 struct SetupSessionT { 0122 QDBusObjectPath sessionPath; 0123 QCA::SymmetricKey symmetricKey; 0124 QByteArray error; 0125 }; 0126 0127 #define SETUP_SESSION_VERIFY(cond) \ 0128 do { \ 0129 if (!(cond)) \ 0130 return SetupSessionT{QDBusObjectPath(), QCA::SymmetricKey(), #cond}; \ 0131 } while (false) 0132 0133 SetupSessionT setupSession(KWalletFreedesktopService *service) 0134 { 0135 SetupSessionT result; 0136 QCA::KeyGenerator keygen; 0137 auto dlGroup = QCA::DLGroup(keygen.createDLGroup(QCA::IETF_1024)); 0138 if (dlGroup.isNull()) { 0139 result.error = "createDLGroup failed, maybe libqca-ossl is missing"; 0140 return result; 0141 } 0142 0143 auto privateKey = QCA::PrivateKey(keygen.createDH(dlGroup)); 0144 auto publicKey = QCA::PublicKey(privateKey); 0145 0146 auto connection = QDBusConnection::sessionBus(); 0147 auto message = QDBusMessage::createSignal("dummy", "dummy", "dummy"); 0148 0149 auto pubKeyBytes = publicKey.toDH().y().toArray().toByteArray(); 0150 auto sessionPubKeyVariant = service->OpenSession("dh-ietf1024-sha256-aes128-cbc-pkcs7", QDBusVariant(pubKeyBytes), result.sessionPath); 0151 SETUP_SESSION_VERIFY(result.sessionPath.path() != "/"); 0152 SETUP_SESSION_VERIFY(sessionPubKeyVariant.variant().canConvert<QByteArray>()); 0153 0154 auto servicePublicKeyBytes = sessionPubKeyVariant.variant().toByteArray(); 0155 SETUP_SESSION_VERIFY(!servicePublicKeyBytes.isEmpty()); 0156 0157 auto servicePublicKey = QCA::DHPublicKey(dlGroup, QCA::BigInteger(QCA::SecureArray(servicePublicKeyBytes))); 0158 auto commonSecret = privateKey.deriveKey(servicePublicKey); 0159 result.symmetricKey = QCA::HKDF().makeKey(commonSecret, {}, {}, FDO_SECRETS_CIPHER_KEY_SIZE); 0160 0161 return result; 0162 } 0163 0164 void FdoSecretsTest::items() 0165 { 0166 const QStringList wallets = {"wallet1"}; 0167 const QStringList folders = {FDO_SECRETS_DEFAULT_DIR}; 0168 const QStringList entries = {"item1", "item2", "item3"}; 0169 SET_FUNCTION_RESULT(KWalletD::wallets, wallets); 0170 SET_FUNCTION_RESULT(KWalletD::folderList, folders); 0171 SET_FUNCTION_RESULT(KWalletD::entryList, entries); 0172 0173 SET_FUNCTION_IMPL(KWalletD::entryType, [](int, const QString &, const QString &key, const QString &) -> int { 0174 if (key == "item1") 0175 return KWallet::Wallet::Password; 0176 else if (key == "item2") 0177 return KWallet::Wallet::Map; 0178 else if (key == "item3") 0179 return KWallet::Wallet::Stream; 0180 0181 QTEST_ASSERT(false); 0182 return KWallet::Wallet::Unknown; 0183 }); 0184 0185 QString _secretHolder1 = "It's a password"; 0186 QByteArray _secretHolder2; 0187 QByteArray _secretHolder3; 0188 0189 { 0190 QByteArray a = "It's a"; 0191 QString b = "stream"; 0192 0193 QDataStream ds{&_secretHolder2, QIODevice::WriteOnly}; 0194 ds << a << b; 0195 } 0196 0197 { 0198 StrStrMap map; 0199 map["it's a"] = "map"; 0200 0201 QDataStream ds{&_secretHolder3, QIODevice::WriteOnly}; 0202 ds << map; 0203 } 0204 0205 SET_FUNCTION_IMPL(KWalletD::readPassword, [&](int, const QString &, const QString &key, const QString &) -> QString { 0206 QTEST_ASSERT(key == "item1"); 0207 return _secretHolder1; 0208 }); 0209 0210 SET_FUNCTION_IMPL(KWalletD::readEntry, [&](int, const QString &, const QString &key, const QString &) -> QByteArray { 0211 QTEST_ASSERT(key == "item3" || key == "item2"); 0212 if (key == "item2") 0213 return _secretHolder2; 0214 else 0215 return _secretHolder3; 0216 }); 0217 0218 SET_FUNCTION_IMPL(KWalletD::writePassword, [&](int, const QString &, const QString &key, const QString &value, const QString &) -> int { 0219 QTEST_ASSERT(key == "item1"); 0220 _secretHolder1 = value; 0221 return 0; 0222 }); 0223 0224 using writeEntryT = int (KWalletD::*)(int, const QString &, const QString &, const QByteArray &, int, const QString &); 0225 SET_FUNCTION_IMPL_OVERLOADED(KWalletD::writeEntry, 0226 writeEntryT, 0227 [&](int, const QString &, const QString &key, const QByteArray &value, int, const QString &) -> int { 0228 QTEST_ASSERT(key == "item3" || key == "item2"); 0229 if (key == "item2") 0230 _secretHolder2 = value; 0231 else 0232 _secretHolder3 = value; 0233 return 0; 0234 }); 0235 0236 std::unique_ptr<KWalletD> kwalletd{new KWalletD}; 0237 std::unique_ptr<KWalletFreedesktopService> service{new KWalletFreedesktopService(kwalletd.get())}; 0238 0239 auto collection = service->getCollectionByWalletName("wallet1"); 0240 QVERIFY(collection); 0241 0242 /* Write some attributes */ 0243 { 0244 collection->itemAttributes().newItem({FDO_SECRETS_DEFAULT_DIR, "item1"}); 0245 collection->itemAttributes().newItem({FDO_SECRETS_DEFAULT_DIR, "item2"}); 0246 collection->itemAttributes().newItem({FDO_SECRETS_DEFAULT_DIR, "item3"}); 0247 collection->itemAttributes().setParam({FDO_SECRETS_DEFAULT_DIR, "item3"}, FDO_KEY_CREATED, 100200300ULL); 0248 collection->itemAttributes().setParam({FDO_SECRETS_DEFAULT_DIR, "item3"}, FDO_KEY_MODIFIED, 100200301ULL); 0249 auto attribs = collection->itemAttributes().getAttributes({FDO_SECRETS_DEFAULT_DIR, "item3"}); 0250 attribs["Attrib1"] = "value1"; 0251 attribs["Attrib2"] = "value2"; 0252 collection->itemAttributes().setAttributes({FDO_SECRETS_DEFAULT_DIR, "item3"}, attribs); 0253 } 0254 0255 /* Create collection */ 0256 using OpenAsyncT = int (KWalletD::*)(const QString &, qlonglong, const QString &, bool, const QDBusConnection &, const QDBusMessage &); 0257 bool openAsyncCalled = false; 0258 SET_FUNCTION_IMPL_OVERLOADED(KWalletD::openAsync, 0259 OpenAsyncT, 0260 [&](const QString &, qlonglong, const QString &, bool, const QDBusConnection &, const QDBusMessage &) -> int { 0261 openAsyncCalled = true; 0262 return 0; 0263 }); 0264 0265 QDBusObjectPath promptPath; 0266 service->Unlock({collection->fdoObjectPath()}, promptPath); 0267 auto prompt = service->getPromptByObjectPath(promptPath); 0268 QVERIFY(prompt); 0269 prompt->Prompt("wndid"); 0270 Q_EMIT kwalletd->walletAsyncOpened(0, 0); 0271 SET_FUNCTION_RESULT_OVERLOADED(KWalletD::isOpen, true, bool(KWalletD::*)(int)); 0272 QVERIFY(!collection->locked()); 0273 0274 auto item1 = collection->findItemByEntryLocation({FDO_SECRETS_DEFAULT_DIR, "item1"}); 0275 auto item2 = collection->findItemByEntryLocation({FDO_SECRETS_DEFAULT_DIR, "item2"}); 0276 auto item3 = collection->findItemByEntryLocation({FDO_SECRETS_DEFAULT_DIR, "item3"}); 0277 QVERIFY(item1 && item2 && item3); 0278 0279 auto message = QDBusMessage::createSignal("dummy", "dummy", "dummy"); 0280 auto [sessionPath, symmetricKey, errorStr] = setupSession(service.get()); 0281 QVERIFY2(errorStr.isEmpty(), errorStr.constData()); 0282 0283 /* Check secrets */ 0284 auto secret1 = item1->GetSecret(sessionPath); 0285 service->desecret(message, secret1); 0286 QCOMPARE(secret1.value.toByteArray(), "It's a password"); 0287 // QCOMPARE(secret1.mimeType, "text/plain"); 0288 0289 auto secret2 = item2->GetSecret(sessionPath); 0290 service->desecret(message, secret2); 0291 QByteArray secretBytes = secret2.value.toByteArray(); 0292 QDataStream ds{secretBytes}; 0293 QByteArray a; 0294 QString b; 0295 ds >> a >> b; 0296 0297 QCOMPARE(secret2.mimeType, "application/octet-stream"); 0298 QCOMPARE(a, "It's a"); 0299 QCOMPARE(b, "stream"); 0300 0301 auto secret3 = item3->GetSecret(sessionPath); 0302 service->desecret(message, secret3); 0303 auto bytes3 = secret3.value.toByteArray(); 0304 QDataStream ds2(bytes3); 0305 StrStrMap map3; 0306 ds2 >> map3; 0307 0308 QVERIFY(map3.find("it's a") != map3.end() && map3["it's a"] == "map"); 0309 QCOMPARE(item3->created(), 100200300); 0310 QCOMPARE(item3->modified(), 100200301); 0311 QCOMPARE(item3->attributes()["Attrib1"], "value1"); 0312 QCOMPARE(item3->attributes()["Attrib2"], "value2"); 0313 0314 /* Set new secrets */ 0315 secret1.value = QByteArray("It's a new password"); 0316 secret1.mimeType = "text/plain"; 0317 service->ensecret(message, secret1); 0318 item1->SetSecret(secret1); 0319 secret1 = item1->GetSecret(sessionPath); 0320 service->desecret(message, secret1); 0321 QCOMPARE(secret1.value.toByteArray(), "It's a new password"); 0322 QCOMPARE(secret1.mimeType, "text/plain"); 0323 0324 secret2.value = QByteArray("It's a new secret"); 0325 secret2.mimeType = "application/octet-stream"; 0326 service->ensecret(message, secret2); 0327 item2->SetSecret(secret2); 0328 auto attribs = item2->attributes(); 0329 attribs["newAttrib"] = ")))"; 0330 item2->setAttributes(attribs); 0331 0332 secret2 = item2->GetSecret(sessionPath); 0333 service->desecret(message, secret2); 0334 QCOMPARE(secret2.value.toByteArray(), "It's a new secret"); 0335 QCOMPARE(item2->attributes()["newAttrib"], ")))"); 0336 0337 /* Search items */ 0338 attribs.clear(); 0339 attribs["Attrib1"] = "value1"; 0340 QList<QDBusObjectPath> lockedItems; 0341 auto unlockedItems = service->SearchItems(attribs, lockedItems); 0342 QCOMPARE(unlockedItems.size(), 1); 0343 QCOMPARE(unlockedItems.front(), item3->fdoObjectPath()); 0344 } 0345 0346 void FdoSecretsTest::createLockUnlockCollection() 0347 { 0348 std::unique_ptr<KWalletD> kwalletd{new KWalletD}; 0349 std::unique_ptr<KWalletFreedesktopService> service{new KWalletFreedesktopService(kwalletd.get())}; 0350 0351 /* Create collection */ 0352 using OpenAsyncT = int (KWalletD::*)(const QString &, qlonglong, const QString &, bool, const QDBusConnection &, const QDBusMessage &); 0353 bool openAsyncCalled = false; 0354 SET_FUNCTION_IMPL_OVERLOADED(KWalletD::openAsync, 0355 OpenAsyncT, 0356 [&](const QString &, qlonglong, const QString &, bool, const QDBusConnection &, const QDBusMessage &) -> int { 0357 openAsyncCalled = true; 0358 return 0; 0359 }); 0360 0361 QVariantMap props; 0362 props["org.freedesktop.Secret.Collection.Label"] = QString("walletName"); 0363 QDBusObjectPath promptPath; 0364 service->CreateCollection(props, "", promptPath); 0365 auto prompt = service->getPromptByObjectPath(promptPath); 0366 QVERIFY(prompt); 0367 prompt->Prompt("wndid"); 0368 QVERIFY(openAsyncCalled); 0369 Q_EMIT kwalletd->walletAsyncOpened(0, 0); 0370 0371 auto createdCollection = service->getCollectionByWalletName("walletName"); 0372 QVERIFY(createdCollection); 0373 QCOMPARE(createdCollection->label(), "walletName"); 0374 0375 /* Check aliases */ 0376 service->createCollectionAlias("alias", "walletName"); 0377 service->createCollectionAlias("alias2", "walletName"); 0378 service->createCollectionAlias("alias3", "walletName"); 0379 0380 QCOMPARE(service->resolveIfAlias(QStringLiteral(FDO_ALIAS_PATH) + "alias"), createdCollection->fdoObjectPath().path()); 0381 QCOMPARE(service->resolveIfAlias(QStringLiteral(FDO_ALIAS_PATH) + "alias2"), createdCollection->fdoObjectPath().path()); 0382 QCOMPARE(service->resolveIfAlias(QStringLiteral(FDO_ALIAS_PATH) + "alias3"), createdCollection->fdoObjectPath().path()); 0383 QCOMPARE(service->ReadAlias("alias"), createdCollection->fdoObjectPath()); 0384 0385 service->removeAlias("alias"); 0386 service->removeAlias("alias2"); 0387 service->removeAlias("alias3"); 0388 0389 /* Lock/Unlock */ 0390 auto lockedObjects = service->Lock({createdCollection->fdoObjectPath()}, promptPath); 0391 QCOMPARE(lockedObjects.size(), 1); 0392 QCOMPARE(lockedObjects.front(), createdCollection->fdoObjectPath()); 0393 SET_FUNCTION_RESULT_OVERLOADED(KWalletD::isOpen, false, bool(KWalletD::*)(int)); 0394 QVERIFY(createdCollection->locked()); 0395 0396 service->Unlock({createdCollection->fdoObjectPath()}, promptPath); 0397 prompt = service->getPromptByObjectPath(promptPath); 0398 QVERIFY(prompt); 0399 openAsyncCalled = false; 0400 prompt->Prompt("wndid"); 0401 QVERIFY(openAsyncCalled); 0402 Q_EMIT kwalletd->walletAsyncOpened(0, 0); 0403 SET_FUNCTION_RESULT_OVERLOADED(KWalletD::isOpen, true, bool(KWalletD::*)(int)); 0404 QVERIFY(!createdCollection->locked()); 0405 } 0406 0407 void FdoSecretsTest::session() 0408 { 0409 std::unique_ptr<KWalletD> kwalletd{new KWalletD}; 0410 std::unique_ptr<KWalletFreedesktopService> service{new KWalletFreedesktopService(kwalletd.get())}; 0411 0412 auto message = QDBusMessage::createSignal("dummy", "dummy", "dummy"); 0413 auto [sessionPath, symmetricKey, errorStr] = setupSession(service.get()); 0414 0415 /* Generate secret */ 0416 auto secret = FreedesktopSecret(sessionPath, QByteArray("It's a secret"), "text/plain"); 0417 QVERIFY(service->ensecret(message, secret)); 0418 0419 /* Try to decrypt by hand with symmetricKey */ 0420 auto cipher = QCA::Cipher("aes128", QCA::Cipher::CBC, QCA::Cipher::PKCS7, QCA::Decode, symmetricKey, secret.parameters); 0421 QCA::SecureArray result; 0422 result.append(cipher.update(QCA::MemoryRegion(secret.value.toByteArray()))); 0423 result.append(cipher.final()); 0424 0425 QCOMPARE(QString::fromUtf8(result.toByteArray()), "It's a secret"); 0426 0427 /* Try to decrypt by session */ 0428 QVERIFY(service->desecret(message, secret)); 0429 QCOMPARE(secret.value.toByteArray(), QByteArray("It's a secret")); 0430 } 0431 0432 void FdoSecretsTest::attributes() 0433 { 0434 KWalletFreedesktopAttributes attribs{"test"}; 0435 0436 attribs.newItem({"dir", "name"}); 0437 0438 attribs.setParam({"dir", "name"}, "param1", 0xff00ff00ff00ff00); 0439 attribs.setParam({"dir", "name"}, "param2", "string_param"); 0440 0441 QCOMPARE(attribs.getULongLongParam({"dir", "name"}, "param1", 0), 0xff00ff00ff00ff00); 0442 QCOMPARE(attribs.getStringParam({"dir", "name"}, "param2", ""), "string_param"); 0443 0444 attribs.renameLabel({"dir", "name"}, {"newdir", "newname"}); 0445 0446 QCOMPARE(attribs.getULongLongParam({"newdir", "newname"}, "param1", 0), 0xff00ff00ff00ff00); 0447 QCOMPARE(attribs.getStringParam({"newdir", "newname"}, "param2", ""), "string_param"); 0448 QCOMPARE(attribs.getULongLongParam({"dir", "name"}, "param1", 0xdef017), 0xdef017); 0449 QCOMPARE(attribs.getStringParam({"dir", "name"}, "param2", "default"), "default"); 0450 0451 attribs.setParam({"newdir", "newname"}, "param1", 100200300ULL); 0452 attribs.setParam({"newdir", "newname"}, "param2", "another_string_param"); 0453 0454 QCOMPARE(attribs.getULongLongParam({"newdir", "newname"}, "param1", 0), 100200300ULL); 0455 QCOMPARE(attribs.getStringParam({"newdir", "newname"}, "param2", ""), "another_string_param"); 0456 0457 QVERIFY(attribs.getAttributes({"newdir", "newname"}).empty()); 0458 0459 StrStrMap attribMap; 0460 attribMap["key1"] = "value1"; 0461 attribMap["key2"] = "value2"; 0462 0463 attribs.setAttributes({"newdir", "newname"}, attribMap); 0464 QCOMPARE(attribs.getAttributes({"newdir", "newname"}), attribMap); 0465 0466 attribs.setAttributes({"dir", "name"}, attribMap); 0467 /* Item not exists - expects empty attributes map */ 0468 QVERIFY(attribs.getAttributes({"dir", "name"}).empty()); 0469 0470 attribs.setParam({"dir1", "name1"}, "param1", "some_param"); 0471 QCOMPARE(attribs.getStringParam({"dir1", "name1"}, "param1", "default"), "default"); 0472 } 0473 0474 void FdoSecretsTest::walletNameEncodeDecode() 0475 { 0476 #define ENCODE_DECODE_CHECK(DECODED, ENCODED) \ 0477 do { \ 0478 auto encodedResult = KWallet::Backend::encodeWalletName(DECODED); \ 0479 auto decodedResult = KWallet::Backend::decodeWalletName(ENCODED); \ 0480 QCOMPARE(encodedResult, ENCODED); \ 0481 QCOMPARE(decodedResult, DECODED); \ 0482 } while (false) 0483 0484 ENCODE_DECODE_CHECK("/", ";2F"); 0485 QString allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789^&'@{}[],$=!-#()%.+_\r\n\t\f\v "; 0486 ENCODE_DECODE_CHECK(allowedChars, allowedChars); 0487 ENCODE_DECODE_CHECK("a/b/c\\", "a;2Fb;2Fc;5C"); 0488 ENCODE_DECODE_CHECK("/\\/", ";2F;5C;2F"); 0489 ENCODE_DECODE_CHECK(";;;", ";3B;3B;3B"); 0490 ENCODE_DECODE_CHECK(";3B", ";3B3B"); 0491 0492 #undef ENCODE_DECODE_CHECK 0493 } 0494 0495 QTEST_GUILESS_MAIN(FdoSecretsTest) 0496 0497 #include "moc_fdo_secrets_test.cpp"