File indexing completed on 2024-11-17 04:50:27
0001 /* 0002 kleo/keygroupimportexport.cpp 0003 0004 This file is part of libkleopatra, the KDE keymanagement library 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 <config-libkleo.h> 0012 0013 #include "keygroupimportexport.h" 0014 0015 #include "debug.h" 0016 #include "keygroup.h" 0017 0018 #include <libkleo/keycache.h> 0019 #include <libkleo/keyhelpers.h> 0020 #include <libkleo/qtstlhelpers.h> 0021 0022 #include <libkleo_debug.h> 0023 0024 #include <QFile> 0025 #include <QSettings> 0026 #include <QString> 0027 0028 using namespace Kleo; 0029 using namespace GpgME; 0030 0031 // use a different, less generic prefix for the config group names than in 0032 // KeyGroupConfig to avoid problems with "Group-*" config groups created by 0033 // other applications; this means that the key groups stored in the normal group 0034 // configuration file cannot be read with the below functions, but that's a good 0035 // thing because the ini files created by KConfig are incompatible with QSettings 0036 static const QString keyGroupNamePrefix = QStringLiteral("KeyGroup-"); 0037 0038 namespace 0039 { 0040 0041 QString readString(const QSettings &settings, const QString &key) 0042 { 0043 return settings.value(key, QString{}).toString(); 0044 } 0045 0046 QStringList readStringList(const QSettings &settings, const QString &key) 0047 { 0048 auto variant = settings.value(key); 0049 if (!variant.isValid()) { 0050 return {}; 0051 } 0052 if ((variant.userType() == QMetaType::QString) && variant.toString().isEmpty()) { 0053 // interpret empty string value as empty list instead of as list with an empty string 0054 return {}; 0055 } 0056 // opportunistically, interpret the value as string list 0057 return variant.toStringList(); 0058 } 0059 0060 void writeString(QSettings &settings, const QString &key, const QString &string) 0061 { 0062 settings.setValue(key, string); 0063 } 0064 0065 void writeStringList(QSettings &settings, const QString &key, const QStringList &list) 0066 { 0067 // write empty list as empty string to avoid Qt's "@Invalid()" 0068 if (list.empty()) { 0069 writeString(settings, key, {}); 0070 } else { 0071 settings.setValue(key, list); 0072 } 0073 } 0074 0075 KeyGroup readGroup(const QSettings &groupsConfig, const QString &groupId) 0076 { 0077 const QString configGroupPath = keyGroupNamePrefix + groupId + QLatin1Char{'/'}; 0078 0079 const auto groupName = readString(groupsConfig, configGroupPath + QLatin1StringView{"Name"}); 0080 const auto fingerprints = readStringList(groupsConfig, configGroupPath + QLatin1StringView{"Keys"}); 0081 const std::vector<Key> groupKeys = KeyCache::instance()->findByFingerprint(toStdStrings(fingerprints)); 0082 0083 KeyGroup g(groupId, groupName, groupKeys, KeyGroup::ApplicationConfig); 0084 qCDebug(LIBKLEO_LOG) << __func__ << "Read group" << g; 0085 0086 return g; 0087 } 0088 0089 void writeGroup(QSettings &groupsConfig, const KeyGroup &group) 0090 { 0091 if (group.isNull()) { 0092 qCDebug(LIBKLEO_LOG) << __func__ << "Error: group is null"; 0093 return; 0094 } 0095 0096 const QString configGroupName = keyGroupNamePrefix + group.id(); 0097 qCDebug(LIBKLEO_LOG) << __func__ << "Writing config group" << configGroupName; 0098 const QString configGroupPath = configGroupName + QLatin1Char{'/'}; 0099 writeString(groupsConfig, configGroupPath + QLatin1StringView{"Name"}, group.name()); 0100 writeStringList(groupsConfig, configGroupPath + QLatin1StringView{"Keys"}, Kleo::getFingerprints(group.keys())); 0101 } 0102 0103 } // namespace 0104 0105 std::vector<KeyGroup> Kleo::readKeyGroups(const QString &filename) 0106 { 0107 std::vector<KeyGroup> groups; 0108 0109 if (filename.isEmpty()) { 0110 return groups; 0111 } 0112 0113 if (!QFile::exists(filename)) { 0114 qCWarning(LIBKLEO_LOG) << __func__ << "File" << filename << "does not exist"; 0115 return groups; 0116 } 0117 0118 const QSettings groupsConfig{filename, QSettings::IniFormat}; 0119 const QStringList configGroups = groupsConfig.childGroups(); 0120 for (const QString &configGroupName : configGroups) { 0121 if (configGroupName.startsWith(keyGroupNamePrefix)) { 0122 qCDebug(LIBKLEO_LOG) << __func__ << "Reading config group" << configGroupName; 0123 const QString keyGroupId = configGroupName.mid(keyGroupNamePrefix.size()); 0124 if (keyGroupId.isEmpty()) { 0125 qCWarning(LIBKLEO_LOG) << __func__ << "Config group" << configGroupName << "has empty group id"; 0126 continue; 0127 } 0128 groups.push_back(readGroup(groupsConfig, keyGroupId)); 0129 } 0130 } 0131 0132 return groups; 0133 } 0134 0135 Kleo::WriteKeyGroups Kleo::writeKeyGroups(const QString &filename, const std::vector<KeyGroup> &groups) 0136 { 0137 if (filename.isEmpty()) { 0138 return WriteKeyGroups::InvalidFilename; 0139 } 0140 0141 QSettings groupsConfig{filename, QSettings::IniFormat}; 0142 for (const auto &group : groups) { 0143 writeGroup(groupsConfig, group); 0144 } 0145 // ensure that the data is written to disk before calling status() 0146 groupsConfig.sync(); 0147 qCDebug(LIBKLEO_LOG) << __func__ << "groupsConfig.status():" << groupsConfig.status(); 0148 return groupsConfig.status() == QSettings::NoError ? WriteKeyGroups::Success : WriteKeyGroups::Error; 0149 }