user

package
v2.7.1 Latest Latest
Warning

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

Go to latest
Published: Nov 12, 2023 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package user deals with authentication and authorization against topics

Index

Constants

View Source
const (
	DefaultUserStatsQueueWriterInterval = 33 * time.Second
	DefaultUserPasswordBcryptCost       = 10
)

Default constants that may be overridden by configs

View Source
const (
	RoleAdmin     = Role("admin") // Some queries have these values hardcoded!
	RoleUser      = Role("user")
	RoleAnonymous = Role("anonymous")
)

User roles

View Source
const (
	Everyone = "*"
)

Everyone is a special username representing anonymous users

Variables

View Source
var (
	ErrUnauthenticated     = errors.New("unauthenticated")
	ErrUnauthorized        = errors.New("unauthorized")
	ErrInvalidArgument     = errors.New("invalid argument")
	ErrUserNotFound        = errors.New("user not found")
	ErrUserExists          = errors.New("user already exists")
	ErrTierNotFound        = errors.New("tier not found")
	ErrTokenNotFound       = errors.New("token not found")
	ErrPhoneNumberNotFound = errors.New("phone number not found")
	ErrTooManyReservations = errors.New("new tier has lower reservation limit")
	ErrPhoneNumberExists   = errors.New("phone number already exists")
)

Error constants used by the package

Functions

func AllowedRole

func AllowedRole(role Role) bool

AllowedRole returns true if the given role can be used for new users

func AllowedTier

func AllowedTier(tier string) bool

AllowedTier returns true if the given tier name is valid

func AllowedTopic

func AllowedTopic(topic string) bool

AllowedTopic returns true if the given topic name is valid

func AllowedTopicPattern

func AllowedTopicPattern(topic string) bool

AllowedTopicPattern returns true if the given topic pattern is valid; this includes the wildcard character (*)

func AllowedUsername

func AllowedUsername(username string) bool

AllowedUsername returns true if the given username is valid

Types

type Auther

type Auther interface {
	// Authenticate checks username and password and returns a user if correct. The method
	// returns in constant-ish time, regardless of whether the user exists or the password is
	// correct or incorrect.
	Authenticate(username, password string) (*User, error)

	// Authorize returns nil if the given user has access to the given topic using the desired
	// permission. The user param may be nil to signal an anonymous user.
	Authorize(user *User, topic string, perm Permission) error
}

Auther is an interface for authentication and authorization

type Billing

type Billing struct {
	StripeCustomerID            string
	StripeSubscriptionID        string
	StripeSubscriptionStatus    stripe.SubscriptionStatus
	StripeSubscriptionInterval  stripe.PriceRecurringInterval
	StripeSubscriptionPaidUntil time.Time
	StripeSubscriptionCancelAt  time.Time
}

Billing is a struct holding a user's billing information

type Grant

type Grant struct {
	TopicPattern string // May include wildcard (*)
	Allow        Permission
}

Grant is a struct that represents an access control entry to a topic by a user

type Manager

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

Manager is an implementation of Manager. It stores users and access control list in a SQLite database.

func NewManager

func NewManager(filename, startupQueries string, defaultAccess Permission, bcryptCost int, queueWriterInterval time.Duration) (*Manager, error)

NewManager creates a new Manager instance

func (*Manager) AddPhoneNumber

func (a *Manager) AddPhoneNumber(userID string, phoneNumber string) error

AddPhoneNumber adds a phone number to the user with the given user ID

func (*Manager) AddReservation

func (a *Manager) AddReservation(username string, topic string, everyone Permission) error

AddReservation creates two access control entries for the given topic: one with full read/write access for the given user, and one for Everyone with the permission passed as everyone. The user also owns the entries, and can modify or delete them.

func (*Manager) AddTier

func (a *Manager) AddTier(tier *Tier) error

AddTier creates a new tier in the database

func (*Manager) AddUser

func (a *Manager) AddUser(username, password string, role Role) error

AddUser adds a user with the given username, password and role

func (*Manager) AllGrants

func (a *Manager) AllGrants() (map[string][]Grant, error)

AllGrants returns all user-specific access control entries, mapped to their respective user IDs

func (*Manager) AllowAccess

