File indexing completed on 2024-06-23 05:13:54
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 crypto/certificateresolver.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include <config-kleopatra.h> 0011 0012 #include "certificateresolver.h" 0013 0014 #include <Libkleo/KeyCache> 0015 0016 #include <gpgme++/key.h> 0017 0018 #include <KConfig> 0019 #include <KConfigGroup> 0020 #include <QRegularExpression> 0021 0022 #include <QByteArray> 0023 #include <QHash> 0024 #include <QSet> 0025 0026 #include <algorithm> 0027 #include <iterator> 0028 0029 using namespace Kleo; 0030 using namespace Kleo::Crypto; 0031 using namespace GpgME; 0032 using namespace KMime::Types; 0033 0034 class KConfigBasedRecipientPreferences::Private 0035 { 0036 friend class ::Kleo::Crypto::KConfigBasedRecipientPreferences; 0037 KConfigBasedRecipientPreferences *const q; 0038 0039 public: 0040 explicit Private(const KSharedConfigPtr &config, KConfigBasedRecipientPreferences *qq); 0041 ~Private(); 0042 0043 private: 0044 void ensurePrefsParsed() const; 0045 void writePrefs(); 0046 0047 private: 0048 KSharedConfigPtr m_config; 0049 0050 mutable QHash<QByteArray, QByteArray> pgpPrefs; 0051 mutable QHash<QByteArray, QByteArray> cmsPrefs; 0052 mutable bool m_parsed; 0053 mutable bool m_dirty; 0054 }; 0055 0056 KConfigBasedRecipientPreferences::Private::Private(const KSharedConfigPtr &config, KConfigBasedRecipientPreferences *qq) 0057 : q(qq) 0058 , m_config(config) 0059 , m_parsed(false) 0060 , m_dirty(false) 0061 { 0062 Q_UNUSED(q); 0063 Q_ASSERT(m_config); 0064 } 0065 0066 KConfigBasedRecipientPreferences::Private::~Private() 0067 { 0068 writePrefs(); 0069 } 0070 0071 void KConfigBasedRecipientPreferences::Private::writePrefs() 0072 { 0073 if (!m_dirty) { 0074 return; 0075 } 0076 const auto pgpPrefsKeys = pgpPrefs.keys(); 0077 const auto cmsPrefsKeys = cmsPrefs.keys(); 0078 const QSet<QByteArray> keys = QSet<QByteArray>(pgpPrefsKeys.begin(), pgpPrefsKeys.end()) + QSet<QByteArray>(cmsPrefsKeys.begin(), cmsPrefsKeys.end()); 0079 0080 int n = 0; 0081 for (const QByteArray &i : keys) { 0082 KConfigGroup group(m_config, QStringLiteral("EncryptionPreference_%1").arg(n++)); 0083 group.writeEntry("email", i); 0084 const QByteArray pgp = pgpPrefs.value(i); 0085 if (!pgp.isEmpty()) { 0086 group.writeEntry("pgpCertificate", pgp); 0087 } 0088 const QByteArray cms = cmsPrefs.value(i); 0089 if (!cms.isEmpty()) { 0090 group.writeEntry("cmsCertificate", cms); 0091 } 0092 } 0093 m_config->sync(); 0094 m_dirty = false; 0095 } 0096 void KConfigBasedRecipientPreferences::Private::ensurePrefsParsed() const 0097 { 0098 if (m_parsed) { 0099 return; 0100 } 0101 const QStringList groups = m_config->groupList().filter(QRegularExpression(QStringLiteral("^EncryptionPreference_\\d+$"))); 0102 0103 for (const QString &i : groups) { 0104 const KConfigGroup group(m_config, i); 0105 const QByteArray id = group.readEntry("email", QByteArray()); 0106 if (id.isEmpty()) { 0107 continue; 0108 } 0109 pgpPrefs.insert(id, group.readEntry("pgpCertificate", QByteArray())); 0110 cmsPrefs.insert(id, group.readEntry("cmsCertificate", QByteArray())); 0111 } 0112 m_parsed = true; 0113 } 0114 0115 KConfigBasedRecipientPreferences::KConfigBasedRecipientPreferences(const KSharedConfigPtr &config) 0116 : d(new Private(config, this)) 0117 { 0118 } 0119 0120 KConfigBasedRecipientPreferences::~KConfigBasedRecipientPreferences() 0121 { 0122 d->writePrefs(); 0123 } 0124 0125 Key KConfigBasedRecipientPreferences::preferredCertificate(const Mailbox &recipient, Protocol protocol) 0126 { 0127 d->ensurePrefsParsed(); 0128 0129 const QByteArray keyId = (protocol == CMS ? d->cmsPrefs : d->pgpPrefs).value(recipient.address()); 0130 return KeyCache::instance()->findByKeyIDOrFingerprint(keyId.constData()); 0131 } 0132 0133 void KConfigBasedRecipientPreferences::setPreferredCertificate(const Mailbox &recipient, Protocol protocol, const Key &certificate) 0134 { 0135 d->ensurePrefsParsed(); 0136 if (!recipient.hasAddress()) { 0137 return; 0138 } 0139 (protocol == CMS ? d->cmsPrefs : d->pgpPrefs).insert(recipient.address(), certificate.keyID()); 0140 d->m_dirty = true; 0141 } 0142 0143 class KConfigBasedSigningPreferences::Private 0144 { 0145 friend class ::Kleo::Crypto::KConfigBasedSigningPreferences; 0146 KConfigBasedSigningPreferences *const q; 0147 0148 public: 0149 explicit Private(const KSharedConfigPtr &config, KConfigBasedSigningPreferences *qq); 0150 ~Private(); 0151 0152 private: 0153 void ensurePrefsParsed() const; 0154 void writePrefs(); 0155 0156 private: 0157 KSharedConfigPtr m_config; 0158 0159 mutable QByteArray pgpSigningCertificate; 0160 mutable QByteArray cmsSigningCertificate; 0161 mutable bool m_parsed; 0162 mutable bool m_dirty; 0163 }; 0164 0165 KConfigBasedSigningPreferences::Private::Private(const KSharedConfigPtr &config, KConfigBasedSigningPreferences *qq) 0166 : q(qq) 0167 , m_config(config) 0168 , m_parsed(false) 0169 , m_dirty(false) 0170 { 0171 Q_UNUSED(q); 0172 Q_ASSERT(m_config); 0173 } 0174 0175 void KConfigBasedSigningPreferences::Private::ensurePrefsParsed() const 0176 { 0177 if (m_parsed) { 0178 return; 0179 } 0180 const KConfigGroup group(m_config, QStringLiteral("SigningPreferences")); 0181 pgpSigningCertificate = group.readEntry("pgpSigningCertificate", QByteArray()); 0182 cmsSigningCertificate = group.readEntry("cmsSigningCertificate", QByteArray()); 0183 m_parsed = true; 0184 } 0185 0186 void KConfigBasedSigningPreferences::Private::writePrefs() 0187 { 0188 if (!m_dirty) { 0189 return; 0190 } 0191 KConfigGroup group(m_config, QStringLiteral("SigningPreferences")); 0192 group.writeEntry("pgpSigningCertificate", pgpSigningCertificate); 0193 group.writeEntry("cmsSigningCertificate", cmsSigningCertificate); 0194 m_config->sync(); 0195 m_dirty = false; 0196 } 0197 0198 KConfigBasedSigningPreferences::Private::~Private() 0199 { 0200 writePrefs(); 0201 } 0202 0203 KConfigBasedSigningPreferences::KConfigBasedSigningPreferences(const KSharedConfigPtr &config) 0204 : d(new Private(config, this)) 0205 { 0206 } 0207 0208 KConfigBasedSigningPreferences::~KConfigBasedSigningPreferences() 0209 { 0210 d->writePrefs(); 0211 } 0212 0213 Key KConfigBasedSigningPreferences::preferredCertificate(Protocol protocol) 0214 { 0215 d->ensurePrefsParsed(); 0216 0217 const QByteArray keyId = (protocol == CMS ? d->cmsSigningCertificate : d->pgpSigningCertificate); 0218 const Key key = KeyCache::instance()->findByKeyIDOrFingerprint(keyId.constData()); 0219 return key.hasSecret() ? key : Key::null; 0220 } 0221 0222 void KConfigBasedSigningPreferences::setPreferredCertificate(Protocol protocol, const Key &certificate) 0223 { 0224 d->ensurePrefsParsed(); 0225 (protocol == CMS ? d->cmsSigningCertificate : d->pgpSigningCertificate) = certificate.keyID(); 0226 d->m_dirty = true; 0227 }