feat(auth): confirm the e-mail address of new accounts by link
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m21s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m21s
- Setting / REGISTRATION_VERIFY_EMAIL; only with SMTP and BASE_URL; invites skip it - Hashed one-time tokens (48 h), resend with cooldown, unconfirmed accounts purged - Approval modes notify admins only after the address is confirmed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1406650b7c
commit
ab97638361
25 files changed
+621
-56
No files matched your search
@@ -43,6 +43,7 @@ func (s *Server) handleAuthStatus(w http.ResponseWriter, r *http.Request) {
|
||||
"allowRegistration": policy.Mode != storage.RegistrationClosed,
|
||||
"registrationMode": policy.Mode,
|
||||
"registrationDomains": policy.Domains,
|
||||
"emailVerification": policy.VerifyEmail,
|
||||
"instanceName": instanceName,
|
||||
"demoMode": s.cfg.DemoMode,
|
||||
"sharingMode": s.store.SharingMode(),
|
||||
@@ -199,6 +200,7 @@ func (s *Server) handleRegister(w http.ResponseWriter, r *http.Request) {
|
||||
role := "member"
|
||||
var validInvite *domain.UserInvite
|
||||
pending := false // registered without invite while approval is needed
|
||||
verify := false // registered without invite while the address must be confirmed
|
||||
|
||||
if strings.TrimSpace(req.InviteCode) != "" {
|
||||
inv, err := s.store.GetUserInviteByCode(req.InviteCode)
|
||||
@@ -215,8 +217,10 @@ func (s *Server) handleRegister(w http.ResponseWriter, r *http.Request) {
|
||||
} else if count == 0 {
|
||||
role = "admin"
|
||||
} else {
|
||||
policy := s.registrationPolicy()
|
||||
var err error
|
||||
pending, err = s.registrationPolicy().registrationOutcome(req.Email)
|
||||
pending, err = policy.registrationOutcome(req.Email)
|
||||
verify = policy.VerifyEmail
|
||||
if err != nil {
|
||||
writeError(w, http.StatusForbidden, err.Error())
|
||||
return
|
||||
@@ -261,22 +265,35 @@ func (s *Server) handleRegister(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// Waiting for approval: the account exists but stays locked, no session yet
|
||||
if pending {
|
||||
// Waiting for the e-mail confirmation and/or approval: the account exists but stays locked, no session
|
||||
if pending || verify {
|
||||
inactive := false
|
||||
if _, err := s.store.UpdateUser(user.ID, nil, nil, nil, &inactive, nil, nil); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "Konto konnte nicht angelegt werden")
|
||||
return
|
||||
}
|
||||
if err := s.store.AddPendingRegistration(user.ID); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "Konto konnte nicht angelegt werden")
|
||||
return
|
||||
if pending {
|
||||
if err := s.store.AddPendingRegistration(user.ID); err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "Konto konnte nicht angelegt werden")
|
||||
return
|
||||
}
|
||||
}
|
||||
slog.Info("Registrierung wartet auf Freigabe", "user_id", user.ID, "email", user.Email)
|
||||
go s.notifyAdminsOfRegistration(user)
|
||||
message := "Dein Konto wurde angelegt und wartet auf die Freigabe durch einen Administrator. Du bekommst eine E-Mail, sobald du dich anmelden kannst."
|
||||
if verify {
|
||||
// Admins hear about it only once the address is confirmed
|
||||
go s.sendVerificationMail(user)
|
||||
message = "Fast geschafft: Wir haben dir eine E-Mail an " + user.Email + " geschickt. Bestätige deine Adresse über den Link darin."
|
||||
if pending {
|
||||
message += " Danach schaltet ein Administrator dein Konto frei."
|
||||
}
|
||||
} else {
|
||||
go s.notifyAdminsOfRegistration(user)
|
||||
}
|
||||
slog.Info("Registrierung wartet", "user_id", user.ID, "email", user.Email, "approval", pending, "verify", verify)
|
||||
writeJSON(w, http.StatusAccepted, map[string]interface{}{
|
||||
"pending": true,
|
||||
"message": "Dein Konto wurde angelegt und wartet auf die Freigabe durch einen Administrator. Du bekommst eine E-Mail, sobald du dich anmelden kannst.",
|
||||
"verify": verify,
|
||||
"message": message,
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -343,6 +360,10 @@ func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
s.loginGuard.recordSuccess(account, ip)
|
||||
if !user.IsActive && s.store.IsEmailUnverified(user.ID) {
|
||||
writeError(w, http.StatusForbidden, "Bitte bestätige zuerst deine E-Mail-Adresse über den Link, den wir dir geschickt haben")
|
||||
return
|
||||
}
|
||||
if !user.IsActive && s.store.IsPendingRegistration(user.ID) {
|
||||
writeError(w, http.StatusForbidden, "Dein Konto wartet noch auf die Freigabe durch einen Administrator")
|
||||
return
|
||||
|
||||
Reference in new issue
Block a user