func (a *Manager) AllowAccess(username string, topicPattern string, permission Permission) error

AllowAccess adds or updates an entry in th access control list for a specific user. It controls read/write access to a topic. The parameter topicPattern may include wildcards (*). The ACL entry owner may either be a user (username), or the system (empty).

func (*Manager) AllowReservation

func (a *Manager) AllowReservation(username string, topic string) error

AllowReservation tests if a user may create an access control entry for the given topic. If there are any ACL entries that are not owned by the user, an error is returned.

func (*Manager) Authenticate

func (a *Manager) Authenticate(username, password string) (*User, error)

Authenticate checks username and password and returns a User if correct, and the user has not been marked as deleted. The method returns in constant-ish time, regardless of whether the user exists or the password is correct or incorrect.

func (*Manager) AuthenticateToken

func (a *Manager) AuthenticateToken(token string) (*User, error)

AuthenticateToken checks if the token exists and returns the associated User if it does. The method sets the User.Token value to the token that was used for authentication.

func (*Manager) Authorize

func (a *Manager) Authorize(user *User, topic string, perm Permission) error

Authorize returns nil if the given user has access to the given topic using the desired permission. The user param may be nil to signal an anonymous user.

func (*Manager) ChangeBilling

func (a *Manager) ChangeBilling(username string, billing *Billing) error

ChangeBilling updates a user's billing fields, namely the Stripe customer ID, and subscription information

func (*Manager) ChangePassword

func (a *Manager) ChangePassword(username, password string) error

ChangePassword changes a user's password

func (*Manager) ChangeRole

func (a *Manager) ChangeRole(username string, role Role) error

ChangeRole changes a user's role. When a role is changed from RoleUser to RoleAdmin, all existing access control entries (Grant) are removed, since they are no longer needed.

func (*Manager) ChangeSettings

func (a *Manager) ChangeSettings(userID string, prefs *Prefs) error

ChangeSettings persists the user settings

func (*Manager) ChangeTier

func (a *Manager) ChangeTier(username, tier string) error

ChangeTier changes a user's tier using the tier code. This function does not delete reservations, messages, or attachments, even if the new tier has lower limits in this regard. That has to be done elsewhere.

func (*Manager) ChangeToken

func (a *Manager) ChangeToken(userID, token string, label *string, expires *time.Time) (*Token, error)

ChangeToken updates a token's label and/or expiry date

func (*Manager) Close

func (a *Manager) Close() error

Close closes the underlying database

func (*Manager) CreateToken

func (a *Manager) CreateToken(userID, label string, expires time.Time, origin netip.Addr) (*Token, error)

CreateToken generates a random token for the given user and returns it. The token expires after a fixed duration unless ChangeToken is called. This function also prunes tokens for the given user, if there are too many of them.

func (*Manager) DefaultAccess

func (a *Manager) DefaultAccess() Permission

DefaultAccess returns the default read/write access if no access control entry matches

func (*Manager) EnqueueTokenUpdate

func (a *Manager) EnqueueTokenUpdate(tokenID string, update *TokenUpdate)

EnqueueTokenUpdate adds the token update to a queue which writes out token access times in batches at a regular interval

func (*Manager) EnqueueUserStats

func (a *Manager) EnqueueUserStats(userID string, stats *Stats)

EnqueueUserStats adds the user to a queue which writes out user stats (messages, emails, ..) in batches at a regular interval

func (*Manager) Grants

func (a *Manager) Grants(username string) ([]Grant, error)

Grants returns all user-specific access control entries

func (*Manager) HasReservation

func (a *Manager) HasReservation(username, topic string) (bool, error)

HasReservation returns true if the given topic access is owned by the user

func (*Manager) MarkUserRemoved

func (a *Manager) MarkUserRemoved(user *User) error

MarkUserRemoved sets the deleted flag on the user, and deletes all access tokens. This prevents successful auth via Authenticate. A background process will delete the user at a later date.

func (*Manager) PhoneNumbers

func (a *Manager) PhoneNumbers(userID string) ([]string, error)

PhoneNumbers returns all phone numbers for the user with the given user ID

func (*Manager) RemoveDeletedUsers

