Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 23 additions & 16 deletions cmd/web/handlers:login.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,41 @@ func (app *application) redirectAfterLogin(ctx context.Context, w http.ResponseW
}
}

type signInData struct {
OIDCProviders []string
EnableEmailPasswordSignup bool
}

func (app *application) getSignIn(w http.ResponseWriter, r *http.Request) *httperr.Error {
names := make([]string, 0, len(app.oidcProviders))
for name := range app.oidcProviders {
names = append(names, name)
}

tmplData := app.html.TemplateData(r)
tmplData.Form = accounts.NewSignInForm()
tmplData.Data = app.loginData()
tmplData.Data = signInData{
EnableEmailPasswordSignup: app.options.EnableEmailPasswordSignup,
OIDCProviders: names,
}
return app.html.Render(w, r, http.StatusOK, pages.SignIn, tmplData)
}

func (app *application) postSignIn(w http.ResponseWriter, r *http.Request) *httperr.Error {
ctx := r.Context()

fail := func(formWithErrors *accounts.SignInForm) *httperr.Error {
names := make([]string, 0, len(app.oidcProviders))
for name := range app.oidcProviders {
names = append(names, name)
}

data := app.html.TemplateData(r)
data.Form = formWithErrors
data.Data = app.loginData()
data.Data = signInData{
EnableEmailPasswordSignup: app.options.EnableEmailPasswordSignup,
OIDCProviders: names,
}
return app.html.Render(w, r, http.StatusUnprocessableEntity, pages.SignIn, data)
}

Expand Down Expand Up @@ -263,20 +284,6 @@ func (app *application) postSignOut(w http.ResponseWriter, r *http.Request) *htt
return nil
}

// LoginData carries the set of enabled OIDC provider names to the sign-in and
// sign-up templates so they can render the appropriate provider buttons.
type LoginData struct {
OIDCProviders []string
}

func (app *application) loginData() LoginData {
names := make([]string, 0, len(app.oidcProviders))
for name := range app.oidcProviders {
names = append(names, name)
}
return LoginData{OIDCProviders: names}
}

// getAuthOIDC initiates the OIDC login flow for the named provider. It generates
// a random state token, stores it in the session for CSRF verification, then
// redirects the browser to the provider's authorization endpoint.
Expand Down
7 changes: 7 additions & 0 deletions cmd/web/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ type options struct {
SMTP SMTP // has SECRET
OIDCProviders OIDCProviderMap // has SECRET
Limits Limits

// EnableEmailPasswordSignup controls whether users can sign up with email and password.
// Selfhosters can signup once to create an account and then disable email password signup
// to prevent further unwanted signups.
EnableEmailPasswordSignup bool
}

func parseOptions(args []string) (*options, error) {
Expand All @@ -60,6 +65,8 @@ func parseOptions(args []string) (*options, error) {
fs.StringVar(&cfg.SMTP.Password, "smtp-password", envOr("SMTP_PASSWORD", ""), "SMTP password (prefer SMTP_PASSWORD env var over flag)")
fs.StringVar(&cfg.SMTP.From, "smtp-from", "", "from address for outgoing mail")

fs.BoolVar(&cfg.EnableEmailPasswordSignup, "enable-email-password-signup", true, "enable email and password signup (default true)")

if err := fs.Parse(args); err != nil {
return nil, fmt.Errorf("parseServeOptions: %w", err)
}
Expand Down
6 changes: 4 additions & 2 deletions cmd/web/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ func (app *application) routes() (http.Handler, error) {
// Login related routes that are only accessible if the user is not logged in.
mux.Handle("GET /signin", app.withGuest(app.html.Handle(app.getSignIn)))
mux.Handle("POST /signin", app.withGuest(app.html.Handle(app.postSignIn)))
mux.Handle("GET /signup", app.withGuest(app.html.Handle(app.getSignUp)))
mux.Handle("POST /signup", app.withGuest(app.html.Handle(app.postSignUp)))
if app.options.EnableEmailPasswordSignup {
mux.Handle("GET /signup", app.withGuest(app.html.Handle(app.getSignUp)))
mux.Handle("POST /signup", app.withGuest(app.html.Handle(app.postSignUp)))
}
mux.Handle("GET /forgot-password", app.withGuest(app.html.Handle(app.getForgotPassword)))
mux.Handle("POST /forgot-password", app.withGuest(app.html.Handle(app.postForgotPassword)))
mux.Handle("GET /forgot-password/success", app.withGuest(app.html.Handle(app.getForgotPasswordSuccess)))
Expand Down
6 changes: 6 additions & 0 deletions internal/templates/pages/docs.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,12 @@
<td><code class="font-mono text-xs">error</code></td>
<td><code class="font-mono text-xs">debug</code>, <code class="font-mono text-xs">info</code>, <code class="font-mono text-xs">warn</code>, <code class="font-mono text-xs">error</code></td>
</tr>
<tr>
<td class="w-full"><code class="badge badge-neutral font-mono">-enable-email-password-signup</code></td>
<td>—</td>
<td><code class="font-mono text-xs">true</code></td>
<td>enable email and password signup (default true)</td>
</tr>

<tr class="bg-base-200/50">
<td colspan="4" class="text-xs uppercase tracking-wider py-1">
Expand Down
2 changes: 2 additions & 0 deletions internal/templates/pages/login/signin.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@
{{ end }}
{{ end }}

{{ if .Data.EnableEmailPasswordSignup }}
<p class="label justify-center">
Don't have an account?
<a href="/signup" class="link link-hover">Sign up.</a>
</p>
{{ end }}
</fieldset>
</form>
</div>
Expand Down