diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index db503b145..d38a20f63 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -3033,6 +3033,11 @@ internalLinkTypeMessage = InternalLinkType; //@text Message draft text @contains_link True, if the first line of the text contains a link. If true, the input field needs to be focused and the text after the link should be selected internalLinkTypeMessageDraft text:formattedText contains_link:Bool = InternalLinkType; +//@description The link contains a request of Telegram passport data. Call getPassportAuthorizationForm to process the link if the link was received outside of the app, otherwise ignore it +//@bot_user_id User identifier of the service's bot @scope Telegram Passport element types requested by the service @public_key Service's public key @nonce Unique request identifier provided by the service +//@callback_url An HTTP URL to open once the request is finished or canceled with the parameter tg_passport=success or tg_passport=cancel respectively. If empty, then the link tgbot{bot_user_id}://passport/success or tgbot{bot_user_id}://passport/cancel needs to be opened instead +internalLinkTypePassportDataRequest bot_user_id:int32 scope:string public_key:string nonce:string callback_url:string = InternalLinkType; + //@description The link can be used to confirm ownership of a phone number to prevent account deletion. Call sendPhoneNumberConfirmationCode with the given hash and phone number to process the link //@hash Hash value from the link @phone_number Phone number value from the link internalLinkTypePhoneNumberConfirmation hash:string phone_number:string = InternalLinkType; @@ -5236,7 +5241,7 @@ resendEmailAddressVerificationCode = EmailAddressAuthenticationCodeInfo; checkEmailAddressVerificationCode code:string = Ok; -//@description Returns a Telegram Passport authorization form for sharing data with a service @bot_user_id User identifier of the service's bot @scope Telegram Passport element types requested by the service @public_key Service's public_key @nonce Authorization form nonce provided by the service +//@description Returns a Telegram Passport authorization form for sharing data with a service @bot_user_id User identifier of the service's bot @scope Telegram Passport element types requested by the service @public_key Service's public key @nonce Unique request identifier provided by the service getPassportAuthorizationForm bot_user_id:int32 scope:string public_key:string nonce:string = PassportAuthorizationForm; //@description Returns already available Telegram Passport elements suitable for completing a Telegram Passport authorization form. Result can be received only once for each authorization form @autorization_form_id Authorization form identifier @password Password of the current user diff --git a/td/telegram/LinkManager.cpp b/td/telegram/LinkManager.cpp index e60f4ac42..dda1b066c 100644 --- a/td/telegram/LinkManager.cpp +++ b/td/telegram/LinkManager.cpp @@ -14,6 +14,7 @@ #include "td/telegram/MessagesManager.h" #include "td/telegram/Td.h" #include "td/telegram/telegram_api.h" +#include "td/telegram/UserId.h" #include "td/mtproto/ProxySecret.h" @@ -213,6 +214,33 @@ class LinkManager::InternalLinkMessageDraft : public InternalLink { } }; +class LinkManager::InternalLinkPassportDataRequest : public InternalLink { + UserId bot_user_id_; + string scope_; + string public_key_; + string nonce_; + string callback_url_; + + td_api::object_ptr get_internal_link_type_object() const final { + return td_api::make_object(bot_user_id_.get(), scope_, public_key_, + nonce_, callback_url_); + } + + InternalLinkType get_type() const final { + return InternalLinkType::PassportDataRequest; + } + + public: + InternalLinkPassportDataRequest(UserId bot_user_id, string scope, string public_key, string nonce, + string callback_url) + : bot_user_id_(bot_user_id) + , scope_(std::move(scope)) + , public_key_(std::move(public_key)) + , nonce_(std::move(nonce)) + , callback_url_(std::move(callback_url)) { + } +}; + class LinkManager::InternalLinkProxy : public InternalLink { string server_; int32 port_; @@ -679,6 +707,10 @@ unique_ptr LinkManager::parse_tg_link_query(Slice que return td::make_unique(get_arg("domain"), arg.second); } } + if (get_arg("domain") == "telegrampassport") { + // resolve?domain=telegrampassport&bot_id=&scope=&public_key=&nonce= + return get_internal_link_passport(url_query.args_); + } // resolve?domain= return td::make_unique(get_arg("domain")); } @@ -691,6 +723,9 @@ unique_ptr LinkManager::parse_tg_link_query(Slice que if (has_arg("token")) { return td::make_unique(); } + } else if (path.size() == 1 && path[0] == "passport") { + // passport?bot_id=&scope=&public_key=&nonce= + return get_internal_link_passport(url_query.args_); } else if (path.size() == 1 && path[0] == "join") { // join?invite= if (has_arg("invite")) { @@ -924,6 +959,33 @@ unique_ptr LinkManager::get_internal_link_message_dra return td::make_unique(std::move(full_text), contains_url); } +unique_ptr LinkManager::get_internal_link_passport( + const vector> &args) { + auto get_arg = [&args](Slice key) { + for (auto &arg : args) { + if (arg.first == key) { + return Slice(arg.second); + } + } + return Slice(); + }; + + UserId bot_user_id(to_integer(get_arg("bot_id"))); + auto scope = get_arg("scope"); + auto public_key = get_arg("public_key"); + auto nonce = get_arg("nonce"); + if (nonce.empty()) { + nonce = get_arg("payload"); + } + auto callback_url = get_arg("callback_url"); + + if (!bot_user_id.is_valid() || scope.empty() || public_key.empty() || nonce.empty()) { + return td::make_unique(); + } + return td::make_unique(bot_user_id, scope.str(), public_key.str(), nonce.str(), + callback_url.str()); +} + void LinkManager::get_login_url_info(DialogId dialog_id, MessageId message_id, int32 button_id, Promise> &&promise) { TRY_RESULT_PROMISE(promise, url, td_->messages_manager_->get_login_button_url(dialog_id, message_id, button_id)); diff --git a/td/telegram/LinkManager.h b/td/telegram/LinkManager.h index 979331dda..a73a46503 100644 --- a/td/telegram/LinkManager.h +++ b/td/telegram/LinkManager.h @@ -45,6 +45,7 @@ class LinkManager : public Actor { Language, Message, MessageDraft, + PassportDataRequest, Proxy, PublicDialog, QrCodeAuthentication, @@ -102,6 +103,7 @@ class LinkManager : public Actor { class InternalLinkLanguage; class InternalLinkMessage; class InternalLinkMessageDraft; + class InternalLinkPassportDataRequest; class InternalLinkProxy; class InternalLinkPublicDialog; class InternalLinkQrCodeAuthentication; @@ -122,6 +124,8 @@ class LinkManager : public Actor { static unique_ptr parse_t_me_link_query(Slice query); + static unique_ptr get_internal_link_passport(const vector> &args); + static unique_ptr get_internal_link_message_draft(Slice url, Slice text); Td *td_; diff --git a/test/link.cpp b/test/link.cpp index 60305a467..86bffb8cf 100644 --- a/test/link.cpp +++ b/test/link.cpp @@ -92,6 +92,11 @@ TEST(Link, parse_internal_link) { formatted_text->text_ = std::move(text); return td::td_api::make_object(std::move(formatted_text), contains_url); }; + auto passport_data_request = [](td::int32 bot_user_id, td::string scope, td::string public_key, td::string nonce, + td::string callback_url) { + return td::td_api::make_object(bot_user_id, scope, public_key, + nonce, callback_url); + }; auto phone_number_confirmation = [](td::string hash, td::string phone_number) { return td::td_api::make_object(hash, phone_number); }; @@ -542,4 +547,23 @@ TEST(Link, parse_internal_link) { parse_internal_link("t.me/username/0", public_chat("username")); parse_internal_link("t.me//username", nullptr); parse_internal_link("https://telegram.dog/tele%63ram", public_chat("telecram")); + + parse_internal_link( + "tg://" + "resolve?domain=telegrampassport&bot_id=543260180&scope=%7B%22v%22%3A1%2C%22d%22%3A%5B%7B%22%22%5D%7D%5D%7D&" + "public_key=BEGIN%20PUBLIC%20KEY%0A&nonce=b8ee&callback_url=https%3A%2F%2Fcore.telegram.org%2Fpassport%2Fexample%" + "3Fpassport_ssid%3Db8ee&payload=nonce", + passport_data_request(543260180, "{\"v\":1,\"d\":[{\"\"]}]}", "BEGIN PUBLIC KEY\n", "b8ee", + "https://core.telegram.org/passport/example?passport_ssid=b8ee")); + parse_internal_link("tg://resolve?domain=telegrampassport&bot_id=12345&public_key=key&scope=asd&payload=nonce", + passport_data_request(12345, "asd", "key", "nonce", "")); + parse_internal_link("tg://passport?bot_id=12345&public_key=key&scope=asd&payload=nonce", + passport_data_request(12345, "asd", "key", "nonce", "")); + parse_internal_link("tg://passport?bot_id=0&public_key=key&scope=asd&payload=nonce", unknown_deep_link()); + parse_internal_link("tg://passport?bot_id=-1&public_key=key&scope=asd&payload=nonce", unknown_deep_link()); + parse_internal_link("tg://passport?bot_id=12345&public_key=&scope=asd&payload=nonce", unknown_deep_link()); + parse_internal_link("tg://passport?bot_id=12345&public_key=key&scope=&payload=nonce", unknown_deep_link()); + parse_internal_link("tg://passport?bot_id=12345&public_key=key&scope=asd&payload=", unknown_deep_link()); + parse_internal_link("t.me/telegrampassport?bot_id=12345&public_key=key&scope=asd&payload=nonce", + public_chat("telegrampassport")); }