Fixed TG login
Build and Publish / Build and Publish Docker Image (push) Successful in 5m9s

This commit is contained in:
ab
2026-07-06 16:30:16 +03:00
parent 3b4899f785
commit 2dbbdb0252
10 changed files with 239 additions and 11 deletions
+75
View File
@@ -162,6 +162,11 @@ struct TelegramLinkResponse {
status: TelegramLinkStatusResponse,
}
#[derive(Debug, Serialize, JsonSchema)]
struct TelegramLoginResponse {
redirect_to: String,
}
#[derive(Debug, Deserialize, JsonSchema)]
struct TelegramWebAppLinkRequest {
init_data: String,
@@ -292,6 +297,71 @@ async fn telegram_link_webapp_handler(
.into_response()
}
async fn telegram_login_webapp_handler(
session: Session,
db: Database,
Json(request): Json<TelegramWebAppLinkRequest>,
) -> cot::Result<cot::response::Response> {
let (config, _) = AppConfig::load_with_db(&db).await;
if !config.telegram_bot_enabled {
return Ok(json_error_typed(
cot::http::StatusCode::CONFLICT,
"telegram_disabled",
"Telegram is disabled",
"Telegram integration is disabled by the administrator.",
"",
));
}
let telegram_user = match telegram::validate_web_app_init_data(
&request.init_data,
&config.telegram_bot_token,
TELEGRAM_INIT_DATA_MAX_AGE,
) {
Ok(user) => user,
Err(e) => {
return Ok(json_error_typed(
cot::http::StatusCode::BAD_REQUEST,
"telegram_webapp_auth_failed",
"Telegram verification failed",
"Could not verify Telegram Web App data.",
&e.to_string(),
));
}
};
let telegram_id = telegram_user.id.to_string();
let Some(user) = User::get_by_telegram_id(&db, &telegram_id)
.await
.map_err(|e| cot::Error::internal(format!("failed to load Telegram user: {e}")))?
else {
return Ok(json_error_typed(
cot::http::StatusCode::UNAUTHORIZED,
"telegram_account_not_linked",
"Telegram is not linked",
"This Telegram account is not connected to any VPN account.",
"",
));
};
if !user.is_active() {
return Ok(json_error_typed(
cot::http::StatusCode::FORBIDDEN,
"user_inactive",
"Account is inactive",
"This account is inactive.",
"",
));
}
auth::login(&session, user.id_val()).await?;
Json(TelegramLoginResponse {
redirect_to: "/configs".to_owned(),
})
.into_response()
}
async fn telegram_link_start_handler(
session: Session,
db: Database,
@@ -831,6 +901,11 @@ impl App for ApiApp {
api_post(telegram_link_webapp_handler),
"api_telegram_link_webapp",
),
Route::with_api_handler_and_name(
"/telegram-login/webapp",
api_post(telegram_login_webapp_handler),
"api_telegram_login_webapp",
),
Route::with_api_handler_and_name(
"/telegram-link/start",
api_post(telegram_link_start_handler),
+4 -1
View File
@@ -42,6 +42,9 @@ translations! {
login_submit: "Sign in" , "Войти";
login_disabled: "Login is currently disabled." , "Вход сейчас отключён.";
login_invalid: "Invalid username or password." , "Неверное имя пользователя или пароль.";
login_telegram_wait: "Signing in with Telegram..." , "Входим через Telegram...";
login_telegram_fallback: "Open the regular login page" , "Открыть обычный вход";
login_telegram_failed: "Telegram login failed. Use regular login." , "Не удалось войти через Telegram. Используйте обычный вход.";
// Logout
nav_logout: "Logout" , "Выход";
@@ -169,7 +172,7 @@ translations! {
telegram_open_bot: "Open bot" , "Открыть бота";
telegram_guide_start: "Open the bot and send /start once if you have not done it before." , "Откройте бота и один раз отправьте /start, если ещё не делали этого.";
telegram_guide_get_id: "Send the secret code below to the bot." , "Отправьте боту секретный код ниже.";
telegram_guide_paste: "Return here and refresh the status." , "Вернитесь сюда и обновите статус.";
telegram_guide_paste: "Return here; the status updates automatically." , "Вернитесь сюда; статус обновится автоматически.";
telegram_secret_label: "Secret code" , "Секретный код";
telegram_save: "Save Telegram" , "Сохранить Telegram";
telegram_saved: "Telegram connected." , "Telegram подключён.";
+11 -3
View File
@@ -67,14 +67,22 @@ struct ClientPortalTemplate {
app_version: &'static str,
}
#[derive(Debug, Template)]
#[template(path = "telegram_login.html")]
struct TelegramLoginTemplate {
t: &'static Translations,
}
async fn configs_page(
session: Session,
db: Database,
i18n: I18n,
) -> cot::Result<cot::response::Response> {
let user = match auth::require_user_or_redirect(&session, &db).await {
Ok(user) => user,
Err(response) => return Ok(response),
let user = match auth::get_session_user(&session, &db).await {
Some(user) => user,
None => {
return Html::new(TelegramLoginTemplate { t: i18n.t }.render()?).into_response();
}
};
let is_admin = user.role == auth::Role::Admin;