From 0ef65937e86b2bc176cff3ba816b2a61ebb826c1 Mon Sep 17 00:00:00 2001 From: ae Date: Mon, 5 May 2025 10:18:07 +0300 Subject: [PATCH] feat: account creation on/off toggling --- .env.template | 5 +- docker/docker-compose-back.yml | 1 + docker/docker-compose-full.yml | 5 +- server/internal/service/auth.go | 6 ++- server/internal/service/service.go | 11 ++-- server/main.go | 34 ++++++------ web/src/lib/components/AuthForm.svelte | 74 +++++++++++++++----------- 7 files changed, 76 insertions(+), 60 deletions(-) diff --git a/.env.template b/.env.template index 524e4d2..f9b112b 100644 --- a/.env.template +++ b/.env.template @@ -10,11 +10,14 @@ JWT_SECRET="" CSRF_SECRET="" # Should be 32 bytes long ADMIN_USERNAME="" ADMIN_PASSWORD="" +ACCOUNT_CREATION_ENABLED="0" LOG_LEVEL="info" APP_ENV="production" DOMAIN="" FRONTEND_URL="" -# Frontend +# Frontend (build-stage) +VITE_ACCOUNT_CREATION_ENABLED="$ACCOUNT_CREATION_ENABLED" VITE_VIEW_COOKIE_PATH="/" VITE_COOKIE_SAME_SITE="strict" +VITE_VIEW_COOKIE_DOMAIN="$DOMAIN" \ No newline at end of file diff --git a/docker/docker-compose-back.yml b/docker/docker-compose-back.yml index 0aaba04..f0fd43f 100644 --- a/docker/docker-compose-back.yml +++ b/docker/docker-compose-back.yml @@ -37,6 +37,7 @@ services: CSRF_SECRET: ${CSRF_SECRET:?csrf secret required} ADMIN_USERNAME: ${ADMIN_USERNAME:?init admin username required} ADMIN_PASSWORD: ${ADMIN_PASSWORD:?init admin password required} + ACCOUNT_CREATION_ENABLED: ${ACCOUNT_CREATION_ENABLED:-0} LOG_LEVEL: debug APP_ENV: development DOMAIN: localhost diff --git a/docker/docker-compose-full.yml b/docker/docker-compose-full.yml index 93d3d71..477b256 100644 --- a/docker/docker-compose-full.yml +++ b/docker/docker-compose-full.yml @@ -35,6 +35,7 @@ services: CSRF_SECRET: ${CSRF_SECRET:?csrf secret required} ADMIN_USERNAME: ${ADMIN_USERNAME:?init admin username required} ADMIN_PASSWORD: ${ADMIN_PASSWORD:?init admin password required} + ACCOUNT_CREATION_ENABLED: ${ACCOUNT_CREATION_ENABLED:-0} LOG_LEVEL: ${LOG_LEVEL:-info} APP_ENV: ${APP_ENV:-production} DOMAIN: ${DOMAIN:-localhost} @@ -53,10 +54,6 @@ services: - 3000:80 # Container port defined in nginx.conf (bound to 3000 for dev.) depends_on: - qnote-server - environment: - VITE_VIEW_COOKIE_PATH: ${VITE_VIEW_COOKIE_PATH:-/} - VITE_VIEW_COOKIE_DOMAIN: ${DOMAIN:-localhost} - VITE_COOKIE_SAME_SITE: ${VITE_COOKIE_SAME_SITE:-strict} networks: qnote: diff --git a/server/internal/service/auth.go b/server/internal/service/auth.go index 312d520..3b37ca4 100644 --- a/server/internal/service/auth.go +++ b/server/internal/service/auth.go @@ -96,8 +96,10 @@ func (rs authResource) Routes() chi.Router { r := chi.NewRouter() // Public routes (the only outside facing endpoints in the whole API with no requirement for auth) - r.Post("/signup", rs.Create) // POST /auth/signup - registration (rate-limited) - r.Post("/login", rs.Login) // POST /auth/login - login (rate-limited) + if rs.Config.IsRegEnabled { + r.Post("/signup", rs.Create) // POST /auth/signup - registration (rate-limited) + } + r.Post("/login", rs.Login) // POST /auth/login - login (rate-limited) // Protected routes (access token required) r.Group(func(r chi.Router) { diff --git a/server/internal/service/service.go b/server/internal/service/service.go index aeb9265..eb3d6d6 100644 --- a/server/internal/service/service.go +++ b/server/internal/service/service.go @@ -17,11 +17,12 @@ import ( const authRateLimit = 5 // req/min type SvcConfig struct { - JWTSecret string - CSRFSecret string - IsProd bool - Domain string - FrontendURL string + JWTSecret string + CSRFSecret string + IsProd bool + IsRegEnabled bool + Domain string + FrontendURL string } func (sc *SvcConfig) allowedOrigins() []string { diff --git a/server/main.go b/server/main.go index 1ead809..3d60af0 100644 --- a/server/main.go +++ b/server/main.go @@ -26,19 +26,18 @@ var ( ) type Config struct { - JWTSecret string `env:"JWT_SECRET,notEmpty"` - CSRFSecret string `env:"CSRF_SECRET,notEmpty"` - DatabaseURL string `env:"DB_URL,notEmpty"` - AdminUsername string `env:"ADMIN_USERNAME,notEmpty,unset"` - AdminPassword string `env:"ADMIN_PASSWORD,notEmpty,unset"` - Domain string `env:"DOMAIN" envDefault:"localhost"` - FrontendURL string `env:"FRONTEND_URL" envDefault:"http://localhost:5173"` - LogLevel string `env:"LOG_LEVEL" envDefault:"info"` - AppEnv string `env:"APP_ENV" envDefault:"production"` + JWTSecret string `env:"JWT_SECRET,notEmpty"` + CSRFSecret string `env:"CSRF_SECRET,notEmpty"` + DatabaseURL string `env:"DB_URL,notEmpty"` + AdminUsername string `env:"ADMIN_USERNAME,notEmpty,unset"` + AdminPassword string `env:"ADMIN_PASSWORD,notEmpty,unset"` + AccountCreationEnabled bool `env:"ACCOUNT_CREATION_ENABLED" envDefault:"0"` + Domain string `env:"DOMAIN" envDefault:"localhost"` + FrontendURL string `env:"FRONTEND_URL" envDefault:"http://localhost:5173"` + LogLevel string `env:"LOG_LEVEL" envDefault:"info"` + AppEnv string `env:"APP_ENV" envDefault:"production"` } -// TODO: add flag to enable/disable registration of new users - func init() { config = Config{} if err := env.Parse(&config); err != nil { @@ -47,14 +46,15 @@ func init() { initLogger() svcConfig = service.SvcConfig{ - JWTSecret: config.JWTSecret, - CSRFSecret: config.CSRFSecret, - IsProd: config.AppEnv == "production", - Domain: config.Domain, - FrontendURL: config.FrontendURL, + JWTSecret: config.JWTSecret, + CSRFSecret: config.CSRFSecret, + IsProd: config.AppEnv == "production", + IsRegEnabled: config.AccountCreationEnabled, + Domain: config.Domain, + FrontendURL: config.FrontendURL, } - log.Debug().Msgf("IsProd=%t, Domain='%s', FrontendURL='%s'", svcConfig.IsProd, svcConfig.Domain, svcConfig.FrontendURL) + log.Debug().Msgf("IsProd=%t, IsRegEnabled=%t, Domain='%s', FrontendURL='%s'", svcConfig.IsProd, svcConfig.IsRegEnabled, svcConfig.Domain, svcConfig.FrontendURL) log.Debug().Msg("Initialization completed") } diff --git a/web/src/lib/components/AuthForm.svelte b/web/src/lib/components/AuthForm.svelte index 7f70b2a..214c2f2 100644 --- a/web/src/lib/components/AuthForm.svelte +++ b/web/src/lib/components/AuthForm.svelte @@ -8,6 +8,10 @@ export let bottomText: string export let bottomLink: string + const ACCOUNT_CREATION_ENABLED = (import.meta.env.VITE_ACCOUNT_CREATION_ENABLED || "0") === "1" + console.log(`[VIEW] Account creation enabled: ${ACCOUNT_CREATION_ENABLED}`) + + // local state let username = "" let password = "" let usernameError = "" @@ -73,44 +77,52 @@ {/if} -
-
- + {#if !ACCOUNT_CREATION_ENABLED && formName === "Register"} +
+

Registration disabled.

+ {:else} + +
+ +
-
- -
+
+ +
- - + + + {/if} -

- {bottomText} - here -

+ {#if ACCOUNT_CREATION_ENABLED} +

+ {bottomText} + here +

+ {/if}
- +