ZaStoGram_desktop/Telegram/SourceFiles/storage/storage_domain.h
loop-uh a27885b97a Поправить сборку после слияния с Telegram Desktop v7.3.1
storage_domain.cpp(103) C2248: WrapLocalKey (свободная функция в анонимном namespace) вызывала приватный MTP::AuthKey::write, friend только Storage::Domain. Сделал WrapLocalKey приватным static-членом Storage::Domain (объявление в storage_domain.h, определение в storage_domain.cpp перед конструктором). Поведение не менял. Проверить, что дальше нет других ошибок: сборка остановилась на 947/1147.
2026-10-16 01:00:29 +03:00

234 lines
8.4 KiB
C++

/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace MTP {
class Config;
class AuthKey;
using AuthKeyPtr = std::shared_ptr<AuthKey>;
} // namespace MTP
namespace Main {
class Account;
class Domain;
} // namespace Main
namespace Storage {
struct PasscodeWrap;
struct KeyData;
struct WalletEngineValue;
// The memory-hard step of a passcode check or change, cut out of Domain as a
// value so that it can run on a worker. It holds copies only - the wrap the
// typed bytes have to open (the live passcode wrap, the legacy blob, or a
// fresh wrap for a change; null when there is none), a deep copy of the typed
// bytes and the derived key - and no pointer into the domain, so it may be
// moved to any thread. run() derives the key for that wrap wherever it is
// called. The typed bytes are cleansed by run() the moment a passcode wrap's
// key exists; on every other leg the destructor cleanses them, because the
// legacy legs still read them on the main thread while the job lives (the
// migration installs its first passcode wrap from them). The domain accepts
// the key back only for a wrap with the same { kdf, salt } this job was made
// for, comparing instead of re-deriving, and never re-derives from bytes that
// were already cleansed - such a mismatch is answered as a wrong passcode.
// checkPasscode() takes one of these jobs and nothing else, so a caller
// holding typed bytes builds it with prepareOpen() and runs it through
// DeriveOnWorker() instead of paying the derivation on the main thread;
// the byte-taking verifyPasscode() and setPasscode() forms remain for the
// legs that still derive where they are called.
class PasscodeDerivation final {
public:
PasscodeDerivation(PasscodeDerivation &&other) noexcept;
PasscodeDerivation &operator=(PasscodeDerivation &&other) noexcept;
~PasscodeDerivation();
void run();
[[nodiscard]] bool empty() const;
private:
friend class Domain;
PasscodeDerivation(
std::unique_ptr<PasscodeWrap> wrap,
const QByteArray &passcode);
[[nodiscard]] MTP::AuthKeyPtr keyFor(const PasscodeWrap &wrap);
void cleanse();
std::unique_ptr<PasscodeWrap> _wrap;
QByteArray _passcode;
MTP::AuthKeyPtr _key;
bool _cleansed = false;
};
// Runs job.run() on a worker and hands the job back to done on the main
// thread. Both callables are moved, never copied, across the two hops, and
// done is built by the caller with crl::guard on the main thread, so the
// guard object is created there and the worker only carries it along.
template <typename Job, typename Done>
void DeriveOnWorker(Job job, Done done) {
crl::async([job = std::move(job), done = std::move(done)]() mutable {
job.run();
crl::on_main([job = std::move(job), done = std::move(done)]() mutable {
done(std::move(job));
});
});
}
enum class StartResult : uchar {
Success,
IncorrectPasscode,
IncorrectPasscodeLegacy,
};
enum class SetPasscodeResult : uchar {
Success,
NeedsVerification,
Failed,
};
// Proof that the passcode currently protecting the local key was typed and
// accepted. Only Domain::verifyPasscode() can mint one, and a token is
// honoured only while the nonce it carries is still the one Domain holds.
// setPasscode() reads it for every change or removal over an existing
// passcode, and setAppLockEnabled() reads it when it turns the lock off,
// because installing an open wrap weakens the data at rest exactly as a
// removal does. A token is single use: both zero that nonce on every exit,
// whichever way they move and whether they accepted the token or refused it,
// so a copy of the token left behind in a settings navigation step cannot
// authorize a second change later on. Both spend it before they fire the
// change notification, so a subscriber that calls back into the domain while
// that notification runs cannot reuse the token either. A default-constructed
// token carries a zero nonce, which never matches an outstanding verification
// and is therefore accepted only where there is no passcode to prove in the
// first place.
class PasscodeVerification final {
public:
PasscodeVerification() = default;
private:
friend class Domain;
explicit PasscodeVerification(quint64 nonce);
quint64 _nonce = 0;
};
class Domain final {
public:
Domain(not_null<Main::Domain*> owner, const QString &dataName);
~Domain();
[[nodiscard]] StartResult start(PasscodeDerivation derived);
void startAdded(
not_null<Main::Account*> account,
std::unique_ptr<MTP::Config> config);
void writeAccounts();
void startFromScratch();
[[nodiscard]] WalletEngineValue readWalletKeyring() const;
[[nodiscard]] bool writeWalletKeyring(const QByteArray &bytes) const;
[[nodiscard]] bool removeWalletKeyring();
[[nodiscard]] PasscodeDerivation prepareOpen(
const QByteArray &passcode) const;
[[nodiscard]] PasscodeDerivation prepareNewWrap(
const QByteArray &passcode) const;
[[nodiscard]] bool checkPasscode(PasscodeDerivation derived) const;
[[nodiscard]] std::optional<PasscodeVerification> verifyPasscode(
const QByteArray &passcode);
[[nodiscard]] std::optional<PasscodeVerification> verifyPasscode(
PasscodeDerivation derived);
[[nodiscard]] SetPasscodeResult setPasscode(
const QByteArray &passcode,
PasscodeVerification verification);
[[nodiscard]] SetPasscodeResult setPasscode(
PasscodeDerivation derived,
PasscodeVerification verification);
// Creates a first passcode in the wallet-only role, keeping the verified
// open wrap so the launch lock stays off. It asks for no proof because it
// is first-create only and weakens nothing - the local key already opens
// without a passcode - and it refuses everything else at the write
// boundary, rechecked here after the derivation instead of wherever the
// caller started it: an existing passcode wrap answers NeedsVerification,
// while retained legacy state and an open wrap that is missing or
// unverified answer Failed. Otherwise it is the same staged, proved and
// committed sequence setPasscode() runs to create or change a passcode,
// one logical operation rather than one physical write, ending in the
// same nonce reset and synchronous localPasscodeChanged().
[[nodiscard]] SetPasscodeResult createPasscodeWithoutAppLock(
PasscodeDerivation derived);
[[nodiscard]] SetPasscodeResult setAppLockEnabled(
bool enabled,
PasscodeVerification verification);
void clearPasscodeAfterReset();
[[nodiscard]] int oldVersion() const;
void clearOldVersion();
[[nodiscard]] rpl::producer<> localPasscodeChanged() const;
[[nodiscard]] bool hasPasscode() const;
[[nodiscard]] bool appLockEnabled() const;
[[nodiscard]] bool hasLocalPasscode() const;
private:
enum class StartModernResult {
Success,
IncorrectPasscode,
Failed,
Empty,
};
[[nodiscard]] StartModernResult startModern(PasscodeDerivation &derived);
void startWithSingleAccount(
const QByteArray &passcode,
std::unique_ptr<Main::Account> account);
void generateLocalKey();
[[nodiscard]] static QByteArray WrapLocalKey(
const MTP::AuthKeyPtr &localKey,
const MTP::AuthKeyPtr &wrapKey);
void installOpenWrap(KeyData &data) const;
void dropOpenWrap(KeyData &data) const;
void installLegacyWrap(KeyData &data, const QByteArray &passcode) const;
[[nodiscard]] MTP::AuthKeyPtr installPasscodeWrap(
KeyData &data,
PasscodeDerivation &derived,
quint32 generation) const;
void migrateFromLegacy(const QByteArray &passcode);
[[nodiscard]] QByteArray prepareAccountsInfo() const;
bool writeKeyData(const KeyData &data, bool sync) const;
[[nodiscard]] bool writeKeyDataChecked(const KeyData &data) const;
[[nodiscard]] bool wrapOnDiskOpensLocalKey(
const PasscodeWrap &staged,
const MTP::AuthKeyPtr &wrapKey) const;
[[nodiscard]] std::unique_ptr<PasscodeWrap> wrapToOpen() const;
[[nodiscard]] bool accepts(PasscodeVerification verification) const;
[[nodiscard]] SetPasscodeResult changePasscode(
PasscodeDerivation *derived,
PasscodeVerification verification);
[[nodiscard]] SetPasscodeResult installPasscode(
PasscodeDerivation &derived,
bool keepOpenWrap);
const not_null<Main::Domain*> _owner;
const QString _dataName;
MTP::AuthKeyPtr _localKey;
std::unique_ptr<KeyData> _keyData;
quint64 _verificationNonce = 0;
int _oldVersion = 0;
bool _keyDataDirty = false;
rpl::event_stream<> _passcodeKeyChanged;
};
} // namespace Storage