feat: account creation on/off toggling
This commit is contained in:
parent
dba81d65cb
commit
0ef65937e8
@ -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"
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
|
@ -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 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<form class="space-y-5" on:submit|preventDefault={handleSubmit}>
|
||||
<div class="form-group">
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
bind:value={username}
|
||||
placeholder="Username"
|
||||
required
|
||||
autocomplete="username"
|
||||
class="auth-input-field"
|
||||
/>
|
||||
{#if !ACCOUNT_CREATION_ENABLED && formName === "Register"}
|
||||
<div>
|
||||
<p>Registration disabled.</p>
|
||||
</div>
|
||||
{:else}
|
||||
<form class="space-y-5" on:submit|preventDefault={handleSubmit}>
|
||||
<div class="form-group">
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
bind:value={username}
|
||||
placeholder="Username"
|
||||
required
|
||||
autocomplete="username"
|
||||
class="auth-input-field"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
bind:value={password}
|
||||
placeholder="Password"
|
||||
required
|
||||
autocomplete={formName === "Login" ? "current-password" : "new-password"}
|
||||
class="auth-input-field"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
bind:value={password}
|
||||
placeholder="Password"
|
||||
required
|
||||
autocomplete={formName === "Login" ? "current-password" : "new-password"}
|
||||
class="auth-input-field"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="auth-button">
|
||||
{formName}
|
||||
</button>
|
||||
</form>
|
||||
<button type="submit" class="auth-button">
|
||||
{formName}
|
||||
</button>
|
||||
</form>
|
||||
{/if}
|
||||
|
||||
<p class="text-center text-sm font-medium">
|
||||
{bottomText}
|
||||
<a href={bottomLink}> here </a>
|
||||
</p>
|
||||
{#if ACCOUNT_CREATION_ENABLED}
|
||||
<p class="text-center text-sm font-medium">
|
||||
{bottomText}
|
||||
<a href={bottomLink}> here </a>
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TODO: add footer with a randomly picked quote (font-copernicus) -->
|
||||
<!-- TODO: add footer with randomized quotes (see KF impl., font-copernicus) -->
|
||||
|
||||
<div class="absolute right-4 top-4">
|
||||
<ThemeToggle />
|
||||
|
Loading…
x
Reference in New Issue
Block a user