4583262ea4
- internal/mailer: SMTP-Out via net/smtp (TLS + STARTTLS), HTML+Text-Templates - internal/tokenstore: auth_tokens Tabelle, SHA-256-Hash, TTL, einmalig verwendbar - userstore: CreateInactive(), Activate(), GetByEmail(), SetPassword() - API: POST /signup, GET /verify, POST /forgot-password, POST /reset-password - API: POST /admin/invite (domain_admin+), GET /auth/invite?token (check) - Login-Seite: Links zu "Passwort vergessen" und "Registrieren" - Frontend: /signup, /verify, /forgot-password, /reset-password Seiten - server.fqdn nicht konfiguriert → Startup-Warnung, Self-Service deaktiviert - LDAP-Nutzer: Passwort-Reset abgewiesen Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
66 lines
3.7 KiB
Go
66 lines
3.7 KiB
Go
package mailer
|
|
|
|
import "fmt"
|
|
|
|
// ── Email templates ───────────────────────────────────────────────────────────
|
|
// Simple inline templates. No embed.FS needed at this stage.
|
|
|
|
// VerifyEmailHTML returns the HTML body for an email verification message.
|
|
func VerifyEmailHTML(fqdn, token, username string) string {
|
|
link := fmt.Sprintf("https://%s/verify?token=%s", fqdn, token)
|
|
return fmt.Sprintf(`<!DOCTYPE html>
|
|
<html><body style="font-family:sans-serif;max-width:600px;margin:40px auto;color:#333">
|
|
<h2>E-Mail-Adresse bestätigen</h2>
|
|
<p>Hallo %s,</p>
|
|
<p>Bitte bestätige deine E-Mail-Adresse, um deinen archivmail-Account zu aktivieren.</p>
|
|
<p><a href="%s" style="background:#2563eb;color:#fff;padding:12px 24px;text-decoration:none;border-radius:6px;display:inline-block">E-Mail bestätigen</a></p>
|
|
<p style="color:#666;font-size:13px">Der Link ist 24 Stunden gültig.<br>Falls du dich nicht registriert hast, kannst du diese E-Mail ignorieren.</p>
|
|
<p style="color:#999;font-size:12px">%s</p>
|
|
</body></html>`, username, link, link)
|
|
}
|
|
|
|
// VerifyEmailText returns the plain-text body for email verification.
|
|
func VerifyEmailText(fqdn, token, username string) string {
|
|
link := fmt.Sprintf("https://%s/verify?token=%s", fqdn, token)
|
|
return fmt.Sprintf("Hallo %s,\n\nbitte bestätige deine E-Mail-Adresse:\n\n%s\n\nDer Link ist 24 Stunden gültig.\n\narcivmail", username, link)
|
|
}
|
|
|
|
// ResetPasswordHTML returns the HTML body for a password-reset message.
|
|
func ResetPasswordHTML(fqdn, token, username string) string {
|
|
link := fmt.Sprintf("https://%s/reset-password?token=%s", fqdn, token)
|
|
return fmt.Sprintf(`<!DOCTYPE html>
|
|
<html><body style="font-family:sans-serif;max-width:600px;margin:40px auto;color:#333">
|
|
<h2>Passwort zurücksetzen</h2>
|
|
<p>Hallo %s,</p>
|
|
<p>Du hast eine Passwort-Reset-Anfrage gestellt. Klicke auf den Link, um ein neues Passwort zu setzen.</p>
|
|
<p><a href="%s" style="background:#2563eb;color:#fff;padding:12px 24px;text-decoration:none;border-radius:6px;display:inline-block">Passwort zurücksetzen</a></p>
|
|
<p style="color:#666;font-size:13px">Der Link ist 1 Stunde gültig und kann nur einmal verwendet werden.<br>Falls du kein Passwort zurücksetzen wolltest, ignoriere diese E-Mail.</p>
|
|
<p style="color:#999;font-size:12px">%s</p>
|
|
</body></html>`, username, link, link)
|
|
}
|
|
|
|
// ResetPasswordText returns the plain-text body for password reset.
|
|
func ResetPasswordText(fqdn, token, username string) string {
|
|
link := fmt.Sprintf("https://%s/reset-password?token=%s", fqdn, token)
|
|
return fmt.Sprintf("Hallo %s,\n\nPasswort zurücksetzen:\n\n%s\n\nDer Link ist 1 Stunde gültig.\n\narcivmail", username, link)
|
|
}
|
|
|
|
// InviteHTML returns the HTML body for a tenant invitation.
|
|
func InviteHTML(fqdn, token, tenantName string) string {
|
|
link := fmt.Sprintf("https://%s/signup?invite=%s", fqdn, token)
|
|
return fmt.Sprintf(`<!DOCTYPE html>
|
|
<html><body style="font-family:sans-serif;max-width:600px;margin:40px auto;color:#333">
|
|
<h2>Einladung zu %s</h2>
|
|
<p>Du wurdest eingeladen, dem archivmail-System beizutreten.</p>
|
|
<p><a href="%s" style="background:#2563eb;color:#fff;padding:12px 24px;text-decoration:none;border-radius:6px;display:inline-block">Einladung annehmen</a></p>
|
|
<p style="color:#666;font-size:13px">Der Link ist 72 Stunden gültig und kann nur einmal verwendet werden.</p>
|
|
<p style="color:#999;font-size:12px">%s</p>
|
|
</body></html>`, tenantName, link, link)
|
|
}
|
|
|
|
// InviteText returns the plain-text body for a tenant invitation.
|
|
func InviteText(fqdn, token, tenantName string) string {
|
|
link := fmt.Sprintf("https://%s/signup?invite=%s", fqdn, token)
|
|
return fmt.Sprintf("Einladung zu %s:\n\n%s\n\nDer Link ist 72 Stunden gültig.\n\narcivmail", tenantName, link)
|
|
}
|