File indexing completed on 2024-06-16 04:55:55

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 }