diff --git a/README.md b/README.md
index 6c561ba..5711dd1 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ Please note that only TDLight-specific issues are suitable for this repository.
- [TDLight features](#tdlight-features)
- [Added features](#added-features)
- [Modified features](#modified-features)
+ - [User Mode](#user-mode)
- [Installation](#installation)
- [Dependencies](#dependencies)
- [Usage](#usage)
@@ -126,6 +127,81 @@ In addition, the member list now shows the full bot list (previously only the bo
The bot will now receive Updates for all received media, even if a destruction timer is set.
+
+### User Mode
+
+You can allow user accounts to access the bot api with the command-line option `--allow-users` or set the env variable
+`TELEGRAM_ALLOW_USERS` to `1` when using docker. User Mode is disabled by default, so only bots can access the api.
+
+You can now log into the bot api with user accounts to create userbots running on your account.
+
+Note: Never send your 2fa password over a plain http connection. Make sure https is enabled or use this api locally.
+
+#### User Authorization Process
+1. Send a request to `{api_url}/userlogin`
+
+ Parameters:
+ - `phone_number`: `string`. The phone number of your Telegram Account.
+
+ Returns your `user_token` as `string`. You can use this just like a normal bot token on the `/user` endpoint
+
+2. Send the received code to `{api_url}/user{user_token}/authcode`
+
+ Parameters:
+ - `code`: `int`. The code send to you by Telegram In-App or by SMS
+
+ Will send `{"ok": true, "result": true}` on success.
+
+3. Optional: Send your 2fa password to `{api_url}/user{user_token}/2fapassword`
+
+ Parameters:
+ - `password`: `string`. Password for 2fa authentication
+
+ Will send `{"ok": true, "result": true}` on success.
+
+4. Optional: Register the user by calling `{api_url}/user{user_token}/registerUser`.
+
+ User registration is disabled by default. You can enable it with the `--allow-users-registration` command line
+ option or the env variable `TELEGRAM_ALLOW_USERS_REGISTRATION` set to `1` when using docker.
+
+ Parameters:
+ - `first_name`: `string`. First name for the new account.
+ - `last_name`: `string`, optional. Last name for the new account.
+
+ Will send `{"ok": true, "result": true}` on success.
+
+You are now logged in and can use all methods like in the bot api, just replace the
+`/bot{bot_token}/` in your urls with `/user{token}/`.
+
+You only need to authenticate once, the account will stay logged in. You can use the `logOut` method to log out
+or simply close the session in your account settings.
+
+Some methods are (obviously) not available as a user. This includes:
+- `answerCallbackQuery`
+- `setMyCommands`
+- `editMessageReplyMarkup`
+- `uploadStickerFile`
+- `createNewStickerSet`
+- `addStickerToSet`
+- `setStickerPositionInSet`
+- `deleteStickerFromSet`
+- `setStickerSetThumb`
+- `sendInvoice`
+- `answerShippingQuery`
+- `answerPreCheckoutQuery`
+- `setPassportDataErrors`
+- `sendGame`
+- `setGameScore`
+- `getGameHighscores`
+
+It is also not possible to attach a `reply_markup` to any message.
+
+Your api wrapper may behave different in
+some cases, for examples command message-entities are not created in chats that don't contain any
+bots, so your Command Handler may not detect it.
+
+It is possible to have multiple user-tokens to multiple client instances on the same bot api server.
+
## Installation
diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
index bd49d8d..6470b67 100755
--- a/docker-entrypoint.sh
+++ b/docker-entrypoint.sh
@@ -40,6 +40,12 @@ fi
if [ -n "$TELEGRAM_NO_FILE_LIMIT" ]; then
CUSTOM_ARGS="${CUSTOM_ARGS} --no-file-limit"
fi
+if [ -n "$TELEGRAM_ALLOW_USERS" ]; then
+ CUSTOM_ARGS="${CUSTOM_ARGS} --allow-users"
+fi
+if [ -n "$TELEGRAM_ALLOW_USERS_REGISTRATION" ]; then
+ CUSTOM_ARGS="${CUSTOM_ARGS} --allow-users-registration"
+fi
if [ -n "$TELEGRAM_INSECURE" ]; then
CUSTOM_ARGS="${CUSTOM_ARGS} --insecure"
fi
diff --git a/td b/td
index b47fab1..2b92c16 160000
--- a/td
+++ b/td
@@ -1 +1 @@
-Subproject commit b47fab11cd7dddbb2829ef1830007632332b717b
+Subproject commit 2b92c16998d39e7bfee580defcb0109151e4fb81
diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp
index 91dccd7..6ac7b2b 100644
--- a/telegram-bot-api/Client.cpp
+++ b/telegram-bot-api/Client.cpp
@@ -34,6 +34,21 @@
#include
+#define CHECK_IS_BOT() \
+ if (is_user_) { \
+ return Status::Error(BOT_ONLY_ERROR_CODE, BOT_ONLY_ERROR_DESCRIPTION); \
+ }
+
+#define CHECK_IS_USER() \
+ if (!is_user_) { \
+ return Status::Error(USER_ONLY_ERROR_CODE, USER_ONLY_ERROR_DESCRIPTION); \
+ }
+
+#define CHECK_USER_REPLY_MARKUP() \
+ if (reply_markup != nullptr && is_user_) { \
+ return Status::Error(BOT_ONLY_ERROR_CODE, BOT_ONLY_ERROR_DESCRIPTION); \
+ }
+
namespace telegram_bot_api {
using td::Jsonable;
@@ -124,6 +139,9 @@ void Client::fail_query_with_error(PromisedQueryPtr query, int32 error_code, Sli
case 403:
prefix = Slice("Forbidden");
break;
+ case 405:
+ prefix = Slice("Method Not Allowed");
+ break;
case 500:
prefix = Slice("Internal Server Error");
break;
@@ -156,11 +174,31 @@ void Client::fail_query_with_error(PromisedQueryPtr &&query, object_ptrcode_, error->message_, default_message);
}
-Client::Client(td::ActorShared<> parent, const td::string &bot_token, bool is_test_dc, int64 tqueue_id,
+Client::Client(td::ActorShared<> parent, const td::string &bot_token, bool is_user, bool is_test_dc, int64 tqueue_id,
std::shared_ptr parameters, td::ActorId stat_actor)
: parent_(std::move(parent))
, bot_token_(bot_token)
, bot_token_id_("")
+ , is_user_(is_user)
+ , is_test_dc_(is_test_dc)
+ , tqueue_id_(tqueue_id)
+ , parameters_(std::move(parameters))
+ , stat_actor_(std::move(stat_actor)) {
+ messages_lru_root_.lru_next = &messages_lru_root_;
+ messages_lru_root_.lru_prev = &messages_lru_root_;
+
+ static auto is_inited = init_methods();
+ CHECK(is_inited);
+}
+
+Client::Client(td::ActorShared<> parent, const td::string &bot_token, const td::string &phone_number, bool is_user,
+ bool is_test_dc, int64 tqueue_id, std::shared_ptr parameters,
+ td::ActorId stat_actor)
+ : parent_(std::move(parent))
+ , bot_token_(bot_token)
+ , bot_token_id_("")
+ , phone_number_(phone_number)
+ , is_user_(is_user)
, is_test_dc_(is_test_dc)
, tqueue_id_(tqueue_id)
, parameters_(std::move(parameters))
@@ -2295,7 +2333,10 @@ class Client::TdOnAuthorizationCallback : public TdQueryCallback {
}
void on_result(object_ptr result) override {
- bool was_ready = client_->authorization_state_->get_id() != td_api::authorizationStateWaitPhoneNumber::ID;
+ bool was_ready = client_->authorization_state_->get_id() != td_api::authorizationStateWaitPhoneNumber::ID &&
+ client_->authorization_state_->get_id() != td_api::authorizationStateWaitCode::ID &&
+ client_->authorization_state_->get_id() != td_api::authorizationStateWaitPassword::ID &&
+ client_->authorization_state_->get_id() != td_api::authorizationStateWaitRegistration::ID;
if (result->get_id() == td_api::error::ID) {
auto error = move_object_as(result);
if (error->code_ == 429 || error->code_ >= 500 || (error->code_ != 401 && was_ready)) {
@@ -2314,6 +2355,38 @@ class Client::TdOnAuthorizationCallback : public TdQueryCallback {
Client *client_;
};
+class Client::TdOnAuthorizationQueryCallback : public TdQueryCallback {
+ public:
+ TdOnAuthorizationQueryCallback(Client *client, PromisedQueryPtr query) :
+ client_(client), query_(std::move(query)) {
+ }
+
+ void on_result(object_ptr result) override {
+ bool was_ready = client_->authorization_state_->get_id() != td_api::authorizationStateWaitPhoneNumber::ID &&
+ client_->authorization_state_->get_id() != td_api::authorizationStateWaitCode::ID &&
+ client_->authorization_state_->get_id() != td_api::authorizationStateWaitPassword::ID &&
+ client_->authorization_state_->get_id() != td_api::authorizationStateWaitRegistration::ID;
+ if (result->get_id() == td_api::error::ID) {
+ auto error = move_object_as(result);
+ if (error->code_ == 429 || error->code_ >= 500 || (error->code_ != 401 && was_ready)) {
+ // try again
+ return client_->on_update_authorization_state();
+ }
+ fail_query(401, "Unauthorized: Log in failed, logging out due to " + td::oneline(to_string(error)),
+ std::move(query_));
+ LOG(WARNING) << "Logging out due to " << td::oneline(to_string(error));
+ client_->log_out();
+ } else {
+ answer_query(td::JsonTrue(), std::move(query_));
+ client_->on_update_authorization_state();
+ }
+ }
+
+ private:
+ Client *client_;
+ PromisedQueryPtr query_;
+};
+
class Client::TdOnInitCallback : public TdQueryCallback {
public:
explicit TdOnInitCallback(Client *client) : client_(client) {
@@ -3237,7 +3310,7 @@ class Client::TdOnSendCustomRequestCallback : public TdQueryCallback {
class Client::TdOnPingCallback : public TdQueryCallback {
public:
- TdOnPingCallback(PromisedQueryPtr query)
+ explicit TdOnPingCallback(PromisedQueryPtr query)
: query_(std::move(query)) {
}
@@ -3245,7 +3318,7 @@ class Client::TdOnPingCallback : public TdQueryCallback {
if (result->get_id() == td_api::error::ID) {
return fail_query_with_error(std::move(query_), move_object_as(result), "Server not available");
}
- CHECK(result->get_id() == 959899022); // id for return type `seconds`
+ CHECK(result->get_id() == td_api::seconds::ID);
auto seconds_ = move_object_as(result);
answer_query(td::VirtuallyJsonableString(std::to_string(seconds_->seconds_)), std::move(query_));
@@ -3386,7 +3459,7 @@ void Client::raw_event(const td::Event::Raw &event) {
}
void Client::loop() {
- if (logging_out_ || closing_ || was_authorized_) {
+ if (logging_out_ || closing_ || was_authorized_ || waiting_for_auth_input_) {
while (!cmd_queue_.empty()) {
auto query = std::move(cmd_queue_.front());
cmd_queue_.pop();
@@ -3947,9 +4020,20 @@ void Client::on_update_authorization_state() {
case td_api::authorizationStateWaitEncryptionKey::ID:
return send_request(make_object(), std::make_unique(this));
case td_api::authorizationStateWaitPhoneNumber::ID:
- return send_request(make_object(bot_token_),
- std::make_unique(this));
+ if (is_user_) {
+ return send_request(make_object(phone_number_, nullptr),
+ std::make_unique(this));
+ } else {
+ return send_request(make_object(bot_token_),
+ std::make_unique(this));
+ }
+ case td_api::authorizationStateWaitCode::ID:
+ case td_api::authorizationStateWaitPassword::ID:
+ case td_api::authorizationStateWaitRegistration::ID:
+ waiting_for_auth_input_ = true;
+ return loop();
case td_api::authorizationStateReady::ID: {
+ waiting_for_auth_input_ = false;
auto user_info = get_user_info(my_id_);
if (my_id_ <= 0 || user_info == nullptr) {
return send_request(make_object(), std::make_unique(this));
@@ -3970,12 +4054,14 @@ void Client::on_update_authorization_state() {
return loop();
}
case td_api::authorizationStateLoggingOut::ID:
+ waiting_for_auth_input_ = false;
if (!logging_out_) {
LOG(WARNING) << "Logging out";
logging_out_ = true;
}
break;
case td_api::authorizationStateClosing::ID:
+ waiting_for_auth_input_ = false;
if (!closing_) {
LOG(WARNING) << "Closing";
closing_ = true;
@@ -4334,6 +4420,7 @@ void Client::on_closed() {
if (logging_out_) {
parameters_->shared_data_->webhook_db_->erase(bot_token_with_dc_);
+ parameters_->shared_data_->user_db_->erase(bot_token_with_dc_);
class RmWorker : public td::Actor {
public:
@@ -6029,6 +6116,17 @@ void Client::on_cmd(PromisedQueryPtr query) {
return do_send_request(make_object(), std::make_unique(std::move(query)));
}
}
+ if (waiting_for_auth_input_) {
+ if (query->method() == "authcode") {
+ return process_authcode_query(query);
+ } else if (query->method() == "2fapassword") {
+ return process_2fapassword_query(query);
+ } else if (query->method() == "registeruser" && parameters_->allow_users_registration_) {
+ return process_register_user_query(query);
+ } else {
+ return fail_query(404, "Not Found: method not found", std::move(query));
+ }
+ }
if (logging_out_) {
return fail_query(LOGGING_OUT_ERROR_CODE, LOGGING_OUT_ERROR_DESCRIPTION, std::move(query));
@@ -6063,6 +6161,7 @@ td::Status Client::process_get_my_commands_query(PromisedQueryPtr &query) {
}
td::Status Client::process_set_my_commands_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
TRY_RESULT(bot_commands, get_bot_commands(query.get()));
send_request(make_object(std::move(bot_commands)),
std::make_unique(std::move(query)));
@@ -6208,12 +6307,14 @@ td::Status Client::process_send_voice_query(PromisedQueryPtr &query) {
}
td::Status Client::process_send_game_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
TRY_RESULT(game_short_name, get_required_string_arg(query.get(), "game_short_name"));
do_send_message(make_object(my_id_, game_short_name.str()), std::move(query));
return Status::OK();
}
td::Status Client::process_send_invoice_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
TRY_RESULT(title, get_required_string_arg(query.get(), "title"));
TRY_RESULT(description, get_required_string_arg(query.get(), "description"));
TRY_RESULT(payload, get_required_string_arg(query.get(), "payload"));
@@ -6351,6 +6452,7 @@ td::Status Client::process_stop_poll_query(PromisedQueryPtr &query) {
auto chat_id = query->arg("chat_id");
auto message_id = get_message_id(query.get());
TRY_RESULT(reply_markup, get_reply_markup(query.get()));
+ CHECK_USER_REPLY_MARKUP();
resolve_reply_markup_bot_usernames(
std::move(reply_markup), std::move(query),
@@ -6446,6 +6548,7 @@ td::Status Client::process_edit_message_text_query(PromisedQueryPtr &query) {
auto chat_id = query->arg("chat_id");
auto message_id = get_message_id(query.get());
TRY_RESULT(reply_markup, get_reply_markup(query.get()));
+ CHECK_USER_REPLY_MARKUP();
if (chat_id.empty() && message_id == 0) {
TRY_RESULT(inline_message_id, get_inline_message_id(query.get()));
@@ -6485,6 +6588,7 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu
auto chat_id = query->arg("chat_id");
auto message_id = get_message_id(query.get());
TRY_RESULT(reply_markup, get_reply_markup(query.get()));
+ CHECK_USER_REPLY_MARKUP();
if (chat_id.empty() && message_id == 0) {
TRY_RESULT(inline_message_id, get_inline_message_id(query.get()));
@@ -6520,6 +6624,7 @@ td::Status Client::process_edit_message_media_query(PromisedQueryPtr &query) {
auto chat_id = query->arg("chat_id");
auto message_id = get_message_id(query.get());
TRY_RESULT(reply_markup, get_reply_markup(query.get()));
+ CHECK_USER_REPLY_MARKUP();
TRY_RESULT(input_media, get_input_media(query.get(), "media", false));
if (chat_id.empty() && message_id == 0) {
@@ -6554,6 +6659,7 @@ td::Status Client::process_edit_message_caption_query(PromisedQueryPtr &query) {
auto chat_id = query->arg("chat_id");
auto message_id = get_message_id(query.get());
TRY_RESULT(reply_markup, get_reply_markup(query.get()));
+ CHECK_USER_REPLY_MARKUP();
TRY_RESULT(caption, get_caption(query.get()));
if (chat_id.empty() && message_id == 0) {
@@ -6584,9 +6690,11 @@ td::Status Client::process_edit_message_caption_query(PromisedQueryPtr &query) {
}
td::Status Client::process_edit_message_reply_markup_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
auto chat_id = query->arg("chat_id");
auto message_id = get_message_id(query.get());
TRY_RESULT(reply_markup, get_reply_markup(query.get()));
+ CHECK_USER_REPLY_MARKUP();
if (chat_id.empty() && message_id == 0) {
TRY_RESULT(inline_message_id, get_inline_message_id(query.get()));
@@ -6636,6 +6744,7 @@ td::Status Client::process_delete_message_query(PromisedQueryPtr &query) {
}
td::Status Client::process_set_game_score_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
auto chat_id = query->arg("chat_id");
auto message_id = get_message_id(query.get());
TRY_RESULT(user_id, get_user_id(query.get()));
@@ -6673,6 +6782,7 @@ td::Status Client::process_set_game_score_query(PromisedQueryPtr &query) {
}
td::Status Client::process_get_game_high_scores_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
auto chat_id = query->arg("chat_id");
auto message_id = get_message_id(query.get());
TRY_RESULT(user_id, get_user_id(query.get()));
@@ -6698,6 +6808,7 @@ td::Status Client::process_get_game_high_scores_query(PromisedQueryPtr &query) {
}
td::Status Client::process_answer_inline_query_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
auto inline_query_id = td::to_integer(query->arg("inline_query_id"));
auto is_personal = to_bool(query->arg("is_personal"));
int32 cache_time = get_integer_arg(query.get(), "cache_time", 300, 0, 24 * 60 * 60);
@@ -6721,6 +6832,7 @@ td::Status Client::process_answer_inline_query_query(PromisedQueryPtr &query) {
}
td::Status Client::process_answer_callback_query_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
auto callback_query_id = td::to_integer(query->arg("callback_query_id"));
td::string text = query->arg("text").str();
bool show_alert = to_bool(query->arg("show_alert"));
@@ -6733,6 +6845,7 @@ td::Status Client::process_answer_callback_query_query(PromisedQueryPtr &query)
}
td::Status Client::process_answer_shipping_query_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
auto shipping_query_id = td::to_integer(query->arg("shipping_query_id"));
auto ok = to_bool(query->arg("ok"));
td::vector> shipping_options;
@@ -6749,6 +6862,7 @@ td::Status Client::process_answer_shipping_query_query(PromisedQueryPtr &query)
}
td::Status Client::process_answer_pre_checkout_query_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
auto pre_checkout_query_id = td::to_integer(query->arg("pre_checkout_query_id"));
auto ok = to_bool(query->arg("ok"));
td::MutableSlice error_message;
@@ -7226,6 +7340,7 @@ td::Status Client::process_get_sticker_set_query(PromisedQueryPtr &query) {
}
td::Status Client::process_upload_sticker_file_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
TRY_RESULT(user_id, get_user_id(query.get()));
auto png_sticker = get_input_file(query.get(), "png_sticker");
@@ -7238,6 +7353,7 @@ td::Status Client::process_upload_sticker_file_query(PromisedQueryPtr &query) {
}
td::Status Client::process_create_new_sticker_set_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
TRY_RESULT(user_id, get_user_id(query.get()));
auto name = query->arg("name");
auto title = query->arg("title");
@@ -7254,6 +7370,7 @@ td::Status Client::process_create_new_sticker_set_query(PromisedQueryPtr &query)
}
td::Status Client::process_add_sticker_to_set_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
TRY_RESULT(user_id, get_user_id(query.get()));
auto name = query->arg("name");
TRY_RESULT(stickers, get_input_stickers(query.get()));
@@ -7268,6 +7385,7 @@ td::Status Client::process_add_sticker_to_set_query(PromisedQueryPtr &query) {
}
td::Status Client::process_set_sticker_set_thumb_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
TRY_RESULT(user_id, get_user_id(query.get()));
auto name = query->arg("name");
auto thumbnail = get_input_file(query.get(), "thumb");
@@ -7280,6 +7398,7 @@ td::Status Client::process_set_sticker_set_thumb_query(PromisedQueryPtr &query)
}
td::Status Client::process_set_sticker_position_in_set_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
auto file_id = trim(query->arg("sticker"));
if (file_id.empty()) {
return Status::Error(400, "Sticker is not specified");
@@ -7293,6 +7412,7 @@ td::Status Client::process_set_sticker_position_in_set_query(PromisedQueryPtr &q
}
td::Status Client::process_delete_sticker_from_set_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
auto file_id = trim(query->arg("sticker"));
if (file_id.empty()) {
return Status::Error(400, "Sticker is not specified");
@@ -7304,6 +7424,7 @@ td::Status Client::process_delete_sticker_from_set_query(PromisedQueryPtr &query
}
td::Status Client::process_set_passport_data_errors_query(PromisedQueryPtr &query) {
+ CHECK_IS_BOT();
TRY_RESULT(user_id, get_user_id(query.get()));
TRY_RESULT(passport_element_errors, get_passport_element_errors(query.get()));
@@ -7557,6 +7678,45 @@ td::Status Client::process_ping_query(PromisedQueryPtr &query) {
}
//end custom methods impl
+//start costom auth methods impl
+
+void Client::process_authcode_query(PromisedQueryPtr &query) {
+ auto code = query->arg("code");
+ if (code.empty()) {
+ return fail_query(400, "Bad Request: code not found", std::move(query));
+ }
+ if (authorization_state_->get_id() != td_api::authorizationStateWaitCode::ID) {
+ return fail_query(400, "Bad Request: currently not waiting for a code", std::move(query));
+ }
+ send_request(make_object(code.str()),
+ std::make_unique(this, std::move(query)));
+}
+
+void Client::process_2fapassword_query(PromisedQueryPtr &query) {
+ auto password = query->arg("password");
+ if (password.empty()) {
+ return fail_query(400, "Bad Request: password not found", std::move(query));
+ }
+ if (authorization_state_->get_id() != td_api::authorizationStateWaitPassword::ID) {
+ return fail_query(400, "Bad Request: currently not waiting for a password", std::move(query));
+ }
+ send_request(make_object(password.str()),
+ std::make_unique(this, std::move(query)));
+}
+
+void Client::process_register_user_query(PromisedQueryPtr &query) {
+ auto first_name = query->arg("first_name");
+ if (first_name.empty()) {
+ return fail_query(400, "Bad Request: first_name not found", std::move(query));
+ }
+ auto last_name = query->arg("last_name");
+ if (authorization_state_->get_id() != td_api::authorizationStateWaitRegistration::ID) {
+ return fail_query(400, "Bad Request: currently not waiting for registration", std::move(query));
+ }
+ send_request(make_object(first_name.str(), last_name.str()),
+ std::make_unique(this, std::move(query)));
+}
+//end custom auth methods impl
void Client::do_get_file(object_ptr file, PromisedQueryPtr query) {
if ((!parameters_->local_mode_ || !parameters_->no_file_limit_) &&
@@ -7776,6 +7936,9 @@ void Client::do_send_message(object_ptr input_messa
return fail_query_with_error(std::move(query), 400, r_reply_markup.error().message());
}
auto reply_markup = r_reply_markup.move_as_ok();
+ if (reply_markup != nullptr && is_user_) {
+ return fail_query_with_error(std::move(query), 405, "Method Not Allowed: reply markup not available as user.");
+ }
resolve_reply_markup_bot_usernames(
std::move(reply_markup), std::move(query),
@@ -9335,6 +9498,12 @@ constexpr Client::Slice Client::LOGGING_OUT_ERROR_DESCRIPTION;
constexpr int Client::CLOSING_ERROR_CODE;
constexpr Client::Slice Client::CLOSING_ERROR_DESCRIPTION;
+constexpr int Client::BOT_ONLY_ERROR_CODE;
+constexpr Client::Slice Client::BOT_ONLY_ERROR_DESCRIPTION;
+
+constexpr int Client::USER_ONLY_ERROR_CODE;
+constexpr Client::Slice Client::USER_ONLY_ERROR_DESCRIPTION;
+
std::unordered_map Client::methods_;
} // namespace telegram_bot_api
diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h
index 4d2dfcf..a0760bf 100644
--- a/telegram-bot-api/Client.h
+++ b/telegram-bot-api/Client.h
@@ -38,9 +38,13 @@ namespace td_api = td::td_api;
class Client : public WebhookActor::Callback {
public:
- Client(td::ActorShared<> parent, const td::string &bot_token, bool is_test_dc, td::int64 tqueue_id,
+ Client(td::ActorShared<> parent, const td::string &bot_token, bool is_user, bool is_test_dc, td::int64 tqueue_id,
std::shared_ptr parameters, td::ActorId stat_actor);
+ Client(td::ActorShared<> parent, const td::string &bot_token, const td::string &phone_number, bool is_user,
+ bool is_test_dc, td::int64 tqueue_id, std::shared_ptr parameters,
+ td::ActorId stat_actor);
+
void send(PromisedQueryPtr query) override;
void close();
@@ -82,6 +86,12 @@ class Client : public WebhookActor::Callback {
static constexpr int CLOSING_ERROR_CODE = 500;
static constexpr Slice CLOSING_ERROR_DESCRIPTION = "Internal Server Error: restart";
+ static constexpr int BOT_ONLY_ERROR_CODE = 405;
+ static constexpr Slice BOT_ONLY_ERROR_DESCRIPTION = "Method Not Allowed: You can only use this method as a bot";
+
+ static constexpr int USER_ONLY_ERROR_CODE = 405;
+ static constexpr Slice USER_ONLY_ERROR_DESCRIPTION = "Method Not Allowed: You can only use this method as a user";
+
class JsonFile;
class JsonDatedFile;
class JsonDatedFiles;
@@ -149,6 +159,7 @@ class Client : public WebhookActor::Callback {
class TdOnOkCallback;
class TdOnAuthorizationCallback;
+ class TdOnAuthorizationQueryCallback;
class TdOnInitCallback;
class TdOnGetUserProfilePhotosCallback;
class TdOnSendMessageCallback;
@@ -498,6 +509,11 @@ class Client : public WebhookActor::Callback {
Status process_toggle_group_invites_query(PromisedQueryPtr &query);
Status process_ping_query(PromisedQueryPtr &query);
+ //custom auth methods
+ void process_authcode_query(PromisedQueryPtr &query);
+ void process_2fapassword_query(PromisedQueryPtr &query);
+ void process_register_user_query(PromisedQueryPtr &query);
+
void webhook_verified(td::string cached_ip_address) override;
void webhook_success() override;
@@ -823,11 +839,14 @@ class Client : public WebhookActor::Callback {
bool logging_out_ = false;
bool need_close_ = false;
bool clear_tqueue_ = false;
+ bool waiting_for_auth_input_ = false;
td::ActorShared<> parent_;
td::string bot_token_;
td::string bot_token_with_dc_;
td::string bot_token_id_;
+ td::string phone_number_;
+ bool is_user_;
bool is_test_dc_;
int64 tqueue_id_;
double start_time_ = 0;
diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp
index f275535..ee2e3d0 100644
--- a/telegram-bot-api/ClientManager.cpp
+++ b/telegram-bot-api/ClientManager.cpp
@@ -33,6 +33,8 @@
#include "td/utils/StackAllocator.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/Time.h"
+#include "td/utils/Random.h"
+#include "td/utils/base64.h"
#include