Add class td_api::InternalLinkType and parse some intenal links.
This commit is contained in:
parent
5f0b24926f
commit
acd6caae9b
@ -2998,6 +2998,15 @@ chatReportReasonFake = ChatReportReason;
|
||||
chatReportReasonCustom = ChatReportReason;
|
||||
|
||||
|
||||
//@class InternalLinkType @description Describes an internal t.me or tg: link, which must be processed by the app in a special way
|
||||
|
||||
//@description The link is a link to a background. Call searchBackground with a given background name to process the link @background_name Name of the background
|
||||
internalLinkTypeBackground background_name:string = InternalLinkType;
|
||||
|
||||
//@description The link is a link to a Telegram message. Call getMessageLinkInfo to process the link
|
||||
internalLinkTypeMessage = InternalLinkType;
|
||||
|
||||
|
||||
//@description Contains an HTTPS link to a message in a supergroup or channel @link Message link @is_public True, if the link will work for non-members of the chat
|
||||
messageLink link:string is_public:Bool = MessageLink;
|
||||
|
||||
|
@ -6,12 +6,15 @@
|
||||
//
|
||||
#include "td/telegram/LinkManager.h"
|
||||
|
||||
#include "td/telegram/ChannelId.h"
|
||||
#include "td/telegram/ConfigShared.h"
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/MessagesManager.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/telegram_api.h"
|
||||
|
||||
#include "td/utils/algorithm.h"
|
||||
#include "td/utils/buffer.h"
|
||||
#include "td/utils/HttpUrl.h"
|
||||
#include "td/utils/logging.h"
|
||||
@ -19,6 +22,32 @@
|
||||
|
||||
namespace td {
|
||||
|
||||
class LinkManager::InternalLinkBackground : public InternalLink {
|
||||
string background_name_;
|
||||
|
||||
td_api::object_ptr<td_api::InternalLinkType> get_internal_link_type_object() const final {
|
||||
return td_api::make_object<td_api::internalLinkTypeBackground>(background_name_);
|
||||
}
|
||||
|
||||
InternalLinkType get_type() const final {
|
||||
return InternalLinkType::Background;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit InternalLinkBackground(string background_name) : background_name_(background_name) {
|
||||
}
|
||||
};
|
||||
|
||||
class LinkManager::InternalLinkMessage : public InternalLink {
|
||||
td_api::object_ptr<td_api::InternalLinkType> get_internal_link_type_object() const final {
|
||||
return td_api::make_object<td_api::internalLinkTypeMessage>();
|
||||
}
|
||||
|
||||
InternalLinkType get_type() const final {
|
||||
return InternalLinkType::Message;
|
||||
}
|
||||
};
|
||||
|
||||
class RequestUrlAuthQuery : public Td::ResultHandler {
|
||||
Promise<td_api::object_ptr<td_api::LoginUrlInfo>> promise_;
|
||||
string url_;
|
||||
@ -203,6 +232,145 @@ Result<string> LinkManager::check_link(Slice link) {
|
||||
return http_url.get_url();
|
||||
}
|
||||
|
||||
LinkManager::LinkInfo LinkManager::get_link_info(Slice link) {
|
||||
LinkInfo result;
|
||||
if (link.empty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_tg = false;
|
||||
if (tolower_begins_with(link, "tg:")) {
|
||||
link.remove_prefix(3);
|
||||
if (begins_with(link, "//")) {
|
||||
link.remove_prefix(2);
|
||||
}
|
||||
is_tg = true;
|
||||
}
|
||||
|
||||
auto r_http_url = parse_url(link);
|
||||
if (r_http_url.is_error()) {
|
||||
return result;
|
||||
}
|
||||
auto http_url = r_http_url.move_as_ok();
|
||||
|
||||
if (!http_url.userinfo_.empty() || http_url.is_ipv6_) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (is_tg) {
|
||||
if (tolower_begins_with(link, "http://") || http_url.protocol_ == HttpUrl::Protocol::Https ||
|
||||
http_url.specified_port_ != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.is_internal_ = true;
|
||||
result.is_tg_ = true;
|
||||
result.query_ = link;
|
||||
return result;
|
||||
} else {
|
||||
if (http_url.port_ != 80 && http_url.port_ != 443) {
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<Slice> t_me_urls{Slice("t.me"), Slice("telegram.me"), Slice("telegram.dog")};
|
||||
string cur_t_me_url = G()->shared_config().get_option_string("t_me_url");
|
||||
if (tolower_begins_with(cur_t_me_url, "http://") || tolower_begins_with(cur_t_me_url, "https://")) {
|
||||
Slice t_me_url = cur_t_me_url;
|
||||
t_me_url = t_me_url.substr(t_me_url[4] == 's' ? 8 : 7);
|
||||
if (!td::contains(t_me_urls, t_me_url)) {
|
||||
t_me_urls.push_back(t_me_url);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto t_me_url : t_me_urls) {
|
||||
if (http_url.host_ == t_me_url) {
|
||||
result.is_internal_ = true;
|
||||
result.is_tg_ = false;
|
||||
result.query_ = http_url.query_;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unique_ptr<LinkManager::InternalLink> LinkManager::parse_internal_link(Slice link) {
|
||||
auto info = get_link_info(link);
|
||||
if (!info.is_internal_) {
|
||||
return nullptr;
|
||||
}
|
||||
if (info.is_tg_) {
|
||||
return parse_tg_link_query(info.query_);
|
||||
} else {
|
||||
return parse_t_me_link_query(info.query_);
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<LinkManager::InternalLink> LinkManager::parse_tg_link_query(Slice query) {
|
||||
const auto url_query = parse_url_query(query);
|
||||
const auto &path = url_query.path_;
|
||||
|
||||
auto copy_arg = [&](Slice name) {
|
||||
auto arg = url_query.get_arg(name);
|
||||
if (arg.empty()) {
|
||||
return string();
|
||||
}
|
||||
return PSTRING() << name << '=' << url_encode(arg);
|
||||
};
|
||||
|
||||
if (path.size() == 1 && path[0] == "resolve") {
|
||||
// resolve?domain=username&post=12345&single
|
||||
if (!url_query.get_arg("domain").empty() && !url_query.get_arg("post").empty()) {
|
||||
return td::make_unique<InternalLinkMessage>();
|
||||
}
|
||||
} else if (path.size() == 1 && path[0] == "privatepost") {
|
||||
// privatepost?channel=123456789&msg_id=12345
|
||||
if (!url_query.get_arg("channel").empty() && !url_query.get_arg("msg_id").empty()) {
|
||||
return td::make_unique<InternalLinkMessage>();
|
||||
}
|
||||
} else if (path.size() == 1 && path[0] == "bg") {
|
||||
// bg?color=<color>
|
||||
// bg?gradient=<hex_color>-<hex_color>&rotation=...
|
||||
// bg?gradient=<hex_color>~<hex_color>~<hex_color>~<hex_color>
|
||||
// bg?slug=<background_name>&mode=blur+motion
|
||||
// bg?slug=<pattern_name>&intensity=...&bg_color=...&mode=blur+motion
|
||||
if (!url_query.get_arg("color").empty()) {
|
||||
return td::make_unique<InternalLinkBackground>(url_query.get_arg("color").str());
|
||||
}
|
||||
if (!url_query.get_arg("gradient").empty()) {
|
||||
return td::make_unique<InternalLinkBackground>(PSTRING() << url_encode(url_query.get_arg("gradient")) << '?'
|
||||
<< copy_arg("rotation"));
|
||||
}
|
||||
if (!url_query.get_arg("slug").empty()) {
|
||||
return td::make_unique<InternalLinkBackground>(PSTRING() << url_encode(url_query.get_arg("slug")) << '?'
|
||||
<< copy_arg("mode") << copy_arg("intensity")
|
||||
<< copy_arg("bg_color") << copy_arg("rotation"));
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unique_ptr<LinkManager::InternalLink> LinkManager::parse_t_me_link_query(Slice query) {
|
||||
CHECK(query[0] == '/');
|
||||
const auto url_query = parse_url_query(query);
|
||||
const auto &path = url_query.path_;
|
||||
if (path.size() == 3 && path[0] == "c") {
|
||||
// /c/123456789/12345
|
||||
return td::make_unique<InternalLinkMessage>();
|
||||
} else if (path.size() == 2 && path[0] == "bg") {
|
||||
// /bg/<hex_color>
|
||||
// /bg/<hex_color>-<hex_color>?rotation=...
|
||||
// /bg/<hex_color>~<hex_color>~<hex_color>~<hex_color>
|
||||
// /bg/<background_name>?mode=blur+motion
|
||||
// /bg/<pattern_name>?intensity=...&bg_color=...&mode=blur+motion
|
||||
return td::make_unique<InternalLinkBackground>(query.substr(4).str());
|
||||
} else if (path.size() == 2 && !path[0].empty()) {
|
||||
// /<username>/12345?single
|
||||
return td::make_unique<InternalLinkMessage>();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void LinkManager::get_login_url_info(DialogId dialog_id, MessageId message_id, int32 button_id,
|
||||
Promise<td_api::object_ptr<td_api::LoginUrlInfo>> &&promise) {
|
||||
TRY_RESULT_PROMISE(promise, url, td_->messages_manager_->get_login_button_url(dialog_id, message_id, button_id));
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace td {
|
||||
|
||||
class Td;
|
||||
@ -31,9 +33,36 @@ class LinkManager : public Actor {
|
||||
LinkManager &operator=(LinkManager &&) = delete;
|
||||
~LinkManager() override;
|
||||
|
||||
// checks whether link is a valid tg, ton or HTTP(S) URL and returns it in a canonical form
|
||||
enum class InternalLinkType : int32 { Background, Message };
|
||||
|
||||
class InternalLink {
|
||||
public:
|
||||
InternalLink() = default;
|
||||
InternalLink(const InternalLink &) = delete;
|
||||
InternalLink &operator=(const InternalLink &) = delete;
|
||||
InternalLink(InternalLink &&) = delete;
|
||||
InternalLink &operator=(InternalLink &&) = delete;
|
||||
virtual ~InternalLink() = default;
|
||||
|
||||
virtual td_api::object_ptr<td_api::InternalLinkType> get_internal_link_type_object() const = 0;
|
||||
|
||||
virtual InternalLinkType get_type() const = 0;
|
||||
};
|
||||
|
||||
// checks whether the link is a valid tg, ton or HTTP(S) URL and returns it in a canonical form
|
||||
static Result<string> check_link(Slice link);
|
||||
|
||||
struct LinkInfo {
|
||||
bool is_internal_ = false;
|
||||
bool is_tg_ = false;
|
||||
Slice query_;
|
||||
};
|
||||
// returns information about the link
|
||||
static LinkInfo get_link_info(Slice link);
|
||||
|
||||
// checks whether the link is a supported tg or t.me URL and parses it
|
||||
static unique_ptr<InternalLink> parse_internal_link(Slice link);
|
||||
|
||||
void get_login_url_info(DialogId dialog_id, MessageId message_id, int32 button_id,
|
||||
Promise<td_api::object_ptr<td_api::LoginUrlInfo>> &&promise);
|
||||
|
||||
@ -48,6 +77,13 @@ class LinkManager : public Actor {
|
||||
private:
|
||||
void tear_down() override;
|
||||
|
||||
class InternalLinkBackground;
|
||||
class InternalLinkMessage;
|
||||
|
||||
static unique_ptr<InternalLink> parse_tg_link_query(Slice query);
|
||||
|
||||
static unique_ptr<InternalLink> parse_t_me_link_query(Slice query);
|
||||
|
||||
Td *td_;
|
||||
ActorShared<> parent_;
|
||||
};
|
||||
|
@ -17457,7 +17457,7 @@ Result<MessagesManager::MessageLinkInfo> MessagesManager::get_message_link_info(
|
||||
string cur_t_me_url = G()->shared_config().get_option_string("t_me_url");
|
||||
if (begins_with(cur_t_me_url, "http://") || begins_with(cur_t_me_url, "https://")) {
|
||||
Slice t_me_url = cur_t_me_url;
|
||||
t_me_url = t_me_url.substr(url[4] == 's' ? 8 : 7);
|
||||
t_me_url = t_me_url.substr(t_me_url[4] == 's' ? 8 : 7);
|
||||
if (!td::contains(t_me_urls, t_me_url)) {
|
||||
t_me_urls.push_back(t_me_url);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user