File indexing completed on 2024-11-17 04:50:27

0001 /*
0002     kleo/keygroupconfig.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 "keygroupconfig.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 <KConfigGroup>
0025 #include <KSharedConfig>
0026 
0027 #include <QString>
0028 
0029 #include <gpgme++/key.h>
0030 
0031 using namespace Kleo;
0032 using namespace GpgME;
0033 
0034 static const QString groupNamePrefix = QStringLiteral("Group-");
0035 
0036 class KeyGroupConfig::Private
0037 {
0038 public:
0039     explicit Private(const QString &filename);
0040 
0041     std::vector<KeyGroup> readGroups() const;
0042     KeyGroup writeGroup(const KeyGroup &group);
0043     bool removeGroup(const KeyGroup &group);
0044 
0045 private:
0046     KeyGroup readGroup(const KSharedConfigPtr &groupsConfig, const QString &groupId) const;
0047 
0048 private:
0049     QString filename;
0050 };
0051 
0052 KeyGroupConfig::Private::Private(const QString &filename)
0053     : filename{filename}
0054 {
0055     if (filename.isEmpty()) {
0056         qCWarning(LIBKLEO_LOG) << __func__ << "Warning: name of configuration file is empty";
0057     }
0058 }
0059 
0060 KeyGroup KeyGroupConfig::Private::readGroup(const KSharedConfigPtr &groupsConfig, const QString &groupId) const
0061 {
0062     const KConfigGroup configGroup = groupsConfig->group(groupNamePrefix + groupId);
0063 
0064     const QString groupName = configGroup.readEntry("Name", QString());
0065     const auto fingerprints = toStdStrings(configGroup.readEntry("Keys", QStringList()));
0066     const std::vector<Key> groupKeys = KeyCache::instance()->findByFingerprint(fingerprints);
0067 
0068     // treat group as immutable if any of its entries is immutable
0069     const QStringList entries = configGroup.keyList();
0070     const bool isImmutable = (configGroup.isImmutable() //
0071                               || std::any_of(entries.begin(), entries.end(), [configGroup](const QString &entry) {
0072                                      return configGroup.isEntryImmutable(entry);
0073                                  }));
0074 
0075     KeyGroup g(groupId, groupName, groupKeys, KeyGroup::ApplicationConfig);
0076     g.setIsImmutable(isImmutable);
0077     qCDebug(LIBKLEO_LOG) << "Read group" << g;
0078 
0079     return g;
0080 }
0081 
0082 std::vector<KeyGroup> KeyGroupConfig::Private::readGroups() const
0083 {
0084     std::vector<KeyGroup> groups;
0085 
0086     if (filename.isEmpty()) {
0087         return groups;
0088     }
0089 
0090     const KSharedConfigPtr groupsConfig = KSharedConfig::openConfig(filename);
0091     const QStringList configGroups = groupsConfig->groupList();
0092     for (const QString &configGroupName : configGroups) {
0093         qCDebug(LIBKLEO_LOG) << "Reading config group" << configGroupName;
0094         if (configGroupName.startsWith(groupNamePrefix)) {
0095             const QString keyGroupId = configGroupName.mid(groupNamePrefix.size());
0096             if (keyGroupId.isEmpty()) {
0097                 qCWarning(LIBKLEO_LOG) << "Config group" << configGroupName << "has empty group id";
0098                 continue;
0099             }
0100             KeyGroup group = readGroup(groupsConfig, keyGroupId);
0101             groups.push_back(group);
0102         }
0103     }
0104 
0105     return groups;
0106 }
0107 
0108 KeyGroup KeyGroupConfig::Private::writeGroup(const KeyGroup &group)
0109 {
0110     if (filename.isEmpty()) {
0111         return {};
0112     }
0113 
0114     if (group.isNull()) {
0115         qCDebug(LIBKLEO_LOG) << __func__ << "Error: group is null";
0116         return group;
0117     }
0118 
0119     KSharedConfigPtr groupsConfig = KSharedConfig::openConfig(filename);
0120     KConfigGroup configGroup = groupsConfig->group(groupNamePrefix + group.id());
0121 
0122     qCDebug(LIBKLEO_LOG) << __func__ << "Writing config group" << configGroup.name();
0123     configGroup.writeEntry("Name", group.name());
0124     configGroup.writeEntry("Keys", Kleo::getFingerprints(group.keys()));
0125 
0126     // reread group to ensure that it reflects the saved group in case of immutable entries
0127     return readGroup(groupsConfig, group.id());
0128 }
0129 
0130 bool KeyGroupConfig::Private::removeGroup(const KeyGroup &group)
0131 {
0132     if (filename.isEmpty()) {
0133         return false;
0134     }
0135 
0136     if (group.isNull()) {
0137         qCDebug(LIBKLEO_LOG) << __func__ << "Error: group is null";
0138         return false;
0139     }
0140 
0141     KSharedConfigPtr groupsConfig = KSharedConfig::openConfig(filename);
0142     KConfigGroup configGroup = groupsConfig->group(groupNamePrefix + group.id());
0143 
0144     qCDebug(LIBKLEO_LOG) << __func__ << "Removing config group" << configGroup.name();
0145     configGroup.deleteGroup(QLatin1StringView());
0146 
0147     return true;
0148 }
0149 
0150 KeyGroupConfig::KeyGroupConfig(const QString &filename)
0151     : d{std::make_unique<Private>(filename)}
0152 {
0153 }
0154 
0155 KeyGroupConfig::~KeyGroupConfig() = default;
0156 
0157 std::vector<KeyGroup> KeyGroupConfig::readGroups() const
0158 {
0159     return d->readGroups();
0160 }
0161 
0162 KeyGroup KeyGroupConfig::writeGroup(const KeyGroup &group)
0163 {
0164     return d->writeGroup(group);
0165 }
0166 
0167 void KeyGroupConfig::writeGroups(const std::vector<KeyGroup> &groups)
0168 {
0169     std::for_each(std::begin(groups), std::end(groups), [this](const auto &group) {
0170         d->writeGroup(group);
0171     });
0172 }
0173 
0174 bool KeyGroupConfig::removeGroup(const KeyGroup &group)
0175 {
0176     return d->removeGroup(group);
0177 }