diff --git a/internal/data/user/user.go b/internal/data/user/user.go index 6d6a8630..8cee2150 100644 --- a/internal/data/user/user.go +++ b/internal/data/user/user.go @@ -129,11 +129,38 @@ func create(username, email, password string) (*User, error) { type Error struct { invalid map[string]string + + // missingEmail gets set when the user tries to log in without a real email. + // This causes the frontend to respond with an "Invalid email or password" message. + // Might want to change this implementation later, just needed something quick. + missingEmail string + missingHash string } -func (err Error) Invalid() map[string]string { return err.invalid } +func (err Error) Invalid() map[string]string { + switch { + case err.missingHash != "": + return map[string]string{ + "confirmation_hash": "Confirmation token unknown or already used.", + } + case err.missingEmail != "": + return map[string]string{ + "email": "Invalid email or password.", + "password": "Invalid email or password.", + } + default: + return err.invalid + } +} func (err Error) Error() string { + switch { + case err.missingEmail != "": + return fmt.Sprintf("user with email %q not found", err.missingEmail) + case err.missingHash != "": + return fmt.Sprintf("user confirmation hash %q", err.missingHash) + } + switch len(err.invalid) { case 0: return "user validation failed" diff --git a/internal/data/user/user_postgres.go b/internal/data/user/user_postgres.go index 4f4c2af9..bb889155 100644 --- a/internal/data/user/user_postgres.go +++ b/internal/data/user/user_postgres.go @@ -56,7 +56,7 @@ func (d *Postgres) ConfirmUser(ctx context.Context, confirmation string) error { if tag, err := d.db.Exec(ctx, q, confirmation); err != nil { return fmt.Errorf("set postgres confirmation_hash to NULL: %w", err) } else if tag.RowsAffected() == 0 { - return errors.New("unknown confirmation_hash in postgres") + return Error{missingHash: confirmation} } return nil @@ -79,7 +79,7 @@ func (d *Postgres) FindUserByEmail(ctx context.Context, email string) (*User, er &u.CreatedAt, &u.UpdatedAt, ); err == pgx.ErrNoRows { - return nil, fmt.Errorf("user (email %q) not found in postgres", email) + return nil, Error{missingEmail: email} } else if err != nil { return nil, err } diff --git a/internal/data/user/user_sqlite.go b/internal/data/user/user_sqlite.go index a871c09c..6bd20adb 100644 --- a/internal/data/user/user_sqlite.go +++ b/internal/data/user/user_sqlite.go @@ -82,7 +82,7 @@ func (d *SQLite) ConfirmUser(ctx context.Context, confirmation string) error { } if conn.Changes() == 0 { - return errors.New("unknown confirmation_hash in sqlite") + return Error{missingHash: confirmation} } return nil @@ -105,7 +105,7 @@ func (d *SQLite) FindUserByEmail(ctx context.Context, email string) (*User, erro if found, err := stmt.Step(); err != nil { return nil, err } else if !found { - return nil, fmt.Errorf("user (email %q) not found in sqlite", email) + return nil, Error{missingEmail: email} } usr, err := sqliteUser(stmt) diff --git a/internal/frontend/account/login.go b/internal/frontend/account/login.go index 8bc44a1c..7c375b05 100644 --- a/internal/frontend/account/login.go +++ b/internal/frontend/account/login.go @@ -37,12 +37,12 @@ func (srv server) loginForm(w http.ResponseWriter, r *http.Request) { usr, err := srv.userdb.FindUserByEmail(ctx, email) if err != nil { - srv.http.Fail(ctx, w, err, "msg", "find user for auth") + srv.http.Fail(ctx, w, err, "login.tmpl", "msg", "find user for auth") return } if err := usr.ValidatePassword(password); err != nil { - srv.http.Fail(ctx, w, err, "msg", "auth user") + srv.http.Fail(ctx, w, err, "login.tmpl", "msg", "auth user") return } diff --git a/internal/frontend/account/register.go b/internal/frontend/account/register.go index 1d132568..7f29ceae 100644 --- a/internal/frontend/account/register.go +++ b/internal/frontend/account/register.go @@ -70,7 +70,7 @@ func (srv server) registerConfirm(w http.ResponseWriter, r *http.Request) { } if err := srv.userdb.ConfirmUser(ctx, confirmation); err != nil { - srv.http.Fail(ctx, w, err, "msg", "confirm user", "confirmation_hash", confirmation) + srv.http.Fail(ctx, w, err, "msg", "register-confirmed.tmpl", "confirm user", "confirmation_hash", confirmation) return } diff --git a/pkg/frontend/frontend.go b/pkg/frontend/frontend.go index 102bd67d..fe192d89 100644 --- a/pkg/frontend/frontend.go +++ b/pkg/frontend/frontend.go @@ -182,6 +182,7 @@ func (srv *Server) Fail(ctx context.Context, w http.ResponseWriter, err error, k return } + tpl = "500.tmpl" // set back to Internal Server Error srv.RenderTemplate(ctx, w, tpl, Data{}. WithLog(err, keyvals...). WithCode(http.StatusInternalServerError), diff --git a/ui/includes/register-confirmed.tmpl b/ui/includes/register-confirmed.tmpl index 7cd5db71..6a919bec 100644 --- a/ui/includes/register-confirmed.tmpl +++ b/ui/includes/register-confirmed.tmpl @@ -6,8 +6,12 @@
- We confirmed your account. You can now use the site. + {{- if .errors -}} +