func (a *Manager) RemoveDeletedUsers() error

RemoveDeletedUsers deletes all users that have been marked deleted for

func (*Manager) RemoveExpiredTokens

func (a *Manager) RemoveExpiredTokens() error

RemoveExpiredTokens deletes all expired tokens from the database

func (*Manager) RemovePhoneNumber

func (a *Manager) RemovePhoneNumber(userID string, phoneNumber string) error

RemovePhoneNumber deletes a phone number from the user with the given user ID

func (*Manager) RemoveReservations

func (a *Manager) RemoveReservations(username string, topics ...string) error

RemoveReservations deletes the access control entries associated with the given username/topic, as well as all entries with Everyone/topic. This is the counterpart for AddReservation.

func (*Manager) RemoveTier

func (a *Manager) RemoveTier(code string) error

RemoveTier deletes the tier with the given code

func (*Manager) RemoveToken

func (a *Manager) RemoveToken(userID, token string) error

RemoveToken deletes the token defined in User.Token

func (*Manager) RemoveUser

func (a *Manager) RemoveUser(username string) error

RemoveUser deletes the user with the given username. The function returns nil on success, even if the user did not exist in the first place.

func (*Manager) ReservationOwner

func (a *Manager) ReservationOwner(topic string) (string, error)

ReservationOwner returns user ID of the user that owns this topic, or an empty string if it's not owned by anyone

func (*Manager) Reservations

func (a *Manager) Reservations(username string) ([]Reservation, error)

Reservations returns all user-owned topics, and the associated everyone-access

func (*Manager) ReservationsCount

func (a *Manager) ReservationsCount(username string) (int64, error)

ReservationsCount returns the number of reservations owned by this user

func (*Manager) ResetAccess

func (a *Manager) ResetAccess(username string, topicPattern string) error

ResetAccess removes an access control list entry for a specific username/topic, or (if topic is empty) for an entire user. The parameter topicPattern may include wildcards (*).

func (*Manager) ResetStats

func (a *Manager) ResetStats() error

ResetStats resets all user stats in the user database. This touches all users.

func (*Manager) ResetTier

func (a *Manager) ResetTier(username string) error

ResetTier removes the tier from the given user

func (*Manager) Tier

func (a *Manager) Tier(code string) (*Tier, error)

Tier returns a Tier based on the code, or ErrTierNotFound if it does not exist

func (*Manager) TierByStripePrice

func (a *Manager) TierByStripePrice(priceID string) (*Tier, error)

TierByStripePrice returns a Tier based on the Stripe price ID, or ErrTierNotFound if it does not exist

func (*Manager) Tiers

func (a *Manager) Tiers() ([]*Tier, error)

Tiers returns a list of all Tier structs

func (*Manager) Token

func (a *Manager) Token(userID, token string) (*Token, error)

Token returns a specific token for a user

func (*Manager) Tokens

func (a *Manager) Tokens(userID string) ([]*Token, error)

Tokens returns all existing tokens for the user with the given user ID

func (*Manager) UpdateTier

func (a *Manager) UpdateTier(tier *Tier) error

UpdateTier updates a tier's properties in the database

func (*Manager) User

func (a *Manager) User(username string) (*User, error)

User returns the user with the given username if it exists, or ErrUserNotFound otherwise. You may also pass Everyone to retrieve the anonymous user and its Grant list.

func (*Manager) UserByID

func (a *Manager) UserByID(id string) (*User, error)

UserByID returns the user with the given ID if it exists, or ErrUserNotFound otherwise

func (*Manager) UserByStripeCustomer

func (a *Manager) UserByStripeCustomer(stripeCustomerID string) (*User, error)

UserByStripeCustomer returns the user with the given Stripe customer ID if it exists, or ErrUserNotFound otherwise.

func (*Manager) Users

func (a *Manager) Users() ([]*User, error)

Users returns a list of users. It always also returns the Everyone user ("*").

func (*Manager) UsersCount

func (a *Manager) UsersCount() (int64, error)

UsersCount returns the number of users in the databsae

type NotificationPrefs

type NotificationPrefs struct {
	Sound       *string `json:"sound,omitempty"`
	MinPriority *int    `json:"min_priority,omitempty"`
	DeleteAfter *int    `json:"delete_after,omitempty"`
}

