From 3512a805974d10a812dbdf7824af76d68d1ee0ca Mon Sep 17 00:00:00 2001 From: Mg Pig Date: Fri, 13 Feb 2026 16:03:11 +0800 Subject: [PATCH] feat(web): add --disable-registration flag to disable user registration (#1881) --- easytier-web/locales/app.yml | 5 ++++- easytier-web/src/main.rs | 8 ++++++++ easytier-web/src/restful/auth.rs | 19 ++++++++++++++++++- easytier-web/src/restful/mod.rs | 9 +++++++-- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/easytier-web/locales/app.yml b/easytier-web/locales/app.yml index 366abf79..79070306 100644 --- a/easytier-web/locales/app.yml +++ b/easytier-web/locales/app.yml @@ -33,4 +33,7 @@ cli: zh-CN: "API 服务器的 URL,用于 web 前端连接" geoip_db: en: "The path to the GeoIP2 database file, used to lookup the location of the client, default is the embedded file (only country information) , recommend https://github.com/P3TERX/GeoLite.mmdb" - zh-CN: "GeoIP2 数据库文件路径,用于查找客户端的位置,默认为嵌入文件(仅国家信息),推荐 https://github.com/P3TERX/GeoLite.mmdb" \ No newline at end of file + zh-CN: "GeoIP2 数据库文件路径,用于查找客户端的位置,默认为嵌入文件(仅国家信息),推荐 https://github.com/P3TERX/GeoLite.mmdb" + disable_registration: + en: "Disable user registration" + zh-CN: "禁用用户注册" \ No newline at end of file diff --git a/easytier-web/src/main.rs b/easytier-web/src/main.rs index 3cb1374d..0b20240d 100644 --- a/easytier-web/src/main.rs +++ b/easytier-web/src/main.rs @@ -109,6 +109,13 @@ struct Cli { help = t!("cli.api_host").to_string() )] api_host: Option, + + #[arg( + long, + default_value = "false", + help = t!("cli.disable_registration").to_string(), + )] + disable_registration: bool, } impl LoggingConfigLoader for &Cli { @@ -212,6 +219,7 @@ async fn main() { mgr.clone(), db, web_router_restful, + cli.disable_registration, ) .await .unwrap() diff --git a/easytier-web/src/restful/auth.rs b/easytier-web/src/restful/auth.rs index 9d0fffef..15f9b398 100644 --- a/easytier-web/src/restful/auth.rs +++ b/easytier-web/src/restful/auth.rs @@ -14,6 +14,13 @@ use super::{ AppStateInner, }; +/// Feature flags for the web server +#[derive(Clone, Default)] +pub struct FeatureFlags { + /// Whether user registration is disabled + pub disable_registration: bool, +} + #[derive(Debug, Deserialize, Serialize)] pub struct LoginResult { messages: Vec, @@ -67,7 +74,7 @@ mod put { } mod post { - use axum::Json; + use axum::{extract::Extension, Json}; use easytier::proto::common::Void; use crate::restful::{ @@ -110,10 +117,20 @@ mod post { } pub async fn register( + Extension(feature_flags): Extension, auth_session: AuthSession, captcha_session: tower_sessions::Session, Json(req): Json, ) -> Result, HttpHandleError> { + // Check if registration is disabled + if feature_flags.disable_registration { + tracing::warn!("Registration attempt blocked: registration is disabled"); + return Err(( + StatusCode::FORBIDDEN, + other_error("Registration is disabled").into(), + )); + } + // 调用CaptchaUtil的静态方法验证验证码是否正确 if !CaptchaUtil::ver(&req.captcha, &captcha_session).await { return Err(( diff --git a/easytier-web/src/restful/mod.rs b/easytier-web/src/restful/mod.rs index 95935c38..362031a6 100644 --- a/easytier-web/src/restful/mod.rs +++ b/easytier-web/src/restful/mod.rs @@ -7,7 +7,7 @@ use std::{net::SocketAddr, sync::Arc}; use axum::http::StatusCode; use axum::routing::post; -use axum::{extract::State, routing::get, Json, Router}; +use axum::{extract::State, routing::get, Extension, Json, Router}; use axum_login::tower_sessions::{ExpiredDeletion, SessionManagerLayer}; use axum_login::{login_required, AuthManagerLayerBuilder, AuthUser, AuthzBackend}; use axum_messages::MessagesManagerLayer; @@ -37,6 +37,7 @@ struct Assets; pub struct RestfulServer { bind_addr: SocketAddr, client_mgr: Arc, + registration_disabled: bool, db: Db, // serve_task: Option>, @@ -104,6 +105,7 @@ impl RestfulServer { client_mgr: Arc, db: Db, web_router: Option, + registration_disabled: bool, ) -> anyhow::Result { assert!(client_mgr.is_running()); @@ -112,6 +114,7 @@ impl RestfulServer { Ok(RestfulServer { bind_addr, client_mgr, + registration_disabled, db, // serve_task: None, // delete_task: None, @@ -240,7 +243,9 @@ impl RestfulServer { .route("/api/v1/sessions", get(Self::handle_list_all_sessions)) .merge(NetworkApi::build_route()) .route_layer(login_required!(Backend)) - .merge(auth::router()) + .merge(auth::router().layer(Extension(auth::FeatureFlags { + disable_registration: self.registration_disabled, + }))) .with_state(self.client_mgr.clone()) .route( "/api/v1/generate-config",