papers

package module
v0.0.0-...-6653ad0 Latest Latest
Warning

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

Go to latest
Published: May 18, 2024 License: MIT Imports: 8 Imported by: 0

README

Not ready for use.

Documentation

Index

Constants

View Source
const (
	// Startup errors
	ErrNoUserStorage    = ConstError("No UserStorage defined")
	ErrNoTokenStorage   = ConstError("No TokenStorage defined")
	ErrNoClientStorage  = ConstError("No CookieStorage defined")
	ErrNoSessionStorage = ConstError("No SessionStorage defined")
	ErrNoRouteParams    = ConstError("No RouteParams defined")

	// Generic errors
	ErrStorageError = ConstError("Unexpected storage error")
	ErrCryptoError  = ConstError("Unexpected cryptography error")

	// Storage errors
	ErrUserNotFound      = ConstError("User not found")
	ErrTokenNotFound     = ConstError("Token not found")
	ErrCookieNotFound    = ConstError("Cookie not found")
	ErrCookieError       = ConstError("Unexpected cookie error")
	ErrCookieDecodeError = ConstError("Couldn't decode cookie")
	ErrCookieEncodeError = ConstError("Couldn't encode cookie")
	ErrSessionError      = ConstError("Unexpected session error")
	ErrSessionMissingKey = ConstError("Session doesn't contain this key")

	// Registration errors
	ErrRegistrationFailed = ConstError("Registration failed")
	ErrDuplicateEmail     = ConstError("Email already in use")
	ErrInvalidEmail       = ConstError("Invalid email address")
	ErrMissingEmail       = ConstError("Email is required")
	ErrDuplicateUsername  = ConstError("Username already in use")
	ErrInvalidUsername    = ConstError("Invalid username")
	ErrMissingUsername    = ConstError("Username is required")
	ErrUsernameTooShort   = ConstError("Username is too short")
	ErrInvalidPassword    = ConstError("Invalid password")
	ErrPasswordError      = ConstError("There was a problem with the password")

	// Login errors
	ErrPasswordMismatch = ConstError("Password mismatch")
	ErrLoginFailed      = ConstError("Login failed")
	ErrUserLocked       = ConstError("Account is locked")

	// TOTP errors
	ErrTOTPUnexpected    = ConstError("Unexpected TOTP request")
	ErrTOTPGenerateError = ConstError("Unexpected TOTP generation error")
	ErrTOTPAlreadySetup  = ConstError("User already has TOTP setup")
	ErrTOTPQRError       = ConstError("Failed to create TOTP QR code")
	ErrTOTPMismatch      = ConstError("TOTP code doesn't match")

	// OAuth2 errors
	ErrOAuth2BadProvider    = ConstError("Invalid OAuth2 provider")
	ErrOAuth2BadState       = ConstError("Invalid OAuth2 state")
	ErrOAuth2LoginFailed    = ConstError("OAuth2 login failed")
	ErrOAuth2ExchangeFailed = ConstError("OAuth2 token exchange failed")
	ErrOAuth2IdentityFailed = ConstError("Couldn't get OAuth2 identity")

	// Mailer errors
	ErrMessageFailed     = ConstError("Failed to send email")
	ErrNoMessageTemplate = ConstError("Missing email template")
)
View Source
const (
	MessageConfirmation = MessageType("confirmation")
	MessageRecovery     = MessageType("recovery")
	MessageLocked       = MessageType("locked")
)

Variables

This section is empty.

Functions

func ComparePassword

func ComparePassword(hash, password string) error

func HashPassword

func HashPassword(p *Papers, password string) (string, error)

Types

type AccessToken

type AccessToken struct {
	Identity    int64     `json:"id"`
	Token       string    `json:"to"`
	Expiration  time.Time `json:"ex"`
	Roles       []string  `json:"ro"`
	Permissions []string  `json:"pe"`
	Chain       string    `json:"ch"`
}

type Config

