Use only safe file saving in localstorage.

This commit is contained in:
John Preston 2020-04-02 18:31:15 +04:00
parent e823fe5891
commit 2ad48f18f2
2 changed files with 235 additions and 209 deletions

View File

@ -111,68 +111,62 @@ bool _userWorking() {
return _manager && !_basePath.isEmpty() && !_userBasePath.isEmpty(); return _manager && !_basePath.isEmpty() && !_userBasePath.isEmpty();
} }
enum class FileOption { enum class FileOwner {
User = (1 << 0), User = (1 << 0),
Safe = (1 << 1), Global = (1 << 1),
}; };
using FileOptions = base::flags<FileOption>;
inline constexpr auto is_flag_type(FileOption) { return true; };
bool keyAlreadyUsed(QString &name, FileOptions options = FileOption::User | FileOption::Safe) { [[nodiscard]] bool KeyAlreadyUsed(QString &name) {
name += '0'; name += '0';
if (QFileInfo(name).exists()) { if (QFileInfo(name).exists()) {
return true; return true;
} }
if (options & (FileOption::Safe)) { name[name.size() - 1] = '1';
name[name.size() - 1] = '1'; if (QFileInfo(name).exists()) {
if (QFileInfo(name).exists()) { return true;
return true; }
} name[name.size() - 1] = 's';
name[name.size() - 1] = 's'; if (QFileInfo(name).exists()) {
if (QFileInfo(name).exists()) { return true;
return true;
}
} }
return false; return false;
} }
FileKey genKey(FileOptions options = FileOption::User | FileOption::Safe) { [[nodiscard]] FileKey GenerateKey(FileOwner owner = FileOwner::User) {
if (options & FileOption::User) { if (owner == FileOwner::User) {
if (!_userWorking()) return 0; if (!_userWorking()) return 0;
} else { } else {
if (!_working()) return 0; if (!_working()) return 0;
} }
FileKey result; FileKey result;
QString base = (options & FileOption::User) ? _userBasePath : _basePath, path; QString base = (owner == FileOwner::User) ? _userBasePath : _basePath, path;
path.reserve(base.size() + 0x11); path.reserve(base.size() + 0x11);
path += base; path += base;
do { do {
result = rand_value<FileKey>(); result = rand_value<FileKey>();
path.resize(base.size()); path.resize(base.size());
path += toFilePart(result); path += toFilePart(result);
} while (!result || keyAlreadyUsed(path, options)); } while (!result || KeyAlreadyUsed(path));
return result; return result;
} }
void clearKey(const FileKey &key, FileOptions options = FileOption::User | FileOption::Safe) { void ClearKey(const FileKey &key, FileOwner owner = FileOwner::User) {
if (options & FileOption::User) { if (owner == FileOwner::User) {
if (!_userWorking()) return; if (!_userWorking()) return;
} else { } else {
if (!_working()) return; if (!_working()) return;
} }
QString base = (options & FileOption::User) ? _userBasePath : _basePath, name; QString base = (owner == FileOwner::User) ? _userBasePath : _basePath, name;
name.reserve(base.size() + 0x11); name.reserve(base.size() + 0x11);
name.append(base).append(toFilePart(key)).append('0'); name.append(base).append(toFilePart(key)).append('0');
QFile::remove(name); QFile::remove(name);
if (options & FileOption::Safe) { name[name.size() - 1] = '1';
name[name.size() - 1] = '1'; QFile::remove(name);
QFile::remove(name); name[name.size() - 1] = 's';
name[name.size() - 1] = 's'; QFile::remove(name);
QFile::remove(name);
}
} }
bool _checkStreamStatus(QDataStream &stream) { bool _checkStreamStatus(QDataStream &stream) {
@ -251,31 +245,37 @@ struct EncryptedDescriptor {
} }
}; };
struct FileWriteDescriptor { class FileWriteDescriptor final {
FileWriteDescriptor( public:
explicit FileWriteDescriptor(
const FileKey &key, const FileKey &key,
FileOptions options = FileOption::User | FileOption::Safe); FileOwner owner = FileOwner::User);
FileWriteDescriptor( explicit FileWriteDescriptor(
const QString &name, const QString &name,
FileOptions options = FileOption::User | FileOption::Safe); FileOwner owner = FileOwner::User);
~FileWriteDescriptor(); ~FileWriteDescriptor();
void init(const QString &name, FileOptions options); void writeData(const QByteArray &data);
bool writeData(const QByteArray &data); void writeEncrypted(
bool writeEncrypted(
EncryptedDescriptor &data, EncryptedDescriptor &data,
const MTP::AuthKeyPtr &key = LocalKey); const MTP::AuthKeyPtr &key = LocalKey);
private:
void init(const QString &name);
[[nodiscard]] QString path(char postfix) const;
template <typename File>
[[nodiscard]] bool open(File &file, char postfix);
[[nodiscard]] bool writeHeader(QFileDevice &file);
void writeFooter(QFileDevice &file);
void finish(); void finish();
QFile plainFile; const FileOwner _owner = FileOwner();
QSaveFile saveFile; QBuffer _buffer;
not_null<QFileDevice*> file; QDataStream _stream;
QDataStream stream; QByteArray _safeData;
QString _base;
QString toDelete; HashMd5 _md5;
int _fullSize = 0;
HashMd5 md5;
int32 dataSize = 0;
}; };
@ -302,152 +302,168 @@ struct FileWriteDescriptor {
FileWriteDescriptor::FileWriteDescriptor( FileWriteDescriptor::FileWriteDescriptor(
const FileKey &key, const FileKey &key,
FileOptions options) FileOwner owner)
: file((options & FileOption::Safe) ? (QFileDevice*)&saveFile : &plainFile) { : FileWriteDescriptor(toFilePart(key), owner) {
init(toFilePart(key), options);
} }
FileWriteDescriptor::FileWriteDescriptor( FileWriteDescriptor::FileWriteDescriptor(
const QString &name, const QString &name,
FileOptions options) FileOwner owner)
: file((options & FileOption::Safe) ? (QFileDevice*)&saveFile : &plainFile) { : _owner(owner) {
init(name, options); init(name);
} }
FileWriteDescriptor::~FileWriteDescriptor() { FileWriteDescriptor::~FileWriteDescriptor() {
finish(); finish();
} }
void FileWriteDescriptor::init(const QString &name, FileOptions options) { QString FileWriteDescriptor::path(char postfix) const {
if (options & FileOption::User) { return _base + postfix;
if (!_userWorking()) return;
} else {
if (!_working()) return;
}
const auto base = ((options & FileOption::User) ? _userBasePath : _basePath) + name;
saveFile.setFileName(base + 's');
plainFile.setFileName(base + '0');
if (options & FileOption::Safe) {
toDelete = base;
}
if (!file->open(QIODevice::WriteOnly)) {
LOG(("Storage Error: Could not open '%1' for writing.").arg(file->fileName()));
if (!(options & FileOption::Safe)) {
return;
}
file = &plainFile;
LOG(("Storage Info: Trying to fallback to '%1'.").arg(file->fileName()));
if (!file->open(QIODevice::WriteOnly)) {
LOG(("Storage Error: Could not open '%1' for safe writing.").arg(file->fileName()));
return;
}
}
file->write(tdfMagic, tdfMagicLen);
qint32 version = AppVersion;
file->write((const char*)&version, sizeof(version));
stream.setDevice(file);
stream.setVersion(QDataStream::Qt_5_1);
} }
bool FileWriteDescriptor::writeData(const QByteArray &data) { template <typename File>
if (!file->isOpen()) { bool FileWriteDescriptor::open(File &file, char postfix) {
const auto name = path(postfix);
file.setFileName(name);
if (!writeHeader(file)) {
LOG(("Storage Error: Could not open '%1' for writing.").arg(name));
return false; return false;
} }
return true;
}
stream << data; bool FileWriteDescriptor::writeHeader(QFileDevice &file) {
if (!file.open(QIODevice::WriteOnly)) {
return false;
}
file.write(tdfMagic, tdfMagicLen);
const auto version = qint32(AppVersion);
file.write((const char*)&version, sizeof(version));
return true;
}
void FileWriteDescriptor::writeFooter(QFileDevice &file) {
file.write((const char*)_md5.result(), 0x10);
}
void FileWriteDescriptor::init(const QString &name) {
const auto working = (_owner == FileOwner::User)
? _userWorking()
: _working();
if (!working) {
return;
}
const auto basePath = (_owner == FileOwner::User)
? _userBasePath
: _basePath;
_base = basePath + name;
_buffer.setBuffer(&_safeData);
const auto opened = _buffer.open(QIODevice::WriteOnly);
Assert(opened);
_stream.setDevice(&_buffer);
}
void FileWriteDescriptor::writeData(const QByteArray &data) {
if (!_stream.device()) {
return;
}
_stream << data;
quint32 len = data.isNull() ? 0xffffffff : data.size(); quint32 len = data.isNull() ? 0xffffffff : data.size();
if (QSysInfo::ByteOrder != QSysInfo::BigEndian) { if (QSysInfo::ByteOrder != QSysInfo::BigEndian) {
len = qbswap(len); len = qbswap(len);
} }
md5.feed(&len, sizeof(len)); _md5.feed(&len, sizeof(len));
md5.feed(data.constData(), data.size()); _md5.feed(data.constData(), data.size());
dataSize += sizeof(len) + data.size(); _fullSize += sizeof(len) + data.size();
return true;
} }
bool FileWriteDescriptor::writeEncrypted( void FileWriteDescriptor::writeEncrypted(
EncryptedDescriptor &data, EncryptedDescriptor &data,
const MTP::AuthKeyPtr &key) { const MTP::AuthKeyPtr &key) {
return writeData(PrepareEncrypted(data, key)); writeData(PrepareEncrypted(data, key));
} }
void FileWriteDescriptor::finish() { void FileWriteDescriptor::finish() {
if (!file->isOpen()) { if (!_stream.device()) {
return; return;
} }
stream.setDevice(nullptr); _stream.setDevice(nullptr);
_md5.feed(&_fullSize, sizeof(_fullSize));
md5.feed(&dataSize, sizeof(dataSize));
qint32 version = AppVersion; qint32 version = AppVersion;
md5.feed(&version, sizeof(version)); _md5.feed(&version, sizeof(version));
md5.feed(tdfMagic, tdfMagicLen); _md5.feed(tdfMagic, tdfMagicLen);
file->write((const char*)md5.result(), 0x10);
if (saveFile.isOpen()) { _buffer.close();
if (!saveFile.commit()) {
LOG(("Storage Error: Could not commit safe writing in '%1'." const auto safe = path('s');
).arg(saveFile.fileName())); const auto simple = path('0');
} const auto backup = path('1');
} else { QSaveFile save;
plainFile.close(); if (open(save, 's')) {
if (!toDelete.isEmpty()) { save.write(_safeData);
QFile::remove(toDelete + '1'); writeFooter(save);
if (!base::Platform::RenameWithOverwrite( if (save.commit()) {
plainFile.fileName(), QFile::remove(simple);
saveFile.fileName())) { QFile::remove(backup);
LOG(("Storage Error: Could not rename '%1' to '%2'" return;
).arg(plainFile.fileName()
).arg(saveFile.fileName()));
}
} }
LOG(("Storage Error: Could not commit '%1'.").arg(safe));
} }
QFile plain;
if (open(plain, '0')) {
plain.write(_safeData);
writeFooter(plain);
base::Platform::FlushFileData(plain);
plain.close();
if (!toDelete.isEmpty()) { QFile::remove(backup);
QFile::remove(toDelete + '0'); if (base::Platform::RenameWithOverwrite(simple, safe)) {
QFile::remove(toDelete + '1'); return;
}
QFile::remove(safe);
LOG(("Storage Error: Could not rename '%1' to '%2', removing."
).arg(simple
).arg(safe));
} }
} }
bool readFile(FileReadDescriptor &result, const QString &name, FileOptions options = FileOption::User | FileOption::Safe) { bool ReadFile(
if (options & FileOption::User) { FileReadDescriptor &result,
const QString &name,
FileOwner owner = FileOwner::User) {
if (owner == FileOwner::User) {
if (!_userWorking()) return false; if (!_userWorking()) return false;
} else { } else {
if (!_working()) return false; if (!_working()) return false;
} }
const auto base = ((options & FileOption::User) ? _userBasePath : _basePath) + name; const auto base = ((owner == FileOwner::User) ? _userBasePath : _basePath) + name;
// detect order of read attempts // detect order of read attempts
QString toTry[2]; QString toTry[2];
if (options & FileOption::Safe) { const auto modern = base + 's';
const auto modern = base + 's'; if (QFileInfo(modern).exists()) {
if (QFileInfo(modern).exists()) { toTry[0] = modern;
toTry[0] = modern; } else {
} else { // Legacy way.
// Legacy way. toTry[0] = base + '0';
toTry[0] = base + '0'; QFileInfo toTry0(toTry[0]);
QFileInfo toTry0(toTry[0]); if (toTry0.exists()) {
if (toTry0.exists()) { toTry[1] = ((owner == FileOwner::User) ? _userBasePath : _basePath) + name + '1';
toTry[1] = ((options & FileOption::User) ? _userBasePath : _basePath) + name + '1'; QFileInfo toTry1(toTry[1]);
QFileInfo toTry1(toTry[1]); if (toTry1.exists()) {
if (toTry1.exists()) { QDateTime mod0 = toTry0.lastModified(), mod1 = toTry1.lastModified();
QDateTime mod0 = toTry0.lastModified(), mod1 = toTry1.lastModified(); if (mod0 < mod1) {
if (mod0 < mod1) { qSwap(toTry[0], toTry[1]);
qSwap(toTry[0], toTry[1]);
}
} else {
toTry[1] = QString();
} }
} else { } else {
toTry[0][toTry[0].size() - 1] = '1'; toTry[1] = QString();
} }
} else {
toTry[0][toTry[0].size() - 1] = '1';
} }
} else {
toTry[0] = base + '0';
} }
for (int32 i = 0; i < 2; ++i) { for (int32 i = 0; i < 2; ++i) {
QString fname(toTry[i]); QString fname(toTry[i]);
@ -555,8 +571,12 @@ bool decryptLocal(EncryptedDescriptor &result, const QByteArray &encrypted, cons
return true; return true;
} }
bool readEncryptedFile(FileReadDescriptor &result, const QString &name, FileOptions options = FileOption::User | FileOption::Safe, const MTP::AuthKeyPtr &key = LocalKey) { bool ReadEncryptedFile(
if (!readFile(result, name, options)) { FileReadDescriptor &result,
const QString &name,
FileOwner owner = FileOwner::User,
const MTP::AuthKeyPtr &key = LocalKey) {
if (!ReadFile(result, name, owner)) {
return false; return false;
} }
QByteArray encrypted; QByteArray encrypted;
@ -585,8 +605,12 @@ bool readEncryptedFile(FileReadDescriptor &result, const QString &name, FileOpti
return true; return true;
} }
bool readEncryptedFile(FileReadDescriptor &result, const FileKey &fkey, FileOptions options = FileOption::User | FileOption::Safe, const MTP::AuthKeyPtr &key = LocalKey) { bool ReadEncryptedFile(
return readEncryptedFile(result, toFilePart(fkey), options, key); FileReadDescriptor &result,
const FileKey &fkey,
FileOwner owner = FileOwner::User,
const MTP::AuthKeyPtr &key = LocalKey) {
return ReadEncryptedFile(result, toFilePart(fkey), owner, key);
} }
FileKey _dataNameKey = 0; FileKey _dataNameKey = 0;
@ -810,14 +834,14 @@ void _writeLocations(WriteMapWhen when = WriteMapWhen::Soon) {
_manager->writingLocations(); _manager->writingLocations();
if (_fileLocations.isEmpty()) { if (_fileLocations.isEmpty()) {
if (_locationsKey) { if (_locationsKey) {
clearKey(_locationsKey); ClearKey(_locationsKey);
_locationsKey = 0; _locationsKey = 0;
_mapChanged = true; _mapChanged = true;
_writeMap(); _writeMap();
} }
} else { } else {
if (!_locationsKey) { if (!_locationsKey) {
_locationsKey = genKey(); _locationsKey = GenerateKey();
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapWhen::Fast); _writeMap(WriteMapWhen::Fast);
} }
@ -874,8 +898,8 @@ void _writeLocations(WriteMapWhen when = WriteMapWhen::Soon) {
void _readLocations() { void _readLocations() {
FileReadDescriptor locations; FileReadDescriptor locations;
if (!readEncryptedFile(locations, _locationsKey)) { if (!ReadEncryptedFile(locations, _locationsKey)) {
clearKey(_locationsKey); ClearKey(_locationsKey);
_locationsKey = 0; _locationsKey = 0;
_writeMap(); _writeMap();
return; return;
@ -924,7 +948,7 @@ void _readLocations() {
quint64 key; quint64 key;
qint32 size; qint32 size;
locations.stream >> url >> key >> size; locations.stream >> url >> key >> size;
clearKey(key, FileOption::User); ClearKey(key, FileOwner::User);
} }
} }
} }
@ -2136,7 +2160,7 @@ void _writeUserSettings() {
LOG(("App Info: writing encrypted user settings...")); LOG(("App Info: writing encrypted user settings..."));
if (!_userSettingsKey) { if (!_userSettingsKey) {
_userSettingsKey = genKey(); _userSettingsKey = GenerateKey();
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapWhen::Fast); _writeMap(WriteMapWhen::Fast);
} }
@ -2231,7 +2255,7 @@ void _writeUserSettings() {
void _readUserSettings() { void _readUserSettings() {
ReadSettingsContext context; ReadSettingsContext context;
FileReadDescriptor userSettings; FileReadDescriptor userSettings;
if (!readEncryptedFile(userSettings, _userSettingsKey)) { if (!ReadEncryptedFile(userSettings, _userSettingsKey)) {
LOG(("App Info: could not read encrypted user settings...")); LOG(("App Info: could not read encrypted user settings..."));
_readOldUserSettings(true, context); _readOldUserSettings(true, context);
@ -2262,7 +2286,7 @@ void _readUserSettings() {
} }
void _writeMtpData() { void _writeMtpData() {
FileWriteDescriptor mtp(toFilePart(_dataNameKey), FileOption::Safe); FileWriteDescriptor mtp(toFilePart(_dataNameKey), FileOwner::Global);
if (!LocalKey) { if (!LocalKey) {
LOG(("App Error: localkey not created in _writeMtpData()")); LOG(("App Error: localkey not created in _writeMtpData()"));
return; return;
@ -2280,7 +2304,7 @@ void _writeMtpData() {
void _readMtpData() { void _readMtpData() {
ReadSettingsContext context; ReadSettingsContext context;
FileReadDescriptor mtp; FileReadDescriptor mtp;
if (!readEncryptedFile(mtp, toFilePart(_dataNameKey), FileOption::Safe)) { if (!ReadEncryptedFile(mtp, toFilePart(_dataNameKey), FileOwner::Global)) {
if (LocalKey) { if (LocalKey) {
_readOldMtpData(true, context); _readOldMtpData(true, context);
applyReadContext(std::move(context)); applyReadContext(std::move(context));
@ -2318,7 +2342,7 @@ ReadMapState _readMap(const QByteArray &pass) {
+ '/'; + '/';
FileReadDescriptor mapData; FileReadDescriptor mapData;
if (!readFile(mapData, qsl("map"))) { if (!ReadFile(mapData, qsl("map"))) {
return ReadMapFailed; return ReadMapFailed;
} }
LOG(("App Info: reading map...")); LOG(("App Info: reading map..."));
@ -2411,7 +2435,7 @@ ReadMapState _readMap(const QByteArray &pass) {
} break; } break;
case lskReportSpamStatusesOld: { case lskReportSpamStatusesOld: {
map.stream >> reportSpamStatusesKey; map.stream >> reportSpamStatusesKey;
clearKey(reportSpamStatusesKey); ClearKey(reportSpamStatusesKey);
} break; } break;
case lskTrustedBots: { case lskTrustedBots: {
map.stream >> trustedBotsKey; map.stream >> trustedBotsKey;
@ -2666,7 +2690,7 @@ void start() {
ReadSettingsContext context; ReadSettingsContext context;
FileReadDescriptor settingsData; FileReadDescriptor settingsData;
if (!readFile(settingsData, cTestMode() ? qsl("settings_test") : qsl("settings"), FileOption::Safe)) { if (!ReadFile(settingsData, cTestMode() ? qsl("settings_test") : qsl("settings"), FileOwner::Global)) {
_readOldSettings(true, context); _readOldSettings(true, context);
_readOldUserSettings(false, context); // needed further in _readUserSettings _readOldUserSettings(false, context); // needed further in _readUserSettings
_readOldMtpData(false, context); // needed further in _readMtpData _readOldMtpData(false, context); // needed further in _readMtpData
@ -2727,7 +2751,9 @@ void writeSettings() {
if (!QDir().exists(_basePath)) QDir().mkpath(_basePath); if (!QDir().exists(_basePath)) QDir().mkpath(_basePath);
FileWriteDescriptor settings(cTestMode() ? qsl("settings_test") : qsl("settings"), FileOption::Safe); FileWriteDescriptor settings(
cTestMode() ? qsl("settings_test") : qsl("settings"),
FileOwner::Global);
if (_settingsSalt.isEmpty() || !SettingsKey) { if (_settingsSalt.isEmpty() || !SettingsKey) {
_settingsSalt.resize(LocalEncryptSaltSize); _settingsSalt.resize(LocalEncryptSaltSize);
memset_rand(_settingsSalt.data(), _settingsSalt.size()); memset_rand(_settingsSalt.data(), _settingsSalt.size());
@ -3008,7 +3034,7 @@ void writeDrafts(const PeerId &peer, const MessageDraft &localDraft, const Messa
if (localDraft.msgId <= 0 && localDraft.textWithTags.text.isEmpty() && editDraft.msgId <= 0) { if (localDraft.msgId <= 0 && localDraft.textWithTags.text.isEmpty() && editDraft.msgId <= 0) {
auto i = _draftsMap.find(peer); auto i = _draftsMap.find(peer);
if (i != _draftsMap.cend()) { if (i != _draftsMap.cend()) {
clearKey(i.value()); ClearKey(i.value());
_draftsMap.erase(i); _draftsMap.erase(i);
_mapChanged = true; _mapChanged = true;
_writeMap(); _writeMap();
@ -3018,7 +3044,7 @@ void writeDrafts(const PeerId &peer, const MessageDraft &localDraft, const Messa
} else { } else {
auto i = _draftsMap.constFind(peer); auto i = _draftsMap.constFind(peer);
if (i == _draftsMap.cend()) { if (i == _draftsMap.cend()) {
i = _draftsMap.insert(peer, genKey()); i = _draftsMap.insert(peer, GenerateKey());
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapWhen::Fast); _writeMap(WriteMapWhen::Fast);
} }
@ -3049,7 +3075,7 @@ void writeDrafts(const PeerId &peer, const MessageDraft &localDraft, const Messa
void clearDraftCursors(const PeerId &peer) { void clearDraftCursors(const PeerId &peer) {
DraftsMap::iterator i = _draftCursorsMap.find(peer); DraftsMap::iterator i = _draftCursorsMap.find(peer);
if (i != _draftCursorsMap.cend()) { if (i != _draftCursorsMap.cend()) {
clearKey(i.value()); ClearKey(i.value());
_draftCursorsMap.erase(i); _draftCursorsMap.erase(i);
_mapChanged = true; _mapChanged = true;
_writeMap(); _writeMap();
@ -3063,7 +3089,7 @@ void _readDraftCursors(const PeerId &peer, MessageCursor &localCursor, MessageCu
} }
FileReadDescriptor draft; FileReadDescriptor draft;
if (!readEncryptedFile(draft, j.value())) { if (!ReadEncryptedFile(draft, j.value())) {
clearDraftCursors(peer); clearDraftCursors(peer);
return; return;
} }
@ -3097,8 +3123,8 @@ void readDraftsWithCursors(History *h) {
return; return;
} }
FileReadDescriptor draft; FileReadDescriptor draft;
if (!readEncryptedFile(draft, j.value())) { if (!ReadEncryptedFile(draft, j.value())) {
clearKey(j.value()); ClearKey(j.value());
_draftsMap.erase(j); _draftsMap.erase(j);
clearDraftCursors(peer); clearDraftCursors(peer);
return; return;
@ -3126,7 +3152,7 @@ void readDraftsWithCursors(History *h) {
} }
} }
if (draftPeer != peer) { if (draftPeer != peer) {
clearKey(j.value()); ClearKey(j.value());
_draftsMap.erase(j); _draftsMap.erase(j);
clearDraftCursors(peer); clearDraftCursors(peer);
return; return;
@ -3172,7 +3198,7 @@ void writeDraftCursors(const PeerId &peer, const MessageCursor &msgCursor, const
} else { } else {
DraftsMap::const_iterator i = _draftCursorsMap.constFind(peer); DraftsMap::const_iterator i = _draftCursorsMap.constFind(peer);
if (i == _draftCursorsMap.cend()) { if (i == _draftCursorsMap.cend()) {
i = _draftCursorsMap.insert(peer, genKey()); i = _draftCursorsMap.insert(peer, GenerateKey());
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapWhen::Fast); _writeMap(WriteMapWhen::Fast);
} }
@ -3453,7 +3479,7 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
const auto &sets = Auth().data().stickerSets(); const auto &sets = Auth().data().stickerSets();
if (sets.isEmpty()) { if (sets.isEmpty()) {
if (stickersKey) { if (stickersKey) {
clearKey(stickersKey); ClearKey(stickersKey);
stickersKey = 0; stickersKey = 0;
_mapChanged = true; _mapChanged = true;
} }
@ -3505,7 +3531,7 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
} }
if (!setsCount && order.isEmpty()) { if (!setsCount && order.isEmpty()) {
if (stickersKey) { if (stickersKey) {
clearKey(stickersKey); ClearKey(stickersKey);
stickersKey = 0; stickersKey = 0;
_mapChanged = true; _mapChanged = true;
} }
@ -3515,7 +3541,7 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
size += sizeof(qint32) + (order.size() * sizeof(quint64)); size += sizeof(qint32) + (order.size() * sizeof(quint64));
if (!stickersKey) { if (!stickersKey) {
stickersKey = genKey(); stickersKey = GenerateKey();
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapWhen::Fast); _writeMap(WriteMapWhen::Fast);
} }
@ -3541,15 +3567,15 @@ void _writeStickerSets(FileKey &stickersKey, CheckSet checkSet, const Stickers::
void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr, MTPDstickerSet::Flags readingFlags = 0) { void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr, MTPDstickerSet::Flags readingFlags = 0) {
FileReadDescriptor stickers; FileReadDescriptor stickers;
if (!readEncryptedFile(stickers, stickersKey)) { if (!ReadEncryptedFile(stickers, stickersKey)) {
clearKey(stickersKey); ClearKey(stickersKey);
stickersKey = 0; stickersKey = 0;
_writeMap(); _writeMap();
return; return;
} }
const auto failed = [&] { const auto failed = [&] {
clearKey(stickersKey); ClearKey(stickersKey);
stickersKey = 0; stickersKey = 0;
}; };
@ -3841,8 +3867,8 @@ void importOldRecentStickers() {
if (!_recentStickersKeyOld) return; if (!_recentStickersKeyOld) return;
FileReadDescriptor stickers; FileReadDescriptor stickers;
if (!readEncryptedFile(stickers, _recentStickersKeyOld)) { if (!ReadEncryptedFile(stickers, _recentStickersKeyOld)) {
clearKey(_recentStickersKeyOld); ClearKey(_recentStickersKeyOld);
_recentStickersKeyOld = 0; _recentStickersKeyOld = 0;
_writeMap(); _writeMap();
return; return;
@ -3940,7 +3966,7 @@ void importOldRecentStickers() {
writeInstalledStickers(); writeInstalledStickers();
writeUserSettings(); writeUserSettings();
clearKey(_recentStickersKeyOld); ClearKey(_recentStickersKeyOld);
_recentStickersKeyOld = 0; _recentStickersKeyOld = 0;
_writeMap(); _writeMap();
} }
@ -4061,7 +4087,7 @@ void writeSavedGifs() {
auto &saved = Auth().data().savedGifs(); auto &saved = Auth().data().savedGifs();
if (saved.isEmpty()) { if (saved.isEmpty()) {
if (_savedGifsKey) { if (_savedGifsKey) {
clearKey(_savedGifsKey); ClearKey(_savedGifsKey);
_savedGifsKey = 0; _savedGifsKey = 0;
_mapChanged = true; _mapChanged = true;
} }
@ -4073,7 +4099,7 @@ void writeSavedGifs() {
} }
if (!_savedGifsKey) { if (!_savedGifsKey) {
_savedGifsKey = genKey(); _savedGifsKey = GenerateKey();
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapWhen::Fast); _writeMap(WriteMapWhen::Fast);
} }
@ -4091,8 +4117,8 @@ void readSavedGifs() {
if (!_savedGifsKey) return; if (!_savedGifsKey) return;
FileReadDescriptor gifs; FileReadDescriptor gifs;
if (!readEncryptedFile(gifs, _savedGifsKey)) { if (!ReadEncryptedFile(gifs, _savedGifsKey)) {
clearKey(_savedGifsKey); ClearKey(_savedGifsKey);
_savedGifsKey = 0; _savedGifsKey = 0;
_writeMap(); _writeMap();
return; return;
@ -4100,7 +4126,7 @@ void readSavedGifs() {
auto &saved = Auth().data().savedGifsRef(); auto &saved = Auth().data().savedGifsRef();
const auto failed = [&] { const auto failed = [&] {
clearKey(_savedGifsKey); ClearKey(_savedGifsKey);
_savedGifsKey = 0; _savedGifsKey = 0;
saved.clear(); saved.clear();
}; };
@ -4168,7 +4194,7 @@ void writeBackground(const Data::WallPaper &paper, const QImage &image) {
} }
} }
if (!backgroundKey) { if (!backgroundKey) {
backgroundKey = genKey(); backgroundKey = GenerateKey();
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapWhen::Fast); _writeMap(WriteMapWhen::Fast);
} }
@ -4191,9 +4217,9 @@ bool readBackground() {
auto &backgroundKey = Window::Theme::IsNightMode() auto &backgroundKey = Window::Theme::IsNightMode()
? _backgroundKeyNight ? _backgroundKeyNight
: _backgroundKeyDay; : _backgroundKeyDay;
if (!readEncryptedFile(bg, backgroundKey)) { if (!ReadEncryptedFile(bg, backgroundKey)) {
if (backgroundKey) { if (backgroundKey) {
clearKey(backgroundKey); ClearKey(backgroundKey);
backgroundKey = 0; backgroundKey = 0;
_mapChanged = true; _mapChanged = true;
_writeMap(); _writeMap();
@ -4308,7 +4334,7 @@ Window::Theme::Saved readThemeUsingKey(FileKey key) {
using namespace Window::Theme; using namespace Window::Theme;
FileReadDescriptor theme; FileReadDescriptor theme;
if (!readEncryptedFile(theme, key, FileOption::Safe, SettingsKey)) { if (!ReadEncryptedFile(theme, key, FileOwner::Global, SettingsKey)) {
return {}; return {};
} }
@ -4397,7 +4423,7 @@ void writeTheme(const Window::Theme::Saved &saved) {
: _themeKeyDay; : _themeKeyDay;
if (saved.object.content.isEmpty()) { if (saved.object.content.isEmpty()) {
if (themeKey) { if (themeKey) {
clearKey(themeKey); ClearKey(themeKey, FileOwner::Global);
themeKey = 0; themeKey = 0;
writeSettings(); writeSettings();
} }
@ -4405,7 +4431,7 @@ void writeTheme(const Window::Theme::Saved &saved) {
} }
if (!themeKey) { if (!themeKey) {
themeKey = genKey(FileOption::Safe); themeKey = GenerateKey(FileOwner::Global);
writeSettings(); writeSettings();
} }
@ -4442,7 +4468,7 @@ void writeTheme(const Window::Theme::Saved &saved) {
<< cache.background << cache.background
<< quint32(cache.tiled ? 1 : 0); << quint32(cache.tiled ? 1 : 0);
FileWriteDescriptor file(themeKey, FileOption::Safe); FileWriteDescriptor file(themeKey, FileOwner::Global);
file.writeEncrypted(data, SettingsKey); file.writeEncrypted(data, SettingsKey);
} }
@ -4494,7 +4520,7 @@ Window::Theme::Saved readThemeAfterSwitch() {
void readLangPack() { void readLangPack() {
FileReadDescriptor langpack; FileReadDescriptor langpack;
if (!_langPackKey || !readEncryptedFile(langpack, _langPackKey, FileOption::Safe, SettingsKey)) { if (!_langPackKey || !ReadEncryptedFile(langpack, _langPackKey, FileOwner::Global, SettingsKey)) {
return; return;
} }
auto data = QByteArray(); auto data = QByteArray();
@ -4507,21 +4533,21 @@ void readLangPack() {
void writeLangPack() { void writeLangPack() {
auto langpack = Lang::Current().serialize(); auto langpack = Lang::Current().serialize();
if (!_langPackKey) { if (!_langPackKey) {
_langPackKey = genKey(FileOption::Safe); _langPackKey = GenerateKey(FileOwner::Global);
writeSettings(); writeSettings();
} }
EncryptedDescriptor data(Serialize::bytearraySize(langpack)); EncryptedDescriptor data(Serialize::bytearraySize(langpack));
data.stream << langpack; data.stream << langpack;
FileWriteDescriptor file(_langPackKey, FileOption::Safe); FileWriteDescriptor file(_langPackKey, FileOwner::Global);
file.writeEncrypted(data, SettingsKey); file.writeEncrypted(data, SettingsKey);
} }
void saveRecentLanguages(const std::vector<Lang::Language> &list) { void saveRecentLanguages(const std::vector<Lang::Language> &list) {
if (list.empty()) { if (list.empty()) {
if (_languagesKey) { if (_languagesKey) {
clearKey(_languagesKey, FileOption::Safe); ClearKey(_languagesKey, FileOwner::Global);
_languagesKey = 0; _languagesKey = 0;
writeSettings(); writeSettings();
} }
@ -4537,7 +4563,7 @@ void saveRecentLanguages(const std::vector<Lang::Language> &list) {
+ Serialize::stringSize(language.nativeName); + Serialize::stringSize(language.nativeName);
} }
if (!_languagesKey) { if (!_languagesKey) {
_languagesKey = genKey(FileOption::Safe); _languagesKey = GenerateKey(FileOwner::Global);
writeSettings(); writeSettings();
} }
@ -4552,7 +4578,7 @@ void saveRecentLanguages(const std::vector<Lang::Language> &list) {
<< language.nativeName; << language.nativeName;
} }
FileWriteDescriptor file(_languagesKey, FileOption::Safe); FileWriteDescriptor file(_languagesKey, FileOwner::Global);
file.writeEncrypted(data, SettingsKey); file.writeEncrypted(data, SettingsKey);
} }
@ -4584,7 +4610,7 @@ void removeRecentLanguage(const QString &id) {
std::vector<Lang::Language> readRecentLanguages() { std::vector<Lang::Language> readRecentLanguages() {
FileReadDescriptor languages; FileReadDescriptor languages;
if (!_languagesKey || !readEncryptedFile(languages, _languagesKey, FileOption::Safe, SettingsKey)) { if (!_languagesKey || !ReadEncryptedFile(languages, _languagesKey, FileOwner::Global, SettingsKey)) {
return {}; return {};
} }
qint32 count = 0; qint32 count = 0;
@ -4619,7 +4645,7 @@ Window::Theme::Object ReadThemeContent() {
} }
FileReadDescriptor theme; FileReadDescriptor theme;
if (!readEncryptedFile(theme, themeKey, FileOption::Safe, SettingsKey)) { if (!ReadEncryptedFile(theme, themeKey, FileOwner::Global, SettingsKey)) {
return Object(); return Object();
} }
@ -4644,14 +4670,14 @@ void writeRecentHashtagsAndBots() {
if (write.isEmpty() && search.isEmpty() && bots.isEmpty()) readRecentHashtagsAndBots(); if (write.isEmpty() && search.isEmpty() && bots.isEmpty()) readRecentHashtagsAndBots();
if (write.isEmpty() && search.isEmpty() && bots.isEmpty()) { if (write.isEmpty() && search.isEmpty() && bots.isEmpty()) {
if (_recentHashtagsAndBotsKey) { if (_recentHashtagsAndBotsKey) {
clearKey(_recentHashtagsAndBotsKey); ClearKey(_recentHashtagsAndBotsKey);
_recentHashtagsAndBotsKey = 0; _recentHashtagsAndBotsKey = 0;
_mapChanged = true; _mapChanged = true;
} }
_writeMap(); _writeMap();
} else { } else {
if (!_recentHashtagsAndBotsKey) { if (!_recentHashtagsAndBotsKey) {
_recentHashtagsAndBotsKey = genKey(); _recentHashtagsAndBotsKey = GenerateKey();
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapWhen::Fast); _writeMap(WriteMapWhen::Fast);
} }
@ -4696,8 +4722,8 @@ void readRecentHashtagsAndBots() {
if (!_recentHashtagsAndBotsKey) return; if (!_recentHashtagsAndBotsKey) return;
FileReadDescriptor hashtags; FileReadDescriptor hashtags;
if (!readEncryptedFile(hashtags, _recentHashtagsAndBotsKey)) { if (!ReadEncryptedFile(hashtags, _recentHashtagsAndBotsKey)) {
clearKey(_recentHashtagsAndBotsKey); ClearKey(_recentHashtagsAndBotsKey);
_recentHashtagsAndBotsKey = 0; _recentHashtagsAndBotsKey = 0;
_writeMap(); _writeMap();
return; return;
@ -4851,14 +4877,14 @@ void WriteExportSettings(const Export::Settings &settings) {
&& settings.availableAt == check.availableAt && settings.availableAt == check.availableAt
&& !settings.onlySinglePeer()) { && !settings.onlySinglePeer()) {
if (_exportSettingsKey) { if (_exportSettingsKey) {
clearKey(_exportSettingsKey); ClearKey(_exportSettingsKey);
_exportSettingsKey = 0; _exportSettingsKey = 0;
_mapChanged = true; _mapChanged = true;
} }
_writeMap(); _writeMap();
} else { } else {
if (!_exportSettingsKey) { if (!_exportSettingsKey) {
_exportSettingsKey = genKey(); _exportSettingsKey = GenerateKey();
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapWhen::Fast); _writeMap(WriteMapWhen::Fast);
} }
@ -4905,8 +4931,8 @@ void WriteExportSettings(const Export::Settings &settings) {
Export::Settings ReadExportSettings() { Export::Settings ReadExportSettings() {
FileReadDescriptor file; FileReadDescriptor file;
if (!readEncryptedFile(file, _exportSettingsKey)) { if (!ReadEncryptedFile(file, _exportSettingsKey)) {
clearKey(_exportSettingsKey); ClearKey(_exportSettingsKey);
_exportSettingsKey = 0; _exportSettingsKey = 0;
_writeMap(); _writeMap();
return Export::Settings(); return Export::Settings();
@ -5006,14 +5032,14 @@ void writeTrustedBots() {
if (_trustedBots.isEmpty()) { if (_trustedBots.isEmpty()) {
if (_trustedBotsKey) { if (_trustedBotsKey) {
clearKey(_trustedBotsKey); ClearKey(_trustedBotsKey);
_trustedBotsKey = 0; _trustedBotsKey = 0;
_mapChanged = true; _mapChanged = true;
_writeMap(); _writeMap();
} }
} else { } else {
if (!_trustedBotsKey) { if (!_trustedBotsKey) {
_trustedBotsKey = genKey(); _trustedBotsKey = GenerateKey();
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapWhen::Fast); _writeMap(WriteMapWhen::Fast);
} }
@ -5033,8 +5059,8 @@ void readTrustedBots() {
if (!_trustedBotsKey) return; if (!_trustedBotsKey) return;
FileReadDescriptor trusted; FileReadDescriptor trusted;
if (!readEncryptedFile(trusted, _trustedBotsKey)) { if (!ReadEncryptedFile(trusted, _trustedBotsKey)) {
clearKey(_trustedBotsKey); ClearKey(_trustedBotsKey);
_trustedBotsKey = 0; _trustedBotsKey = 0;
_writeMap(); _writeMap();
return; return;

@ -1 +1 @@
Subproject commit 05b4e4e2a813b2888858acde80f67c4eafffdbce Subproject commit 0ce28e94b29c34eb9f3b271b4b3252b37c02ef12