ZaStoGram_desktop/Telegram/SourceFiles/wallet/wallet_custody.h

98 lines
3.3 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 Storage {
class Account;
} // namespace Storage
namespace Wallet {
inline constexpr auto kCustodyPublicKeySize = 32;
// publicKey is the anchor: words 1-12 of the phrase, it derives the
// address and never changes. signingKey is the current signing key this
// device established for the wallet; empty means not established (a
// pre-v4 store). awaitingServerKey marks a journal-confirmed promotion
// the server has not served yet: it is set only by
// Session::promotePendingRotation, maintained only by
// Session::reconcileCustody and ignored while signingKey is empty.
struct CustodyRecord {
QString recordId;
QString address;
QByteArray publicKey;
QByteArray signingKey;
int network = 1;
QString secretRef;
bool active = false;
bool rotatedSinceBackup = false;
bool awaitingServerKey = false;
[[nodiscard]] bool signsWith(const QByteArray &servedKey) const;
// A pre-v4 record whose anchor is not the served key: the wallet
// rotated, and nothing but the phrase itself says whether this record
// holds the current signing key or an obsolete one. Session keeps such
// a record reachable through the parked reveal, and the identity of
// the revealed words is what establishes its signing key.
[[nodiscard]] bool unresolved(const QByteArray &servedKey) const;
friend bool operator==(
const CustodyRecord &,
const CustodyRecord &) = default;
};
struct PendingRotation {
QString recordId;
QString secretRef;
QString operationId;
// The replacement signing key from PreparedKeyRotation::new_public_key,
// empty on a pre-v4 pending, which can resolve only through the journal.
QByteArray newPublicKey;
};
struct CustodyStore {
std::vector<CustodyRecord> records;
QByteArray lastSeenServerKey;
std::optional<PendingRotation> pendingRotation;
[[nodiscard]] const CustodyRecord *byAnchor(
const QByteArray &publicKey) const;
// The record of the same wallet whether or not it signs for it; an
// empty address answers nothing.
[[nodiscard]] const CustodyRecord *forAddress(
const QString &canonicalAddress) const;
// The record of the same wallet that signs with the served key.
[[nodiscard]] const CustodyRecord *current(
const QString &canonicalAddress,
const QByteArray &servedKey) const;
[[nodiscard]] bool anyAwaitingServerKey() const;
};
[[nodiscard]] std::optional<CustodyStore> ReadCustodyStore(
Storage::Account &local);
[[nodiscard]] bool WriteCustodyStore(
Storage::Account &local,
const CustodyStore &store);
// The custody fields that name a secret, in store order: every record's
// secretRef and then the pending rotation's, each offered once; an empty
// reference names nothing and is skipped. A callback answering true
// detaches the entry that carries the reference - the record is erased,
// the pending rotation is cleared. Every pass that acts on the values the
// store names walks this one definition, so a field that names a secret
// is added in exactly one place.
void ForEachCustodySecretRef(
CustodyStore &store,
Fn<bool(const QString &secretRef)> drop);
} // namespace Wallet