lavender/auth/auth.go

100 lines
2.3 KiB
Go
Raw Permalink Normal View History

2024-09-13 15:31:40 +01:00
package auth
2024-10-06 21:30:39 +01:00
import (
"context"
"errors"
"fmt"
2025-01-19 12:04:25 +00:00
"github.com/1f349/lavender/auth/authContext"
2024-10-06 21:30:39 +01:00
"github.com/1f349/lavender/database"
"net/http"
)
2024-09-13 15:31:40 +01:00
// State defines the currently reached authentication state
type State byte
2024-10-06 21:30:39 +01:00
const (
// StateUnauthorized defines the "unauthorized" state of a session
StateUnauthorized State = iota
// StateBasic defines the "username and password with no OTP" user state
// This is skipped if OTP/passkey is optional and not enabled for the user
StateBasic
// StateExtended defines the "logged in" user state
StateExtended
// StateSudo defines the "sudo" user state
// This state is temporary and has a configurable duration
StateSudo
2024-10-06 21:30:39 +01:00
)
2024-12-09 18:40:18 +00:00
func (s State) IsLoggedIn() bool { return s >= StateExtended }
2024-12-09 18:40:18 +00:00
func (s State) IsSudoAvailable() bool { return s == StateSudo }
2024-10-06 21:30:39 +01:00
type Provider interface {
// AccessState defines the state at which the provider is allowed to show.
// Some factors might be unavailable due to user preference.
AccessState() State
2024-10-06 21:30:39 +01:00
// Name defines a string value for the provider.
2024-10-06 21:30:39 +01:00
Name() string
// RenderTemplate returns HTML to embed in the page template.
2025-01-19 12:04:25 +00:00
RenderTemplate(ctx authContext.TemplateContext) error
2024-10-06 21:30:39 +01:00
// AttemptLogin processes the login request.
2025-01-19 12:04:25 +00:00
AttemptLogin(ctx authContext.TemplateContext) error
2024-10-06 21:30:39 +01:00
}
type UserSafeError struct {
Display string
Code int
Internal error
}
func (e UserSafeError) Error() string {
return fmt.Sprintf("%s [%d]: %v", e.Display, e.Code, e.Internal)
}
func (e UserSafeError) Unwrap() error {
return e.Internal
}
func BasicUserSafeError(code int, message string) UserSafeError {
return UserSafeError{
Code: code,
Display: message,
Internal: errors.New(message),
}
}
func AdminSafeError(inner error) UserSafeError {
return UserSafeError{
Code: http.StatusInternalServerError,
Display: "Internal server error",
Internal: inner,
}
}
type RedirectError struct {
Target string
Code int
}
func (e RedirectError) TargetUrl() string { return e.Target }
func (e RedirectError) Error() string {
return fmt.Sprintf("redirect to '%s'", e.Target)
}
type LookupUserDB interface {
2024-10-06 21:30:39 +01:00
GetUser(ctx context.Context, subject string) (database.User, error)
2024-09-13 15:31:40 +01:00
}
func LookupUser(ctx context.Context, db LookupUserDB, subject string, user *database.User) error {
2024-10-06 21:30:39 +01:00
getUser, err := db.GetUser(ctx, subject)
if err != nil {
return err
}
*user = getUser
return nil
2024-09-13 15:31:40 +01:00
}