File indexing completed on 2024-05-12 05:22:53
0001 /* 0002 test_cryptoconfig.cpp 0003 0004 This file is part of libkleopatra's test suite. 0005 SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB 0006 0007 SPDX-License-Identifier: GPL-2.0-only 0008 */ 0009 0010 #include <utils/compat.h> 0011 0012 #include <qgpgme/qgpgmenewcryptoconfig.h> 0013 0014 #include <QCoreApplication> 0015 #include <iostream> 0016 0017 using namespace std; 0018 using namespace QGpgME; 0019 0020 #include <gpgme++/engineinfo.h> 0021 #include <gpgme++/error.h> 0022 #include <gpgme++/global.h> 0023 0024 #include <stdlib.h> 0025 0026 int main(int argc, char **argv) 0027 { 0028 if (GpgME::initializeLibrary(0)) { 0029 return 1; 0030 } 0031 0032 if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.2.2") { 0033 cerr << "This test requires GnuPG 2.2.2 or later."; 0034 return 1; 0035 } 0036 0037 QCoreApplication::setApplicationName(QStringLiteral("test_cryptoconfig")); 0038 QCoreApplication app(argc, argv); 0039 0040 QGpgME::CryptoConfig *config = new QGpgMENewCryptoConfig; 0041 0042 // Dynamic querying of the options 0043 cout << "Components:" << endl; 0044 QStringList components = config->componentList(); 0045 0046 for (QStringList::Iterator compit = components.begin(); compit != components.end(); ++compit) { 0047 cout << "Component " << (*compit).toLocal8Bit().constData() << ":" << endl; 0048 const QGpgME::CryptoConfigComponent *comp = config->component(*compit); 0049 Q_ASSERT(comp); 0050 QStringList groups = comp->groupList(); 0051 for (QStringList::Iterator groupit = groups.begin(); groupit != groups.end(); ++groupit) { 0052 const QGpgME::CryptoConfigGroup *group = comp->group(*groupit); 0053 Q_ASSERT(group); 0054 cout << " Group " << (*groupit).toLocal8Bit().constData() << ": descr=\"" << group->description().toLocal8Bit().constData() << "\"" 0055 << " level=" << group->level() << endl; 0056 QStringList entries = group->entryList(); 0057 for (QStringList::Iterator entryit = entries.begin(); entryit != entries.end(); ++entryit) { 0058 const QGpgME::CryptoConfigEntry *entry = group->entry(*entryit); 0059 Q_ASSERT(entry); 0060 cout << " Entry " << (*entryit).toLocal8Bit().constData() << ":" 0061 << " descr=\"" << entry->description().toLocal8Bit().constData() << "\"" 0062 << " " << (entry->isSet() ? "is set" : "is not set"); 0063 if (!entry->isList()) { 0064 switch (entry->argType()) { 0065 case QGpgME::CryptoConfigEntry::ArgType_None: 0066 break; 0067 case QGpgME::CryptoConfigEntry::ArgType_Int: 0068 cout << " int value=" << entry->intValue(); 0069 break; 0070 case QGpgME::CryptoConfigEntry::ArgType_UInt: 0071 cout << " uint value=" << entry->uintValue(); 0072 break; 0073 case QGpgME::CryptoConfigEntry::ArgType_LDAPURL: 0074 case QGpgME::CryptoConfigEntry::ArgType_Path: 0075 // fallthrough 0076 case QGpgME::CryptoConfigEntry::ArgType_DirPath: 0077 // fallthrough 0078 case QGpgME::CryptoConfigEntry::ArgType_String: 0079 0080 cout << " string value=" << entry->stringValue().toLocal8Bit().constData(); 0081 break; 0082 case QGpgME::CryptoConfigEntry::NumArgType: 0083 // just metadata and should never actually occur in the switch 0084 break; 0085 } 0086 } else { // lists 0087 switch (entry->argType()) { 0088 case QGpgME::CryptoConfigEntry::ArgType_None: { 0089 cout << " set " << entry->numberOfTimesSet() << " times"; 0090 break; 0091 } 0092 case QGpgME::CryptoConfigEntry::ArgType_Int: { 0093 // (marc) if an entry isn't optional, you have to unset it for the default to take effect, so this Q_ASSERT is wrong: 0094 // Q_ASSERT( entry->isOptional() ); // empty lists must be allowed (see https://www.intevation.de/roundup/aegypten/issue121) 0095 std::vector<int> lst = entry->intValueList(); 0096 QString str; 0097 for (std::vector<int>::const_iterator it = lst.begin(); it != lst.end(); ++it) { 0098 str += QString::number(*it); 0099 } 0100 cout << " int values=" << str.toLocal8Bit().constData(); 0101 break; 0102 } 0103 case QGpgME::CryptoConfigEntry::ArgType_UInt: { 0104 // (marc) if an entry isn't optional, you have to unset it for the default to take effect, so this Q_ASSERT is wrong: 0105 // Q_ASSERT( entry->isOptional() ); // empty lists must be allowed (see https://www.intevation.de/roundup/aegypten/issue121) 0106 std::vector<uint> lst = entry->uintValueList(); 0107 QString str; 0108 for (std::vector<uint>::const_iterator it = lst.begin(); it != lst.end(); ++it) { 0109 str += QString::number(*it); 0110 } 0111 cout << " uint values=" << str.toLocal8Bit().constData(); 0112 break; 0113 } 0114 case QGpgME::CryptoConfigEntry::ArgType_LDAPURL: { 0115 // (marc) if an entry isn't optional, you have to unset it for the default to take effect, so this Q_ASSERT is wrong: 0116 // Q_ASSERT( entry->isOptional() ); // empty lists must be allowed (see https://www.intevation.de/roundup/aegypten/issue121) 0117 const QList<QUrl> urls = entry->urlValueList(); 0118 cout << " url values "; 0119 for (const QUrl &url : urls) { 0120 cout << url.toString().toLocal8Bit().constData() << " "; 0121 } 0122 cout << endl; 0123 } 0124 // fallthrough 0125 case QGpgME::CryptoConfigEntry::ArgType_Path: 0126 // fallthrough 0127 case QGpgME::CryptoConfigEntry::ArgType_DirPath: 0128 // fallthrough 0129 case QGpgME::CryptoConfigEntry::ArgType_String: 0130 // fallthrough string value lists were removed from 0131 // gpgconf in 2008 0132 case QGpgME::CryptoConfigEntry::NumArgType: 0133 // just metadata and should never actually occur in the switch 0134 break; 0135 } 0136 } 0137 cout << endl; 0138 } 0139 // ... 0140 } 0141 } 0142 0143 { 0144 // Static querying of a single boolean option 0145 static const char *s_entryName = "quiet"; 0146 QGpgME::CryptoConfigEntry *entry = Kleo::getCryptoConfigEntry(config, "dirmngr", s_entryName); 0147 if (entry) { 0148 Q_ASSERT(entry->argType() == QGpgME::CryptoConfigEntry::ArgType_None); 0149 bool val = entry->boolValue(); 0150 cout << "quiet option initially: " << (val ? "is set" : "is not set") << endl; 0151 0152 entry->setBoolValue(!val); 0153 Q_ASSERT(entry->isDirty()); 0154 config->sync(true); 0155 0156 // Clear cached values! 0157 config->clear(); 0158 0159 // Check new value 0160 entry = Kleo::getCryptoConfigEntry(config, "dirmngr", s_entryName); 0161 Q_ASSERT(entry); 0162 Q_ASSERT(entry->argType() == QGpgME::CryptoConfigEntry::ArgType_None); 0163 cout << "quiet option now: " << (val ? "is set" : "is not set") << endl; 0164 Q_ASSERT(entry->boolValue() == !val); 0165 0166 // Set to default 0167 entry->resetToDefault(); 0168 Q_ASSERT(entry->boolValue() == false); // that's the default 0169 Q_ASSERT(entry->isDirty()); 0170 Q_ASSERT(!entry->isSet()); 0171 config->sync(true); 0172 config->clear(); 0173 0174 // Check value 0175 entry = Kleo::getCryptoConfigEntry(config, "dirmngr", s_entryName); 0176 Q_ASSERT(!entry->isDirty()); 0177 Q_ASSERT(!entry->isSet()); 0178 cout << "quiet option reset to default: " << (entry->boolValue() ? "is set" : "is not set") << endl; 0179 Q_ASSERT(entry->boolValue() == false); 0180 0181 // Reset old value 0182 entry->setBoolValue(val); 0183 Q_ASSERT(entry->isDirty()); 0184 config->sync(true); 0185 0186 cout << "quiet option reset to initial: " << (val ? "is set" : "is not set") << endl; 0187 } else { 0188 cout << "Entry 'dirmngr/" << s_entryName << "' not found" << endl; 0189 } 0190 } 0191 0192 { 0193 // Static querying and setting of a single int option 0194 static const char *s_entryName = "ldaptimeout"; 0195 QGpgME::CryptoConfigEntry *entry = Kleo::getCryptoConfigEntry(config, "dirmngr", s_entryName); 0196 if (entry) { 0197 // type of entry should be int (since 2.3) or uint (until 2.2) 0198 Q_ASSERT(entry->argType() == QGpgME::CryptoConfigEntry::ArgType_Int || entry->argType() == QGpgME::CryptoConfigEntry::ArgType_UInt); 0199 const int initialValue = entry->argType() == QGpgME::CryptoConfigEntry::ArgType_Int ? entry->intValue() : static_cast<int>(entry->uintValue()); 0200 cout << "LDAP timeout initially: " << initialValue << " seconds." << endl; 0201 0202 // Test setting the option directly, then querying again 0203 // system( "echo 'ldaptimeout:0:101' | gpgconf --change-options dirmngr" ); 0204 // Now let's do it with the C++ API instead 0205 if (entry->argType() == QGpgME::CryptoConfigEntry::ArgType_Int) { 0206 entry->setIntValue(101); 0207 } else { 0208 entry->setUIntValue(101); 0209 } 0210 Q_ASSERT(entry->isDirty()); 0211 config->sync(true); 0212 0213 // Clear cached values! 0214 config->clear(); 0215 0216 // Check new value 0217 { 0218 entry = Kleo::getCryptoConfigEntry(config, "dirmngr", s_entryName); 0219 Q_ASSERT(entry); 0220 const int newValue = entry->argType() == QGpgME::CryptoConfigEntry::ArgType_Int ? entry->intValue() : static_cast<int>(entry->uintValue()); 0221 cout << "LDAP timeout now: " << newValue << " seconds." << endl; 0222 Q_ASSERT(newValue == 101); 0223 } 0224 0225 // Set to default 0226 { 0227 entry->resetToDefault(); 0228 const int defaultValue = entry->argType() == QGpgME::CryptoConfigEntry::ArgType_Int ? entry->intValue() : static_cast<int>(entry->uintValue()); 0229 cout << "LDAP timeout reset to default, " << defaultValue << " seconds." << endl; 0230 Q_ASSERT(defaultValue == 15); 0231 Q_ASSERT(entry->isDirty()); 0232 Q_ASSERT(!entry->isSet()); 0233 config->sync(true); 0234 config->clear(); 0235 } 0236 0237 // Check value 0238 { 0239 entry = Kleo::getCryptoConfigEntry(config, "dirmngr", s_entryName); 0240 Q_ASSERT(!entry->isDirty()); 0241 Q_ASSERT(!entry->isSet()); 0242 const int defaultValue = entry->argType() == QGpgME::CryptoConfigEntry::ArgType_Int ? entry->intValue() : static_cast<int>(entry->uintValue()); 0243 cout << "LDAP timeout reset to default, " << defaultValue << " seconds." << endl; 0244 Q_ASSERT(defaultValue == 15); 0245 } 0246 0247 // Reset old value 0248 if (entry->argType() == QGpgME::CryptoConfigEntry::ArgType_Int) { 0249 entry->setIntValue(initialValue); 0250 } else { 0251 entry->setUIntValue(initialValue); 0252 } 0253 Q_ASSERT(entry->isDirty()); 0254 config->sync(true); 0255 0256 cout << "LDAP timeout reset to initial " << initialValue << " seconds." << endl; 0257 } else { 0258 cout << "Entry 'dirmngr/" << s_entryName << "' not found" << endl; 0259 } 0260 } 0261 0262 { 0263 // Static querying and setting of a single string option 0264 static const char *s_entryName = "log-file"; 0265 QGpgME::CryptoConfigEntry *entry = Kleo::getCryptoConfigEntry(config, "dirmngr", s_entryName); 0266 if (entry) { 0267 Q_ASSERT(entry->argType() == QGpgME::CryptoConfigEntry::ArgType_Path); 0268 QString val = entry->stringValue(); 0269 cout << "Log-file initially: " << val.toLocal8Bit().constData() << endl; 0270 0271 // Test setting the option, sync'ing, then querying again 0272 entry->setStringValue(QStringLiteral("/tmp/test:%e5ä")); 0273 Q_ASSERT(entry->isDirty()); 0274 config->sync(true); 0275 0276 // Let's see how it prints it 0277 system("gpgconf --list-options dirmngr | grep log-file"); 0278 0279 // Clear cached values! 0280 config->clear(); 0281 0282 // Check new value 0283 entry = Kleo::getCryptoConfigEntry(config, "dirmngr", s_entryName); 0284 Q_ASSERT(entry); 0285 Q_ASSERT(entry->argType() == QGpgME::CryptoConfigEntry::ArgType_Path); 0286 cout << "Log-file now: " << entry->stringValue().toLocal8Bit().constData() << endl; 0287 Q_ASSERT(entry->stringValue() == QStringLiteral("/tmp/test:%e5ä")); // (or even with %e5 decoded) 0288 0289 // Reset old value 0290 #if 0 0291 QString arg(val); 0292 if (!arg.isEmpty()) { 0293 arg.prepend('"'); 0294 } 0295 Q3CString sys; 0296 sys.sprintf("echo 'log-file:%s' | gpgconf --change-options dirmngr", arg.local8Bit().data()); 0297 system(sys.data()); 0298 #endif 0299 entry->setStringValue(val); 0300 Q_ASSERT(entry->isDirty()); 0301 config->sync(true); 0302 0303 cout << "Log-file reset to initial " << val.toLocal8Bit().constData() << endl; 0304 } else { 0305 cout << "Entry 'dirmngr/" << s_entryName << "' not found" << endl; 0306 } 0307 } 0308 0309 { 0310 // Static querying and setting of the keyserver list option 0311 static const char *s_entryName = "keyserver"; 0312 QGpgME::CryptoConfigEntry *entry = Kleo::getCryptoConfigEntry(config, "gpgsm", s_entryName); 0313 if (entry) { 0314 Q_ASSERT(entry->argType() == QGpgME::CryptoConfigEntry::ArgType_LDAPURL); 0315 Q_ASSERT(entry->isList()); 0316 const QList<QUrl> val = entry->urlValueList(); 0317 cout << "URL list initially: "; 0318 for (const QUrl &url : val) { 0319 cout << url.toString().toLocal8Bit().constData() << ", "; 0320 } 0321 cout << endl; 0322 0323 // Test setting the option, sync'ing, then querying again 0324 QList<QUrl> lst; 0325 lst << QUrl(QStringLiteral("ldap://a:389?b")); 0326 Q_ASSERT(lst[0].query() == QLatin1Char('b')); 0327 lst << QUrl(QStringLiteral("ldap://foo:389?a:b c")); 0328 Q_ASSERT(lst[1].query() == QStringLiteral("a:b c")); // see, the space got _not_escaped 0329 lst << QUrl(QStringLiteral("ldap://server:389?a=b,c=DE")); 0330 Q_ASSERT(lst[2].query() == QStringLiteral("a=b,c=DE")); // the query contains a literal ',' 0331 lst << QUrl(QStringLiteral("ldap://foo:389?a#ldaps")); 0332 Q_ASSERT(lst[3].fragment() == QStringLiteral("ldaps")); 0333 // cout << " trying to set: " << lst.toStringList().join(", ").local8Bit() << endl; 0334 entry->setURLValueList(lst); 0335 Q_ASSERT(entry->isDirty()); 0336 config->sync(true); 0337 0338 // Let's see how it prints it 0339 system("gpgconf --list-options gpgsm | grep 'keyserver'"); 0340 0341 // Clear cached values! 0342 config->clear(); 0343 0344 // Check new value 0345 entry = Kleo::getCryptoConfigEntry(config, "gpgsm", s_entryName); 0346 Q_ASSERT(entry); 0347 Q_ASSERT(entry->argType() == QGpgME::CryptoConfigEntry::ArgType_LDAPURL); 0348 Q_ASSERT(entry->isList()); 0349 // Get QUrl form 0350 const QList<QUrl> newlst = entry->urlValueList(); 0351 cout << "URL list now: "; 0352 for (const QUrl &url : newlst) { 0353 cout << url.toString().toLocal8Bit().constData() << ", "; 0354 } 0355 cout << endl; 0356 Q_ASSERT(newlst.size() == lst.size()); 0357 Q_ASSERT(newlst[0].url() == lst[0].url()); 0358 Q_ASSERT(newlst[1].url() == lst[1].url()); 0359 Q_ASSERT(newlst[2].url() == lst[2].url()); 0360 Q_ASSERT(newlst[3].url() == lst[3].url()); 0361 0362 // Reset old value 0363 entry->setURLValueList(val); 0364 Q_ASSERT(entry->isDirty()); 0365 config->sync(true); 0366 0367 const QList<QUrl> resetList = entry->urlValueList(); 0368 cout << "URL list reset to initial: "; 0369 for (const QUrl &url : resetList) { 0370 cout << url.toString().toLocal8Bit().constData() << ", "; 0371 } 0372 cout << endl; 0373 } else { 0374 cout << "Entry 'gpgsm/" << s_entryName << "' not found" << endl; 0375 } 0376 } 0377 0378 cout << "Done." << endl; 0379 }