Allow to specify a secret_token in setWebhook to ensure that webhook was set by the domain owner.

This commit is contained in:
levlam 2022-05-13 16:39:32 +03:00
parent fd7489f6da
commit 06d40edb0a
5 changed files with 29 additions and 5 deletions

View File

@ -8382,13 +8382,14 @@ td::Status Client::process_set_webhook_query(PromisedQueryPtr &query) {
int32 new_max_connections = new_url.empty() ? 0 : get_webhook_max_connections(query.get());
Slice new_ip_address = new_url.empty() ? Slice() : query->arg("ip_address");
bool new_fix_ip_address = new_url.empty() ? false : get_webhook_fix_ip_address(query.get());
Slice new_secret_token = new_url.empty() ? Slice() : query->arg("secret_token");
bool drop_pending_updates = to_bool(query->arg("drop_pending_updates"));
if (webhook_set_query_) {
// already updating webhook. Cancel previous request
fail_query_conflict("Conflict: terminated by other setWebhook", std::move(webhook_set_query_));
} else if (webhook_url_ == new_url && !has_webhook_certificate_ && query->file("certificate") == nullptr &&
query->arg("certificate").empty() && new_max_connections == webhook_max_connections_ &&
new_fix_ip_address == webhook_fix_ip_address_ &&
new_fix_ip_address == webhook_fix_ip_address_ && new_secret_token == webhook_secret_token_ &&
(!new_fix_ip_address || new_ip_address == webhook_ip_address_) && !drop_pending_updates) {
if (update_allowed_update_types(query.get())) {
save_webhook();
@ -8512,6 +8513,9 @@ void Client::save_webhook() const {
if (webhook_fix_ip_address_) {
value += "#fix_ip/";
}
if (!webhook_secret_token_.empty()) {
value += PSTRING() << "#secret" << webhook_secret_token_ << '/';
}
if (allowed_update_types_ != DEFAULT_ALLOWED_UPDATE_TYPES) {
value += PSTRING() << "#allow" << allowed_update_types_ << '/';
}
@ -8555,6 +8559,7 @@ void Client::webhook_closed(Status status) {
webhook_max_connections_ = 0;
webhook_ip_address_ = td::string();
webhook_fix_ip_address_ = false;
webhook_secret_token_ = td::string();
webhook_set_time_ = td::Time::now();
last_webhook_error_date_ = 0;
last_webhook_error_ = Status::OK();
@ -8604,6 +8609,13 @@ void Client::do_set_webhook(PromisedQueryPtr query, bool was_deleted) {
if (url.is_error()) {
return fail_query(400, "Bad Request: invalid webhook URL specified", std::move(query));
}
auto secret_token = query->arg("secret_token");
if (secret_token.size() > 256) {
return fail_query(400, "Bad Request: secret token is too long", std::move(query));
}
if (!td::is_base64url_characters(secret_token)) {
return fail_query(400, "Bad Request: secret token contains unallowed characters", std::move(query));
}
auto *cert_file_ptr = query->file("certificate");
has_webhook_certificate_ = false;
if (cert_file_ptr != nullptr) {
@ -8627,6 +8639,7 @@ void Client::do_set_webhook(PromisedQueryPtr query, bool was_deleted) {
webhook_url_ = new_url.str();
webhook_set_time_ = td::Time::now();
webhook_max_connections_ = get_webhook_max_connections(query.get());
webhook_secret_token_ = secret_token.str();
webhook_ip_address_ = query->arg("ip_address").str();
webhook_fix_ip_address_ = get_webhook_fix_ip_address(query.get());
last_webhook_error_date_ = 0;
@ -8639,7 +8652,7 @@ void Client::do_set_webhook(PromisedQueryPtr query, bool was_deleted) {
webhook_id_ = td::create_actor<WebhookActor>(
webhook_actor_name, actor_shared(this, webhook_generation_), tqueue_id_, url.move_as_ok(),
has_webhook_certificate_ ? get_webhook_certificate_path() : "", webhook_max_connections_, query->is_internal(),
webhook_ip_address_, webhook_fix_ip_address_, parameters_);
webhook_ip_address_, webhook_fix_ip_address_, webhook_secret_token_, parameters_);
// wait for webhook verified or webhook callback
webhook_query_type_ = WebhookQueryType::Verify;
webhook_set_query_ = std::move(query);

View File

@ -1007,6 +1007,7 @@ class Client final : public WebhookActor::Callback {
int32 webhook_max_connections_ = 0;
td::string webhook_ip_address_;
bool webhook_fix_ip_address_ = false;
td::string webhook_secret_token_;
int32 last_webhook_error_date_ = 0;
Status last_webhook_error_;
double next_allowed_set_webhook_time_ = 0;

View File

@ -378,6 +378,11 @@ PromisedQueryPtr ClientManager::get_webhook_restore_query(td::Slice token, td::S
parser.skip('/');
}
if (parser.try_skip("#secret")) {
args.emplace_back(add_string("secret_token"), add_string(parser.read_till('/')));
parser.skip('/');
}
if (parser.try_skip("#allow")) {
args.emplace_back(add_string("allowed_updates"), add_string(parser.read_till('/')));
parser.skip('/');

View File

@ -42,7 +42,7 @@ std::atomic<td::uint64> WebhookActor::total_connections_count_{0};
WebhookActor::WebhookActor(td::ActorShared<Callback> callback, td::int64 tqueue_id, td::HttpUrl url,
td::string cert_path, td::int32 max_connections, bool from_db_flag,
td::string cached_ip_address, bool fix_ip_address,
td::string cached_ip_address, bool fix_ip_address, td::string secret_token,
std::shared_ptr<const ClientParameters> parameters)
: callback_(std::move(callback))
, tqueue_id_(tqueue_id)
@ -51,7 +51,8 @@ WebhookActor::WebhookActor(td::ActorShared<Callback> callback, td::int64 tqueue_
, parameters_(std::move(parameters))
, fix_ip_address_(fix_ip_address)
, from_db_flag_(from_db_flag)
, max_connections_(max_connections) {
, max_connections_(max_connections)
, secret_token_(std::move(secret_token)) {
CHECK(max_connections_ > 0);
if (!cached_ip_address.empty()) {
@ -539,6 +540,9 @@ td::Status WebhookActor::send_update() {
if (!url_.userinfo_.empty()) {
hc.add_header("Authorization", PSLICE() << "Basic " << td::base64_encode(url_.userinfo_));
}
if (!secret_token_.empty()) {
hc.add_header("X-Telegram-Bot-Api-Secret-Token", secret_token_);
}
hc.set_content_type("application/json");
hc.set_content_size(body.size());
hc.set_keep_alive();

View File

@ -54,7 +54,7 @@ class WebhookActor final : public td::HttpOutboundConnection::Callback {
WebhookActor(td::ActorShared<Callback> callback, td::int64 tqueue_id, td::HttpUrl url, td::string cert_path,
td::int32 max_connections, bool from_db_flag, td::string cached_ip_address, bool fix_ip_address,
std::shared_ptr<const ClientParameters> parameters);
td::string secret_token, std::shared_ptr<const ClientParameters> parameters);
void update();
@ -163,6 +163,7 @@ class WebhookActor final : public td::HttpOutboundConnection::Callback {
td::vector<td::BufferedFd<td::SocketFd>> ready_sockets_;
td::int32 max_connections_ = 0;
td::string secret_token_;
td::Container<Connection> connections_;
td::ListNode ready_connections_;
td::FloodControlFast active_new_connection_flood_;