type Config struct {
	Storage struct {
		Users      UserStorage
		Tokens     TokenStorage
		Cookies    CookieStorage
		Session    SessionStorage
		TokenCache TokenCache
	}

	Mailer struct {
		Mailer Mailer
		From   Email
	}

	Routes struct {
		// Path of the confirmation page with a printf style placeholder for the token, e.g. /confirm/%s
		Confirm string
		// Path of the recovery page for the forgot password flow with a printf style placeholder for the token, e.g. /recover/%s
		Recover string
	}

	// Adapter for getting parameters from the current request
	RouteParams RouteParams

	// Complete root level URL of the application, with no trailing slash, e.g. https://example.com
	BaseURL string
	// Name of the application (used when generating TOTP secret)
	ApplicationName string

	// Key to use when storing the logged in User in the request context
	UserContextKey string

	// Require a standard email/password account to be confirmed before being usable
	RequireConfirmation bool
	// Require a username when registering an account
	RequireUsername bool
	// Require usernames to be unique
	UniqueUsernames bool
	// Minimum length of a username
	UsernameMinLength int

	BCryptCost        int
	PasswordMinLength int
	// Require both lower and upper case letters
	PasswordRequireMixedCase bool
	// Require at least one number
	PasswordRequireNumbers bool
	// Require at least one special character
	PasswordRequireSpecials bool
	// Password length that other character requirements are ignored. Intended to allow for passphrases
	PasswordRelaxedLength int

	// Width/height of TOTP setup QR code
	TOTPQRSize int
	// If set, key used to encrypt the TOTP secret before saving it in storage. Must be 16/24/32 bytes for AES-128/AES-192/AES-256 respectively
	TOTPSecretEncryptionKey string

	OAuth2Providers map[string]OAuth2Provider

	// Name of the login token cookie
	LoginCookieName string
	// Name of the access token cookie
	AccessCookieName string
	// Name of the refresh token cookie
	RefreshCookieName string

	// How long until an access token expires
	AccessExpiration time.Duration
	// How long until a refresh token expires
	RefreshExpiration time.Duration
	// How long until a recovery token expires
	RecoveryExpiration time.Duration
	// How long tokens are cached before expiring
	TokenCacheExpiration time.Duration

	// How much leeway is given when checking token expiration
	ExpirationLeeway time.Duration

	// Store all access tokens for extra verification, instead of only storing invalidated access tokens
	StoreAllAccessTokens bool
	// Invalidate and issue a new refresh token each time a refresh token is used
	RotateRefreshTokens bool

	// How long to wait between pruning expired access tokens. 0 to disable
	PruneAccessTokensInterval time.Duration
	// How long to wait between pruning expired refresh tokens. 0 to disable
	PruneRefreshTokensInterval time.Duration

	// How old access tokens must be before they are pruned
	StaleAccessTokensAge time.Duration
	// How old refresh tokens must be before they are pruned
	StaleRefreshTokensAge time.Duration

	// Temporarily lock accounts that have too many failed login attempts
	Locking bool
	// The number of failed login attempts to allow before locking an account
	LockAttempts int
	// How long to wait after a failed login attempt before resetting the number of attempts
	LockWindow time.Duration
	// How long to lock an account after too many failed attempts
	LockDuration time.Duration
}

type ConstError

type ConstError string

func (ConstError) Error

func (e ConstError) Error() string

type CookieStorage

type CookieStorage interface {
	Read(name string, r *http.Request, value interface{}) error
	Write(name string, w http.ResponseWriter, maxAge time.Duration, value interface{}) error
	Remove(name string, w http.ResponseWriter)
}

type Email

type Email struct {
	Address string
	Name    string
}

type Mailer

type Mailer interface {
	SendMessage(ctx context.Context, p *Papers, msg Message) error
}

type Message

type Message struct {
	Type    MessageType
	To      []Email
	Cc      []Email
	Bcc     []Email
	ReplyTo []Email
	Data    map[string]interface{}
}

type MessageType

type MessageType string

type OAuth2Identity

type OAuth2Identity interface {
	GetID() string
	GetEmail() string
}

type OAuth2Provider

type OAuth2Provider struct {
	Config      oauth2.Config
	GetIdentity func(ctx context.Context, cfg oauth2.Config, token *oauth2.Token) (OAuth2Identity, error)
}

type Papers

type Papers struct {
	Config Config
	Logger *slog.Logger
	Roles  map[string][]string
}

func New

func New() *Papers

func (*Papers) IsUserConfirmed

func (p *Papers) IsUserConfirmed(u User) bool

func (*Papers) IsUserLocked

func (p *Papers) IsUserLocked(u User) bool

func (*Papers) IsUserValid

func (p *Papers) IsUserValid(u User) bool

func (*Papers) LoadUserRoles

func (p *Papers) LoadUserRoles(ctx context.Context, u User) error

func (*Papers) LoggedInUser

func (p *Papers) LoggedInUser(r *http.Request) (User, bool)

func (*Papers) NewAccessToken

func (p *Papers) NewAccessToken(ctx context.Context, userID int64, refresh *RefreshToken) (*AccessToken, error)

func (*Papers) NewAccessTokenFromRefreshToken

func (p *Papers) NewAccessTokenFromRefreshToken(ctx context.Context, refresh *RefreshToken) (*AccessToken, *RefreshToken, error)

func (*Papers) NewRefreshToken

func (p *Papers) NewRefreshToken(ctx context.Context, access *AccessToken) (*RefreshToken, error)

