storage_domain.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "storage/storage_domain.h"
  8. #include "storage/details/storage_file_utilities.h"
  9. #include "storage/serialize_common.h"
  10. #include "mtproto/mtproto_config.h"
  11. #include "main/main_domain.h"
  12. #include "main/main_account.h"
  13. #include "base/random.h"
  14. namespace Storage {
  15. namespace {
  16. using namespace details;
  17. [[nodiscard]] QString BaseGlobalPath() {
  18. return cWorkingDir() + u"tdata/"_q;
  19. }
  20. [[nodiscard]] QString ComputeKeyName(const QString &dataName) {
  21. // We dropped old test authorizations when migrated to multi auth.
  22. //return "key_" + dataName + (cTestMode() ? "[test]" : "");
  23. return "key_" + dataName;
  24. }
  25. } // namespace
  26. Domain::Domain(not_null<Main::Domain*> owner, const QString &dataName)
  27. : _owner(owner)
  28. , _dataName(dataName) {
  29. }
  30. Domain::~Domain() = default;
  31. StartResult Domain::start(const QByteArray &passcode) {
  32. const auto modern = startModern(passcode);
  33. if (modern == StartModernResult::Success) {
  34. if (_oldVersion < AppVersion) {
  35. writeAccounts();
  36. }
  37. return StartResult::Success;
  38. } else if (modern == StartModernResult::IncorrectPasscode) {
  39. return StartResult::IncorrectPasscode;
  40. } else if (modern == StartModernResult::Failed) {
  41. startFromScratch();
  42. return StartResult::Success;
  43. }
  44. auto legacy = std::make_unique<Main::Account>(_owner, _dataName, 0);
  45. const auto result = legacy->legacyStart(passcode);
  46. if (result == StartResult::Success) {
  47. _oldVersion = legacy->local().oldMapVersion();
  48. startWithSingleAccount(passcode, std::move(legacy));
  49. }
  50. return result;
  51. }
  52. void Domain::startAdded(
  53. not_null<Main::Account*> account,
  54. std::unique_ptr<MTP::Config> config) {
  55. Expects(_localKey != nullptr);
  56. account->prepareToStartAdded(_localKey);
  57. account->start(std::move(config));
  58. }
  59. void Domain::startWithSingleAccount(
  60. const QByteArray &passcode,
  61. std::unique_ptr<Main::Account> account) {
  62. Expects(account != nullptr);
  63. if (auto localKey = account->local().peekLegacyLocalKey()) {
  64. _localKey = std::move(localKey);
  65. encryptLocalKey(passcode);
  66. account->start(nullptr);
  67. } else {
  68. generateLocalKey();
  69. account->start(account->prepareToStart(_localKey));
  70. }
  71. _owner->accountAddedInStorage(Main::Domain::AccountWithIndex{
  72. .account = std::move(account)
  73. });
  74. writeAccounts();
  75. }
  76. void Domain::generateLocalKey() {
  77. Expects(_localKey == nullptr);
  78. Expects(_passcodeKeySalt.isEmpty());
  79. Expects(_passcodeKeyEncrypted.isEmpty());
  80. auto pass = QByteArray(MTP::AuthKey::kSize, Qt::Uninitialized);
  81. auto salt = QByteArray(LocalEncryptSaltSize, Qt::Uninitialized);
  82. base::RandomFill(pass.data(), pass.size());
  83. base::RandomFill(salt.data(), salt.size());
  84. _localKey = CreateLocalKey(pass, salt);
  85. encryptLocalKey(QByteArray());
  86. }
  87. void Domain::encryptLocalKey(const QByteArray &passcode) {
  88. _passcodeKeySalt.resize(LocalEncryptSaltSize);
  89. base::RandomFill(_passcodeKeySalt.data(), _passcodeKeySalt.size());
  90. _passcodeKey = CreateLocalKey(passcode, _passcodeKeySalt);
  91. EncryptedDescriptor passKeyData(MTP::AuthKey::kSize);
  92. _localKey->write(passKeyData.stream);
  93. _passcodeKeyEncrypted = PrepareEncrypted(passKeyData, _passcodeKey);
  94. _hasLocalPasscode = !passcode.isEmpty();
  95. }
  96. Domain::StartModernResult Domain::startModern(
  97. const QByteArray &passcode) {
  98. const auto name = ComputeKeyName(_dataName);
  99. FileReadDescriptor keyData;
  100. if (!ReadFile(keyData, name, BaseGlobalPath())) {
  101. return StartModernResult::Empty;
  102. }
  103. LOG(("App Info: reading accounts info..."));
  104. QByteArray salt, keyEncrypted, infoEncrypted;
  105. keyData.stream >> salt >> keyEncrypted >> infoEncrypted;
  106. if (!CheckStreamStatus(keyData.stream)) {
  107. return StartModernResult::Failed;
  108. }
  109. if (salt.size() != LocalEncryptSaltSize) {
  110. LOG(("App Error: bad salt in info file, size: %1").arg(salt.size()));
  111. return StartModernResult::Failed;
  112. }
  113. _passcodeKey = CreateLocalKey(passcode, salt);
  114. EncryptedDescriptor keyInnerData, info;
  115. if (!DecryptLocal(keyInnerData, keyEncrypted, _passcodeKey)) {
  116. LOG(("App Info: could not decrypt pass-protected key from info file, "
  117. "maybe bad password..."));
  118. return StartModernResult::IncorrectPasscode;
  119. }
  120. auto key = Serialize::read<MTP::AuthKey::Data>(keyInnerData.stream);
  121. if (keyInnerData.stream.status() != QDataStream::Ok
  122. || !keyInnerData.stream.atEnd()) {
  123. LOG(("App Error: could not read pass-protected key from info file"));
  124. return StartModernResult::Failed;
  125. }
  126. _localKey = std::make_shared<MTP::AuthKey>(key);
  127. _passcodeKeyEncrypted = keyEncrypted;
  128. _passcodeKeySalt = salt;
  129. _hasLocalPasscode = !passcode.isEmpty();
  130. if (!DecryptLocal(info, infoEncrypted, _localKey)) {
  131. LOG(("App Error: could not decrypt info."));
  132. return StartModernResult::Failed;
  133. }
  134. LOG(("App Info: reading encrypted info..."));
  135. auto count = qint32();
  136. info.stream >> count;
  137. if (count <= 0 || count > Main::Domain::kPremiumMaxAccounts) {
  138. LOG(("App Error: bad accounts count: %1").arg(count));
  139. return StartModernResult::Failed;
  140. }
  141. _oldVersion = keyData.version;
  142. auto tried = base::flat_set<int>();
  143. auto sessions = base::flat_set<uint64>();
  144. auto active = 0;
  145. for (auto i = 0; i != count; ++i) {
  146. auto index = qint32();
  147. info.stream >> index;
  148. if (index >= 0
  149. && index < Main::Domain::kPremiumMaxAccounts
  150. && tried.emplace(index).second) {
  151. auto account = std::make_unique<Main::Account>(
  152. _owner,
  153. _dataName,
  154. index);
  155. auto config = account->prepareToStart(_localKey);
  156. const auto sessionId = account->willHaveSessionUniqueId(
  157. config.get());
  158. if (!sessions.contains(sessionId)
  159. && (sessionId != 0 || (sessions.empty() && i + 1 == count))) {
  160. if (sessions.empty()) {
  161. active = index;
  162. }
  163. account->start(std::move(config));
  164. _owner->accountAddedInStorage({
  165. .index = index,
  166. .account = std::move(account)
  167. });
  168. sessions.emplace(sessionId);
  169. }
  170. }
  171. }
  172. if (sessions.empty()) {
  173. LOG(("App Error: no accounts read."));
  174. return StartModernResult::Failed;
  175. }
  176. if (!info.stream.atEnd()) {
  177. info.stream >> active;
  178. }
  179. _owner->activateFromStorage(active);
  180. Ensures(!sessions.empty());
  181. return StartModernResult::Success;
  182. }
  183. void Domain::writeAccounts() {
  184. Expects(!_owner->accounts().empty());
  185. const auto path = BaseGlobalPath();
  186. if (!QDir().exists(path)) {
  187. QDir().mkpath(path);
  188. }
  189. FileWriteDescriptor key(ComputeKeyName(_dataName), path);
  190. key.writeData(_passcodeKeySalt);
  191. key.writeData(_passcodeKeyEncrypted);
  192. const auto &list = _owner->accounts();
  193. auto keySize = sizeof(qint32) + sizeof(qint32) * list.size();
  194. EncryptedDescriptor keyData(keySize);
  195. keyData.stream << qint32(list.size());
  196. for (const auto &[index, account] : list) {
  197. keyData.stream << qint32(index);
  198. }
  199. keyData.stream << qint32(_owner->activeForStorage());
  200. key.writeEncrypted(keyData, _localKey);
  201. }
  202. void Domain::startFromScratch() {
  203. startWithSingleAccount(
  204. QByteArray(),
  205. std::make_unique<Main::Account>(_owner, _dataName, 0));
  206. }
  207. bool Domain::checkPasscode(const QByteArray &passcode) const {
  208. Expects(!_passcodeKeySalt.isEmpty());
  209. Expects(_passcodeKey != nullptr);
  210. const auto checkKey = CreateLocalKey(passcode, _passcodeKeySalt);
  211. return checkKey->equals(_passcodeKey);
  212. }
  213. void Domain::setPasscode(const QByteArray &passcode) {
  214. Expects(!_passcodeKeySalt.isEmpty());
  215. Expects(_localKey != nullptr);
  216. encryptLocalKey(passcode);
  217. writeAccounts();
  218. _passcodeKeyChanged.fire({});
  219. }
  220. int Domain::oldVersion() const {
  221. return _oldVersion;
  222. }
  223. void Domain::clearOldVersion() {
  224. _oldVersion = 0;
  225. }
  226. rpl::producer<> Domain::localPasscodeChanged() const {
  227. return _passcodeKeyChanged.events();
  228. }
  229. bool Domain::hasLocalPasscode() const {
  230. return _hasLocalPasscode;
  231. }
  232. } // namespace Storage