Add td_api::internalLinkTypeChatFilterInvite.

This commit is contained in:
levlam 2023-03-30 21:11:15 +03:00
parent 49b9ea2ec1
commit 02a2e23cac
4 changed files with 121 additions and 8 deletions

View File

@ -4641,6 +4641,9 @@ internalLinkTypeBotStartInGroup bot_username:string start_parameter:string admin
//@description The link is a link to the change phone number section of the app //@description The link is a link to the change phone number section of the app
internalLinkTypeChangePhoneNumber = InternalLinkType; internalLinkTypeChangePhoneNumber = InternalLinkType;
//@description The link is an invite link to a chat filter. Call checkChatFilterInviteLink with the given invite link to process the link @invite_link Internal representation of the invite link
internalLinkTypeChatFilterInvite invite_link:string = InternalLinkType;
//@description The link is a chat invite link. Call checkChatInviteLink with the given invite link to process the link @invite_link Internal representation of the invite link //@description The link is a chat invite link. Call checkChatInviteLink with the given invite link to process the link @invite_link Internal representation of the invite link
internalLinkTypeChatInvite invite_link:string = InternalLinkType; internalLinkTypeChatInvite invite_link:string = InternalLinkType;

View File

@ -71,12 +71,12 @@ static string get_url_query_hash(bool is_tg, const HttpUrlQuery &url_query) {
const auto &path = url_query.path_; const auto &path = url_query.path_;
if (is_tg) { if (is_tg) {
if (path.size() == 1 && path[0] == "join" && !url_query.get_arg("invite").empty()) { if (path.size() == 1 && path[0] == "join" && !url_query.get_arg("invite").empty()) {
// join?invite=abcdef // join?invite=<hash>
return url_query.get_arg("invite").str(); return url_query.get_arg("invite").str();
} }
} else { } else {
if (path.size() >= 2 && path[0] == "joinchat" && !path[1].empty()) { if (path.size() >= 2 && path[0] == "joinchat" && !path[1].empty()) {
// /joinchat/<link> // /joinchat/<hash>
return path[1]; return path[1];
} }
if (!path.empty() && path[0].size() >= 2 && (path[0][0] == ' ' || path[0][0] == '+')) { if (!path.empty() && path[0].size() >= 2 && (path[0][0] == ' ' || path[0][0] == '+')) {
@ -87,6 +87,22 @@ static string get_url_query_hash(bool is_tg, const HttpUrlQuery &url_query) {
return string(); return string();
} }
static string get_url_query_slug(bool is_tg, const HttpUrlQuery &url_query) {
const auto &path = url_query.path_;
if (is_tg) {
if (path.size() == 1 && path[0] == "list" && !url_query.get_arg("slug").empty()) {
// list?slug=<hash>
return url_query.get_arg("slug").str();
}
} else {
if (path.size() >= 2 && path[0] == "list" && !path[1].empty()) {
// /list/<hash>
return path[1];
}
}
return string();
}
static AdministratorRights get_administrator_rights(Slice rights, bool for_channel) { static AdministratorRights get_administrator_rights(Slice rights, bool for_channel) {
bool can_manage_dialog = false; bool can_manage_dialog = false;
bool can_change_info = false; bool can_change_info = false;
@ -350,6 +366,18 @@ class LinkManager::InternalLinkDefaultMessageAutoDeleteTimerSettings final : pub
} }
}; };
class LinkManager::InternalLinkDialogFilterInvite final : public InternalLink {
string url_;
td_api::object_ptr<td_api::InternalLinkType> get_internal_link_type_object() const final {
return td_api::make_object<td_api::internalLinkTypeChatFilterInvite>(url_);
}
public:
explicit InternalLinkDialogFilterInvite(string url) : url_(std::move(url)) {
}
};
class LinkManager::InternalLinkDialogInvite final : public InternalLink { class LinkManager::InternalLinkDialogInvite final : public InternalLink {
string url_; string url_;
@ -989,8 +1017,9 @@ LinkManager::LinkInfo LinkManager::get_link_info(Slice link) {
Slice subdomain(&host[0], host.size() - 5); Slice subdomain(&host[0], host.size() - 5);
if (is_valid_username(subdomain) && subdomain != "addemoji" && subdomain != "addstickers" && if (is_valid_username(subdomain) && subdomain != "addemoji" && subdomain != "addstickers" &&
subdomain != "addtheme" && subdomain != "auth" && subdomain != "confirmphone" && subdomain != "invoice" && subdomain != "addtheme" && subdomain != "auth" && subdomain != "confirmphone" && subdomain != "invoice" &&
subdomain != "joinchat" && subdomain != "login" && subdomain != "proxy" && subdomain != "setlanguage" && subdomain != "joinchat" && subdomain != "list" && subdomain != "login" && subdomain != "proxy" &&
subdomain != "share" && subdomain != "socks" && subdomain != "web" && subdomain != "k" && subdomain != "z") { subdomain != "setlanguage" && subdomain != "share" && subdomain != "socks" && subdomain != "web" &&
subdomain != "k" && subdomain != "z") {
result.type_ = LinkType::TMe; result.type_ = LinkType::TMe;
result.query_ = PSTRING() << '/' << subdomain << http_url.query_; result.query_ = PSTRING() << '/' << subdomain << http_url.query_;
return result; return result;
@ -1260,12 +1289,20 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_tg_link_query(Slice que
} }
// settings // settings
return td::make_unique<InternalLinkSettings>(); return td::make_unique<InternalLinkSettings>();
} else if (path.size() == 1 && path[0] == "list") {
// list?slug=<hash>
if (has_arg("slug")) {
auto slug = get_url_query_slug(true, url_query);
if (!slug.empty() && is_base64url_characters(slug)) {
return td::make_unique<InternalLinkDialogFilterInvite>(PSTRING() << "tg:list?slug=" << slug);
}
}
} else if (path.size() == 1 && path[0] == "join") { } else if (path.size() == 1 && path[0] == "join") {
// join?invite=<hash> // join?invite=<hash>
if (has_arg("invite")) { if (has_arg("invite")) {
auto invite_hash = get_url_query_hash(true, url_query); auto invite_hash = get_url_query_hash(true, url_query);
if (!invite_hash.empty() && !is_valid_phone_number(invite_hash) && is_base64url_characters(invite_hash)) { if (!invite_hash.empty() && !is_valid_phone_number(invite_hash) && is_base64url_characters(invite_hash)) {
return td::make_unique<InternalLinkDialogInvite>(PSTRING() << "tg:join?invite=" << url_encode(invite_hash)); return td::make_unique<InternalLinkDialogInvite>(PSTRING() << "tg:join?invite=" << invite_hash);
} }
} }
} else if (path.size() == 1 && (path[0] == "addstickers" || path[0] == "addemoji")) { } else if (path.size() == 1 && (path[0] == "addstickers" || path[0] == "addemoji")) {
@ -1392,12 +1429,20 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_t_me_link_query(Slice q
// /login/<code> // /login/<code>
return td::make_unique<InternalLinkAuthenticationCode>(path[1]); return td::make_unique<InternalLinkAuthenticationCode>(path[1]);
} }
} else if (path[0] == "list") {
if (path.size() >= 2 && !path[1].empty()) {
auto slug = get_url_query_slug(false, url_query);
if (!slug.empty() && is_base64url_characters(slug)) {
// /list/<slug>
return td::make_unique<InternalLinkDialogFilterInvite>(PSTRING() << "tg:list?slug=" << slug);
}
}
} else if (path[0] == "joinchat") { } else if (path[0] == "joinchat") {
if (path.size() >= 2 && !path[1].empty()) { if (path.size() >= 2 && !path[1].empty()) {
auto invite_hash = get_url_query_hash(false, url_query); auto invite_hash = get_url_query_hash(false, url_query);
if (!invite_hash.empty() && !is_valid_phone_number(invite_hash) && is_base64url_characters(invite_hash)) { if (!invite_hash.empty() && !is_valid_phone_number(invite_hash) && is_base64url_characters(invite_hash)) {
// /joinchat/<link> // /joinchat/<hash>
return td::make_unique<InternalLinkDialogInvite>(PSTRING() << "tg:join?invite=" << url_encode(invite_hash)); return td::make_unique<InternalLinkDialogInvite>(PSTRING() << "tg:join?invite=" << invite_hash);
} }
} }
} else if (path[0][0] == ' ' || path[0][0] == '+') { } else if (path[0][0] == ' ' || path[0][0] == '+') {
@ -1415,7 +1460,7 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_t_me_link_query(Slice q
return std::move(user_link); return std::move(user_link);
} else if (!invite_hash.empty() && is_base64url_characters(invite_hash)) { } else if (!invite_hash.empty() && is_base64url_characters(invite_hash)) {
// /+<link> // /+<link>
return td::make_unique<InternalLinkDialogInvite>(PSTRING() << "tg:join?invite=" << url_encode(invite_hash)); return td::make_unique<InternalLinkDialogInvite>(PSTRING() << "tg:join?invite=" << invite_hash);
} }
} }
} else if (path[0] == "contact") { } else if (path[0] == "contact") {
@ -1832,6 +1877,14 @@ Result<string> LinkManager::get_internal_link_impl(const td_api::InternalLinkTyp
return Status::Error("HTTP link is unavailable for the link type"); return Status::Error("HTTP link is unavailable for the link type");
} }
return "tg://settings/change_number"; return "tg://settings/change_number";
case td_api::internalLinkTypeChatFilterInvite::ID: {
auto link = static_cast<const td_api::internalLinkTypeChatFilterInvite *>(type_ptr);
auto slug = get_dialog_filter_invite_link_slug(link->invite_link_);
if (slug.empty()) {
return Status::Error(400, "Invalid invite link specified");
}
return get_dialog_filter_invite_link(slug, is_internal);
}
case td_api::internalLinkTypeChatInvite::ID: { case td_api::internalLinkTypeChatInvite::ID: {
auto link = static_cast<const td_api::internalLinkTypeChatInvite *>(type_ptr); auto link = static_cast<const td_api::internalLinkTypeChatInvite *>(type_ptr);
auto invite_hash = get_dialog_invite_link_hash(link->invite_link_); auto invite_hash = get_dialog_invite_link_hash(link->invite_link_);
@ -2267,6 +2320,30 @@ Result<string> LinkManager::get_background_url(const string &name,
return url; return url;
} }
string LinkManager::get_dialog_filter_invite_link_slug(Slice invite_link) {
auto link_info = get_link_info(invite_link);
if (link_info.type_ != LinkType::Tg && link_info.type_ != LinkType::TMe) {
return string();
}
const auto url_query = parse_url_query(link_info.query_);
auto slug = get_url_query_slug(link_info.type_ == LinkType::Tg, url_query);
if (!is_base64url_characters(slug)) {
return string();
}
return slug;
}
string LinkManager::get_dialog_filter_invite_link(Slice slug, bool is_internal) {
if (!is_base64url_characters(slug)) {
return string();
}
if (is_internal) {
return PSTRING() << "tg:list?slug=" << slug;
} else {
return PSTRING() << get_t_me_url() << "list/" << slug;
}
}
string LinkManager::get_dialog_invite_link_hash(Slice invite_link) { string LinkManager::get_dialog_invite_link_hash(Slice invite_link) {
auto link_info = get_link_info(invite_link); auto link_info = get_link_info(invite_link);
if (link_info.type_ != LinkType::Tg && link_info.type_ != LinkType::TMe) { if (link_info.type_ != LinkType::Tg && link_info.type_ != LinkType::TMe) {

View File

@ -83,6 +83,10 @@ class LinkManager final : public Actor {
static Result<string> get_background_url(const string &name, static Result<string> get_background_url(const string &name,
td_api::object_ptr<td_api::BackgroundType> background_type); td_api::object_ptr<td_api::BackgroundType> background_type);
static string get_dialog_filter_invite_link_slug(Slice invite_link);
static string get_dialog_filter_invite_link(Slice slug, bool is_internal);
static string get_dialog_invite_link_hash(Slice invite_link); static string get_dialog_invite_link_hash(Slice invite_link);
static string get_dialog_invite_link(Slice hash, bool is_internal); static string get_dialog_invite_link(Slice hash, bool is_internal);
@ -120,6 +124,7 @@ class LinkManager final : public Actor {
class InternalLinkChangePhoneNumber; class InternalLinkChangePhoneNumber;
class InternalLinkConfirmPhone; class InternalLinkConfirmPhone;
class InternalLinkDefaultMessageAutoDeleteTimerSettings; class InternalLinkDefaultMessageAutoDeleteTimerSettings;
class InternalLinkDialogFilterInvite;
class InternalLinkDialogInvite; class InternalLinkDialogInvite;
class InternalLinkEditProfileSettings; class InternalLinkEditProfileSettings;
class InternalLinkFilterSettings; class InternalLinkFilterSettings;

View File

@ -218,6 +218,10 @@ static auto change_phone_number() {
return td::td_api::make_object<td::td_api::internalLinkTypeChangePhoneNumber>(); return td::td_api::make_object<td::td_api::internalLinkTypeChangePhoneNumber>();
} }
static auto chat_filter_invite(const td::string &slug) {
return td::td_api::make_object<td::td_api::internalLinkTypeChatFilterInvite>("tg:list?slug=" + slug);
}
static auto chat_invite(const td::string &hash) { static auto chat_invite(const td::string &hash) {
return td::td_api::make_object<td::td_api::internalLinkTypeChatInvite>("tg:join?invite=" + hash); return td::td_api::make_object<td::td_api::internalLinkTypeChatInvite>("tg:join?invite=" + hash);
} }
@ -703,6 +707,24 @@ TEST(Link, parse_internal_link_part2) {
parse_internal_link("t.me/+123456?attach=bot&startattach=1", parse_internal_link("t.me/+123456?attach=bot&startattach=1",
attachment_menu_bot(nullptr, user_phone_number("123456"), "bot", "1")); attachment_menu_bot(nullptr, user_phone_number("123456"), "bot", "1"));
parse_internal_link("t.me/list?invite=abcdef", nullptr);
parse_internal_link("t.me/list", nullptr);
parse_internal_link("t.me/list/", nullptr);
parse_internal_link("t.me/list//abcdef", nullptr);
parse_internal_link("t.me/list?/abcdef", nullptr);
parse_internal_link("t.me/list/?abcdef", nullptr);
parse_internal_link("t.me/list/#abcdef", nullptr);
parse_internal_link("t.me/list/abacaba", chat_filter_invite("abacaba"));
parse_internal_link("t.me/list/aba%20aba", nullptr);
parse_internal_link("t.me/list/aba%30aba", chat_filter_invite("aba0aba"));
parse_internal_link("t.me/list/123456a", chat_filter_invite("123456a"));
parse_internal_link("t.me/list/12345678901", chat_filter_invite("12345678901"));
parse_internal_link("t.me/list/123456", chat_filter_invite("123456"));
parse_internal_link("t.me/list/123456/123123/12/31/a/s//21w/?asdas#test", chat_filter_invite("123456"));
parse_internal_link("t.me/list/12345678901a", chat_filter_invite("12345678901a"));
parse_internal_link("t.me/list/123456a", chat_filter_invite("123456a"));
parse_internal_link("t.me/list/123456a/123123/12/31/a/s//21w/?asdas#test", chat_filter_invite("123456a"));
parse_internal_link("t.me/contact/startattach/adasd", user_token("startattach")); parse_internal_link("t.me/contact/startattach/adasd", user_token("startattach"));
parse_internal_link("t.me/contact/startattach", user_token("startattach")); parse_internal_link("t.me/contact/startattach", user_token("startattach"));
parse_internal_link("t.me/contact/startattach=1", user_token("startattach=1")); parse_internal_link("t.me/contact/startattach=1", user_token("startattach=1"));
@ -714,6 +736,11 @@ TEST(Link, parse_internal_link_part2) {
parse_internal_link("tg://join?invite=abc%30def", chat_invite("abc0def")); parse_internal_link("tg://join?invite=abc%30def", chat_invite("abc0def"));
parse_internal_link("tg:join?invite=", unknown_deep_link("tg://join?invite=")); parse_internal_link("tg:join?invite=", unknown_deep_link("tg://join?invite="));
parse_internal_link("tg:list?slug=abcdef", chat_filter_invite("abcdef"));
parse_internal_link("tg:list?slug=abc%20def", unknown_deep_link("tg://list?slug=abc%20def"));
parse_internal_link("tg://list?slug=abc%30def", chat_filter_invite("abc0def"));
parse_internal_link("tg:list?slug=", unknown_deep_link("tg://list?slug="));
parse_internal_link("t.me/addstickers?set=abcdef", nullptr); parse_internal_link("t.me/addstickers?set=abcdef", nullptr);
parse_internal_link("t.me/addstickers", nullptr); parse_internal_link("t.me/addstickers", nullptr);
parse_internal_link("t.me/addstickers/", nullptr); parse_internal_link("t.me/addstickers/", nullptr);
@ -1142,6 +1169,7 @@ TEST(Link, parse_internal_link_part4) {
parse_internal_link("confirmphone.t.me", nullptr); parse_internal_link("confirmphone.t.me", nullptr);
parse_internal_link("invoice.t.me", nullptr); parse_internal_link("invoice.t.me", nullptr);
parse_internal_link("joinchat.t.me", nullptr); parse_internal_link("joinchat.t.me", nullptr);
parse_internal_link("list.t.me", nullptr);
parse_internal_link("login.t.me", nullptr); parse_internal_link("login.t.me", nullptr);
parse_internal_link("proxy.t.me", nullptr); parse_internal_link("proxy.t.me", nullptr);
parse_internal_link("setlanguage.t.me", nullptr); parse_internal_link("setlanguage.t.me", nullptr);