mtproto_dc_options.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  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 "mtproto/mtproto_dc_options.h"
  8. #include "mtproto/details/mtproto_rsa_public_key.h"
  9. #include "mtproto/facade.h"
  10. #include "mtproto/connection_tcp.h"
  11. #include "storage/serialize_common.h"
  12. #include <QtCore/QFile>
  13. #include <QtCore/QRegularExpression>
  14. namespace MTP {
  15. namespace {
  16. constexpr auto kVersion = 2;
  17. using namespace details;
  18. struct BuiltInDc {
  19. int id;
  20. const char *ip;
  21. int port;
  22. };
  23. const BuiltInDc kBuiltInDcs[] = {
  24. { 1, "149.154.175.50" , 443 },
  25. { 2, "149.154.167.51" , 443 },
  26. { 2, "95.161.76.100" , 443 },
  27. { 3, "149.154.175.100", 443 },
  28. { 4, "149.154.167.91" , 443 },
  29. { 5, "149.154.171.5" , 443 },
  30. };
  31. const BuiltInDc kBuiltInDcsIPv6[] = {
  32. { 1, "2001:0b28:f23d:f001:0000:0000:0000:000a", 443 },
  33. { 2, "2001:067c:04e8:f002:0000:0000:0000:000a", 443 },
  34. { 3, "2001:0b28:f23d:f003:0000:0000:0000:000a", 443 },
  35. { 4, "2001:067c:04e8:f004:0000:0000:0000:000a", 443 },
  36. { 5, "2001:0b28:f23f:f005:0000:0000:0000:000a", 443 },
  37. };
  38. const BuiltInDc kBuiltInDcsTest[] = {
  39. { 1, "149.154.175.10" , 443 },
  40. { 2, "149.154.167.40" , 443 },
  41. { 3, "149.154.175.117", 443 }
  42. };
  43. const BuiltInDc kBuiltInDcsIPv6Test[] = {
  44. { 1, "2001:0b28:f23d:f001:0000:0000:0000:000e", 443 },
  45. { 2, "2001:067c:04e8:f002:0000:0000:0000:000e", 443 },
  46. { 3, "2001:0b28:f23d:f003:0000:0000:0000:000e", 443 }
  47. };
  48. const char *kTestPublicRSAKeys[] = { "\
  49. -----BEGIN RSA PUBLIC KEY-----\n\
  50. MIIBCgKCAQEAyMEdY1aR+sCR3ZSJrtztKTKqigvO/vBfqACJLZtS7QMgCGXJ6XIR\n\
  51. yy7mx66W0/sOFa7/1mAZtEoIokDP3ShoqF4fVNb6XeqgQfaUHd8wJpDWHcR2OFwv\n\
  52. plUUI1PLTktZ9uW2WE23b+ixNwJjJGwBDJPQEQFBE+vfmH0JP503wr5INS1poWg/\n\
  53. j25sIWeYPHYeOrFp/eXaqhISP6G+q2IeTaWTXpwZj4LzXq5YOpk4bYEQ6mvRq7D1\n\
  54. aHWfYmlEGepfaYR8Q0YqvvhYtMte3ITnuSJs171+GDqpdKcSwHnd6FudwGO4pcCO\n\
  55. j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB\n\
  56. -----END RSA PUBLIC KEY-----" };
  57. const char *kPublicRSAKeys[] = { "\
  58. -----BEGIN RSA PUBLIC KEY-----\n\
  59. MIIBCgKCAQEA6LszBcC1LGzyr992NzE0ieY+BSaOW622Aa9Bd4ZHLl+TuFQ4lo4g\n\
  60. 5nKaMBwK/BIb9xUfg0Q29/2mgIR6Zr9krM7HjuIcCzFvDtr+L0GQjae9H0pRB2OO\n\
  61. 62cECs5HKhT5DZ98K33vmWiLowc621dQuwKWSQKjWf50XYFw42h21P2KXUGyp2y/\n\
  62. +aEyZ+uVgLLQbRA1dEjSDZ2iGRy12Mk5gpYc397aYp438fsJoHIgJ2lgMv5h7WY9\n\
  63. t6N/byY9Nw9p21Og3AoXSL2q/2IJ1WRUhebgAdGVMlV1fkuOQoEzR7EdpqtQD9Cs\n\
  64. 5+bfo3Nhmcyvk5ftB0WkJ9z6bNZ7yxrP8wIDAQAB\n\
  65. -----END RSA PUBLIC KEY-----" };
  66. } // namespace
  67. class DcOptions::WriteLocker {
  68. public:
  69. WriteLocker(not_null<DcOptions*> that)
  70. : _that(that)
  71. , _lock(&_that->_useThroughLockers) {
  72. }
  73. void unlock() {
  74. _lock.unlock();
  75. }
  76. ~WriteLocker() {
  77. _that->computeCdnDcIds();
  78. }
  79. private:
  80. not_null<DcOptions*> _that;
  81. QWriteLocker _lock;
  82. };
  83. class DcOptions::ReadLocker {
  84. public:
  85. ReadLocker(not_null<const DcOptions*> that)
  86. : _lock(&that->_useThroughLockers) {
  87. }
  88. void unlock() {
  89. _lock.unlock();
  90. }
  91. private:
  92. QReadLocker _lock;
  93. };
  94. DcOptions::DcOptions(Environment environment)
  95. : _environment(environment) {
  96. constructFromBuiltIn();
  97. }
  98. DcOptions::DcOptions(const DcOptions &other)
  99. : _environment(other._environment)
  100. , _data(other._data)
  101. , _cdnDcIds(other._cdnDcIds)
  102. , _publicKeys(other._publicKeys)
  103. , _cdnPublicKeys(other._cdnPublicKeys)
  104. , _immutable(other._immutable) {
  105. }
  106. DcOptions::~DcOptions() = default;
  107. bool DcOptions::ValidateSecret(bytes::const_span secret) {
  108. // See also TcpConnection::Protocol::Create.
  109. return (secret.size() >= 21 && secret[0] == bytes::type(0xEE))
  110. || (secret.size() == 17 && secret[0] == bytes::type(0xDD))
  111. || (secret.size() == 16)
  112. || secret.empty();
  113. }
  114. void DcOptions::readBuiltInPublicKeys() {
  115. const auto builtin = (_environment == Environment::Test)
  116. ? gsl::make_span(kTestPublicRSAKeys)
  117. : gsl::make_span(kPublicRSAKeys);
  118. for (const auto key : builtin) {
  119. const auto keyBytes = bytes::make_span(key, strlen(key));
  120. auto parsed = RSAPublicKey(keyBytes);
  121. if (parsed.valid()) {
  122. _publicKeys.emplace(parsed.fingerprint(), std::move(parsed));
  123. } else {
  124. LOG(("MTP Error: could not read this public RSA key:"));
  125. LOG((key));
  126. }
  127. }
  128. }
  129. Environment DcOptions::environment() const {
  130. return _environment;
  131. }
  132. bool DcOptions::isTestMode() const {
  133. return (_environment != Environment::Production);
  134. }
  135. void DcOptions::constructFromBuiltIn() {
  136. WriteLocker lock(this);
  137. _data.clear();
  138. readBuiltInPublicKeys();
  139. const auto list = isTestMode()
  140. ? gsl::make_span(kBuiltInDcsTest)
  141. : gsl::make_span(kBuiltInDcs).subspan(0);
  142. for (const auto &entry : list) {
  143. const auto flags = Flag::f_static | 0;
  144. applyOneGuarded(entry.id, flags, entry.ip, entry.port, {});
  145. DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: %2:%3"
  146. ).arg(entry.id
  147. ).arg(entry.ip
  148. ).arg(entry.port));
  149. }
  150. const auto listv6 = isTestMode()
  151. ? gsl::make_span(kBuiltInDcsIPv6Test)
  152. : gsl::make_span(kBuiltInDcsIPv6).subspan(0);
  153. for (const auto &entry : listv6) {
  154. const auto flags = Flag::f_static | Flag::f_ipv6;
  155. applyOneGuarded(entry.id, flags, entry.ip, entry.port, {});
  156. DEBUG_LOG(("MTP Info: adding built in DC %1 IPv6 connect option: "
  157. "%2:%3"
  158. ).arg(entry.id
  159. ).arg(entry.ip
  160. ).arg(entry.port));
  161. }
  162. }
  163. void DcOptions::processFromList(
  164. const QVector<MTPDcOption> &options,
  165. bool overwrite) {
  166. if (options.empty() || _immutable) {
  167. return;
  168. }
  169. auto data = [&] {
  170. if (overwrite) {
  171. return base::flat_map<DcId, std::vector<Endpoint>>();
  172. }
  173. ReadLocker lock(this);
  174. return _data;
  175. }();
  176. for (auto &mtpOption : options) {
  177. if (mtpOption.type() != mtpc_dcOption) {
  178. LOG(("Wrong type in DcOptions: %1").arg(mtpOption.type()));
  179. continue;
  180. }
  181. auto &option = mtpOption.c_dcOption();
  182. auto dcId = option.vid().v;
  183. auto flags = option.vflags().v;
  184. auto ip = std::string(
  185. option.vip_address().v.constData(),
  186. option.vip_address().v.size());
  187. auto port = option.vport().v;
  188. auto secret = bytes::make_vector(option.vsecret().value_or_empty());
  189. ApplyOneOption(data, dcId, flags, ip, port, secret);
  190. }
  191. const auto difference = [&] {
  192. WriteLocker lock(this);
  193. auto result = CountOptionsDifference(_data, data);
  194. if (!result.empty()) {
  195. _data = std::move(data);
  196. }
  197. return result;
  198. }();
  199. for (const auto dcId : difference) {
  200. _changed.fire_copy(dcId);
  201. }
  202. }
  203. void DcOptions::setFromList(const MTPVector<MTPDcOption> &options) {
  204. processFromList(options.v, true);
  205. }
  206. void DcOptions::addFromList(const MTPVector<MTPDcOption> &options) {
  207. processFromList(options.v, false);
  208. }
  209. void DcOptions::addFromOther(DcOptions &&options) {
  210. if (this == &options || _immutable) {
  211. return;
  212. }
  213. auto idsChanged = std::vector<DcId>();
  214. {
  215. ReadLocker lock(&options);
  216. if (options._data.empty()) {
  217. return;
  218. }
  219. idsChanged.reserve(options._data.size());
  220. {
  221. WriteLocker lock(this);
  222. const auto changed = [&](const std::vector<Endpoint> &list) {
  223. auto result = false;
  224. for (const auto &endpoint : list) {
  225. const auto dcId = endpoint.id;
  226. const auto flags = endpoint.flags;
  227. const auto &ip = endpoint.ip;
  228. const auto port = endpoint.port;
  229. const auto &secret = endpoint.secret;
  230. if (applyOneGuarded(dcId, flags, ip, port, secret)) {
  231. result = true;
  232. }
  233. }
  234. return result;
  235. };
  236. for (const auto &item : base::take(options._data)) {
  237. if (changed(item.second)) {
  238. idsChanged.push_back(item.first);
  239. }
  240. }
  241. for (auto &item : options._cdnPublicKeys) {
  242. for (auto &entry : item.second) {
  243. _cdnPublicKeys[item.first].insert(std::move(entry));
  244. }
  245. }
  246. }
  247. }
  248. for (const auto dcId : idsChanged) {
  249. _changed.fire_copy(dcId);
  250. }
  251. }
  252. void DcOptions::constructAddOne(
  253. int id,
  254. Flags flags,
  255. const std::string &ip,
  256. int port,
  257. const bytes::vector &secret) {
  258. WriteLocker lock(this);
  259. applyOneGuarded(BareDcId(id), flags, ip, port, secret);
  260. }
  261. bool DcOptions::applyOneGuarded(
  262. DcId dcId,
  263. Flags flags,
  264. const std::string &ip,
  265. int port,
  266. const bytes::vector &secret) {
  267. return ApplyOneOption(_data, dcId, flags, ip, port, secret);
  268. }
  269. bool DcOptions::ApplyOneOption(
  270. base::flat_map<DcId, std::vector<Endpoint>> &data,
  271. DcId dcId,
  272. Flags flags,
  273. const std::string &ip,
  274. int port,
  275. const bytes::vector &secret) {
  276. auto i = data.find(dcId);
  277. if (i != data.cend()) {
  278. for (auto &endpoint : i->second) {
  279. if (endpoint.ip == ip && endpoint.port == port) {
  280. return false;
  281. }
  282. }
  283. i->second.emplace_back(dcId, flags, ip, port, secret);
  284. } else {
  285. data.emplace(dcId, std::vector<Endpoint>(
  286. 1,
  287. Endpoint(dcId, flags, ip, port, secret)));
  288. }
  289. return true;
  290. }
  291. std::vector<DcId> DcOptions::CountOptionsDifference(
  292. const base::flat_map<DcId, std::vector<Endpoint>> &a,
  293. const base::flat_map<DcId, std::vector<Endpoint>> &b) {
  294. auto result = std::vector<DcId>();
  295. const auto find = [](
  296. const std::vector<Endpoint> &where,
  297. const Endpoint &what) {
  298. for (const auto &endpoint : where) {
  299. if (endpoint.ip == what.ip && endpoint.port == what.port) {
  300. return true;
  301. }
  302. }
  303. return false;
  304. };
  305. const auto equal = [&](
  306. const std::vector<Endpoint> &m,
  307. const std::vector<Endpoint> &n) {
  308. if (m.size() != n.size()) {
  309. return false;
  310. }
  311. for (const auto &endpoint : m) {
  312. if (!find(n, endpoint)) {
  313. return false;
  314. }
  315. }
  316. return true;
  317. };
  318. auto i = begin(a);
  319. auto j = begin(b);
  320. const auto max = std::numeric_limits<DcId>::max();
  321. while (i != end(a) || j != end(b)) {
  322. const auto aId = (i == end(a)) ? max : i->first;
  323. const auto bId = (j == end(b)) ? max : j->first;
  324. if (aId < bId) {
  325. result.push_back(aId);
  326. ++i;
  327. } else if (bId < aId) {
  328. result.push_back(bId);
  329. ++j;
  330. } else {
  331. if (!equal(i->second, j->second)) {
  332. result.push_back(aId);
  333. }
  334. ++i;
  335. ++j;
  336. }
  337. }
  338. return result;
  339. }
  340. QByteArray DcOptions::serialize() const {
  341. if (_immutable) {
  342. // Don't write the overriden options to our settings.
  343. return DcOptions(_environment).serialize();
  344. }
  345. ReadLocker lock(this);
  346. auto size = sizeof(qint32);
  347. // Dc options.
  348. auto optionsCount = 0;
  349. size += sizeof(qint32);
  350. for (const auto &item : _data) {
  351. if (isTemporaryDcId(item.first)) {
  352. continue;
  353. }
  354. for (const auto &endpoint : item.second) {
  355. ++optionsCount;
  356. // id + flags + port
  357. size += sizeof(qint32) + sizeof(qint32) + sizeof(qint32);
  358. size += sizeof(qint32) + endpoint.ip.size();
  359. size += sizeof(qint32) + endpoint.secret.size();
  360. }
  361. }
  362. // CDN public keys.
  363. auto count = 0;
  364. for (auto &keysInDc : _cdnPublicKeys) {
  365. count += keysInDc.second.size();
  366. }
  367. struct SerializedPublicKey {
  368. DcId dcId;
  369. bytes::vector n;
  370. bytes::vector e;
  371. };
  372. std::vector<SerializedPublicKey> publicKeys;
  373. publicKeys.reserve(count);
  374. size += sizeof(qint32);
  375. for (const auto &keysInDc : _cdnPublicKeys) {
  376. for (const auto &entry : keysInDc.second) {
  377. publicKeys.push_back({
  378. keysInDc.first,
  379. entry.second.getN(),
  380. entry.second.getE()
  381. });
  382. size += sizeof(qint32)
  383. + Serialize::bytesSize(publicKeys.back().n)
  384. + Serialize::bytesSize(publicKeys.back().e);
  385. }
  386. }
  387. auto result = QByteArray();
  388. result.reserve(size);
  389. {
  390. QDataStream stream(&result, QIODevice::WriteOnly);
  391. stream.setVersion(QDataStream::Qt_5_1);
  392. stream << qint32(-kVersion);
  393. // Dc options.
  394. stream << qint32(optionsCount);
  395. for (const auto &item : _data) {
  396. if (isTemporaryDcId(item.first)) {
  397. continue;
  398. }
  399. for (const auto &endpoint : item.second) {
  400. stream << qint32(endpoint.id)
  401. << qint32(endpoint.flags)
  402. << qint32(endpoint.port)
  403. << qint32(endpoint.ip.size());
  404. stream.writeRawData(endpoint.ip.data(), endpoint.ip.size());
  405. stream << qint32(endpoint.secret.size());
  406. stream.writeRawData(
  407. reinterpret_cast<const char*>(endpoint.secret.data()),
  408. endpoint.secret.size());
  409. }
  410. }
  411. // CDN public keys.
  412. stream << qint32(publicKeys.size());
  413. for (auto &key : publicKeys) {
  414. stream << qint32(key.dcId)
  415. << Serialize::bytes(key.n)
  416. << Serialize::bytes(key.e);
  417. }
  418. }
  419. return result;
  420. }
  421. bool DcOptions::constructFromSerialized(const QByteArray &serialized) {
  422. QDataStream stream(serialized);
  423. stream.setVersion(QDataStream::Qt_5_1);
  424. auto minusVersion = qint32(0);
  425. stream >> minusVersion;
  426. const auto version = (minusVersion < 0) ? (-minusVersion) : 0;
  427. auto count = qint32(0);
  428. if (version > 0) {
  429. stream >> count;
  430. } else {
  431. count = minusVersion;
  432. }
  433. if (stream.status() != QDataStream::Ok) {
  434. LOG(("MTP Error: Bad data for DcOptions::constructFromSerialized()"));
  435. return false;
  436. }
  437. WriteLocker lock(this);
  438. _data.clear();
  439. for (auto i = 0; i != count; ++i) {
  440. qint32 id = 0, flags = 0, port = 0, ipSize = 0;
  441. stream >> id >> flags >> port >> ipSize;
  442. // https://stackoverflow.com/questions/1076714/max-length-for-client-ip-address
  443. constexpr auto kMaxIpSize = 45;
  444. if (ipSize <= 0 || ipSize > kMaxIpSize) {
  445. LOG(("MTP Error: Bad data inside DcOptions::constructFromSerialized()"));
  446. return false;
  447. }
  448. auto ip = std::string(ipSize, ' ');
  449. stream.readRawData(ip.data(), ipSize);
  450. constexpr auto kMaxSecretSize = 32;
  451. auto secret = bytes::vector();
  452. if (version > 0) {
  453. auto secretSize = qint32(0);
  454. stream >> secretSize;
  455. if (secretSize < 0 || secretSize > kMaxSecretSize) {
  456. LOG(("MTP Error: Bad data inside DcOptions::constructFromSerialized()"));
  457. return false;
  458. } else if (secretSize > 0) {
  459. secret.resize(secretSize);
  460. stream.readRawData(
  461. reinterpret_cast<char*>(secret.data()),
  462. secretSize);
  463. }
  464. }
  465. if (stream.status() != QDataStream::Ok) {
  466. LOG(("MTP Error: Bad data inside DcOptions::constructFromSerialized()"));
  467. return false;
  468. }
  469. applyOneGuarded(
  470. DcId(id),
  471. Flags::from_raw(flags),
  472. ip,
  473. port,
  474. secret);
  475. }
  476. // Read CDN config
  477. if (!stream.atEnd() && version > 1) {
  478. auto count = qint32(0);
  479. stream >> count;
  480. if (stream.status() != QDataStream::Ok) {
  481. LOG(("MTP Error: Bad data for CDN config in DcOptions::constructFromSerialized()"));
  482. return false;
  483. }
  484. for (auto i = 0; i != count; ++i) {
  485. qint32 dcId = 0;
  486. bytes::vector n, e;
  487. stream >> dcId >> Serialize::bytes(n) >> Serialize::bytes(e);
  488. if (stream.status() != QDataStream::Ok) {
  489. LOG(("MTP Error: Bad data for CDN config inside DcOptions::constructFromSerialized()"));
  490. return false;
  491. }
  492. auto key = RSAPublicKey(n, e);
  493. if (key.valid()) {
  494. _cdnPublicKeys[dcId].emplace(key.fingerprint(), std::move(key));
  495. } else {
  496. LOG(("MTP Error: Could not read valid CDN public key."));
  497. return false;
  498. }
  499. }
  500. }
  501. return true;
  502. }
  503. rpl::producer<DcId> DcOptions::changed() const {
  504. return _changed.events();
  505. }
  506. rpl::producer<> DcOptions::cdnConfigChanged() const {
  507. return _cdnConfigChanged.events();
  508. }
  509. std::vector<DcId> DcOptions::configEnumDcIds() const {
  510. auto result = std::vector<DcId>();
  511. {
  512. ReadLocker lock(this);
  513. result.reserve(_data.size());
  514. for (auto &item : _data) {
  515. const auto dcId = item.first;
  516. Assert(!item.second.empty());
  517. if (!isCdnDc(item.second.front().flags)
  518. && !isTemporaryDcId(dcId)) {
  519. result.push_back(dcId);
  520. }
  521. }
  522. }
  523. ranges::sort(result);
  524. return result;
  525. }
  526. DcType DcOptions::dcType(ShiftedDcId shiftedDcId) const {
  527. if (isTemporaryDcId(shiftedDcId)) {
  528. return DcType::Temporary;
  529. }
  530. ReadLocker lock(this);
  531. if (_cdnDcIds.find(BareDcId(shiftedDcId)) != _cdnDcIds.cend()) {
  532. return DcType::Cdn;
  533. }
  534. const auto dcId = BareDcId(shiftedDcId);
  535. if (isMediaClusterDcId(shiftedDcId) && hasMediaOnlyOptionsFor(dcId)) {
  536. return DcType::MediaCluster;
  537. }
  538. return DcType::Regular;
  539. }
  540. void DcOptions::setCDNConfig(const MTPDcdnConfig &config) {
  541. WriteLocker lock(this);
  542. _cdnPublicKeys.clear();
  543. for (const auto &key : config.vpublic_keys().v) {
  544. key.match([&](const MTPDcdnPublicKey &data) {
  545. const auto keyBytes = bytes::make_span(data.vpublic_key().v);
  546. auto key = RSAPublicKey(keyBytes);
  547. if (key.valid()) {
  548. _cdnPublicKeys[data.vdc_id().v].emplace(
  549. key.fingerprint(),
  550. std::move(key));
  551. } else {
  552. LOG(("MTP Error: could not read this public RSA key:"));
  553. LOG((qs(data.vpublic_key())));
  554. }
  555. });
  556. }
  557. lock.unlock();
  558. _cdnConfigChanged.fire({});
  559. }
  560. bool DcOptions::hasCDNKeysForDc(DcId dcId) const {
  561. ReadLocker lock(this);
  562. return _cdnPublicKeys.find(dcId) != _cdnPublicKeys.cend();
  563. }
  564. RSAPublicKey DcOptions::getDcRSAKey(
  565. DcId dcId,
  566. const QVector<MTPlong> &fingerprints) const {
  567. const auto findKey = [&](
  568. const base::flat_map<uint64, RSAPublicKey> &keys) {
  569. for (const auto &fingerprint : fingerprints) {
  570. const auto it = keys.find(static_cast<uint64>(fingerprint.v));
  571. if (it != keys.cend()) {
  572. return it->second;
  573. }
  574. }
  575. return RSAPublicKey();
  576. };
  577. {
  578. ReadLocker lock(this);
  579. const auto it = _cdnPublicKeys.find(dcId);
  580. if (it != _cdnPublicKeys.cend()) {
  581. return findKey(it->second);
  582. }
  583. }
  584. return findKey(_publicKeys);
  585. }
  586. auto DcOptions::lookup(
  587. DcId dcId,
  588. DcType type,
  589. bool throughProxy) const -> Variants {
  590. using Flag = Flag;
  591. auto result = Variants();
  592. ReadLocker lock(this);
  593. const auto i = _data.find(dcId);
  594. if (i == end(_data)) {
  595. return result;
  596. }
  597. for (const auto &endpoint : i->second) {
  598. const auto flags = endpoint.flags;
  599. if (type == DcType::Cdn && !(flags & Flag::f_cdn)) {
  600. continue;
  601. } else if (type != DcType::MediaCluster
  602. && (flags & Flag::f_media_only)) {
  603. continue;
  604. } else if (!ValidateSecret(endpoint.secret)) {
  605. continue;
  606. }
  607. const auto address = (flags & Flag::f_ipv6)
  608. ? Variants::IPv6
  609. : Variants::IPv4;
  610. result.data[address][Variants::Tcp].push_back(endpoint);
  611. if (!(flags & (Flag::f_tcpo_only | Flag::f_secret))) {
  612. result.data[address][Variants::Http].push_back(endpoint);
  613. }
  614. }
  615. if (type == DcType::MediaCluster) {
  616. FilterIfHasWithFlag(result, Flag::f_media_only);
  617. }
  618. if (throughProxy) {
  619. FilterIfHasWithFlag(result, Flag::f_static);
  620. }
  621. return result;
  622. }
  623. bool DcOptions::hasMediaOnlyOptionsFor(DcId dcId) const {
  624. ReadLocker lock(this);
  625. const auto i = _data.find(dcId);
  626. if (i == end(_data)) {
  627. return false;
  628. }
  629. for (const auto &endpoint : i->second) {
  630. const auto flags = endpoint.flags;
  631. if (flags & Flag::f_media_only) {
  632. return true;
  633. }
  634. }
  635. return false;
  636. }
  637. void DcOptions::FilterIfHasWithFlag(Variants &variants, Flag flag) {
  638. const auto is = [&](const Endpoint &endpoint) {
  639. return (endpoint.flags & flag) != 0;
  640. };
  641. const auto has = [&](const std::vector<Endpoint> &list) {
  642. return ranges::any_of(list, is);
  643. };
  644. for (auto &byAddress : variants.data) {
  645. for (auto &list : byAddress) {
  646. if (has(list)) {
  647. list = ranges::views::all(
  648. list
  649. ) | ranges::views::filter(
  650. is
  651. ) | ranges::to_vector;
  652. }
  653. }
  654. }
  655. }
  656. void DcOptions::computeCdnDcIds() {
  657. _cdnDcIds.clear();
  658. for (auto &item : _data) {
  659. Assert(!item.second.empty());
  660. if (item.second.front().flags & Flag::f_cdn) {
  661. _cdnDcIds.insert(BareDcId(item.first));
  662. }
  663. }
  664. }
  665. bool DcOptions::loadFromFile(const QString &path) {
  666. QVector<MTPDcOption> options;
  667. QFile f(path);
  668. if (!f.open(QIODevice::ReadOnly)) {
  669. LOG(("MTP Error: could not read '%1'").arg(path));
  670. return false;
  671. }
  672. QTextStream stream(&f);
  673. #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
  674. stream.setCodec("UTF-8");
  675. #endif // Qt < 6.0.0
  676. while (!stream.atEnd()) {
  677. static const auto RegExp = QRegularExpression(R"(\s)");
  678. auto line = stream.readLine();
  679. auto components = line.split(RegExp, Qt::SkipEmptyParts);
  680. if (components.isEmpty() || components[0].startsWith('#')) {
  681. continue;
  682. }
  683. auto error = [line] {
  684. LOG(("MTP Error: in .tdesktop-endpoints expected 'dcId host port [tcpo_only] [media_only]', got '%1'").arg(line));
  685. return false;
  686. };
  687. if (components.size() < 3) {
  688. return error();
  689. }
  690. auto dcId = components[0].toInt();
  691. auto ip = components[1];
  692. auto port = components[2].toInt();
  693. auto host = QHostAddress();
  694. if (dcId <= 0 || dcId >= kDcShift || !host.setAddress(ip) || port <= 0) {
  695. return error();
  696. }
  697. auto flags = Flags(0);
  698. if (host.protocol() == QAbstractSocket::IPv6Protocol) {
  699. flags |= Flag::f_ipv6;
  700. }
  701. for (auto &option : components.mid(3)) {
  702. if (option.startsWith('#')) {
  703. break;
  704. } else if (option == u"tcpo_only"_q) {
  705. flags |= Flag::f_tcpo_only;
  706. } else if (option == u"media_only"_q) {
  707. flags |= Flag::f_media_only;
  708. } else {
  709. return error();
  710. }
  711. }
  712. options.push_back(MTP_dcOption(
  713. MTP_flags(flags),
  714. MTP_int(dcId),
  715. MTP_string(ip),
  716. MTP_int(port),
  717. MTPbytes()));
  718. }
  719. if (options.isEmpty()) {
  720. LOG(("MTP Error: in .tdesktop-endpoints expected at least one endpoint being provided."));
  721. return false;
  722. }
  723. _immutable = false;
  724. setFromList(MTP_vector<MTPDcOption>(options));
  725. _immutable = true;
  726. return true;
  727. }
  728. bool DcOptions::writeToFile(const QString &path) const {
  729. QFile f(path);
  730. if (!f.open(QIODevice::WriteOnly)) {
  731. return false;
  732. }
  733. QTextStream stream(&f);
  734. #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
  735. stream.setCodec("UTF-8");
  736. #endif // Qt < 6.0.0
  737. ReadLocker lock(this);
  738. for (const auto &item : _data) {
  739. for (const auto &option : item.second) {
  740. stream
  741. << option.id
  742. << ' '
  743. << QString::fromStdString(option.ip)
  744. << ' ' << option.port;
  745. if (option.flags & Flag::f_tcpo_only) {
  746. stream << " tcpo_only";
  747. }
  748. if (option.flags & Flag::f_media_only) {
  749. stream << " media_only";
  750. }
  751. stream << '\n';
  752. }
  753. }
  754. return true;
  755. }
  756. } // namespace MTP