From 356c4ebaf2d5420f7af2313a655a854bfa87d68e Mon Sep 17 00:00:00 2001 From: haturatu Date: Sun, 12 Oct 2025 21:04:21 +0900 Subject: feat(register): register option --- README.ja.md | 1 + README.md | 1 + cmd/server/main.go | 14 +++++++++----- config/config.go | 1 + handlers/auth.go | 13 +++++++++++-- templates/login.html | 2 ++ types/types.go | 1 + 7 files changed, 26 insertions(+), 7 deletions(-) diff --git a/README.ja.md b/README.ja.md index 2c101ed..255c1fb 100644 --- a/README.ja.md +++ b/README.ja.md @@ -356,5 +356,6 @@ Authorization: Bearer | `PROTECT_API` | `true`の場合、すべてのAPIパスをベアラートークン認証経由でプロキシします。 | `false` | | `FRONT_PATH` | `PROTECT_FRONTEND`で保護されるフロントエンドのベースパス。 | `/` | | `API_PATH` | `PROTECT_API`で保護されるAPIルートのベースパス。 | `/api/` | +| `REGISTER` | `false`に設定すると、新規ユーザー登録を無効にします。 | `true` | | `AUTH_PATH_*` | ログイン、管理者ページなどの内部URLをカスタマイズするための変数セット。 | 様々、例: `/login`| | `AUTH_ASSETS_PATH` | 内部静的アセット(CSS, JS)を提供するためのURLパス。 | `/assets` | diff --git a/README.md b/README.md index f22e873..a99af8c 100644 --- a/README.md +++ b/README.md @@ -354,5 +354,6 @@ The `refresh_token` is a long-lived token that can be used to obtain a new acces | `PROTECT_API` | If `true`, proxies all API paths through bearer token authentication. | `false` | | `FRONT_PATH` | The base path for frontend routes to be protected by `PROTECT_FRONTEND`. | `/` | | `API_PATH` | The base path for API routes to be protected by `PROTECT_API`. | `/api/` | +| `REGISTER` | If set to `false`, disables new user registration. | `true` | | `AUTH_PATH_*` | A set of variables to customize the internal URLs for login, admin, etc. | Various, e.g., `/login`| | `AUTH_ASSETS_PATH` | The URL path for serving internal static assets (CSS, JS). | `/assets` | \ No newline at end of file diff --git a/cmd/server/main.go b/cmd/server/main.go index 7d2fa25..89d17bc 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -79,10 +79,12 @@ func main() { loginHandler := methodSwitch(loginPageHandler, http.HandlerFunc(handlers.LoginHandler)) mux.Handle(config.Paths.Login, loginHandler) - // For /register, GET goes to PHP, POST goes to Go's register logic - registerPostHandler := middleware.RateLimitMiddleware(rateLimiter)(http.HandlerFunc(handlers.RegisterHandler)) - registerHandler := methodSwitch(registerPageHandler, registerPostHandler) - mux.Handle(config.Paths.Register, registerHandler) + if config.Paths.RegisterEnabled { + // For /register, GET goes to PHP, POST goes to Go's register logic + registerPostHandler := middleware.RateLimitMiddleware(rateLimiter)(http.HandlerFunc(handlers.RegisterHandler)) + registerHandler := methodSwitch(registerPageHandler, registerPostHandler) + mux.Handle(config.Paths.Register, registerHandler) + } // For account pages, GET goes to PHP, POST (for password change) goes to Go accountPasswordPostHandler := http.HandlerFunc(handlers.ChangePasswordHandler) @@ -95,7 +97,9 @@ func main() { } else { // --- Public Auth Routes (Go templates) --- mux.HandleFunc(config.Paths.Login, handlers.LoginHandler) - mux.Handle(config.Paths.Register, middleware.RateLimitMiddleware(rateLimiter)(http.HandlerFunc(handlers.RegisterHandler))) + if config.Paths.RegisterEnabled { + mux.Handle(config.Paths.Register, middleware.RateLimitMiddleware(rateLimiter)(http.HandlerFunc(handlers.RegisterHandler))) + } // --- Auth HTML pages (Protected by SessionAuth, Go templates) --- mux.Handle(config.Paths.Account, middleware.SessionAuth(http.HandlerFunc(handlers.AccountPageHandler))) mux.Handle(config.Paths.Admin, middleware.SessionAuth(middleware.AdminMiddleware(http.HandlerFunc(handlers.AdminPageHandler)))) diff --git a/config/config.go b/config/config.go index a73bf23..2de3c36 100644 --- a/config/config.go +++ b/config/config.go @@ -47,5 +47,6 @@ func Init() { ProtectAPI: getEnvAsBool("PROTECT_API", false), FrontPath: getEnv("FRONT_PATH", "/"), APIPath: getEnv("API_PATH", "/api/"), + RegisterEnabled: getEnvAsBool("REGISTER", true), } } diff --git a/handlers/auth.go b/handlers/auth.go index 2d5eb68..f7773a8 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -17,8 +17,9 @@ var templates = template.Must(template.ParseGlob("templates/*.html")) func renderLoginWithError(w http.ResponseWriter, message string) { data := map[string]interface{}{ - "Paths": config.Paths, - "Error": message, + "Paths": config.Paths, + "Error": message, + "RegisterEnabled": config.Paths.RegisterEnabled, } w.WriteHeader(http.StatusUnauthorized) // Set status to indicate failure if err := templates.ExecuteTemplate(w, "login.html", data); err != nil { @@ -34,6 +35,10 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { } if r.Method == http.MethodGet { + data := map[string]interface{}{ + "Paths": config.Paths, + "RegisterEnabled": config.Paths.RegisterEnabled, + } if err := templates.ExecuteTemplate(w, "login.html", data); err != nil { logging.AppLog.Error("Failed to execute login template", "error", err, "ip", ip) } @@ -192,6 +197,10 @@ func renderRegisterWithError(w http.ResponseWriter, message string) { // RegisterHandler handles displaying and processing the user registration form. func RegisterHandler(w http.ResponseWriter, r *http.Request) { + if !config.Paths.RegisterEnabled { + http.Error(w, "User registration is disabled.", http.StatusForbidden) + return + } ip := logging.GetClientIP(r) data := map[string]interface{}{ "Paths": config.Paths, diff --git a/templates/login.html b/templates/login.html index 8875cb1..12f27eb 100644 --- a/templates/login.html +++ b/templates/login.html @@ -26,7 +26,9 @@ {{end}}

+ {{if .RegisterEnabled}} Don't have an account? Register + {{end}}
diff --git a/types/types.go b/types/types.go index a91fbcd..b94d89a 100644 --- a/types/types.go +++ b/types/types.go @@ -20,6 +20,7 @@ type PathConfig struct { ProtectAPI bool FrontPath string APIPath string + RegisterEnabled bool } // ContextKey is a custom type for context keys to avoid collisions. -- cgit v1.2.3