NotificationPrefs represents the user's notification settings

type Permission

type Permission uint8

Permission represents a read or write permission to a topic

const (
	PermissionDenyAll Permission = iota
	PermissionRead
	PermissionWrite
	PermissionReadWrite // 3!
)

Permissions to a topic

func NewPermission

func NewPermission(read, write bool) Permission

NewPermission is a helper to create a Permission based on read/write bool values

func ParsePermission

func ParsePermission(s string) (Permission, error)

ParsePermission parses the string representation and returns a Permission

func (Permission) IsRead

func (p Permission) IsRead() bool

IsRead returns true if readable

func (Permission) IsReadWrite

func (p Permission) IsReadWrite() bool

IsReadWrite returns true if readable and writable

func (Permission) IsWrite

func (p Permission) IsWrite() bool

IsWrite returns true if writable

func (Permission) String

func (p Permission) String() string

String returns a string representation of the permission

type Prefs

type Prefs struct {
	Language      *string            `json:"language,omitempty"`
	Notification  *NotificationPrefs `json:"notification,omitempty"`
	Subscriptions []*Subscription    `json:"subscriptions,omitempty"`
}

Prefs represents a user's configuration settings

type Reservation

type Reservation struct {
	Topic    string
	Owner    Permission
	Everyone Permission
}

Reservation is a struct that represents the ownership over a topic by a user

type Role

type Role string

Role represents a user's role, either admin or regular user

type Stats

type Stats struct {
	Messages int64
	Emails   int64
	Calls    int64
}

Stats is a struct holding daily user statistics

type Subscription

type Subscription struct {
	BaseURL     string  `json:"base_url"`
	Topic       string  `json:"topic"`
	DisplayName *string `json:"display_name"`
}

Subscription represents a user's topic subscription

func (*Subscription) Context

func (s *Subscription) Context() log.Context

Context returns fields for the log

type Tier

type Tier struct {
	ID                       string        // Tier identifier (ti_...)
	Code                     string        // Code of the tier
	Name                     string        // Name of the tier
	MessageLimit             int64         // Daily message limit
	MessageExpiryDuration    time.Duration // Cache duration for messages
	EmailLimit               int64         // Daily email limit
	CallLimit                int64         // Daily phone call limit
	ReservationLimit         int64         // Number of topic reservations allowed by user
	AttachmentFileSizeLimit  int64         // Max file size per file (bytes)
	AttachmentTotalSizeLimit int64         // Total file size for all files of this user (bytes)
	AttachmentExpiryDuration time.Duration // Duration after which attachments will be deleted
	AttachmentBandwidthLimit int64         // Daily bandwidth limit for the user
	StripeMonthlyPriceID     string        // Monthly price ID for paid tiers (price_...)
	StripeYearlyPriceID      string        // Yearly price ID for paid tiers (price_...)
}

Tier represents a user's account type, including its account limits

func (*Tier) Context

func (t *Tier) Context() log.Context

Context returns fields for the log

type Token

type Token struct {
	Value      string
	Label      string
	LastAccess time.Time
	LastOrigin netip.Addr
	Expires    time.Time
}

Token represents a user token, including expiry date

type TokenUpdate

type TokenUpdate struct {
	LastAccess time.Time
	LastOrigin netip.Addr
}

TokenUpdate holds information about the last access time and origin IP address of a token

type User

type User struct {
	ID        string
	Name      string
	Hash      string // password hash (bcrypt)
	Token     string // Only set if token was used to log in
	Role      Role
	Prefs     *Prefs
	Tier      *Tier
	Stats     *Stats
	Billing   *Billing
	SyncTopic string
	Deleted   bool
}

User is a struct that represents a user

func (*User) IsAdmin

func (u *User) IsAdmin() bool

IsAdmin returns true if the user is an admin

func (*User) IsUser

func (u *User) IsUser() bool

IsUser returns true if the user is a regular user, not an admin

func (*User) TierID

func (u *User) TierID() string

TierID returns the ID of the User.Tier, or an empty string if the user has no tier, or if the user itself is nil.

Jump to

Keyboard shortcuts

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