1 /* 2 SPDX-FileCopyrightText: 2020 Sandro Kanuß <sknauss@kde.org> 3 4 SPDX-License-Identifier: LGPL-2.0-or-later 5 */ 6 7 #include "autocryptstorage.h" 8 #include "autocryptrecipient_p.h" 9 #include "autocryptstorage_p.h" 10 11 #include <QDir> 12 #include <QFile> 13 #include <QStandardPaths> 14 #include <QTemporaryFile> 15 #include <QUrl> 16 #include <autocrypt_debug.h> 17 18 using namespace MessageCore; 19 AutocryptStoragePrivate()20AutocryptStoragePrivate::AutocryptStoragePrivate() 21 : basePath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/autocrypt")) 22 { 23 } 24 25 AutocryptStorage::Ptr AutocryptStorage::mSelf = nullptr; 26 self()27AutocryptStorage::Ptr AutocryptStorage::self() 28 { 29 if (!mSelf) { 30 mSelf = AutocryptStorage::Ptr(new AutocryptStorage()); 31 } 32 33 return mSelf; 34 } 35 address2Filename(const QByteArray & addr)36QString address2Filename(const QByteArray &addr) 37 { 38 const auto url = QUrl::toPercentEncoding(QString::fromUtf8(addr)); 39 return QString::fromLatin1(url + ".json"); 40 } 41 AutocryptStorage()42AutocryptStorage::AutocryptStorage() 43 : d_ptr(new AutocryptStoragePrivate()) 44 { 45 } 46 getRecipient(const QByteArray & addr)47AutocryptRecipient::Ptr AutocryptStorage::getRecipient(const QByteArray &addr) 48 { 49 Q_D(AutocryptStorage); 50 if (d->recipients.contains(addr)) { 51 return d->recipients.value(addr); 52 } 53 54 const QString fileName(address2Filename(addr)); 55 if (d->basePath.exists(fileName)) { 56 QFile file(d->basePath.filePath(fileName)); 57 auto recipient = AutocryptRecipient::Ptr(new AutocryptRecipient); 58 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { 59 return nullptr; 60 } 61 recipient->fromJson(file.readAll()); 62 d->recipients[addr] = recipient; 63 return recipient; 64 } 65 return nullptr; 66 } 67 addRecipient(const QByteArray & addr)68AutocryptRecipient::Ptr AutocryptStorage::addRecipient(const QByteArray &addr) 69 { 70 Q_D(AutocryptStorage); 71 72 auto recipient = getRecipient(addr); 73 if (recipient) { 74 return recipient; 75 } 76 77 recipient = AutocryptRecipient::Ptr(new AutocryptRecipient); 78 recipient->d_func()->addr = addr; 79 d->recipients[addr] = recipient; 80 return recipient; 81 } 82 deleteRecipient(const QByteArray & addr)83void AutocryptStorage::deleteRecipient(const QByteArray &addr) 84 { 85 Q_D(AutocryptStorage); 86 const QString fileName(address2Filename(addr)); 87 d->basePath.remove(fileName); 88 d->recipients.remove(addr); 89 } 90 save()91void AutocryptStorage::save() 92 { 93 Q_D(AutocryptStorage); 94 if (!d->basePath.exists()) { 95 QDir parent = d->basePath; 96 if (!parent.cdUp()) { 97 qCWarning(AUTOCRYPT_LOG) << parent.absolutePath() << "does not exist. Cancel saving Autocrypt storage."; 98 return; 99 } 100 101 if (!parent.mkdir(d->basePath.dirName())) { 102 qCWarning(AUTOCRYPT_LOG) << "Cancel saving Autocrypt storage, because failed to create" << d->basePath.absolutePath(); 103 return; 104 } 105 } 106 const auto keys = d->recipients.keys(); 107 for (const auto &addr : keys) { 108 const auto recipient = d->recipients.value(addr); 109 const QString fileName(address2Filename(addr)); 110 if (recipient->hasChanged() || !d->basePath.exists(fileName)) { 111 QTemporaryFile file(d->basePath.path() + QLatin1Char('/')); 112 if (!file.open()) { 113 continue; 114 } 115 file.write(recipient->toJson(QJsonDocument::Compact)); 116 file.close(); 117 d->basePath.remove(fileName); 118 file.rename(d->basePath.filePath(fileName)); 119 file.setAutoRemove(false); 120 recipient->setChangedFlag(false); 121 } 122 } 123 } 124