auth

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 26, 2026 License: MIT Imports: 25 Imported by: 0

Documentation

Overview

Package auth owns login state: the encrypted session cookie, the route guards, password reset tokens and the login and password endpoints.

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidCredentials = errors.New("invalid email or password")

ErrInvalidCredentials is returned for any failed login, without saying why.

View Source
var ErrTooManyAttempts = errors.New("too many sign-in attempts; try again in 15 minutes")

ErrTooManyAttempts is returned while sign-in is throttled.

Functions

func Current

func Current(c echo.Context) (user.User, bool)

Current returns the user loaded by a guard earlier in the chain.

func PasswordProblems

func PasswordProblems(pw string) string

PasswordProblems describes what a new password is missing ("" when it is acceptable). Rules match legacy minRequirementsMet, including its "longer than 8 characters" length rule.

Types

type Config

type Config struct {
	CookieName        string
	AuthenticationKey string
	EncryptionKey     string
	Secure            bool
}

Config configures the session cookie. Keys are hex encoded; an empty or invalid (non-hex) key falls back to a random one (sessions then reset on restart, exactly as today). A valid-hex key of an unexpected length (e.g. a truncated AuthenticationKey) is still used as-is — production keeps using its existing keys — but a startup warning is logged naming the weak key.

type CurrentUser

type CurrentUser struct {
	ID          int         `json:"id"`
	Name        string      `json:"name"`
	Email       string      `json:"email"`
	Phone       string      `json:"phone,omitempty"`
	Role        string      `json:"role"`
	TeamID      int         `json:"teamId,omitempty"`
	ImageURL    string      `json:"imageUrl,omitempty"`
	Permissions Permissions `json:"permissions"`
}

CurrentUser is the logged-in user as the API exposes it.

func NewCurrentUser

func NewCurrentUser(u user.User, files *upload.Files) CurrentUser

NewCurrentUser projects u for the API; it never includes password data.

type Handlers

type Handlers struct {
	// contains filtered or unexported fields
}

Handlers serves the /auth endpoints.

func NewHandlers

func NewHandlers(sessions *Sessions, svc *Service, files *upload.Files) *Handlers

func (*Handlers) Register

func (h *Handlers) Register(g *echo.Group, guards web.Guards)

Register mounts the /auth routes on the /api/v1 group.

type LoginInput

type LoginInput struct {
	Email    string `json:"email"`
	Password string `json:"password"`
	Remember bool   `json:"remember"`
}

LoginInput is the body of POST /auth/login.

type LoginResponse

type LoginResponse struct {
	User          *CurrentUser `json:"user,omitempty"`
	ResetRequired bool         `json:"resetRequired"`
	ResetURL      string       `json:"resetUrl,omitempty"`
}

LoginResponse is either the logged-in user or a reset instruction.

type LoginResult

type LoginResult struct {
	User          user.User
	ResetRequired bool
	ResetURL      string
}

LoginResult is a successful credential check. When ResetRequired is set no session should be created; the user must visit ResetURL.

type PasswordConfig

type PasswordConfig struct {
	Iterations              int
	ScryptWorkFactor        int
	ScryptBlockSize         int
	ScryptParallelismFactor int
	KeyLength               int
}

PasswordConfig holds the password hashing parameters (legacy PBKDF2 iterations plus scrypt parameters), loaded from the environment.

type PasswordInput

type PasswordInput struct {
	OldPassword          string `json:"oldPassword"`
	NewPassword          string `json:"newPassword"`
	ConfirmationPassword string `json:"confirmationPassword"`
}

PasswordInput is the body of POST /auth/password.

type Permissions

type Permissions struct {
	CanEdit          bool `json:"canEdit"`
	CanManageGallery bool `json:"canManageGallery"`
	CanManagePlayers bool `json:"canManagePlayers"`
	CanManageUsers   bool `json:"canManageUsers"`
}

Permissions tells the client which admin controls to show. The server still enforces every rule with guards.

type RedisConfig

type RedisConfig struct {
	Addresses  []string
	MasterName string
	Username   string
	Password   string
	DB         int
	TLS        bool
	// KeyPrefix namespaces keys per environment, e.g. "afc:prod:". Defaults to "afc:".
	KeyPrefix string
}

RedisConfig configures the optional Redis/Valkey used to share reset tokens across instances. With no Addresses an in-process cache is used, which only works for a single instance.

type ResetInput

type ResetInput struct {
	NewPassword          string `json:"newPassword"`
	ConfirmationPassword string `json:"confirmationPassword"`
}

ResetInput is the body of POST /auth/reset/{token}.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service handles logins and password changes.

