File indexing completed on 2025-03-09 04:54:13
0001 /* 0002 SPDX-FileCopyrightText: 2020 Sandro Kanuß <sknauss@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "autocryptstorage.h" 0008 #include "autocryptrecipient_p.h" 0009 #include "autocryptstorage_p.h" 0010 0011 #include <QDir> 0012 #include <QFile> 0013 #include <QStandardPaths> 0014 #include <QTemporaryFile> 0015 #include <QUrl> 0016 #include <autocrypt_debug.h> 0017 0018 using namespace MessageCore; 0019 0020 AutocryptStoragePrivate::AutocryptStoragePrivate() 0021 : basePath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/autocrypt")) 0022 { 0023 } 0024 0025 AutocryptStorage::Ptr AutocryptStorage::mSelf = nullptr; 0026 0027 AutocryptStorage::Ptr AutocryptStorage::self() 0028 { 0029 if (!mSelf) { 0030 mSelf = AutocryptStorage::Ptr(new AutocryptStorage()); 0031 } 0032 0033 return mSelf; 0034 } 0035 0036 QString address2Filename(const QByteArray &addr) 0037 { 0038 const auto url = QUrl::toPercentEncoding(QString::fromUtf8(addr)); 0039 return QString::fromLatin1(url + ".json"); 0040 } 0041 0042 AutocryptStorage::AutocryptStorage() 0043 : d_ptr(new AutocryptStoragePrivate()) 0044 { 0045 } 0046 0047 AutocryptRecipient::Ptr AutocryptStorage::getRecipient(const QByteArray &addr) 0048 { 0049 Q_D(AutocryptStorage); 0050 if (d->recipients.contains(addr)) { 0051 return d->recipients.value(addr); 0052 } 0053 0054 const QString fileName(address2Filename(addr)); 0055 if (d->basePath.exists(fileName)) { 0056 QFile file(d->basePath.filePath(fileName)); 0057 auto recipient = AutocryptRecipient::Ptr(new AutocryptRecipient); 0058 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { 0059 return nullptr; 0060 } 0061 recipient->fromJson(file.readAll()); 0062 d->recipients[addr] = recipient; 0063 return recipient; 0064 } 0065 return nullptr; 0066 } 0067 0068 AutocryptRecipient::Ptr AutocryptStorage::addRecipient(const QByteArray &addr) 0069 { 0070 Q_D(AutocryptStorage); 0071 0072 auto recipient = getRecipient(addr); 0073 if (recipient) { 0074 return recipient; 0075 } 0076 0077 recipient = AutocryptRecipient::Ptr(new AutocryptRecipient); 0078 recipient->d_func()->addr = addr; 0079 d->recipients[addr] = recipient; 0080 return recipient; 0081 } 0082 0083 void AutocryptStorage::deleteRecipient(const QByteArray &addr) 0084 { 0085 Q_D(AutocryptStorage); 0086 const QString fileName(address2Filename(addr)); 0087 d->basePath.remove(fileName); 0088 d->recipients.remove(addr); 0089 } 0090 0091 void AutocryptStorage::save() 0092 { 0093 Q_D(AutocryptStorage); 0094 if (!d->basePath.exists()) { 0095 QDir parent = d->basePath; 0096 if (!parent.cdUp()) { 0097 qCWarning(AUTOCRYPT_LOG) << parent.absolutePath() << "does not exist. Cancel saving Autocrypt storage."; 0098 return; 0099 } 0100 0101 if (!parent.mkdir(d->basePath.dirName())) { 0102 qCWarning(AUTOCRYPT_LOG) << "Cancel saving Autocrypt storage, because failed to create" << d->basePath.absolutePath(); 0103 return; 0104 } 0105 } 0106 const auto keys = d->recipients.keys(); 0107 for (const auto &addr : keys) { 0108 const auto recipient = d->recipients.value(addr); 0109 const QString fileName(address2Filename(addr)); 0110 if (recipient->hasChanged() || !d->basePath.exists(fileName)) { 0111 QTemporaryFile file(d->basePath.path() + QLatin1Char('/')); 0112 if (!file.open()) { 0113 continue; 0114 } 0115 file.write(recipient->toJson(QJsonDocument::Compact)); 0116 file.close(); 0117 d->basePath.remove(fileName); 0118 file.rename(d->basePath.filePath(fileName)); 0119 file.setAutoRemove(false); 0120 recipient->setChangedFlag(false); 0121 } 0122 } 0123 }