From 91c0411b907864d184714bd34ea213f12267d2a5 Mon Sep 17 00:00:00 2001 From: Leopere Date: Tue, 3 Mar 2026 17:30:38 -0500 Subject: [PATCH] Add /resend-reset endpoint so set-password button sends email directly The welcome page button was linking to Authelia's reset page which requires an active login session. Now it POSTs to /resend-reset which calls the Authelia API server-side and sends the email immediately. Button text updated from "Reset Password" to "Set Password". Made-with: Cursor --- docker/ss-atlas/internal/handlers/authelia.go | 17 +++++++++++ docker/ss-atlas/internal/handlers/routes.go | 1 + .../internal/handlers/subscription.go | 1 - docker/ss-atlas/templates/pages/welcome.html | 28 +++++++++++++++++-- stack.yml | 2 +- 5 files changed, 45 insertions(+), 4 deletions(-) diff --git a/docker/ss-atlas/internal/handlers/authelia.go b/docker/ss-atlas/internal/handlers/authelia.go index 5cf6c7a..432fd72 100644 --- a/docker/ss-atlas/internal/handlers/authelia.go +++ b/docker/ss-atlas/internal/handlers/authelia.go @@ -4,10 +4,27 @@ import ( "bytes" "encoding/json" "fmt" + "log" "net/http" "strings" ) +func (a *App) handleResendReset(w http.ResponseWriter, r *http.Request) { + username := r.FormValue("username") + if username == "" { + http.Error(w, "username required", http.StatusBadRequest) + return + } + if err := a.triggerPasswordReset(username); err != nil { + log.Printf("resend-reset: failed for %s: %v", username, err) + http.Error(w, "failed to send email", http.StatusInternalServerError) + return + } + log.Printf("resend-reset: password reset email sent for %s", username) + w.WriteHeader(http.StatusOK) + w.Write([]byte("Password setup email sent. Check your inbox.")) +} + func (a *App) triggerPasswordReset(username string) error { body, _ := json.Marshal(map[string]string{"username": username}) diff --git a/docker/ss-atlas/internal/handlers/routes.go b/docker/ss-atlas/internal/handlers/routes.go index 1c399b3..9bb15f9 100644 --- a/docker/ss-atlas/internal/handlers/routes.go +++ b/docker/ss-atlas/internal/handlers/routes.go @@ -47,6 +47,7 @@ func NewRouter(cfg *config.Config, sc *ssstripe.Client, lc *ldap.Client, sw *swa r.Get("/dashboard", app.handleDashboard) r.Post("/stack-manage", app.handleStackManage) r.Post("/subscribe", app.handleCreateCheckout) + r.Post("/resend-reset", app.handleResendReset) r.Post("/portal", app.handlePortal) r.Post("/resubscribe", app.handleResubscribe) r.Post("/webhook/stripe", app.handleWebhook) diff --git a/docker/ss-atlas/internal/handlers/subscription.go b/docker/ss-atlas/internal/handlers/subscription.go index 8e5eb0e..62f6d23 100644 --- a/docker/ss-atlas/internal/handlers/subscription.go +++ b/docker/ss-atlas/internal/handlers/subscription.go @@ -85,7 +85,6 @@ func (a *App) handleSuccess(w http.ResponseWriter, r *http.Request) { "IsNew": result.IsNew, "Email": email, "LoginURL": a.cfg.AutheliaURL, - "ResetURL": a.cfg.AutheliaURL + "/#/reset-password/step1", "ActivateURL": a.cfg.AppURL + "/activate", "DashboardURL": a.cfg.AppURL + "/dashboard", "InstanceURL": "https://" + result.Username + "." + a.cfg.CustomerDomain, diff --git a/docker/ss-atlas/templates/pages/welcome.html b/docker/ss-atlas/templates/pages/welcome.html index 387c8c3..bb99202 100644 --- a/docker/ss-atlas/templates/pages/welcome.html +++ b/docker/ss-atlas/templates/pages/welcome.html @@ -177,7 +177,8 @@
- Resend / Set Password + Activate Stack
{{else}} @@ -204,11 +205,34 @@
- Reset Password + Sign In Dashboard
{{end}} + diff --git a/stack.yml b/stack.yml index 619f3e6..5a5d7e6 100644 --- a/stack.yml +++ b/stack.yml @@ -77,7 +77,7 @@ services: echo "$${CLIENT_SECRET_HEADADMIN}" > /run/secrets/CLIENT_SECRET_HEADADMIN echo "$${CLIENT_SECRET_PORTAINER}" > /run/secrets/CLIENT_SECRET_PORTAINER echo "$${CLIENT_SECRET_GITEA}" > /run/secrets/CLIENT_SECRET_GITEA - { echo 'access_control:'; echo ' default_policy: deny'; echo ' rules:'; echo ' - domain: login.bc.a250.ca'; echo ' policy: bypass'; echo ' - domain: app.bc.a250.ca'; echo ' policy: bypass'; echo ' resources:'; echo " - '^/$$'"; echo " - '^/subscribe$$'"; echo " - '^/success(\\?.*)?$$'"; echo " - '^/webhook/stripe$$'"; echo " - '^/health$$'"; echo " - '^/version$$'"; echo ' - domain: app.bc.a250.ca'; echo ' policy: one_factor'; echo ' resources:'; echo " - '^/dashboard$$'"; echo " - '^/activate$$'"; echo " - '^/portal$$'"; echo " - '^/resubscribe$$'"; echo " - '^/stack-manage$$'"; echo ' - domain:'; echo ' - lldap.bc.a250.ca'; echo ' - whoami.bc.a250.ca'; echo ' policy: bypass'; echo ' - domain: "{user}.bc.a250.ca"'; echo ' policy: one_factor'; echo ' - domain: "*.bc.a250.ca"'; echo ' policy: deny'; } > /config/configuration.acl.yml + { echo 'access_control:'; echo ' default_policy: deny'; echo ' rules:'; echo ' - domain: login.bc.a250.ca'; echo ' policy: bypass'; echo ' - domain: app.bc.a250.ca'; echo ' policy: bypass'; echo ' resources:'; echo " - '^/$$'"; echo " - '^/subscribe$$'"; echo " - '^/success(\\?.*)?$$'"; echo " - '^/webhook/stripe$$'"; echo " - '^/resend-reset$$'"; echo " - '^/health$$'"; echo " - '^/version$$'"; echo ' - domain: app.bc.a250.ca'; echo ' policy: one_factor'; echo ' resources:'; echo " - '^/dashboard$$'"; echo " - '^/activate$$'"; echo " - '^/portal$$'"; echo " - '^/resubscribe$$'"; echo " - '^/stack-manage$$'"; echo ' - domain:'; echo ' - lldap.bc.a250.ca'; echo ' - whoami.bc.a250.ca'; echo ' policy: bypass'; echo ' - domain: "{user}.bc.a250.ca"'; echo ' policy: one_factor'; echo ' - domain: "*.bc.a250.ca"'; echo ' policy: deny'; } > /config/configuration.acl.yml exec authelia --config=/config/configuration.server.yml --config=/config/configuration.ldap.yml --config=/config/configuration.acl.yml --config=/config/configuration.notifier.yml --config=/config/configuration.identity.providers.yml --config=/config/configuration.oidc.clients.yml environment: X_AUTHELIA_EMAIL: authelia@a250.ca