Allow tg URLs in text links and url buttons.

GitOrigin-RevId: 9708c3016375564e737bf5a8f79494807d61c10f
This commit is contained in:
levlam 2018-06-19 13:23:52 +03:00
parent 537d96cc8e
commit 1ef5c89a91
7 changed files with 60 additions and 30 deletions

View File

@ -582,7 +582,7 @@ keyboardButton text:string type:KeyboardButtonType = KeyboardButton;
//@class InlineKeyboardButtonType @description Describes the type of an inline keyboard button
//@description A button that opens a specified URL @url URL to open
//@description A button that opens a specified URL @url HTTP or tg:// URL to open
inlineKeyboardButtonTypeUrl url:string = InlineKeyboardButtonType;
//@description A button that sends a special callback query to a bot @data Data to be sent to the bot via a callback query
@ -1179,7 +1179,7 @@ textEntityTypePre = TextEntityType;
//@description Text that must be formatted as if inside pre, and code HTML tags @language Programming language of the code; as defined by the sender
textEntityTypePreCode language:string = TextEntityType;
//@description A text description shown instead of a raw URL @url URL to be opened when the link is clicked
//@description A text description shown instead of a raw URL @url HTTP or tg:// URL to be opened when the link is clicked
textEntityTypeTextUrl url:string = TextEntityType;
//@description A text shows instead of a raw mention of the user (e.g., when the user has no username) @user_id Identifier of the mentioned user

View File

