Libkleo

keygroupimportexport.cpp
1/*
2 kleo/keygroupimportexport.cpp
3
4 This file is part of libkleopatra, the KDE keymanagement library
5 SPDX-FileCopyrightText: 2021 g10 Code GmbH
6 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
7
8 SPDX-License-Identifier: GPL-2.0-or-later
9*/
10
11#include <config-libkleo.h>
12
13#include "keygroupimportexport.h"
14
15#include "debug.h"
16#include "keygroup.h"
17
18#include <libkleo/keycache.h>
19#include <libkleo/keyhelpers.h>
20#include <libkleo/qtstlhelpers.h>
21
22#include <libkleo_debug.h>
23
24#include <QFile>
25#include <QSettings>
26#include <QString>
27
28using namespace Kleo;
29using namespace GpgME;
30
31// use a different, less generic prefix for the config group names than in
32// KeyGroupConfig to avoid problems with "Group-*" config groups created by
33// other applications; this means that the key groups stored in the normal group
34// configuration file cannot be read with the below functions, but that's a good
35// thing because the ini files created by KConfig are incompatible with QSettings
36static const QString keyGroupNamePrefix = QStringLiteral("KeyGroup-");
37
38namespace
39{
40
41QString readString(const QSettings &settings, const QString &key)
42{
43 return settings.value(key, QString{}).toString();
44}
45
46QStringList readStringList(const QSettings &settings, const QString &key)
47{
48 auto variant = settings.value(key);
49 if (!variant.isValid()) {
50 return {};
51 }
52 if ((variant.userType() == QMetaType::QString) && variant.toString().isEmpty()) {
53 // interpret empty string value as empty list instead of as list with an empty string
54 return {};
55 }
56 // opportunistically, interpret the value as string list
57 return variant.toStringList();
58}
59
60void writeString(QSettings &settings, const QString &key, const QString &string)
61{
62 settings.setValue(key, string);
63}
64
65void writeStringList(QSettings &settings, const QString &key, const QStringList &list)
66{
67 // write empty list as empty string to avoid Qt's "@Invalid()"
68 if (list.empty()) {
69 writeString(settings, key, {});
70 } else {
71 settings.setValue(key, list);
72 }
73}
74
75KeyGroup readGroup(const QSettings &groupsConfig, const QString &groupId)
76{
77 const QString configGroupPath = keyGroupNamePrefix + groupId + QLatin1Char{'/'};
78
79 const auto groupName = readString(groupsConfig, configGroupPath + QLatin1StringView{"Name"});
80 const auto fingerprints = readStringList(groupsConfig, configGroupPath + QLatin1StringView{"Keys"});
81 const std::vector<Key> groupKeys = KeyCache::instance()->findByFingerprint(toStdStrings(fingerprints));
82
83 KeyGroup g(groupId, groupName, groupKeys, KeyGroup::ApplicationConfig);
84 qCDebug(LIBKLEO_LOG) << __func__ << "Read group" << g;
85
86 return g;
87}
88
89void writeGroup(QSettings &groupsConfig, const KeyGroup &group)
90{
91 if (group.isNull()) {
92 qCDebug(LIBKLEO_LOG) << __func__ << "Error: group is null";
93 return;
94 }
95
96 const QString configGroupName = keyGroupNamePrefix + group.id();
97 qCDebug(LIBKLEO_LOG) << __func__ << "Writing config group" << configGroupName;
98 const QString configGroupPath = configGroupName + QLatin1Char{'/'};
99 writeString(groupsConfig, configGroupPath + QLatin1StringView{"Name"}, group.name());
100 writeStringList(groupsConfig, configGroupPath + QLatin1StringView{"Keys"}, Kleo::getFingerprints(group.keys()));
101}
102
103} // namespace
104
105std::vector<KeyGroup> Kleo::readKeyGroups(const QString &filename)
106{
107 std::vector<KeyGroup> groups;
108
109 if (filename.isEmpty()) {
110 return groups;
111 }
112
113 if (!QFile::exists(filename)) {
114 qCWarning(LIBKLEO_LOG) << __func__ << "File" << filename << "does not exist";
115 return groups;
116 }
117
118 const QSettings groupsConfig{filename, QSettings::IniFormat};
119 const QStringList configGroups = groupsConfig.childGroups();
120 for (const QString &configGroupName : configGroups) {
121 if (configGroupName.startsWith(keyGroupNamePrefix)) {
122 qCDebug(LIBKLEO_LOG) << __func__ << "Reading config group" << configGroupName;
123 const QString keyGroupId = configGroupName.mid(keyGroupNamePrefix.size());
124 if (keyGroupId.isEmpty()) {
125 qCWarning(LIBKLEO_LOG) << __func__ << "Config group" << configGroupName << "has empty group id";
126 continue;
127 }
128 groups.push_back(readGroup(groupsConfig, keyGroupId));
129 }
130 }
131
132 return groups;
133}
134
135Kleo::WriteKeyGroups Kleo::writeKeyGroups(const QString &filename, const std::vector<KeyGroup> &groups)
136{
137 if (filename.isEmpty()) {
138 return WriteKeyGroups::InvalidFilename;
139 }
140
141 QSettings groupsConfig{filename, QSettings::IniFormat};
142 for (const auto &group : groups) {
143 writeGroup(groupsConfig, group);
144 }
145 // ensure that the data is written to disk before calling status()
146 groupsConfig.sync();
147 qCDebug(LIBKLEO_LOG) << __func__ << "groupsConfig.status():" << groupsConfig.status();
148 return groupsConfig.status() == QSettings::NoError ? WriteKeyGroups::Success : WriteKeyGroups::Error;
149}
char * toString(const EngineQuery &query)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
bool exists() const const
bool empty() const const
QStringList childGroups() const const
void setValue(QAnyStringView key, const QVariant &value)
Status status() const const
void sync()
QVariant value(QAnyStringView key) const const
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) const const
void push_back(QChar ch)
qsizetype size() const const
QStringList toStringList() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:12 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.