feat(auth): invite links for several people, invite by email, registration with approval or email domains
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m20s

- Invites: link /?invite=CODE, copy link, send by email, max uses with counter
- Registration modes closed | approval | domain | domain+approval | open, waiting list with approve/reject
- REGISTRATION_MODE / REGISTRATION_DOMAINS lock the admin setting; ALLOW_REGISTRATION=true is honoured

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-31 13:43:54 +01:00
1 parent db5c5cde9b
commit af77b9e809
24 files changed
+1077 -142

No files matched your search

+26 -3
View File
@@ -20,9 +20,15 @@ type Config struct {
// from it, never from the request's Host header.
BaseURLSet bool
AllowRegistration bool
LogLevel string
Debug bool
DemoMode bool
// RegistrationMode / RegistrationDomains: REGISTRATION_MODE (closed | approval | domain |
// domain+approval | open) and REGISTRATION_DOMAINS. When set they win over the admin settings,
// which then cannot change them. ALLOW_REGISTRATION=true counts as REGISTRATION_MODE=open;
// ALLOW_REGISTRATION=false (the template default) leaves the choice to the admin settings.
RegistrationMode string
RegistrationDomains string
LogLevel string
Debug bool
DemoMode bool
// DemoResetMinutes: in demo mode the database is reset to the sample data this often (0 = never)
DemoResetMinutes int
// TrustedProxies: whose X-Forwarded-For/X-Real-IP is believed ("private", "all", "none" or CIDRs)
@@ -234,6 +240,8 @@ func Load() *Config {
BaseURL: baseURL,
BaseURLSet: strings.TrimSpace(os.Getenv("BASE_URL")) != "",
AllowRegistration: allowReg,
RegistrationMode: registrationMode(allowReg),
RegistrationDomains: strings.TrimSpace(os.Getenv("REGISTRATION_DOMAINS")),
LogLevel: logLevel,
Debug: debug,
DemoMode: demoMode,
@@ -326,3 +334,18 @@ func demoResetMinutes() int {
}
return n
}
// registrationMode reads REGISTRATION_MODE; unknown values are ignored ("" = admin settings decide).
func registrationMode(allowReg bool) string {
switch m := strings.ToLower(strings.TrimSpace(os.Getenv("REGISTRATION_MODE"))); m {
case "closed", "approval", "domain", "domain+approval", "open":
return m
case "":
default:
slog.Warn("REGISTRATION_MODE unbekannt, wird ignoriert", "value", m)
}
if allowReg {
return "open"
}
return ""
}