func (*Papers) SetDefaultConfig

func (p *Papers) SetDefaultConfig()

func (*Papers) Start

func (p *Papers) Start(ctx context.Context) error

func (*Papers) UserHasRole

func (p *Papers) UserHasRole(ctx context.Context, u User, role string) bool

func (*Papers) UserHasTOTP

func (p *Papers) UserHasTOTP(u User) bool

type RefreshToken

type RefreshToken struct {
	Identity int64  `json:"id"`
	Token    string `json:"to"`
	Chain    string `json:"ch"`
	Limited  bool   `json:"li"`
}

type RouteParams

type RouteParams interface {
	Get(r *http.Request, key string) string
}

type SessionStorage

type SessionStorage interface {
	Get(r *http.Request, key string) (string, error)
	Set(r *http.Request, key string, value string) error
	MultiSet(r *http.Request, vals map[string]string) error
	Delete(r *http.Request, key string) error
	MultiDelete(r *http.Request, keys []string) error
	Write(r *http.Request, w http.ResponseWriter) error
}

type TTLStorage

type TTLStorage interface {
	Set(key string, value string, expiration time.Duration)
	Get(key string) (string, bool)
}

type Token

type Token interface {
	GetUserID() int64
	GetToken() string
	GetValid() bool
	GetChain() string
	GetCreatedAt() time.Time

	SetUserID(id int64)
	SetToken(token string)
	SetValid(valid bool)
	SetChain(chain string)
	SetCreatedAt(at time.Time)
}

type TokenCache

type TokenCache interface {
	IsTokenValid(token, chain string) (bool, bool)
	SetTokenValidity(token string, valid bool)
	SetChainValidity(chain string, valid bool)
}

type TokenStorage

type TokenStorage interface {
	CreateAccessToken(ctx context.Context, userID int64, token, chain string, valid bool) error
	CreateRefreshToken(ctx context.Context, userID int64, token, chain string, valid bool) error
	GetAccessToken(ctx context.Context, userID int64, token string) (Token, error)
	GetRefreshToken(ctx context.Context, userID int64, token string) (Token, error)
	InvalidateAccessTokens(ctx context.Context, userID int64) error
	InvalidateRefreshToken(ctx context.Context, userID int64, token string) error
	InvalidateRefreshTokens(ctx context.Context, userID int64) error
	InvalidateTokenChain(ctx context.Context, userID int64, chain string) error
	PruneAccessTokens(ctx context.Context, timeToStale time.Duration) error
	PruneRefreshTokens(ctx context.Context, timeToStale time.Duration) error
}

type User

type User interface {
	GetID() int64
	GetEmail() string
	GetUsername() string
	GetPassword() string
	GetConfirmed() bool
	GetConfirmToken() string
	GetRecoveryToken() string
	GetLockedUntil() time.Time
	GetAttempts() int
	GetLastAttempt() time.Time
	GetCreatedAt() time.Time
	GetLastLogin() time.Time
	GetTOTPSecret() string
	GetRoles() []string

	SetID(id int64)
	SetEmail(email string)
	SetUsername(username string)
	SetPassword(password string)
	SetConfirmed(confirmed bool)
	SetConfirmToken(token string)
	SetRecoveryToken(token string)
	SetLockedUntil(until time.Time)
	SetAttempts(attempts int)
	SetLastAttempt(at time.Time)
	SetCreatedAt(at time.Time)
	SetLastLogin(at time.Time)
	SetTOTPSecret(secret string)
	SetRoles(roles []string)
}

type UserStorage

type UserStorage interface {
	// Factory method that returns an empty User
	NewUser() User
	// Persists a new user. The storage implementation must call User.SetID with the new ID
	CreateUser(ctx context.Context, user User) error
	UpdateUser(ctx context.Context, user User) error
	CreateOAuth2Identity(ctx context.Context, user User, provider, identity string) error
	RemoveOAuth2Identity(ctx context.Context, user User, provider, identity string) error
	GetUserByID(ctx context.Context, id int64) (User, error)
	GetUserByEmail(ctx context.Context, email string) (User, error)
	GetUserByUsername(ctx context.Context, username string) (User, error)
	GetUserByOAuth2Identity(ctx context.Context, provider, identity string) (User, error)
	GetUserByConfirmationToken(ctx context.Context, token string) (User, error)
	GetUserByRecoveryToken(ctx context.Context, token string) (User, error)
	GetUserRoles(ctx context.Context, user User) ([]string, error)
	GetUserPermissions(ctx context.Context, user User) ([]string, error)
}

Directories

Path Synopsis
oauth2
chi

Jump to

Keyboard shortcuts

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