api_authorizations.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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 "api/api_authorizations.h"
  8. #include "apiwrap.h"
  9. #include "base/unixtime.h"
  10. #include "core/changelogs.h"
  11. #include "core/application.h"
  12. #include "core/core_settings.h"
  13. #include "lang/lang_keys.h"
  14. namespace Api {
  15. namespace {
  16. constexpr auto TestApiId = 17349;
  17. constexpr auto SnapApiId = 611335;
  18. constexpr auto DesktopApiId = 2040;
  19. Authorizations::Entry ParseEntry(const MTPDauthorization &data) {
  20. auto result = Authorizations::Entry();
  21. result.hash = data.is_current() ? 0 : data.vhash().v;
  22. result.incomplete = data.is_password_pending();
  23. result.callsDisabled = data.is_call_requests_disabled();
  24. const auto apiId = result.apiId = data.vapi_id().v;
  25. const auto isTest = (apiId == TestApiId);
  26. const auto isDesktop = (apiId == DesktopApiId)
  27. || (apiId == SnapApiId)
  28. || isTest;
  29. const auto appName = isDesktop
  30. ? u"Telegram Desktop%1"_q.arg(isTest ? " (GitHub)" : QString())
  31. : qs(data.vapp_name());// + u" for "_q + qs(d.vplatform());
  32. const auto appVer = [&] {
  33. const auto version = qs(data.vapp_version());
  34. if (isDesktop) {
  35. const auto verInt = version.toInt();
  36. if (version == QString::number(verInt)) {
  37. return Core::FormatVersionDisplay(verInt);
  38. }
  39. } else {
  40. if (const auto index = version.indexOf('('); index >= 0) {
  41. return version.mid(index);
  42. }
  43. }
  44. return version;
  45. }();
  46. result.name = result.hash
  47. ? qs(data.vdevice_model())
  48. : Core::App().settings().deviceModel();
  49. const auto country = qs(data.vcountry());
  50. //const auto platform = qs(data.vplatform());
  51. //const auto &countries = countriesByISO2();
  52. //const auto j = countries.constFind(country);
  53. //if (j != countries.cend()) {
  54. // country = QString::fromUtf8(j.value()->name);
  55. //}
  56. result.system = qs(data.vsystem_version());
  57. result.platform = qs(data.vplatform());
  58. result.activeTime = data.vdate_active().v
  59. ? data.vdate_active().v
  60. : data.vdate_created().v;
  61. result.info = QString("%1%2").arg(
  62. appName,
  63. appVer.isEmpty() ? QString() : (' ' + appVer));
  64. result.ip = qs(data.vip());
  65. result.active = result.hash
  66. ? Authorizations::ActiveDateString(result.activeTime)
  67. : tr::lng_status_online(tr::now);
  68. result.location = country;
  69. return result;
  70. }
  71. } // namespace
  72. Authorizations::Authorizations(not_null<ApiWrap*> api)
  73. : _api(&api->instance()) {
  74. Core::App().settings().deviceModelChanges(
  75. ) | rpl::start_with_next([=](const QString &model) {
  76. auto changed = false;
  77. for (auto &entry : _list) {
  78. if (!entry.hash) {
  79. entry.name = model;
  80. changed = true;
  81. }
  82. }
  83. if (changed) {
  84. _listChanges.fire({});
  85. }
  86. }, _lifetime);
  87. if (Core::App().settings().disableCallsLegacy()) {
  88. toggleCallsDisabledHere(true);
  89. }
  90. }
  91. void Authorizations::reload() {
  92. if (_requestId) {
  93. return;
  94. }
  95. _requestId = _api.request(MTPaccount_GetAuthorizations(
  96. )).done([=](const MTPaccount_Authorizations &result) {
  97. _requestId = 0;
  98. _lastReceived = crl::now();
  99. const auto &data = result.data();
  100. _ttlDays = data.vauthorization_ttl_days().v;
  101. _list = ranges::views::all(
  102. data.vauthorizations().v
  103. ) | ranges::views::transform([](const MTPAuthorization &auth) {
  104. return ParseEntry(auth.data());
  105. }) | ranges::to<List>;
  106. refreshCallsDisabledHereFromCloud();
  107. _listChanges.fire({});
  108. }).fail([=] {
  109. _requestId = 0;
  110. }).send();
  111. }
  112. void Authorizations::cancelCurrentRequest() {
  113. _api.request(base::take(_requestId)).cancel();
  114. }
  115. void Authorizations::refreshCallsDisabledHereFromCloud() {
  116. const auto that = ranges::find(_list, 0, &Entry::hash);
  117. if (that != end(_list)
  118. && !_toggleCallsDisabledRequests.contains(0)) {
  119. _callsDisabledHere = that->callsDisabled;
  120. }
  121. }
  122. void Authorizations::requestTerminate(
  123. Fn<void(const MTPBool &result)> &&done,
  124. Fn<void(const MTP::Error &error)> &&fail,
  125. std::optional<uint64> hash) {
  126. const auto send = [&](auto request) {
  127. _api.request(
  128. std::move(request)
  129. ).done([=, done = std::move(done)](const MTPBool &result) {
  130. done(result);
  131. if (mtpIsTrue(result)) {
  132. if (hash) {
  133. _list.erase(
  134. ranges::remove(_list, *hash, &Entry::hash),
  135. end(_list));
  136. } else {
  137. _list.clear();
  138. }
  139. _listChanges.fire({});
  140. }
  141. }).fail(
  142. std::move(fail)
  143. ).send();
  144. };
  145. if (hash) {
  146. send(MTPaccount_ResetAuthorization(MTP_long(*hash)));
  147. } else {
  148. send(MTPauth_ResetAuthorizations());
  149. }
  150. }
  151. Authorizations::List Authorizations::list() const {
  152. return _list;
  153. }
  154. auto Authorizations::listValue() const
  155. -> rpl::producer<Authorizations::List> {
  156. return rpl::single(
  157. list()
  158. ) | rpl::then(
  159. _listChanges.events() | rpl::map([=] { return list(); })
  160. );
  161. }
  162. rpl::producer<int> Authorizations::totalValue() const {
  163. return rpl::single(
  164. total()
  165. ) | rpl::then(
  166. _listChanges.events() | rpl::map([=] { return total(); })
  167. );
  168. }
  169. void Authorizations::updateTTL(int days) {
  170. _api.request(_ttlRequestId).cancel();
  171. _ttlRequestId = _api.request(MTPaccount_SetAuthorizationTTL(
  172. MTP_int(days)
  173. )).done([=] {
  174. _ttlRequestId = 0;
  175. }).fail([=] {
  176. _ttlRequestId = 0;
  177. }).send();
  178. _ttlDays = days;
  179. }
  180. rpl::producer<int> Authorizations::ttlDays() const {
  181. return _ttlDays.value() | rpl::filter(rpl::mappers::_1 != 0);
  182. }
  183. void Authorizations::toggleCallsDisabled(uint64 hash, bool disabled) {
  184. if (const auto sent = _toggleCallsDisabledRequests.take(hash)) {
  185. _api.request(*sent).cancel();
  186. }
  187. using Flag = MTPaccount_ChangeAuthorizationSettings::Flag;
  188. const auto id = _api.request(MTPaccount_ChangeAuthorizationSettings(
  189. MTP_flags(Flag::f_call_requests_disabled),
  190. MTP_long(hash),
  191. MTPBool(), // encrypted_requests_disabled
  192. MTP_bool(disabled)
  193. )).done([=] {
  194. _toggleCallsDisabledRequests.remove(hash);
  195. }).fail([=](const MTP::Error &error) {
  196. LOG(("API Error: toggle calls %1. Hash: %2. %3.")
  197. .arg(disabled ? u"disabled"_q : u"enabled"_q)
  198. .arg(hash)
  199. .arg(error.type()));
  200. _toggleCallsDisabledRequests.remove(hash);
  201. }).send();
  202. _toggleCallsDisabledRequests.emplace(hash, id);
  203. if (!hash) {
  204. _callsDisabledHere = disabled;
  205. }
  206. }
  207. bool Authorizations::callsDisabledHere() const {
  208. return _callsDisabledHere.current();
  209. }
  210. rpl::producer<bool> Authorizations::callsDisabledHereValue() const {
  211. return _callsDisabledHere.value();
  212. }
  213. rpl::producer<bool> Authorizations::callsDisabledHereChanges() const {
  214. return _callsDisabledHere.changes();
  215. }
  216. QString Authorizations::ActiveDateString(TimeId active) {
  217. const auto now = QDateTime::currentDateTime();
  218. const auto lastTime = base::unixtime::parse(active);
  219. const auto nowDate = now.date();
  220. const auto lastDate = lastTime.date();
  221. return (lastDate == nowDate)
  222. ? QLocale().toString(lastTime.time(), QLocale::ShortFormat)
  223. : (lastDate.year() == nowDate.year()
  224. && lastDate.weekNumber() == nowDate.weekNumber())
  225. ? langDayOfWeek(lastDate)
  226. : QLocale().toString(lastDate, QLocale::ShortFormat);
  227. }
  228. int Authorizations::total() const {
  229. return ranges::count_if(
  230. _list,
  231. ranges::not_fn(&Entry::incomplete));
  232. }
  233. crl::time Authorizations::lastReceivedTime() {
  234. return _lastReceived;
  235. }
  236. } // namespace Api