@ -9,7 +9,6 @@
#include "td/telegram/ContactsManager.h"
#include "td/telegram/misc.h"
#include "td/utils/HttpUrl.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/unicode.h"
@ -1329,10 +1328,10 @@ Result<vector<MessageEntity>> parse_markdown(string &text) {
if (user_id.is_valid()) {
entities.emplace_back(utf16_offset, utf16_entity_length, user_id);
} else {
auto r_http_url = parse_url(url);
if (r_http_url.is_ok() && url.find('.') != string::npos) {
auto r_url = check_url(url);
if (r_url.is_ok()) {
entities.emplace_back(MessageEntity::Type::TextUrl, utf16_offset, utf16_entity_length,
r_http_url.ok().get_url());
r_url.move_as_ok());
}
}
break;
@ -1585,10 +1584,9 @@ Result<vector<MessageEntity>> parse_html(string &text) {
if (user_id.is_valid()) {
entities.emplace_back(utf16_offset, utf16_entity_length, user_id);
} else {
auto r_http_url = parse_url(url);
if (r_http_url.is_ok() && url.find('.') != string::npos) {
entities.emplace_back(MessageEntity::Type::TextUrl, utf16_offset, utf16_entity_length,
r_http_url.ok().get_url());
auto r_url = check_url(url);
if (r_url.is_ok()) {
entities.emplace_back(MessageEntity::Type::TextUrl, utf16_offset, utf16_entity_length, r_url.move_as_ok());
}
}
} else if (tag_name == "pre") {
@ -1746,12 +1744,11 @@ Result<vector<MessageEntity>> get_message_entities(const ContactsManager *contac
if (!clean_input_string(entity_text_url->url_)) {
return Status::Error(400, "MessageEntityTextUrl.url must be encoded in UTF-8");
}
auto r_http_url = parse_url(entity_text_url->url_);
if (r_http_url.is_error()) {
return Status::Error(400, PSTRING() << "Wrong message entity: " << r_http_url.error().message());
auto r_url = check_url(entity_text_url->url_);
if (r_url.is_error()) {
return Status::Error(400, PSTRING() << "Wrong message entity: " << r_url.error().message());
}
entities.emplace_back(MessageEntity::Type::TextUrl, entity->offset_, entity->length_,
r_http_url.ok().get_url());
entities.emplace_back(MessageEntity::Type::TextUrl, entity->offset_, entity->length_, r_url.move_as_ok());
break;
}
case td_api::textEntityTypeMentionName::ID: {
@ -1843,14 +1840,14 @@ vector<MessageEntity> get_message_entities(const ContactsManager *contacts_manag
case telegram_api::messageEntityTextUrl::ID: {
// TODO const telegram_api::messageEntityTextUrl *
auto entity_text_url = static_cast<telegram_api::messageEntityTextUrl *>(entity.get());
auto r_http_url = parse_url(entity_text_url->url_);
if (r_http_url.is_error()) {
LOG(ERROR) << "Wrong URL entity: \"" << entity_text_url->url_ << "\": " << r_http_url.error().message()
<< " from " << source;
auto r_url = check_url(entity_text_url->url_);
if (r_url.is_error()) {
LOG(ERROR) << "Wrong URL entity: \"" << entity_text_url->url_ << "\": " << r_url.error().message() << " from "
<< source;
continue;
}
entities.emplace_back(MessageEntity::Type::TextUrl, entity_text_url->offset_, entity_text_url->length_,
r_http_url.ok().get_url());
r_url.move_as_ok());
break;
}
case telegram_api::messageEntityMentionName::ID: {
@ -1947,13 +1944,13 @@ vector<MessageEntity> get_message_entities(vector<tl_object_ptr<secret_api::Mess
LOG(WARNING) << "Wrong URL entity: \"" << entity_text_url->url_ << '"';
continue;
}
auto r_http_url = parse_url(entity_text_url->url_);
if (r_http_url.is_error()) {
LOG(WARNING) << "Wrong URL entity: \"" << entity_text_url->url_ << "\": " << r_http_url.error().message();
auto r_url = check_url(entity_text_url->url_);
if (r_url.is_error()) {
LOG(WARNING) << "Wrong URL entity: \"" << entity_text_url->url_ << "\": " << r_url.error().message();
continue;
}
entities.emplace_back(MessageEntity::Type::TextUrl, entity_text_url->offset_, entity_text_url->length_,
r_http_url.ok().get_url());
r_url.move_as_ok());
break;
}
case secret_api::messageEntityMentionName::ID:

View File

@ -13,7 +13,6 @@
#include "td/utils/buffer.h"
#include "td/utils/format.h"
#include "td/utils/HttpUrl.h"
#include "td/utils/logging.h"
namespace td {
@ -363,8 +362,8 @@ static Result<InlineKeyboardButton> get_inline_keyboard_button(tl_object_ptr<td_
switch (button_type_id) {
case td_api::inlineKeyboardButtonTypeUrl::ID: {
current_button.type = InlineKeyboardButton::Type::Url;
TRY_RESULT(http_url, parse_url(static_cast<td_api::inlineKeyboardButtonTypeUrl *>(button->type_.get())->url_));
current_button.data = http_url.get_url();
TRY_RESULT(url, check_url(static_cast<td_api::inlineKeyboardButtonTypeUrl *>(button->type_.get())->url_));
current_button.data = std::move(url);
if (!clean_input_string(current_button.data)) {
return Status::Error(400, "Inline keyboard button url must be encoded in UTF-8");
}

View File

@ -7,6 +7,7 @@
#include "td/telegram/misc.h"
#include "td/utils/common.h"
#include "td/utils/HttpUrl.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/Slice.h"
@ -274,4 +275,32 @@ string get_emoji_fingerprint(uint64 num) {
return emojis[(num & 0x7FFFFFFFFFFFFFFF) % emojis.size()].str();
}
Result<string> check_url(MutableSlice url) {
bool is_tg = false;
if (begins_with(url, "tg://")) {
url.remove_prefix(5);
is_tg = true;
} else if (begins_with(url, "tg:")) {
url.remove_prefix(3);
is_tg = true;
} else {
is_tg = false;
}
TRY_RESULT(http_url, parse_url(url));
if (is_tg) {
if (begins_with(url, "http://") || http_url.protocol_ == HttpUrl::Protocol::HTTPS || !http_url.userinfo_.empty() || http_url.specified_port_ != 0 || http_url.is_ipv6_) {
return Status::Error("Wrong tg URL");
}
auto result = http_url.get_url();
CHECK(begins_with(result, "http://"));
return PSTRING() << "tg" << Slice(result).substr(4);
}
if (url.find('.') == string::npos) {
return Status::Error("Wrong HTTP URL");
}
return http_url.get_url();
}
} // namespace td

View File

@ -7,6 +7,8 @@
#pragma once
#include "td/utils/common.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
namespace td {
@ -31,4 +33,7 @@ int32 get_vector_hash(const vector<uint32> &numbers) TD_WARN_UNUSED_RESULT;
// returns emoji corresponding to the specified number
string get_emoji_fingerprint(uint64 num);
// checks whether url is a valid tg or HTTP(S) URL and returns its in a canonical form
Result<string> check_url(MutableSlice url);
} // namespace td

View File

@ -29,11 +29,11 @@ string HttpUrl::get_url() const {
result += userinfo_;
result += '@';
}
if (is_ipv6) {
if (is_ipv6_) {
result += '[';
}
result += host_;
if (is_ipv6) {
if (is_ipv6_) {
result += ']';
}
if (specified_port_ > 0) {

View File

@ -18,7 +18,7 @@ class HttpUrl {
enum class Protocol { HTTP, HTTPS } protocol_;
string userinfo_;
string host_;
bool is_ipv6;
bool is_ipv6_;
int specified_port_;
int port_;
string query_;