From f09d2d22ebaeea089d79f77972277bdd80d4c1c2 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 26 Aug 2025 17:00:32 +0300 Subject: [PATCH] Added api support of new unconfirmed authorizations. --- .../SourceFiles/api/api_authorizations.cpp | 145 +++++++++++++++++- Telegram/SourceFiles/api/api_authorizations.h | 15 ++ Telegram/SourceFiles/api/api_updates.cpp | 4 + 3 files changed, 162 insertions(+), 2 deletions(-) diff --git a/Telegram/SourceFiles/api/api_authorizations.cpp b/Telegram/SourceFiles/api/api_authorizations.cpp index 78e463c116..01caa44e61 100644 --- a/Telegram/SourceFiles/api/api_authorizations.cpp +++ b/Telegram/SourceFiles/api/api_authorizations.cpp @@ -9,10 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "base/unixtime.h" -#include "core/changelogs.h" #include "core/application.h" +#include "core/changelogs.h" #include "core/core_settings.h" #include "lang/lang_keys.h" +#include "main/main_app_config.h" +#include "main/main_session_settings.h" +#include "main/main_session.h" namespace Api { namespace { @@ -83,7 +86,19 @@ Authorizations::Entry ParseEntry(const MTPDauthorization &data) { } // namespace Authorizations::Authorizations(not_null api) -: _api(&api->instance()) { +: _api(&api->instance()) +, _autoconfirmPeriod([=] { + constexpr auto kFallbackCount = 604800; + return api->session().appConfig().get( + u"authorization_autoconfirm_period"_q, + kFallbackCount); +}) +, _saveUnreviewed([=] { + api->session().settings().setUnreviewed(_unreviewed); + api->session().saveSettingsDelayed(); +}) { + _unreviewed = api->session().settings().unreviewed(); + removeExpiredUnreviewed(); Core::App().settings().deviceModelChanges( ) | rpl::start_with_next([=](const QString &model) { auto changed = false; @@ -119,6 +134,7 @@ void Authorizations::reload() { ) | ranges::views::transform([](const MTPAuthorization &auth) { return ParseEntry(auth.data()); }) | ranges::to; + removeExpiredUnreviewed(); refreshCallsDisabledHereFromCloud(); _listChanges.fire({}); }).fail([=] { @@ -261,4 +277,129 @@ crl::time Authorizations::lastReceivedTime() { return _lastReceived; } +const std::vector &Authorizations::unreviewed() { + removeExpiredUnreviewed(); + return _unreviewed; +} + +void Authorizations::removeExpiredUnreviewed() { + const auto now = base::unixtime::now(); + const auto period = _autoconfirmPeriod(); + + const auto oldSize = _unreviewed.size(); + _unreviewed.erase( + std::remove_if(_unreviewed.begin(), _unreviewed.end(), + [=](const auto &auth) { + return (now - auth.date) >= period; + }), + _unreviewed.end()); + + if (_unreviewed.size() != oldSize) { + _saveUnreviewed(); + } +} + +void Authorizations::review(const std::vector &hashes, bool confirm) { + for (const auto hash : hashes) { + if (const auto sent = _reviewRequests.take(hash)) { + _api.request(*sent).cancel(); + } + } + + const auto checkComplete = [=] { + if (_reviewRequests.empty()) { + _saveUnreviewed(); + _unreviewedChanges.fire({}); + } + }; + + for (const auto hash : hashes) { + const auto removeFromUnreviewed = [=] { + _unreviewed.erase( + std::remove_if(_unreviewed.begin(), _unreviewed.end(), + [hash](const auto &auth) { return auth.hash == hash; }), + _unreviewed.end()); + _reviewRequests.remove(hash); + checkComplete(); + }; + + if (confirm) { + using Flag = MTPaccount_ChangeAuthorizationSettings::Flag; + const auto id = _api.request(MTPaccount_ChangeAuthorizationSettings( + MTP_flags(Flag::f_confirmed), + MTP_long(hash), + MTPBool(), // encrypted_requests_disabled + MTPBool() // call_requests_disabled + )).done([=] { + removeFromUnreviewed(); + }).fail([=] { + removeFromUnreviewed(); + }).send(); + _reviewRequests.emplace(hash, id); + } else { + const auto id = _api.request(MTPaccount_ResetAuthorization( + MTP_long(hash) + )).done([=](const MTPBool &result) { + if (mtpIsTrue(result)) { + _list.erase( + ranges::remove(_list, hash, &Entry::hash), + end(_list)); + _listChanges.fire({}); + } + removeFromUnreviewed(); + }).fail([=] { + removeFromUnreviewed(); + }).send(); + _reviewRequests.emplace(hash, id); + } + } +} + +rpl::producer<> Authorizations::unreviewedChanges() const { + return _unreviewedChanges.events(); +} + +void Authorizations::apply(const MTPUpdate &update) { + removeExpiredUnreviewed(); + update.match([&](const MTPDupdateNewAuthorization &data) { + auto unreviewed = Data::UnreviewedAuth{ + .hash = data.vhash().v, + .unconfirmed = data.is_unconfirmed(), + .date = data.vdate().value_or_empty(), + .device = qs(data.vdevice().value_or_empty()), + .location = qs(data.vlocation().value_or_empty()) + }; + if (!unreviewed.unconfirmed) { + const auto hash = unreviewed.hash; + const auto was = _unreviewed.size(); + _unreviewed.erase( + std::remove_if( + _unreviewed.begin(), + _unreviewed.end(), + [hash](const auto &auth) { return auth.hash == hash; }), + _unreviewed.end()); + if (was != _unreviewed.size()) { + _saveUnreviewed(); + _unreviewedChanges.fire({}); + } + return; + } + + for (auto &auth : _unreviewed) { + if (auth.hash == unreviewed.hash) { + auth = std::move(unreviewed); + _saveUnreviewed(); + _unreviewedChanges.fire({}); + return; + } + } + + _unreviewed.push_back(std::move(unreviewed)); + _saveUnreviewed(); + _unreviewedChanges.fire({}); + }, [](auto&&) { + Unexpected("Update in Authorizations::apply."); + }); +} + } // namespace Api diff --git a/Telegram/SourceFiles/api/api_authorizations.h b/Telegram/SourceFiles/api/api_authorizations.h index 5e2a41c9f9..25c97f3945 100644 --- a/Telegram/SourceFiles/api/api_authorizations.h +++ b/Telegram/SourceFiles/api/api_authorizations.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "data/data_authorization.h" #include "mtproto/sender.h" class ApiWrap; @@ -35,6 +36,8 @@ public: Fn &&fail, std::optional hash = std::nullopt); + void apply(const MTPUpdate &update); + [[nodiscard]] crl::time lastReceivedTime(); [[nodiscard]] List list() const; @@ -42,6 +45,11 @@ public: [[nodiscard]] int total() const; [[nodiscard]] rpl::producer totalValue() const; + [[nodiscard]] const std::vector &unreviewed(); + [[nodiscard]] rpl::producer<> unreviewedChanges() const; + + void review(const std::vector &hashes, bool confirm); + void updateTTL(int days); [[nodiscard]] rpl::producer ttlDays() const; @@ -57,6 +65,7 @@ public: private: void refreshCallsDisabledHereFromCloud(); + void removeExpiredUnreviewed(); MTP::Sender _api; mtpRequestId _requestId = 0; @@ -64,10 +73,16 @@ private: List _list; rpl::event_stream<> _listChanges; + Fn _autoconfirmPeriod; + std::vector _unreviewed; + rpl::event_stream<> _unreviewedChanges; + Fn _saveUnreviewed; + mtpRequestId _ttlRequestId = 0; rpl::variable _ttlDays = 0; base::flat_map _toggleCallsDisabledRequests; + base::flat_map _reviewRequests; rpl::variable _callsDisabledHere; crl::time _lastReceived = 0; diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index d2a19a7420..893476bfe4 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -2213,6 +2213,10 @@ void Updates::feedUpdate(const MTPUpdate &update) { } } break; + case mtpc_updateNewAuthorization: { + session().api().authorizations().apply(update); + } break; + case mtpc_updateServiceNotification: { const auto &d = update.c_updateServiceNotification(); const auto text = TextWithEntities {