diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 204235846..577d1c10d 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -66,6 +66,18 @@ authenticationCodeInfo phone_number:string type:AuthenticationCodeType next_type emailAddressAuthenticationCodeInfo email_address_pattern:string length:int32 = EmailAddressAuthenticationCodeInfo; +//@class EmailAddressAuthentication @description Contains authentication data for a email address + +//@description An authentication code delivered to a user's email address @code The code +emailAddressAuthenticationCode code:string = EmailAddressAuthentication; + +//@description An authentication token received through Apple ID @token The token +emailAddressAuthenticationAppleId token:string = EmailAddressAuthentication; + +//@description An authentication token received through Google ID @token The token +emailAddressAuthenticationGoogleId token:string = EmailAddressAuthentication; + + //@description Represents a part of the text that needs to be formatted in some unusual way @offset Offset of the entity, in UTF-16 code units @length Length of the entity, in UTF-16 code units @type Type of the entity textEntity offset:int32 length:int32 type:TextEntityType = TextEntity; @@ -4625,6 +4637,9 @@ setAuthenticationEmailAddress email_address:string = Ok; //@description Re-sends an authentication code to the user. Works only when the current authorization state is authorizationStateWaitCode, the next_code_type of the result is not null and the server-specified timeout has passed resendAuthenticationCode = Ok; +//@description Checks the authentication of a email address. Works only when the current authorization state is authorizationStateWaitEmailCode @code Email address authentication to check +checkAuthenticationEmailCode code:EmailAddressAuthentication = Ok; + //@description Checks the authentication code. Works only when the current authorization state is authorizationStateWaitCode @code Authentication code to check checkAuthenticationCode code:string = Ok; diff --git a/td/telegram/AuthManager.cpp b/td/telegram/AuthManager.cpp index 90f4eb8d9..49c67eca4 100644 --- a/td/telegram/AuthManager.cpp +++ b/td/telegram/AuthManager.cpp @@ -315,6 +315,21 @@ void AuthManager::resend_authentication_code(uint64 query_id) { start_net_query(NetQueryType::SendCode, G()->net_query_creator().create_unauth(r_resend_code.move_as_ok())); } +void AuthManager::check_email_code(uint64 query_id, td_api::object_ptr &&code) { + if (code == nullptr) { + return on_query_error(query_id, Status::Error(400, "Code must be non-empty")); + } + if (state_ != State::WaitEmailCode && + !(state_ == State::WaitEmailAddress && code->get_id() == td_api::emailAddressAuthenticationCode::ID)) { + return on_query_error(query_id, Status::Error(400, "Call to checkAuthenticationEmailCode unexpected")); + } + + on_new_query(query_id); + start_net_query(NetQueryType::VerifyEmailAddress, + G()->net_query_creator().create_unauth(telegram_api::account_verifyEmail( + send_code_helper_.get_email_verify_purpose_login_setup(), get_input_email_verification(code)))); +} + void AuthManager::check_code(uint64 query_id, string code) { if (state_ != State::WaitCode) { return on_query_error(query_id, Status::Error(400, "Call to checkAuthenticationCode unexpected")); @@ -513,15 +528,7 @@ void AuthManager::start_net_query(NetQueryType net_query_type, NetQueryPtr net_q G()->net_query_dispatcher().dispatch_with_callback(std::move(net_query), actor_shared(this)); } -void AuthManager::on_send_code_result(NetQueryPtr &result) { - auto r_sent_code = fetch_result(result->ok()); - if (r_sent_code.is_error()) { - return on_query_error(r_sent_code.move_as_error()); - } - auto sent_code = r_sent_code.move_as_ok(); - - LOG(INFO) << "Receive " << to_string(sent_code); - +void AuthManager::on_sent_code(telegram_api::object_ptr &&sent_code) { if (sent_code->type_->get_id() == telegram_api::auth_sentCodeTypeSetUpEmailRequired::ID) { auto code_type = move_tl_object_as(std::move(sent_code->type_)); send_code_helper_.on_phone_code_hash(std::move(sent_code->phone_code_hash_)); @@ -532,6 +539,17 @@ void AuthManager::on_send_code_result(NetQueryPtr &result) { send_code_helper_.on_sent_code(std::move(sent_code)); update_state(State::WaitCode, true); } +} + +void AuthManager::on_send_code_result(NetQueryPtr &result) { + auto r_sent_code = fetch_result(result->ok()); + if (r_sent_code.is_error()) { + return on_query_error(r_sent_code.move_as_error()); + } + auto sent_code = r_sent_code.move_as_ok(); + + LOG(INFO) << "Receive " << to_string(sent_code); + on_sent_code(std::move(sent_code)); on_query_ok(); } @@ -553,6 +571,23 @@ void AuthManager::on_send_email_code_result(NetQueryPtr &result) { on_query_ok(); } +void AuthManager::on_verify_email_address_result(NetQueryPtr &result) { + auto r_email_verified = fetch_result(result->ok()); + if (r_email_verified.is_error()) { + return on_query_error(r_email_verified.move_as_error()); + } + auto email_verified = r_email_verified.move_as_ok(); + + LOG(INFO) << "Receive " << to_string(email_verified); + if (email_verified->get_id() != telegram_api::account_emailVerifiedLogin::ID) { + return on_query_error(Status::Error(500, "Receive invalid response")); + } + + auto verified_login = telegram_api::move_object_as(email_verified); + on_sent_code(std::move(verified_login->sent_code_)); + on_query_ok(); +} + void AuthManager::on_request_qr_code_result(NetQueryPtr &result, bool is_import) { Status status; if (result->is_ok()) { @@ -918,7 +953,8 @@ void AuthManager::on_result(NetQueryPtr result) { type = net_query_type_; net_query_type_ = NetQueryType::None; if (result->is_error()) { - if ((type == NetQueryType::SendCode || type == NetQueryType::SendEmailCode || type == NetQueryType::SignIn || + if ((type == NetQueryType::SendCode || type == NetQueryType::SendEmailCode || + type == NetQueryType::VerifyEmailAddress || type == NetQueryType::SignIn || type == NetQueryType::RequestQrCode || type == NetQueryType::ImportQrCode) && result->error().code() == 401 && result->error().message() == CSlice("SESSION_PASSWORD_NEEDED")) { auto dc_id = DcId::main(); @@ -977,6 +1013,9 @@ void AuthManager::on_result(NetQueryPtr result) { case NetQueryType::SendEmailCode: on_send_email_code_result(result); break; + case NetQueryType::VerifyEmailAddress: + on_verify_email_address_result(result); + break; case NetQueryType::RequestQrCode: on_request_qr_code_result(result, false); break; @@ -1127,4 +1166,35 @@ void AuthManager::save_state() { G()->td_db()->get_binlog_pmc()->set("auth_state", log_event_store(db_state).as_slice().str()); } +telegram_api::object_ptr AuthManager::get_input_email_verification( + const td_api::object_ptr &code) { + CHECK(code != nullptr); + switch (code->get_id()) { + case td_api::emailAddressAuthenticationCode::ID: { + auto token = static_cast(code.get())->code_; + if (!clean_input_string(token)) { + token.clear(); + } + return telegram_api::make_object(token); + } + case td_api::emailAddressAuthenticationAppleId::ID: { + auto token = static_cast(code.get())->token_; + if (!clean_input_string(token)) { + token.clear(); + } + return telegram_api::make_object(token); + } + case td_api::emailAddressAuthenticationGoogleId::ID: { + auto token = static_cast(code.get())->token_; + if (!clean_input_string(token)) { + token.clear(); + } + return telegram_api::make_object(token); + } + default: + UNREACHABLE(); + return nullptr; + } +} + } // namespace td diff --git a/td/telegram/AuthManager.h b/td/telegram/AuthManager.h index b9da53708..7fd9a0b69 100644 --- a/td/telegram/AuthManager.h +++ b/td/telegram/AuthManager.h @@ -38,6 +38,7 @@ class AuthManager final : public NetActor { td_api::object_ptr settings); void set_email_address(uint64 query_id, string email_address); void resend_authentication_code(uint64 query_id); + void check_email_code(uint64 query_id, td_api::object_ptr &&code); void check_code(uint64 query_id, string code); void register_user(uint64 query_id, string first_name, string last_name); void request_qr_code_authentication(uint64 query_id, vector other_user_ids); @@ -80,6 +81,7 @@ class AuthManager final : public NetActor { SignUp, SendCode, SendEmailCode, + VerifyEmailAddress, RequestQrCode, ImportQrCode, GetPassword, @@ -271,8 +273,11 @@ class AuthManager final : public NetActor { void send_log_out_query(); void destroy_auth_keys(); + void on_sent_code(telegram_api::object_ptr &&sent_code); + void on_send_code_result(NetQueryPtr &result); void on_send_email_code_result(NetQueryPtr &result); + void on_verify_email_address_result(NetQueryPtr &result); 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); @@ -291,6 +296,9 @@ class AuthManager final : public NetActor { static void send_ok(uint64 query_id); static void on_query_error(uint64 query_id, Status status); + static telegram_api::object_ptr get_input_email_verification( + const td_api::object_ptr &code); + void start_up() final; void tear_down() final; }; diff --git a/td/telegram/SendCodeHelper.h b/td/telegram/SendCodeHelper.h index bae0cc45d..6ace7fad4 100644 --- a/td/telegram/SendCodeHelper.h +++ b/td/telegram/SendCodeHelper.h @@ -42,6 +42,8 @@ class SendCodeHelper { telegram_api::account_sendConfirmPhoneCode send_confirm_phone_code(const string &hash, Slice phone_number, const Settings &settings); + telegram_api::object_ptr get_email_verify_purpose_login_setup() const; + Slice phone_number() const { return phone_number_; } @@ -92,8 +94,6 @@ class SendCodeHelper { const AuthenticationCodeInfo &authentication_code_info); static telegram_api::object_ptr get_input_code_settings(const Settings &settings); - - telegram_api::object_ptr get_email_verify_purpose_login_setup() const; }; } // namespace td diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 93c96311e..f0a59d9a1 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -2781,7 +2781,9 @@ bool Td::is_authentication_request(int32 id) { case td_api::setDatabaseEncryptionKey::ID: case td_api::getAuthorizationState::ID: case td_api::setAuthenticationPhoneNumber::ID: + case td_api::setAuthenticationEmailAddress::ID: case td_api::resendAuthenticationCode::ID: + case td_api::checkAuthenticationEmailCode::ID: case td_api::checkAuthenticationCode::ID: case td_api::registerUser::ID: case td_api::requestQrCodeAuthentication::ID: @@ -4271,6 +4273,10 @@ void Td::on_request(uint64 id, const td_api::resendAuthenticationCode &request) send_closure(auth_manager_actor_, &AuthManager::resend_authentication_code, id); } +void Td::on_request(uint64 id, td_api::checkAuthenticationEmailCode &request) { + send_closure(auth_manager_actor_, &AuthManager::check_email_code, id, std::move(request.code_)); +} + void Td::on_request(uint64 id, td_api::checkAuthenticationCode &request) { CLEAN_INPUT_STRING(request.code_); send_closure(auth_manager_actor_, &AuthManager::check_code, id, std::move(request.code_)); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 57375315c..9b187add6 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -402,6 +402,8 @@ class Td final : public Actor { void on_request(uint64 id, const td_api::resendAuthenticationCode &request); + void on_request(uint64 id, td_api::checkAuthenticationEmailCode &request); + void on_request(uint64 id, td_api::checkAuthenticationCode &request); void on_request(uint64 id, td_api::registerUser &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index bfeb46937..fa42fa7e0 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1850,6 +1850,16 @@ class CliClient final : public Actor { send_request(td_api::make_object(args)); } else if (op == "sdek" || op == "SetDatabaseEncryptionKey") { send_request(td_api::make_object(args)); + } else if (op == "caec") { + td_api::object_ptr code; + if (begins_with(args, "a ")) { + code = td_api::make_object(args.substr(2)); + } else if (begins_with(args, "g ")) { + code = td_api::make_object(args.substr(2)); + } else if (!args.empty()) { + code = td_api::make_object(args); + } + send_request(td_api::make_object(std::move(code))); } else if (op == "cac") { send_request(td_api::make_object(args)); } else if (op == "ru") {