func NewService

func NewService(users UserStore, tokens *Tokens, passwords PasswordConfig) *Service

func (*Service) ChangePassword

func (s *Service) ChangePassword(ctx context.Context, u user.User, oldPassword, newPassword, confirm string) (user.User, error)

ChangePassword changes the logged-in user's password after re-checking the old one. The change signs the user out everywhere, so it returns the user as they now are, for the caller to start a fresh session with.

func (*Service) CheckResetToken

func (s *Service) CheckResetToken(ctx context.Context, token string) error

CheckResetToken reports NotFound for an unknown or expired token.

func (*Service) Login

func (s *Service) Login(ctx context.Context, email, password, ip string) (LoginResult, error)

Login checks credentials. A reset-flagged account (Task 21: only after a correct password) gets a one-hour reset link instead of a session. Too many failures for the email address or from ip return ErrTooManyAttempts.

func (*Service) ResetPassword

func (s *Service) ResetPassword(ctx context.Context, token, newPassword, confirm string) error

ResetPassword sets a new password using a single-use reset token.

type Sessions

type Sessions struct {
	// contains filtered or unexported fields
}

Sessions reads and writes the session cookie.

func NewSessions

func NewSessions(conf Config, users UserGetter) *Sessions

func (*Sessions) CookieStore

func (s *Sessions) CookieStore() *sessions.CookieStore

CookieStore exposes the underlying store (tests decode the cookie with it).

func (*Sessions) Guards

func (s *Sessions) Guards() web.Guards

Guards returns the guard set handlers attach to routes.

func (*Sessions) Identify

func (s *Sessions) Identify(next echo.HandlerFunc) echo.HandlerFunc

Identify loads the user when a valid session is present, but lets anonymous (or stale-session) requests through.

func (*Sessions) Login

func (s *Sessions) Login(w http.ResponseWriter, r *http.Request, u user.User, remember bool) error

Login records u in the session. remember extends the cookie to 31 days.

func (*Sessions) Logout

func (s *Sessions) Logout(w http.ResponseWriter, r *http.Request) error

Logout clears the session and expires the cookie.

func (*Sessions) Name

func (s *Sessions) Name() string

Name is the session cookie name.

func (*Sessions) Refresh

func (s *Sessions) Refresh(w http.ResponseWriter, r *http.Request, u user.User) error

Refresh reissues the current session for u (e.g. after the user changed their own password, which bumps their session version), keeping its "remember me" length.

func (*Sessions) RequireLogin

func (s *Sessions) RequireLogin(next echo.HandlerFunc) echo.HandlerFunc

RequireLogin rejects anonymous requests with 401. It reloads the user from the database so role changes and deletions take effect immediately.

func (*Sessions) RequireRole

func (s *Sessions) RequireRole(allowed func(role.Role) bool) echo.MiddlewareFunc

RequireRole rejects anonymous requests with 401 and users whose role fails allowed with 403.

func (*Sessions) User

func (s *Sessions) User(r *http.Request) (user.User, bool)

User returns the user recorded in the session cookie, without touching the database. ok is false when nobody is logged in.

type Tokens

type Tokens struct {
	// contains filtered or unexported fields
}

Tokens stores one-time password reset tokens.

func NewTokens

func NewTokens(conf RedisConfig) *Tokens

func (*Tokens) Close

func (t *Tokens) Close()

Close releases the Redis client, if any.

func (*Tokens) Delete

func (t *Tokens) Delete(ctx context.Context, token string)

Delete invalidates a token after use.

func (*Tokens) Get

func (t *Tokens) Get(ctx context.Context, token string) (int, bool)

Get returns the user ID a token was issued for.

func (*Tokens) Set

func (t *Tokens) Set(ctx context.Context, token string, userID int, ttl time.Duration) error

Set maps token to userID for ttl.

type UserGetter

type UserGetter interface {
	GetUser(ctx context.Context, u user.User) (user.User, error)
}

UserGetter loads a user from the database (satisfied by *user.Store).

type UserStore

type UserStore interface {
	GetUser(ctx context.Context, userParam user.User) (user.User, error)
	VerifyUser(ctx context.Context, userParam user.User, iter, workFactor, blockSize, parallelismFactor, keyLen int) (user.User, bool, error)
	EditUserPassword(ctx context.Context, userParam user.User, workFactor, blockSize, parallelismFactor, keyLen int) error
}

UserStore is the credential side of the user store (satisfied by *user.Store).

Directories

Path Synopsis
Package authtest builds sessions and cookies for handler tests.
Package authtest builds sessions and cookies for handler tests.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL