Merge remote-tracking branch 'td/master'

This commit is contained in:
Andrea Cavalli 2021-07-02 13:52:51 +02:00
commit e8c9db61d0
24 changed files with 561 additions and 135 deletions

View File

@ -6,7 +6,7 @@ if (POLICY CMP0065)
cmake_policy(SET CMP0065 NEW)
endif()
project(TDLib VERSION 1.7.4 LANGUAGES CXX C)
project(TDLib VERSION 1.7.5 LANGUAGES CXX C)
if (NOT DEFINED CMAKE_MODULE_PATH)
set(CMAKE_MODULE_PATH "")
@ -375,6 +375,7 @@ set(TDLIB_SOURCE
td/telegram/net/Session.cpp
td/telegram/net/SessionProxy.cpp
td/telegram/net/SessionMultiProxy.cpp
td/telegram/NewPasswordState.cpp
td/telegram/NotificationManager.cpp
td/telegram/NotificationSettings.cpp
td/telegram/NotificationType.cpp
@ -569,6 +570,7 @@ set(TDLIB_SOURCE
td/telegram/net/SessionProxy.h
td/telegram/net/SessionMultiProxy.h
td/telegram/net/TempAuthKeyWatchdog.h
td/telegram/NewPasswordState.h
td/telegram/Notification.h
td/telegram/NotificationGroupId.h
td/telegram/NotificationGroupKey.h

View File

@ -217,7 +217,7 @@ target_link_libraries(YourTarget PRIVATE Td::TdStatic)
Or you could install `TDLib` and then reference it in your CMakeLists.txt like this:
```
find_package(Td 1.7.4 REQUIRED)
find_package(Td 1.7.5 REQUIRED)
target_link_libraries(YourTarget PRIVATE Td::TdStatic)
```
See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/tree/master/example/cpp/CMakeLists.txt).

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
project(TdExample VERSION 1.0 LANGUAGES CXX)
find_package(Td 1.7.4 REQUIRED)
find_package(Td 1.7.5 REQUIRED)
add_executable(tdjson_example tdjson_example.cpp)
target_link_libraries(tdjson_example PRIVATE Td::TdJson)

View File

@ -1,6 +1,6 @@
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
<Metadata>
<Identity Id="Telegram.Td.UWP" Version="1.7.4" Language="en-US" Publisher="Telegram LLC" />
<Identity Id="Telegram.Td.UWP" Version="1.7.5" Language="en-US" Publisher="Telegram LLC" />
<DisplayName>TDLib for Universal Windows Platform</DisplayName>
<Description>TDLib is a library for building Telegram clients</Description>
<MoreInfo>https://core.telegram.org/tdlib</MoreInfo>

View File

@ -119,7 +119,8 @@ authorizationStateClosed = AuthorizationState;
//@description Represents the current state of 2-step verification @has_password True, if a 2-step verification password is set @password_hint Hint for the password; may be empty
//@has_recovery_email_address True, if a recovery email is set @has_passport_data True, if some Telegram Passport elements were saved
//@recovery_email_address_code_info Information about the recovery email address to which the confirmation email was sent; may be null
passwordState has_password:Bool password_hint:string has_recovery_email_address:Bool has_passport_data:Bool recovery_email_address_code_info:emailAddressAuthenticationCodeInfo = PasswordState;
//@pending_reset_date If not 0, point in time (Unix timestamp) after which the password can be reset immediately using resetPassword
passwordState has_password:Bool password_hint:string has_recovery_email_address:Bool has_passport_data:Bool recovery_email_address_code_info:emailAddressAuthenticationCodeInfo pending_reset_date:int32 = PasswordState;
//@description Contains information about the current recovery email address @recovery_email_address Recovery email address
recoveryEmailAddress recovery_email_address:string = RecoveryEmailAddress;
@ -2717,6 +2718,18 @@ checkStickerSetNameResultNameInvalid = CheckStickerSetNameResult;
checkStickerSetNameResultNameOccupied = CheckStickerSetNameResult;
//@class ResetPasswordResult @description Represents result of 2-step verification password reset
//@description The password was reset
resetPasswordResultOk = ResetPasswordResult;
//@description The password reset request is pending @pending_reset_date Point in time (Unix timestamp) after which the password can be reset immediately using resetPassword
resetPasswordResultPending pending_reset_date:int32 = ResetPasswordResult;
//@description The password reset request was declined @retry_date Point in time (Unix timestamp) when the password reset can be retried
resetPasswordResultDeclined retry_date:int32 = ResetPasswordResult;
//@class MessageFileType @description Contains information about a file with messages exported from another app
//@description The messages was exported from a private chat @name Name of the other party; may be empty if unrecognized
@ -3877,8 +3890,12 @@ checkAuthenticationPassword password:string = Ok;
//@description Requests to send a password recovery code to an email address that was previously set up. Works only when the current authorization state is authorizationStateWaitPassword
requestAuthenticationPasswordRecovery = Ok;
//@description Recovers the password with a password recovery code sent to an email address that was previously set up. Works only when the current authorization state is authorizationStateWaitPassword @recovery_code Recovery code to check
recoverAuthenticationPassword recovery_code:string = Ok;
//@description Checks whether a password recovery code sent to an email address is valid. Works only when the current authorization state is authorizationStateWaitPassword @recovery_code Recovery code to check
checkAuthenticationPasswordRecoveryCode recovery_code:string = Ok;
//@description Recovers the password with a password recovery code sent to an email address that was previously set up. Works only when the current authorization state is authorizationStateWaitPassword
//@recovery_code Recovery code to check @new_password New password of the user; may be empty to remove the password @new_hint New password hint; may be empty
recoverAuthenticationPassword recovery_code:string new_password:string new_hint:string = Ok;
//@description Checks the authentication token of a bot; to log in as a bot. Works only when the current authorization state is authorizationStateWaitPhoneNumber. Can be used instead of setAuthenticationPhoneNumber and checkAuthenticationCode to log in @token The bot token
checkAuthenticationBotToken token:string = Ok;
@ -3925,11 +3942,21 @@ checkRecoveryEmailAddressCode code:string = PasswordState;
//@description Resends the 2-step verification recovery email address verification code
resendRecoveryEmailAddressCode = PasswordState;
//@description Requests to send a password recovery code to an email address that was previously set up
//@description Requests to send a 2-step verification password recovery code to an email address that was previously set up
requestPasswordRecovery = EmailAddressAuthenticationCodeInfo;
//@description Recovers the password using a recovery code sent to an email address that was previously set up @recovery_code Recovery code to check
recoverPassword recovery_code:string = PasswordState;
//@description Checks whether a 2-step verification password recovery code sent to an email address is valid @recovery_code Recovery code to check
checkPasswordRecoveryCode recovery_code:string = Ok;
//@description Recovers the 2-step verification password using a recovery code sent to an email address that was previously set up
//@recovery_code Recovery code to check @new_password New password of the user; may be empty to remove the password @new_hint New password hint; may be empty
recoverPassword recovery_code:string new_password:string new_hint:string = PasswordState;
//@description Removes 2-step verification password without previous password and access to recovery email address. The password can't be reset immediately and the request needs to be repeated after the specified time
resetPassword = ResetPasswordResult;
//@description Cancels reset of 2-step verification password. The method can be called if passwordState.pending_reset_date > 0
cancelPasswordReset = Ok;
//@description Creates a new temporary password for processing payments @password Persistent user password @valid_for Time during which the temporary password will be valid, in seconds; should be between 60 and 86400
createTemporaryPassword password:string valid_for:int32 = TemporaryPasswordState;

View File

@ -366,6 +366,7 @@ updateChatParticipant#f3b3781f flags:# chat_id:int date:int actor_id:int user_id
updateChannelParticipant#7fecb1ec flags:# channel_id:int date:int actor_id:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update;
updateBotStopped#7f9488a user_id:int date:int stopped:Bool qts:int = Update;
updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update;
updateBotCommands#cf7e0873 peer:Peer bot_id:int commands:Vector<BotCommand> = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@ -524,7 +525,7 @@ authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true pa
account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations;
account.password#ad2641f8 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password;
account.password#185b184f flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int = account.Password;
account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings;
@ -1250,6 +1251,10 @@ botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope;
botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope;
botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope;
account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult;
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@ -1271,13 +1276,14 @@ auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int en
auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization;
auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization;
auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery;
auth.recoverPassword#4ea56e92 code:string = auth.Authorization;
auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization;
auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode;
auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
auth.exportLoginToken#b1b41517 api_id:int api_hash:string except_ids:Vector<int> = auth.LoginToken;
auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken;
auth.acceptLoginToken#e894ad4d token:bytes = Authorization;
auth.checkRecoveryPassword#d36bf79 code:string = Bool;
account.registerDevice#68976c6f flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<int> = Bool;
account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector<int> = Bool;
@ -1347,6 +1353,8 @@ account.getMultiWallPapers#65ad71dc wallpapers:Vector<InputWallPaper> = Vector<W
account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings;
account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings;
account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool;
account.resetPassword#9308ce1b = account.ResetPasswordResult;
account.declinePasswordReset#4c9409f6 = Bool;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#ca30a5b1 id:InputUser = UserFull;

View File

@ -128,7 +128,7 @@ struct NoCryptoHeader {
#endif
#pragma pack(pop)
// mtproto v1.0
// MTProto v1.0
template <class HeaderT>
std::pair<uint32, UInt128> Transport::calc_message_ack_and_key(const HeaderT &head, size_t data_size) {
Slice part(head.encrypt_begin(), head.data + data_size);
@ -144,7 +144,7 @@ size_t Transport::calc_crypto_size(size_t data_size) {
return raw_size + ((enc_size + data_size + 15) & ~15);
}
// mtproto v2.0
// MTProto v2.0
std::pair<uint32, UInt128> Transport::calc_message_key2(const AuthKey &auth_key, int X, Slice to_encrypt) {
// msg_key_large = SHA256 (substr (auth_key, 88+x, 32) + plaintext + random_padding);
Sha256State state;
@ -207,7 +207,7 @@ size_t Transport::calc_no_crypto_size(size_t data_size) {
Status Transport::read_no_crypto(MutableSlice message, PacketInfo *info, MutableSlice *data) {
if (message.size() < sizeof(NoCryptoHeader)) {
return Status::Error(PSLICE() << "Invalid mtproto message: too small [message.size() = " << message.size()
return Status::Error(PSLICE() << "Invalid MTProto message: too small [message.size() = " << message.size()
<< "] < [sizeof(NoCryptoHeader) = " << sizeof(NoCryptoHeader) << "]");
}
size_t data_size = message.size() - sizeof(NoCryptoHeader);
@ -220,7 +220,7 @@ template <class HeaderT, class PrefixT>
Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &auth_key, HeaderT **header_ptr,
PrefixT **prefix_ptr, MutableSlice *data, PacketInfo *info) {
if (message.size() < sizeof(HeaderT)) {
return Status::Error(PSLICE() << "Invalid mtproto message: too small [message.size() = " << message.size()
return Status::Error(PSLICE() << "Invalid MTProto message: too small [message.size() = " << message.size()
<< "] < [sizeof(HeaderT) = " << sizeof(HeaderT) << "]");
}
//FIXME: rewrite without reinterpret cast
@ -230,7 +230,7 @@ Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &a
to_decrypt.remove_suffix(to_decrypt.size() & 15);
if (header->auth_key_id != auth_key.id()) {
return Status::Error(PSLICE() << "Invalid mtproto message: auth_key_id mismatch [found = "
return Status::Error(PSLICE() << "Invalid MTProto message: auth_key_id mismatch [found = "
<< format::as_hex(header->auth_key_id)
<< "] [expected = " << format::as_hex(auth_key.id()) << "]");
}
@ -272,31 +272,31 @@ Status Transport::read_crypto_impl(int X, MutableSlice message, const AuthKey &a
}
if (!is_key_ok) {
return Status::Error(PSLICE() << "Invalid mtproto message: message_key mismatch [found = "
return Status::Error(PSLICE() << "Invalid MTProto message: message_key mismatch [found = "
<< format::as_hex_dump(header->message_key)
<< "] [expected = " << format::as_hex_dump(real_message_key) << "]");
}
if (info->version == 2) {
if (info->check_mod4 && prefix->message_data_length % 4 != 0) {
return Status::Error(PSLICE() << "Invalid mtproto message: invalid length (not divisible by four)"
return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (not divisible by four)"
<< tag("total_size", message.size())
<< tag("message_data_length", prefix->message_data_length));
}
if (tail_size - sizeof(PrefixT) < prefix->message_data_length) {
return Status::Error(PSLICE() << "Invalid mtproto message: invalid length (message_data_length is too big)"
return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (message_data_length is too big)"
<< tag("total_size", message.size())
<< tag("message_data_length", prefix->message_data_length));
}
size_t pad_size = tail_size - data_size;
if (pad_size < 12 || pad_size > 1024) {
return Status::Error(PSLICE() << "Invalid mtproto message: invalid length (invalid padding length)"
return Status::Error(PSLICE() << "Invalid MTProto message: invalid length (invalid padding length)"
<< tag("padding_size", pad_size) << tag("total_size", message.size())
<< tag("message_data_length", prefix->message_data_length));
}
} else {
if (!is_length_ok) {
return Status::Error(PSLICE() << "Invalid mtproto message: invalid length " << tag("total_size", message.size())
return Status::Error(PSLICE() << "Invalid MTProto message: invalid length " << tag("total_size", message.size())
<< tag("message_data_length", prefix->message_data_length));
}
}
@ -428,7 +428,7 @@ size_t Transport::write_e2e_crypto(const Storer &storer, const AuthKey &auth_key
Result<uint64> Transport::read_auth_key_id(Slice message) {
if (message.size() < 8) {
return Status::Error(PSLICE() << "Invalid mtproto message: smaller than 8 bytes [size = " << message.size() << "]");
return Status::Error(PSLICE() << "Invalid MTProto message: smaller than 8 bytes [size = " << message.size() << "]");
}
return as<uint64>(message.begin());
}
@ -436,7 +436,7 @@ Result<uint64> Transport::read_auth_key_id(Slice message) {
Result<Transport::ReadResult> Transport::read(MutableSlice message, const AuthKey &auth_key, PacketInfo *info) {
if (message.size() < 12) {
if (message.size() < 4) {
return Status::Error(PSLICE() << "Invalid mtproto message: smaller than 4 bytes [size = " << message.size()
return Status::Error(PSLICE() << "Invalid MTProto message: smaller than 4 bytes [size = " << message.size()
<< "]");
}
@ -459,7 +459,7 @@ Result<Transport::ReadResult> Transport::read(MutableSlice message, const AuthKe
TRY_STATUS(read_no_crypto(message, info, &data));
} else {
if (auth_key.empty()) {
return Status::Error("Failed to decrypt mtproto message: auth key is empty");
return Status::Error("Failed to decrypt MTProto message: auth key is empty");
}
TRY_STATUS(read_crypto(message, auth_key, info, &data));
}

View File

@ -80,10 +80,10 @@ class Transport {
static Result<uint64> read_auth_key_id(Slice message);
// Reads mtproto packet from [message] and saves into [data].
// Reads MTProto packet from [message] and saves it into [data].
// If message is encrypted, [auth_key] is used.
// Decryption and unpacking is made inplace, so [data] will be subslice of [message].
// Returns size of mtproto packet.
// Returns size of MTProto packet.
// If dest.size() >= size, the packet is also written into [dest].
// If auth_key is nonempty, encryption will be used.
static Result<ReadResult> read(MutableSlice message, const AuthKey &auth_key, PacketInfo *info) TD_WARN_UNUSED_RESULT;

View File

@ -19,6 +19,7 @@
#include "td/telegram/misc.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/NewPasswordState.h"
#include "td/telegram/NotificationManager.h"
#include "td/telegram/PasswordManager.h"
#include "td/telegram/StateManager.h"
@ -311,6 +312,9 @@ void AuthManager::check_password(uint64 query_id, string password) {
LOG(INFO) << "Have SRP ID " << wait_password_state_.srp_id_;
on_new_query(query_id);
password_ = std::move(password);
recovery_code_.clear();
new_password_.clear();
new_hint_.clear();
start_net_query(NetQueryType::GetPassword,
G()->net_query_creator().create_unauth(telegram_api::account_getPassword()));
}
@ -325,14 +329,33 @@ void AuthManager::request_password_recovery(uint64 query_id) {
G()->net_query_creator().create_unauth(telegram_api::auth_requestPasswordRecovery()));
}
void AuthManager::recover_password(uint64 query_id, string code) {
void AuthManager::check_password_recovery_code(uint64 query_id, string code) {
if (state_ != State::WaitPassword) {
return on_query_error(query_id, Status::Error(8, "Call to checkAuthenticationPasswordRecoveryCode unexpected"));
}
on_new_query(query_id);
start_net_query(NetQueryType::CheckPasswordRecoveryCode,
G()->net_query_creator().create_unauth(telegram_api::auth_checkRecoveryPassword(code)));
}
void AuthManager::recover_password(uint64 query_id, string code, string new_password, string new_hint) {
if (state_ != State::WaitPassword) {
return on_query_error(query_id, Status::Error(8, "Call to recoverAuthenticationPassword unexpected"));
}
on_new_query(query_id);
if (!new_password.empty()) {
password_.clear();
recovery_code_ = std::move(code);
new_password_ = std::move(new_password);
new_hint_ = std::move(new_hint);
start_net_query(NetQueryType::GetPassword,
G()->net_query_creator().create_unauth(telegram_api::account_getPassword()));
return;
}
start_net_query(NetQueryType::RecoverPassword,
G()->net_query_creator().create_unauth(telegram_api::auth_recoverPassword(code)));
G()->net_query_creator().create_unauth(telegram_api::auth_recoverPassword(0, code, nullptr)));
}
void AuthManager::log_out(uint64 query_id) {
@ -531,6 +554,7 @@ void AuthManager::on_get_password_result(NetQueryPtr &result) {
LOG(INFO) << "Receive password info: " << to_string(password);
wait_password_state_ = WaitPasswordState();
Result<NewPasswordState> r_new_password_state;
if (password != nullptr && password->current_algo_ != nullptr) {
switch (password->current_algo_->get_id()) {
case telegram_api::passwordKdfAlgoUnknown::ID:
@ -552,6 +576,9 @@ void AuthManager::on_get_password_result(NetQueryPtr &result) {
default:
UNREACHABLE();
}
r_new_password_state =
get_new_password_state(std::move(password->new_algo_), std::move(password->new_secure_algo_));
} else if (was_qr_code_request_) {
imported_dc_id_ = -1;
login_code_retry_delay_ = clamp(2 * login_code_retry_delay_, 1, 60);
@ -570,6 +597,23 @@ void AuthManager::on_get_password_result(NetQueryPtr &result) {
}
if (state_ == State::WaitPassword) {
if (!new_password_.empty()) {
if (r_new_password_state.is_error()) {
return on_query_error(r_new_password_state.move_as_error());
}
auto r_new_settings = PasswordManager::get_password_input_settings(std::move(new_password_), std::move(new_hint_),
r_new_password_state.ok());
if (r_new_settings.is_error()) {
return on_query_error(r_new_settings.move_as_error());
}
int32 flags = telegram_api::auth_recoverPassword::NEW_SETTINGS_MASK;
start_net_query(NetQueryType::RecoverPassword,
G()->net_query_creator().create_unauth(
telegram_api::auth_recoverPassword(flags, recovery_code_, r_new_settings.move_as_ok())));
return;
}
LOG(INFO) << "Have SRP ID " << wait_password_state_.srp_id_;
auto hash = PasswordManager::get_input_check_password(password_, wait_password_state_.current_client_salt_,
wait_password_state_.current_server_salt_,
@ -598,6 +642,17 @@ void AuthManager::on_request_password_recovery_result(NetQueryPtr &result) {
on_query_ok();
}
void AuthManager::on_check_password_recovery_code_result(NetQueryPtr &result) {
auto r_success = fetch_result<telegram_api::auth_checkRecoveryPassword>(result->ok());
if (r_success.is_error()) {
return on_query_error(r_success.move_as_error());
}
if (!r_success.ok()) {
return on_query_error(Status::Error(400, "Invalid recovery code"));
}
on_query_ok();
}
void AuthManager::on_authentication_result(NetQueryPtr &result, bool is_from_current_query) {
auto r_sign_in = fetch_result<telegram_api::auth_signIn>(result->ok());
if (r_sign_in.is_error()) {
@ -706,6 +761,9 @@ void AuthManager::on_get_authorization(tl_object_ptr<telegram_api::auth_Authoriz
G()->td_db()->get_binlog_pmc()->set("auth", "ok");
code_.clear();
password_.clear();
recovery_code_.clear();
new_password_.clear();
new_hint_.clear();
state_ = State::Ok;
td->contacts_manager_->on_get_user(std::move(auth->user_), "on_get_authorization", true);
update_state(State::Ok, true);
@ -818,6 +876,9 @@ void AuthManager::on_result(NetQueryPtr result) {
case NetQueryType::RequestPasswordRecovery:
on_request_password_recovery_result(result);
break;
case NetQueryType::CheckPasswordRecoveryCode:
on_check_password_recovery_code_result(result);
break;
case NetQueryType::LogOut:
on_log_out_result(result);
break;

View File

@ -42,7 +42,8 @@ class AuthManager : public NetActor {
void check_bot_token(uint64 query_id, string bot_token);
void check_password(uint64 query_id, string password);
void request_password_recovery(uint64 query_id);
void recover_password(uint64 query_id, string code);
void check_password_recovery_code(uint64 query_id, string code);
void recover_password(uint64 query_id, string code, string new_password, string new_hint);
void log_out(uint64 query_id);
void delete_account(uint64 query_id, const string &reason);
@ -79,6 +80,7 @@ class AuthManager : public NetActor {
GetPassword,
CheckPassword,
RequestPasswordRecovery,
CheckPasswordRecoveryCode,
RecoverPassword,
BotAuthentication,
Authentication,
@ -197,6 +199,10 @@ class AuthManager : public NetActor {
WaitPasswordState wait_password_state_;
string recovery_code_;
string new_password_;
string new_hint_;
int32 login_code_retry_delay_ = 0;
Timeout poll_export_login_code_timeout_;
@ -225,6 +231,7 @@ class AuthManager : public NetActor {
void on_request_qr_code_result(NetQueryPtr &result, bool is_import);
void on_get_password_result(NetQueryPtr &result);
void on_request_password_recovery_result(NetQueryPtr &result);
void on_check_password_recovery_code_result(NetQueryPtr &result);
void on_authentication_result(NetQueryPtr &result, bool expected_flag);
void on_log_out_result(NetQueryPtr &result);
void on_delete_account_result(NetQueryPtr &result);

View File

@ -6057,6 +6057,90 @@ void ContactsManager::update_is_location_visible() {
G()->shared_config().set_option_boolean("is_location_visible", expire_date != 0);
}
void ContactsManager::on_update_bot_commands(DialogId dialog_id, UserId bot_user_id,
vector<tl_object_ptr<telegram_api::botCommand>> &&bot_commands) {
if (!bot_user_id.is_valid()) {
LOG(ERROR) << "Receive updateBotCOmmands about invalid " << bot_user_id;
return;
}
if (!have_user(bot_user_id) || !is_user_bot(bot_user_id)) {
return;
}
if (td_->auth_manager_->is_bot()) {
return;
}
auto is_from_bot = [bot_user_id](const BotCommands &commands) {
return commands.get_bot_user_id() == bot_user_id;
};
switch (dialog_id.get_type()) {
case DialogType::User: {
UserId user_id(dialog_id.get_user_id());
auto user_full = get_user_full(user_id);
if (user_full != nullptr) {
on_update_user_full_commands(user_full, user_id, std::move(bot_commands));
update_user_full(user_full, user_id);
}
break;
}
case DialogType::Chat: {
ChatId chat_id(dialog_id.get_chat_id());
auto chat_full = get_chat_full(chat_id);
if (chat_full != nullptr) {
if (bot_commands.empty()) {
if (td::remove_if(chat_full->bot_commands, is_from_bot)) {
chat_full->is_changed = true;
}
} else {
BotCommands commands(bot_user_id, std::move(bot_commands));
auto it = std::find_if(chat_full->bot_commands.begin(), chat_full->bot_commands.end(), is_from_bot);
if (it != chat_full->bot_commands.end()) {
if (*it != commands) {
*it = std::move(commands);
chat_full->is_changed = true;
}
} else {
chat_full->bot_commands.push_back(std::move(commands));
chat_full->is_changed = true;
}
}
update_chat_full(chat_full, chat_id);
}
break;
}
case DialogType::Channel: {
ChannelId channel_id(dialog_id.get_channel_id());
auto channel_full = get_channel_full(channel_id, "on_update_bot_commands");
if (channel_full != nullptr) {
if (bot_commands.empty()) {
if (td::remove_if(channel_full->bot_commands, is_from_bot)) {
channel_full->is_changed = true;
}
} else {
BotCommands commands(bot_user_id, std::move(bot_commands));
auto it = std::find_if(channel_full->bot_commands.begin(), channel_full->bot_commands.end(), is_from_bot);
if (it != channel_full->bot_commands.end()) {
if (*it != commands) {
*it = std::move(commands);
channel_full->is_changed = true;
}
} else {
channel_full->bot_commands.push_back(std::move(commands));
channel_full->is_changed = true;
}
}
update_channel_full(channel_full, channel_id);
}
break;
}
case DialogType::SecretChat:
default:
LOG(ERROR) << "Receive updateBotCommands in " << dialog_id;
break;
}
}
FileId ContactsManager::get_profile_photo_file_id(int64 photo_id) const {
auto it = my_photo_file_id_.find(photo_id);
if (it == my_photo_file_id_.end()) {
@ -10080,9 +10164,7 @@ void ContactsManager::on_get_user_full(tl_object_ptr<telegram_api::userFull> &&u
if (user->bot_info_ != nullptr && !td_->auth_manager_->is_bot()) {
description = std::move(user->bot_info_->description_);
auto commands = transform(std::move(user->bot_info_->commands_),
[](auto &&bot_command) { return BotCommand(std::move(bot_command)); });
on_update_user_full_commands(user_full, user_id, std::move(commands));
on_update_user_full_commands(user_full, user_id, std::move(user->bot_info_->commands_));
}
if (user_full->description != description) {
user_full->description = std::move(description);
@ -11011,8 +11093,11 @@ void ContactsManager::on_update_user_full_common_chat_count(UserFull *user_full,
}
}
void ContactsManager::on_update_user_full_commands(UserFull *user_full, UserId user_id, vector<BotCommand> &&commands) {
void ContactsManager::on_update_user_full_commands(UserFull *user_full, UserId user_id,
vector<tl_object_ptr<telegram_api::botCommand>> &&bot_commands) {
CHECK(user_full != nullptr);
auto commands =
transform(std::move(bot_commands), [](auto &&bot_command) { return BotCommand(std::move(bot_command)); });
if (user_full->commands != commands) {
user_full->commands = std::move(commands);
user_full->is_changed = true;

View File

@ -210,6 +210,9 @@ class ContactsManager : public Actor {
int32 on_update_peer_located(vector<tl_object_ptr<telegram_api::PeerLocated>> &&peers, bool from_update);
void on_update_bot_commands(DialogId dialog_id, UserId bot_user_id,
vector<tl_object_ptr<telegram_api::botCommand>> &&bot_commands);
void on_update_dialog_administrators(DialogId dialog_id, vector<DialogAdministrator> &&administrators,
bool have_access, bool from_database);
@ -1184,7 +1187,8 @@ class ContactsManager : public Actor {
void on_update_user_full_is_blocked(UserFull *user_full, UserId user_id, bool is_blocked);
void on_update_user_full_common_chat_count(UserFull *user_full, UserId user_id, int32 common_chat_count);
void on_update_user_full_commands(UserFull *user_full, UserId user_id, vector<BotCommand> &&commands);
void on_update_user_full_commands(UserFull *user_full, UserId user_id,
vector<tl_object_ptr<telegram_api::botCommand>> &&bot_commands);
void on_update_user_full_need_phone_number_privacy_exception(UserFull *user_full, UserId user_id,
bool need_phone_number_privacy_exception);

View File

@ -0,0 +1,59 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/telegram/NewPasswordState.h"
namespace td {
Result<NewPasswordState> get_new_password_state(
tl_object_ptr<telegram_api::PasswordKdfAlgo> new_algo,
tl_object_ptr<telegram_api::SecurePasswordKdfAlgo> new_secure_algo) {
NewPasswordState state;
CHECK(new_algo != nullptr);
switch (new_algo->get_id()) {
case telegram_api::passwordKdfAlgoUnknown::ID:
return Status::Error(400, "Please update client to continue");
case telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow::ID: {
auto algo =
move_tl_object_as<telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow>(new_algo);
state.client_salt = algo->salt1_.as_slice().str();
state.server_salt = algo->salt2_.as_slice().str();
state.srp_g = algo->g_;
state.srp_p = algo->p_.as_slice().str();
break;
}
default:
UNREACHABLE();
}
CHECK(new_secure_algo != nullptr);
switch (new_secure_algo->get_id()) {
case telegram_api::securePasswordKdfAlgoUnknown::ID:
return Status::Error(400, "Please update client to continue");
case telegram_api::securePasswordKdfAlgoSHA512::ID:
return Status::Error(500, "Server has sent outdated secret encryption mode");
case telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000::ID: {
auto algo = move_tl_object_as<telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000>(new_secure_algo);
state.secure_salt = algo->salt_.as_slice().str();
break;
}
default:
UNREACHABLE();
}
static constexpr size_t MIN_NEW_SECURE_SALT_SIZE = 8;
if (state.secure_salt.size() < MIN_NEW_SECURE_SALT_SIZE) {
return Status::Error(500, "New secure salt length too small");
}
static constexpr size_t MIN_NEW_SALT_SIZE = 8;
if (state.client_salt.size() < MIN_NEW_SALT_SIZE) {
return Status::Error(500, "New salt length too small");
}
return state;
}
} // namespace td

View File

@ -0,0 +1,28 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/telegram/telegram_api.h"
#include "td/utils/common.h"
#include "td/utils/Status.h"
namespace td {
struct NewPasswordState {
string client_salt;
string server_salt;
string srp_p;
string secure_salt;
int32 srp_g = 0;
};
Result<NewPasswordState> get_new_password_state(
tl_object_ptr<telegram_api::PasswordKdfAlgo> new_algo,
tl_object_ptr<telegram_api::SecurePasswordKdfAlgo> new_secure_algo);
} // namespace td

View File

@ -465,7 +465,7 @@ void PasswordManager::check_email_address_verification_code(string code, Promise
void PasswordManager::request_password_recovery(
Promise<td_api::object_ptr<td_api::emailAddressAuthenticationCodeInfo>> promise) {
// is called only after authoriation
// is called only after authorization
send_with_promise(
G()->net_query_creator().create(telegram_api::auth_requestPasswordRecovery()),
PromiseCreator::lambda([promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
@ -478,9 +478,55 @@ void PasswordManager::request_password_recovery(
}));
}
void PasswordManager::recover_password(string code, Promise<State> promise) {
// is called only after authoriation
send_with_promise(G()->net_query_creator().create(telegram_api::auth_recoverPassword(std::move(code))),
void PasswordManager::check_password_recovery_code(string code, Promise<Unit> promise) {
// is called only after authorization
send_with_promise(G()->net_query_creator().create(telegram_api::auth_checkRecoveryPassword(code)),
PromiseCreator::lambda([promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
auto r_result = fetch_result<telegram_api::auth_checkRecoveryPassword>(std::move(r_query));
if (r_result.is_error()) {
return promise.set_error(r_result.move_as_error());
}
if (!r_result.ok()) {
return promise.set_error(Status::Error(400, "Invalid recovery code"));
}
return promise.set_value(Unit());
}));
}
void PasswordManager::recover_password(string code, string new_password, string new_hint, Promise<State> promise) {
// is called only after authorization
if (new_password.empty()) {
return do_recover_password(std::move(code), nullptr, std::move(promise));
}
UpdateSettings update_settings;
update_settings.update_password = true;
update_settings.new_password = std::move(new_password);
update_settings.new_hint = std::move(new_hint);
do_get_state(PromiseCreator::lambda([actor_id = actor_id(this), code = std::move(code),
update_settings = std::move(update_settings),
promise = std::move(promise)](Result<PasswordState> r_state) mutable {
if (r_state.is_error()) {
return promise.set_error(r_state.move_as_error());
}
TRY_RESULT_PROMISE(
promise, new_settings,
get_password_input_settings(update_settings, r_state.ok().has_password, r_state.ok().new_state, nullptr));
send_closure(actor_id, &PasswordManager::do_recover_password, std::move(code), std::move(new_settings),
std::move(promise));
}));
}
void PasswordManager::do_recover_password(string code, PasswordInputSettings &&new_settings, Promise<State> &&promise) {
int32 flags = 0;
if (new_settings != nullptr) {
flags |= telegram_api::auth_recoverPassword::NEW_SETTINGS_MASK;
}
send_with_promise(G()->net_query_creator().create(
telegram_api::auth_recoverPassword(flags, std::move(code), std::move(new_settings))),
PromiseCreator::lambda(
[actor_id = actor_id(this), promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
auto r_result = fetch_result<telegram_api::auth_recoverPassword>(std::move(r_query));
@ -491,6 +537,44 @@ void PasswordManager::recover_password(string code, Promise<State> promise) {
}));
}
void PasswordManager::reset_password(Promise<ResetPasswordResult> promise) {
send_with_promise(
G()->net_query_creator().create(telegram_api::account_resetPassword()),
PromiseCreator::lambda([promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
auto r_result = fetch_result<telegram_api::account_resetPassword>(std::move(r_query));
if (r_result.is_error()) {
return promise.set_error(r_result.move_as_error());
}
auto result_ptr = r_result.move_as_ok();
switch (result_ptr->get_id()) {
case telegram_api::account_resetPasswordOk::ID:
return promise.set_value(td_api::make_object<td_api::resetPasswordResultOk>());
case telegram_api::account_resetPasswordRequestedWait::ID: {
auto result = move_tl_object_as<telegram_api::account_resetPasswordRequestedWait>(result_ptr);
return promise.set_value(td_api::make_object<td_api::resetPasswordResultPending>(result->until_date_));
}
case telegram_api::account_resetPasswordFailedWait::ID: {
auto result = move_tl_object_as<telegram_api::account_resetPasswordFailedWait>(result_ptr);
return promise.set_value(td_api::make_object<td_api::resetPasswordResultDeclined>(result->retry_date_));
}
default:
UNREACHABLE();
break;
}
}));
}
void PasswordManager::cancel_password_reset(Promise<Unit> promise) {
send_with_promise(G()->net_query_creator().create(telegram_api::account_declinePasswordReset()),
PromiseCreator::lambda([promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
auto r_result = fetch_result<telegram_api::account_declinePasswordReset>(std::move(r_query));
if (r_result.is_error() && r_result.error().message() != "RESET_REQUEST_MISSING") {
return promise.set_error(r_result.move_as_error());
}
return promise.set_value(Unit());
}));
}
void PasswordManager::update_password_settings(UpdateSettings update_settings, Promise<State> promise) {
auto result_promise = PromiseCreator::lambda(
[actor_id = actor_id(this), promise = std::move(promise)](Result<bool> r_update_settings) mutable {
@ -538,61 +622,80 @@ void PasswordManager::do_update_password_settings(UpdateSettings update_settings
}));
}
void PasswordManager::do_update_password_settings_impl(UpdateSettings update_settings, PasswordState state,
PasswordPrivateState private_state, Promise<bool> promise) {
auto new_settings = make_tl_object<telegram_api::account_passwordInputSettings>();
Result<PasswordManager::PasswordInputSettings> PasswordManager::get_password_input_settings(
string new_password, string new_hint, const NewPasswordState &state) {
UpdateSettings update_settings;
update_settings.update_password = true;
update_settings.new_password = std::move(new_password);
update_settings.new_hint = std::move(new_hint);
return get_password_input_settings(update_settings, true, state, nullptr);
}
Result<PasswordManager::PasswordInputSettings> PasswordManager::get_password_input_settings(
const UpdateSettings &update_settings, bool has_password, const NewPasswordState &state,
const PasswordPrivateState *private_state) {
auto settings = make_tl_object<telegram_api::account_passwordInputSettings>();
bool have_secret = private_state != nullptr && private_state->secret;
auto update_secure_secret = update_settings.update_secure_secret;
if (update_settings.update_password) {
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_PASSWORD_HASH_MASK;
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_ALGO_MASK;
new_settings->flags_ |= telegram_api::account_passwordInputSettings::HINT_MASK;
settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_PASSWORD_HASH_MASK;
settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_ALGO_MASK;
settings->flags_ |= telegram_api::account_passwordInputSettings::HINT_MASK;
if (!update_settings.new_password.empty()) {
auto new_client_salt = create_salt(state.new_client_salt);
auto new_client_salt = create_salt(state.client_salt);
auto new_hash = calc_password_srp_hash(update_settings.new_password, new_client_salt.as_slice(),
state.new_server_salt, state.new_srp_g, state.new_srp_p);
state.server_salt, state.srp_g, state.srp_p);
if (new_hash.is_error()) {
return promise.set_error(Status::Error(400, "Unable to change password, because it may be unsafe"));
return Status::Error(400, "Unable to change password, because it may be unsafe");
}
new_settings->new_password_hash_ = new_hash.move_as_ok();
new_settings->new_algo_ =
settings->new_password_hash_ = new_hash.move_as_ok();
settings->new_algo_ =
make_tl_object<telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow>(
std::move(new_client_salt), BufferSlice(state.new_server_salt), state.new_srp_g,
BufferSlice(state.new_srp_p));
new_settings->hint_ = std::move(update_settings.new_hint);
if (private_state.secret) {
update_settings.update_secure_secret = true;
std::move(new_client_salt), BufferSlice(state.server_salt), state.srp_g, BufferSlice(state.srp_p));
settings->hint_ = std::move(update_settings.new_hint);
if (have_secret) {
update_secure_secret = true;
}
} else {
new_settings->new_algo_ = make_tl_object<telegram_api::passwordKdfAlgoUnknown>();
settings->new_algo_ = make_tl_object<telegram_api::passwordKdfAlgoUnknown>();
}
}
// Has no password and not setting one.
if (!update_settings.update_password && !state.has_password) {
update_settings.update_secure_secret = false;
// have no password and not setting one
if (!update_settings.update_password && !has_password) {
update_secure_secret = false;
}
// Setting an empty password
// setting an empty password
if (update_settings.update_password && update_settings.new_password.empty()) {
update_settings.update_secure_secret = false;
update_secure_secret = false;
}
if (update_settings.update_secure_secret) {
auto secret = private_state.secret ? std::move(private_state.secret.value()) : secure_storage::Secret::create_new();
auto algorithm = make_tl_object<telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000>(
create_salt(state.new_secure_salt));
if (update_secure_secret) {
auto secret = have_secret ? std::move(private_state->secret.value()) : secure_storage::Secret::create_new();
auto algorithm =
make_tl_object<telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000>(create_salt(state.secure_salt));
auto encrypted_secret = secret.encrypt(
update_settings.update_password ? update_settings.new_password : update_settings.current_password,
algorithm->salt_.as_slice(), secure_storage::EnryptionAlgorithm::Pbkdf2);
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SETTINGS_MASK;
new_settings->new_secure_settings_ = make_tl_object<telegram_api::secureSecretSettings>(
settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SETTINGS_MASK;
settings->new_secure_settings_ = make_tl_object<telegram_api::secureSecretSettings>(
std::move(algorithm), BufferSlice(encrypted_secret.as_slice()), secret.get_hash());
}
if (update_settings.update_recovery_email_address) {
new_settings->flags_ |= telegram_api::account_passwordInputSettings::EMAIL_MASK;
new_settings->email_ = std::move(update_settings.recovery_email_address);
settings->flags_ |= telegram_api::account_passwordInputSettings::EMAIL_MASK;
settings->email_ = std::move(update_settings.recovery_email_address);
}
return settings;
}
void PasswordManager::do_update_password_settings_impl(UpdateSettings update_settings, PasswordState state,
PasswordPrivateState private_state, Promise<bool> promise) {
TRY_RESULT_PROMISE(promise, new_settings,
get_password_input_settings(update_settings, state.has_password, state.new_state, &private_state));
auto current_hash = get_input_check_password(state.has_password ? update_settings.current_password : Slice(), state);
auto query = G()->net_query_creator().create(
telegram_api::account_updatePasswordSettings(std::move(current_hash), std::move(new_settings)));
@ -681,46 +784,15 @@ void PasswordManager::do_get_state(Promise<PasswordState> promise) {
state.unconfirmed_recovery_email_address_pattern = std::move(password->email_unconfirmed_pattern_);
state.code_length = code_length;
CHECK(password->new_algo_ != nullptr);
switch (password->new_algo_->get_id()) {
case telegram_api::passwordKdfAlgoUnknown::ID:
return promise.set_error(Status::Error(400, "Please update client to continue"));
case telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow::ID: {
auto algo =
move_tl_object_as<telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow>(
password->new_algo_);
state.new_client_salt = algo->salt1_.as_slice().str();
state.new_server_salt = algo->salt2_.as_slice().str();
state.new_srp_g = algo->g_;
state.new_srp_p = algo->p_.as_slice().str();
break;
}
default:
UNREACHABLE();
if (password->flags_ & telegram_api::account_password::PENDING_RESET_DATE_MASK) {
state.pending_reset_date = td::max(password->pending_reset_date_, 0);
}
CHECK(password->new_secure_algo_ != nullptr);
switch (password->new_secure_algo_->get_id()) {
case telegram_api::securePasswordKdfAlgoUnknown::ID:
return promise.set_error(Status::Error(400, "Please update client to continue"));
case telegram_api::securePasswordKdfAlgoSHA512::ID:
return promise.set_error(Status::Error(500, "Server has sent outdated secret encryption mode"));
case telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000::ID: {
auto algo = move_tl_object_as<telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000>(
password->new_secure_algo_);
state.new_secure_salt = algo->salt_.as_slice().str();
break;
}
default:
UNREACHABLE();
}
auto &new_state = state.new_state;
TRY_RESULT_PROMISE_ASSIGN(
promise, new_state,
get_new_password_state(std::move(password->new_algo_), std::move(password->new_secure_algo_)));
if (state.new_secure_salt.size() < MIN_NEW_SECURE_SALT_SIZE) {
return promise.set_error(Status::Error(500, "New secure salt length too small"));
}
if (state.new_client_salt.size() < MIN_NEW_SALT_SIZE) {
return promise.set_error(Status::Error(500, "New salt length too small"));
}
promise.set_value(std::move(state));
}));
}

View File

@ -7,6 +7,7 @@
#pragma once
#include "td/telegram/net/NetQuery.h"
#include "td/telegram/NewPasswordState.h"
#include "td/telegram/SecureStorage.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
@ -52,6 +53,8 @@ class PasswordManager : public NetQueryCallback {
public:
using State = tl_object_ptr<td_api::passwordState>;
using TempState = tl_object_ptr<td_api::temporaryPasswordState>;
using ResetPasswordResult = tl_object_ptr<td_api::ResetPasswordResult>;
using PasswordInputSettings = tl_object_ptr<telegram_api::account_passwordInputSettings>;
explicit PasswordManager(ActorShared<> parent) : parent_(std::move(parent)) {
}
@ -60,6 +63,9 @@ class PasswordManager : public NetQueryCallback {
Slice server_salt, int32 g,
Slice p, Slice B, int64 id);
static Result<PasswordInputSettings> get_password_input_settings(string new_password, string new_hint,
const NewPasswordState &state);
void get_state(Promise<State> promise);
void set_password(string current_password, string new_password, string new_hint, bool set_recovery_email_address,
string recovery_email_address, Promise<State> promise);
@ -75,7 +81,11 @@ class PasswordManager : public NetQueryCallback {
void check_email_address_verification_code(string code, Promise<Unit> promise);
void request_password_recovery(Promise<td_api::object_ptr<td_api::emailAddressAuthenticationCodeInfo>> promise);
void recover_password(string code, Promise<State> promise);
void check_password_recovery_code(string code, Promise<Unit> promise);
void recover_password(string code, string new_password, string new_hint, Promise<State> promise);
void reset_password(Promise<ResetPasswordResult> promise);
void cancel_password_reset(Promise<Unit> promise);
void get_secure_secret(string password, Promise<secure_storage::Secret> promise);
void get_input_check_password_srp(string password,
@ -89,9 +99,6 @@ class PasswordManager : public NetQueryCallback {
static TempPasswordState get_temp_password_state_sync();
private:
static constexpr size_t MIN_NEW_SALT_SIZE = 8;
static constexpr size_t MIN_NEW_SECURE_SALT_SIZE = 8;
ActorShared<> parent_;
struct PasswordState {
@ -101,6 +108,7 @@ class PasswordManager : public NetQueryCallback {
bool has_secure_values = false;
string unconfirmed_recovery_email_address_pattern;
int32 code_length = 0;
int32 pending_reset_date = 0;
string current_client_salt;
string current_server_salt;
@ -108,12 +116,8 @@ class PasswordManager : public NetQueryCallback {
string current_srp_p;
string current_srp_B;
int64 current_srp_id;
string new_client_salt;
string new_server_salt;
int32 new_srp_g;
string new_srp_p;
string new_secure_salt;
NewPasswordState new_state;
State get_password_state_object() const {
td_api::object_ptr<td_api::emailAddressAuthenticationCodeInfo> code_info;
@ -122,7 +126,7 @@ class PasswordManager : public NetQueryCallback {
unconfirmed_recovery_email_address_pattern, code_length);
}
return td_api::make_object<td_api::passwordState>(has_password, password_hint, has_recovery_email_address,
has_secure_values, std::move(code_info));
has_secure_values, std::move(code_info), pending_reset_date);
}
};
@ -170,6 +174,12 @@ class PasswordManager : public NetQueryCallback {
static tl_object_ptr<telegram_api::InputCheckPasswordSRP> get_input_check_password(Slice password,
const PasswordState &state);
static Result<PasswordInputSettings> get_password_input_settings(const UpdateSettings &update_settings,
bool has_password, const NewPasswordState &state,
const PasswordPrivateState *private_state);
void do_recover_password(string code, PasswordInputSettings &&new_settings, Promise<State> &&promise);
void update_password_settings(UpdateSettings update_settings, Promise<State> promise);
void do_update_password_settings(UpdateSettings update_settings, PasswordFullState full_state, Promise<bool> promise);
void do_update_password_settings_impl(UpdateSettings update_settings, PasswordState state,

View File

@ -780,12 +780,7 @@ Result<std::tuple<uint64, BufferSlice, int32>> SecretChatActor::decrypt(BufferSl
<< tag("crc", crc64(encrypted_message.as_slice())));
}
// expect that message is encrypted with mtproto 2.0 if their layer is at least MTPROTO_2_LAYER
std::array<int, 2> versions{{1, 2}};
if (config_state_.his_layer >= MTPROTO_2_LAYER) {
std::swap(versions[0], versions[1]);
}
std::array<int, 2> versions{{2, 1}};
BufferSlice encrypted_message_copy;
int32 mtproto_version = -1;
Result<mtproto::Transport::ReadResult> r_read_result;
@ -800,7 +795,7 @@ Result<std::tuple<uint64, BufferSlice, int32>> SecretChatActor::decrypt(BufferSl
info.version = mtproto_version;
info.is_creator = auth_state_.x == 0;
r_read_result = mtproto::Transport::read(data, *auth_key, &info);
if (i + 1 == versions.size() && r_read_result.is_error()) {
if (i + 1 != versions.size() && r_read_result.is_error()) {
LOG(WARNING) << tag("mtproto", mtproto_version) << " decryption failed " << r_read_result.error();
continue;
}
@ -850,7 +845,7 @@ Status SecretChatActor::do_inbound_message_encrypted(unique_ptr<log_event::Inbou
parser.fetch_end();
if (!parser.get_error()) {
auto layer = message_with_layer->layer_;
if (layer < DEFAULT_LAYER && false /* Android app can send such messages */) {
if (layer < DEFAULT_LAYER && false /* old Android app could send such messages */) {
LOG(ERROR) << "Layer " << layer << " is not supported, drop message " << to_string(message_with_layer);
return Status::OK();
}

View File

@ -3223,6 +3223,7 @@ bool Td::is_authentication_request(int32 id) {
case td_api::requestQrCodeAuthentication::ID:
case td_api::checkAuthenticationPassword::ID:
case td_api::requestAuthenticationPasswordRecovery::ID:
case td_api::checkAuthenticationPasswordRecoveryCode::ID:
case td_api::recoverAuthenticationPassword::ID:
case td_api::deleteAccount::ID:
case td_api::logOut::ID:
@ -4816,9 +4817,17 @@ void Td::on_request(uint64 id, const td_api::requestAuthenticationPasswordRecove
send_closure(auth_manager_actor_, &AuthManager::request_password_recovery, id);
}
void Td::on_request(uint64 id, td_api::checkAuthenticationPasswordRecoveryCode &request) {
CLEAN_INPUT_STRING(request.recovery_code_);
send_closure(auth_manager_actor_, &AuthManager::check_password_recovery_code, id, std::move(request.recovery_code_));
}
void Td::on_request(uint64 id, td_api::recoverAuthenticationPassword &request) {
CLEAN_INPUT_STRING(request.recovery_code_);
send_closure(auth_manager_actor_, &AuthManager::recover_password, id, std::move(request.recovery_code_));
CLEAN_INPUT_STRING(request.new_password_);
CLEAN_INPUT_STRING(request.new_hint_);
send_closure(auth_manager_actor_, &AuthManager::recover_password, id, std::move(request.recovery_code_),
std::move(request.new_password_), std::move(request.new_hint_));
}
void Td::on_request(uint64 id, const td_api::logOut &request) {
@ -4958,12 +4967,34 @@ void Td::on_request(uint64 id, td_api::requestPasswordRecovery &request) {
send_closure(password_manager_, &PasswordManager::request_password_recovery, std::move(promise));
}
void Td::on_request(uint64 id, td_api::checkPasswordRecoveryCode &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.recovery_code_);
CREATE_OK_REQUEST_PROMISE();
send_closure(password_manager_, &PasswordManager::check_password_recovery_code, std::move(request.recovery_code_),
std::move(promise));
}
void Td::on_request(uint64 id, td_api::recoverPassword &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.recovery_code_);
CLEAN_INPUT_STRING(request.new_password_);
CLEAN_INPUT_STRING(request.new_hint_);
CREATE_REQUEST_PROMISE();
send_closure(password_manager_, &PasswordManager::recover_password, std::move(request.recovery_code_),
std::move(promise));
std::move(request.new_password_), std::move(request.new_hint_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::resetPassword &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
send_closure(password_manager_, &PasswordManager::reset_password, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::cancelPasswordReset &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();
send_closure(password_manager_, &PasswordManager::cancel_password_reset, std::move(promise));
}
void Td::on_request(uint64 id, td_api::getTemporaryPasswordState &request) {

View File

@ -248,7 +248,7 @@ class Td final : public NetQueryCallback {
static td_api::object_ptr<td_api::Object> static_request(td_api::object_ptr<td_api::Function> function);
private:
static constexpr const char *TDLIB_VERSION = "1.7.4";
static constexpr const char *TDLIB_VERSION = "1.7.5";
static constexpr int64 ONLINE_ALARM_ID = 0;
static constexpr int64 PING_SERVER_ALARM_ID = -1;
static constexpr int32 PING_SERVER_TIMEOUT = 300;
@ -418,6 +418,8 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, const td_api::requestAuthenticationPasswordRecovery &request);
void on_request(uint64 id, td_api::checkAuthenticationPasswordRecoveryCode &request);
void on_request(uint64 id, td_api::recoverAuthenticationPassword &request);
void on_request(uint64 id, const td_api::logOut &request);
@ -446,8 +448,14 @@ class Td final : public NetQueryCallback {
void on_request(uint64 id, td_api::requestPasswordRecovery &request);
void on_request(uint64 id, td_api::checkPasswordRecoveryCode &request);
void on_request(uint64 id, td_api::recoverPassword &request);
void on_request(uint64 id, const td_api::resetPassword &request);
void on_request(uint64 id, const td_api::cancelPasswordReset &request);
void on_request(uint64 id, td_api::getTemporaryPasswordState &request);
void on_request(uint64 id, td_api::createTemporaryPassword &request);

View File

@ -2613,6 +2613,12 @@ void UpdatesManager::on_update(tl_object_ptr<telegram_api::updatePeerBlocked> up
promise.set_value(Unit());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateBotCommands> update, Promise<Unit> &&promise) {
td_->contacts_manager_->on_update_bot_commands(DialogId(update->peer_), UserId(update->bot_id_),
std::move(update->commands_));
promise.set_value(Unit());
}
void UpdatesManager::on_update(tl_object_ptr<telegram_api::updateChatParticipants> update, Promise<Unit> &&promise) {
td_->contacts_manager_->on_get_chat_participants(std::move(update->participants_), true);
promise.set_value(Unit());

View File

@ -361,6 +361,7 @@ class UpdatesManager : public Actor {
void on_update(tl_object_ptr<telegram_api::updateUserPhoto> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updatePeerBlocked> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateBotCommands> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateChatParticipants> update, Promise<Unit> &&promise);
void on_update(tl_object_ptr<telegram_api::updateChatParticipantAdd> update, Promise<Unit> &&promise);

View File

@ -8,7 +8,7 @@
namespace td {
constexpr int32 MTPROTO_LAYER = 130;
constexpr int32 MTPROTO_LAYER = 131;
enum class Version : int32 {
Initial, // 0

View File

@ -1415,11 +1415,15 @@ void WebPagesManager::on_pending_web_page_timeout(WebPageId web_page_id) {
if (it != web_page_messages_.end()) {
vector<FullMessageId> full_message_ids;
for (auto full_message_id : it->second) {
full_message_ids.push_back(full_message_id);
if (full_message_id.get_dialog_id().get_type() != DialogType::SecretChat) {
full_message_ids.push_back(full_message_id);
}
count++;
}
send_closure_later(G()->messages_manager(), &MessagesManager::get_messages_from_server, std::move(full_message_ids),
Promise<Unit>(), nullptr);
if (!full_message_ids.empty()) {
send_closure_later(G()->messages_manager(), &MessagesManager::get_messages_from_server,
std::move(full_message_ids), Promise<Unit>(), nullptr);
}
}
auto get_it = pending_get_web_pages_.find(web_page_id);
if (get_it != pending_get_web_pages_.end()) {

View File

@ -1655,8 +1655,15 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::getCurrentState>());
} else if (op == "rapr") {
send_request(td_api::make_object<td_api::requestAuthenticationPasswordRecovery>());
} else if (op == "caprc") {
string recovery_code = args;
send_request(td_api::make_object<td_api::checkAuthenticationPasswordRecoveryCode>(recovery_code));
} else if (op == "rap") {
send_request(td_api::make_object<td_api::recoverAuthenticationPassword>(args));
string recovery_code;
string new_password;
string new_hint;
get_args(args, recovery_code, new_password, new_hint);
send_request(td_api::make_object<td_api::recoverAuthenticationPassword>(recovery_code, new_password, new_hint));
} else if (op == "lo" || op == "LogOut" || op == "logout") {
send_request(td_api::make_object<td_api::logOut>());
} else if (op == "destroy") {
@ -1775,10 +1782,21 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::checkPhoneNumberVerificationCode>(args));
} else if (op == "rpncc") {
send_request(td_api::make_object<td_api::resendPhoneNumberVerificationCode>());
} else if (op == "rpr" || op == "RequestPasswordRecovery") {
} else if (op == "rpr") {
send_request(td_api::make_object<td_api::requestPasswordRecovery>());
} else if (op == "rp" || op == "RecoverPassword") {
send_request(td_api::make_object<td_api::recoverPassword>(args));
} else if (op == "cprc") {
string recovery_code = args;
send_request(td_api::make_object<td_api::checkPasswordRecoveryCode>(recovery_code));
} else if (op == "rp") {
string recovery_code;
string new_password;
string new_hint;
get_args(args, recovery_code, new_password, new_hint);
send_request(td_api::make_object<td_api::recoverPassword>(recovery_code, new_password, new_hint));
} else if (op == "resetp") {
send_request(td_api::make_object<td_api::resetPassword>());
} else if (op == "cpr") {
send_request(td_api::make_object<td_api::cancelPasswordReset>());
} else if (op == "gtp" || op == "GetTemporaryPassword") {
send_request(td_api::make_object<td_api::getTemporaryPasswordState>());
} else if (op == "ctp" || op == "CreateTemporaryPassword") {