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 
28 using namespace Kleo;
29 using 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
36 static const QString keyGroupNamePrefix = QStringLiteral("KeyGroup-");
37 
38 namespace
39 {
40 
41 QString readString(const QSettings &settings, const QString &key)
42 {
43  return settings.value(key, QString{}).toString();
44 }
45 
46 QStringList 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 
60 void writeString(QSettings &settings, const QString &key, const QString &string)
61 {
62  settings.setValue(key, string);
63 }
64 
65 void 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 
75 KeyGroup 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 
89 void 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 
105 std::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 
135 Kleo::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 }
int size() const const
void sync()
KIOCORE_EXPORT QStringList list(const QString &fileClass)
bool exists() const const
bool empty() const const
void setValue(const QString &key, const QVariant &value)
bool isEmpty() const const
QStringList childGroups() const const
void push_back(QChar ch)
QVariant value(const QString &key, const QVariant &defaultValue) const const
QStringList toStringList() const const
QString mid(int position, int n) const const
QSettings::Status status() const const
char * toString(const EngineQuery &query)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Thu Feb 15 2024 03:56:14 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.