database

package
v0.19.1 Latest Latest
Warning

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

Go to latest
Published: Jan 8, 2021 License: Apache-2.0 Imports: 61 Imported by: 0

Documentation

Overview

Package database manages database connections and ORM integration.

Index

Constants

View Source
const (
	SMSRegion        = "[region]"
	SMSCode          = "[code]"
	SMSExpires       = "[expires]"
	SMSLongCode      = "[longcode]"
	SMSLongExpires   = "[longexpires]"
	SMSENExpressLink = "[enslink]"

	SMSTemplateMaxLength    = 800
	SMSTemplateExpansionMax = 918

	DefaultTemplateLabel   = "Default SMS template"
	DefaultSMSTextTemplate = "This is your Exposure Notifications Verification code: [longcode] Expires in [longexpires] hours"

	EmailInviteLink        = "[invitelink]"
	EmailPasswordResetLink = "[passwordresetlink]"
	EmailVerifyLink        = "[verifylink]"
	RealmName              = "[realmname]"

	// MaxPageSize is the maximum allowed page size for a list query.
	MaxPageSize = 1000
)
View Source
const (

	// MinCodeLength defines the minimum number of digits in a code.
	MinCodeLength = 6
)
View Source
const VerCodesCodeUniqueIndex = "uix_verification_codes_realm_code"
View Source
const VerCodesLongCodeUniqueIndex = "uix_verification_codes_realm_long_code"

Variables

View Source
var (
	// ErrNoSigningKeyManager is the error returned when the key manager cannot be
	// used as a SigningKeyManager.
	ErrNoSigningKeyManager = errors.New("configured key manager cannot be used to manage per-realm keys")

	// ErrValidationFailed is the error returned when validation failed. This
	// should always be considered user error.
	ErrValidationFailed = errors.New("validation failed")
)
View Source
var (
	ErrNoSigningKeyManagement = errors.New("no signing key management")
	ErrBadDateRange           = errors.New("bad date range")
)
View Source
var (
	ErrVerificationCodeNotFound = errors.New("verification code not found")
	ErrVerificationCodeExpired  = errors.New("verification code expired")
	ErrVerificationCodeUsed     = errors.New("verification code used")
	ErrTokenExpired             = errors.New("verification token expired")
	ErrTokenUsed                = errors.New("verification token used")
	ErrTokenMetadataMismatch    = errors.New("verification token test metadata mismatch")
	ErrUnsupportedTestType      = errors.New("verification code has unsupported test type")
)
View Source
var (
	// ValidTestTypes is a map containing the valid test types.
	ValidTestTypes = map[string]struct{}{
		"confirmed": {},
		"likely":    {},
		"negative":  {},
	}

	ErrInvalidTestType    = errors.New("invalid test type, must be confirmed, likely, or negative")
	ErrCodeAlreadyExpired = errors.New("code already expired")
	ErrCodeAlreadyClaimed = errors.New("code already claimed")
	ErrCodeTooShort       = errors.New("verification code is too short")
)
View Source
var (
	// ApproxTime is a compare helper for clock skew.
	ApproxTime = cmp.Options{cmpopts.EquateApproxTime(1 * time.Second)}
)
View Source
var CleanupName = "cleanup"
View Source
var Countries = map[string]string{}/* 242 elements not displayed */
View Source
var (
	ErrCleanupWrongGeneration = errors.New("cleanup wrong generation")
)

Functions

func IsNotFound added in v0.3.0

func IsNotFound(err error) bool

IsNotFound determines if an error is a record not found.

func IsValidationError added in v0.19.0

func IsValidationError(err error) bool

IsValidationError returns true if the error is a validation error (user error), or false otherwise.

func Paginate added in v0.16.0

func Paginate(query *gorm.DB, result interface{}, page, limit uint64) (*pagination.Paginator, error)

Paginate is a helper that paginates a gorm query into the given result. In addition to reflecting into the provided result, it returns a pagination struct.

If page is 0, it defaults to 1. If limit is 0, it defaults to the global pagination default limit.

func PaginateFn added in v0.16.0

func PaginateFn(query *gorm.DB, page, limit uint64, populateFn func(query *gorm.DB, offset uint64) error) (*pagination.Paginator, error)

PaginateFn paginates with a custom function for returning results.

func ToCIDRList added in v0.10.0

func ToCIDRList(s string) ([]string, error)

ToCIDRList converts the newline-separated and/or comma-separated CIDR list into an array of strings.

Types

type APIKeyType added in v0.11.0

type APIKeyType int
const (
	APIKeyTypeInvalid APIKeyType = iota - 1
	APIKeyTypeDevice
	APIKeyTypeAdmin
	APIKeyTypeStats
)

func (APIKeyType) Display added in v0.11.0

func (a APIKeyType) Display() string

type AuditEntry added in v0.11.0

type AuditEntry struct {
	Errorable

	// ID is the entry's ID.
	ID uint `gorm:"primary_key;"`

	// RealmID is the ID of the realm against which this event took place, if the
	// event took place against a realm. This can be 0 in situations where the
	// event took place outside of a realm (e.g. user creation), which means it's
	// a system event.
	RealmID uint `gorm:"column:realm_id; type:integer; not null;"`

	// ActorID is the ID of the actor which performed this event. It's usually of
	// the form `model:id` (e.g. users:1), but there's no guarantee that the
	// underlying resource still exists when the audit is read. It's primarily
	// used for sorting/filtering where an audit viewer wants to see all events a
	// particular entity took.
	//
	// ActorDisplay is the display name of the actor. The actor defines how it
	// will be displayed in audit logs.
	ActorID      string `gorm:"column:actor_id; type:text; not null;"`
	ActorDisplay string `gorm:"column:actor_display; type:text; not null;"`

	// Action is the auditable action.
	Action string `gorm:"column:action; type:text; not null;"`

	// TargetID and TargetDisplay are the same as the actor, but are for the
	// target of the action.
	TargetID      string `gorm:"column:target_id; type:text; not null;"`
	TargetDisplay string `gorm:"column:target_display; type:text; not null;"`

	// Diff is the change of structure that occurred, if any.
	Diff string `gorm:"column:diff; type:text;"`

	// CreatedAt is when the entry was created.
	CreatedAt time.Time
}

AuditEntry represents an event in the system. These records are purged after a configurable number of days by the cleanup job. The AuditEntry specifically does NOT make use of foreign keys or relationships to avoid breaking an audit entry if the upstream data which was audited is removed or changed. These records should be considered immutable.

func BuildAuditEntry added in v0.11.0

func BuildAuditEntry(actor Auditable, action string, target Auditable, realmID uint) *AuditEntry

BuildAuditEntry builds an AuditEntry from the given parameters. For actions that don't take place on a realm, use a realmID of 0.

func (*AuditEntry) BeforeSave added in v0.19.0

func (a *AuditEntry) BeforeSave(tx *gorm.DB) error

BeforeSave runs validations. If there are errors, the save fails.

type Auditable added in v0.11.0

type Auditable interface {
	// AuditID returns the id for this resource as it will be stored in audit
	// logs. This ID is usually of the format `table:id`.
	AuditID() string

	// AuditDisplay returns how this resource should appear in audit logs.
	AuditDisplay() string
}

Auditable represents a resource that can be audited as an actor or actee.

var System Auditable = new(system)

System represents the system and actions it has taken. It's not stored in the database.

var SystemTest Auditable = new(systemTest)

SystemTest represents the system and actions it has taken. It's not stored in the database.

type AuthRequirement added in v0.9.0

type AuthRequirement int16

AuthRequirement represents authentication requirements for the realm

const (
	// MFAOptionalPrompt will prompt users for MFA on login.
	MFAOptionalPrompt AuthRequirement = iota
	// MFARequired will not allow users to proceed without MFA on their account.
	MFARequired
	// MFAOptional will not prompt users to enable MFA.
	MFAOptional
)

func (AuthRequirement) String added in v0.9.0

func (r AuthRequirement) String() string

type AuthorizedApp

type AuthorizedApp struct {
	gorm.Model
	Errorable

	// AuthorizedApps belong to exactly one realm.
	RealmID uint `gorm:"unique_index:realm_apikey_name"`

	// Name is the name of the authorized app.
	Name string `gorm:"type:varchar(100);unique_index:realm_apikey_name"`

	// APIKeyPreview is the first few characters of the API key for display
	// purposes. This can help admins in the UI when determining which API key is
	// in use.
	APIKeyPreview string `gorm:"type:varchar(32)"`

	// APIKey is the HMACed API key.
	APIKey string `gorm:"type:varchar(512);unique_index"`

	// APIKeyType is the API key type.
	APIKeyType APIKeyType `gorm:"column:api_key_type; type:integer; not null;"`
}

AuthorizedApp represents an application that is authorized to verify verification codes and perform token exchanges. This is controlled via a generated API key.

Admin Keys are able to issue diagnosis keys and are not able to participate the verification protocol.

func (*AuthorizedApp) AuditDisplay added in v0.11.0

func (a *AuthorizedApp) AuditDisplay() string

func (*AuthorizedApp) AuditID added in v0.11.0

func (a *AuthorizedApp) AuditID() string

func (*AuthorizedApp) BeforeSave added in v0.4.0

func (a *AuthorizedApp) BeforeSave(tx *gorm.DB) error

BeforeSave runs validations. If there are errors, the save fails.

func (*AuthorizedApp) IsAdminType

func (a *AuthorizedApp) IsAdminType() bool

func (*AuthorizedApp) IsDeviceType

func (a *AuthorizedApp) IsDeviceType() bool

func (*AuthorizedApp) IsStatsType added in v0.19.0

func (a *AuthorizedApp) IsStatsType() bool

func (*AuthorizedApp) Realm

func (a *AuthorizedApp) Realm(db *Database) (*Realm, error)

Realm returns the associated realm for this app. If you only need the ID, call .RealmID instead of a full database lookup.

func (*AuthorizedApp) Stats added in v0.5.0

func (a *AuthorizedApp) Stats(db *Database, start, stop time.Time) (AuthorizedAppStats, error)

Stats returns the usage statistics for this app. If no stats exist, it returns an empty array.

type AuthorizedAppStat added in v0.18.0

type AuthorizedAppStat struct {
	Date            time.Time `gorm:"date; not null;"`
	AuthorizedAppID uint      `gorm:"column:authorized_app_id; type:integer; not null; not null;"`

	// CodesIssued is the number of codes issued. Only keys of type "admin" can
	// issue codes. CodesClaimed and CodesInvalid are the number of codes claimed
	// and valid, respectively. These fields are only valid for "device" API keys.
	CodesIssued  uint `gorm:"column:codes_issued; type:integer; not null; default: 0;"`
	CodesClaimed uint `gorm:"column:codes_claimed; type:integer; not null; default: 0;"`
	CodesInvalid uint `gorm:"column:codes_invalid; type:integer; not null; default:0;"`

	// TokensClaimed and TokensInvalid are the number of tokens exchanged for a
	// certificate or failures. These fields are only valid for "device" API keys.
	TokensClaimed uint `gorm:"column:tokens_claimed; type:integer; not null; default:0;"`
	TokensInvalid uint `gorm:"column:tokens_invalid; type:integer; not null; default:0;"`

	// Non-database fields, these are added via the stats lookup using the join
	// table.
	AuthorizedAppName string `gorm:"-"`
}

AuthorizedAppStat represents statistics related to an API key in the database.

type AuthorizedAppStats added in v0.3.0

type AuthorizedAppStats []*AuthorizedAppStat

AuthorizedAppStats represents a logical collection of stats for an authorized app.

func (AuthorizedAppStats) MarshalCSV added in v0.18.0

func (s AuthorizedAppStats) MarshalCSV() ([]byte, error)

MarshalCSV returns bytes in CSV format.

func (AuthorizedAppStats) MarshalJSON added in v0.18.0

func (s AuthorizedAppStats) MarshalJSON() ([]byte, error)

MarshalJSON is a custom JSON marshaller.

func (*AuthorizedAppStats) UnmarshalJSON added in v0.18.0

func (s *AuthorizedAppStats) UnmarshalJSON(b []byte) error

type BulkPermission added in v0.19.1

type BulkPermission struct {
	Errorable

	RealmID     uint
	UserIDs     []uint
	Permissions rbac.Permission
	Action      BulkPermissionAction
}

BulkPermission represents a bulk permission operation. This is not actually a table in the database.

func (*BulkPermission) Apply added in v0.19.1

func (b *BulkPermission) Apply(db *Database, actor Auditable) error

Apply converges the bulk operation. If a user isn't in the realm, no action is taken.

For add operations, if the user already has the permission, no action is taken. For remove opreations, if the user does not have the permission, no action is taken.

Other permissions not in the list are unchanged.

type BulkPermissionAction added in v0.19.1

type BulkPermissionAction uint8

BulkPermissionAction is the permission action to take.

const (
	BulkPermissionActionAdd BulkPermissionAction
	BulkPermissionActionRemove
)

type CleanupStatus

type CleanupStatus struct {
	gorm.Model
	Type       string `gorm:"type:varchar(50);unique_index"`
	Generation uint
	NotBefore  time.Time
}

type CodeType added in v0.16.0

type CodeType int
const (
	CodeTypeShort CodeType
	CodeTypeLong
)

type Config

type Config struct {
	Name              string `env:"DB_NAME" json:",omitempty"`
	User              string `env:"DB_USER" json:",omitempty"`
	Host              string `env:"DB_HOST, default=localhost" json:",omitempty"`
	Port              string `env:"DB_PORT, default=5432" json:",omitempty"`
	SSLMode           string `env:"DB_SSLMODE, default=require" json:",omitempty"`
	ConnectionTimeout uint   `env:"DB_CONNECT_TIMEOUT" json:",omitempty"`
	Password          string `env:"DB_PASSWORD" json:"-"` // ignored by zap's JSON formatter
	SSLCertPath       string `env:"DB_SSLCERT" json:",omitempty"`
	SSLKeyPath        string `env:"DB_SSLKEY" json:",omitempty"`
	SSLRootCertPath   string `env:"DB_SSLROOTCERT" json:",omitempty"`

	// MaxConnectionLifetime and MaxConnectionIdleTime determine the connection
	// configuration. Note that MaxConnectionIdleTime must be less than
	// MaxConnectionLifetime.
	MaxConnectionLifetime time.Duration `env:"DB_MAX_CONN_LIFETIME, default=5m" json:",omitempty"`
	MaxConnectionIdleTime time.Duration `env:"DB_MAX_CONN_IDLE_TIME, default=1m" json:",omitempty"`

	// Debug is a boolean that indicates whether the database should log SQL
	// commands.
	Debug bool `env:"DB_DEBUG,default=false"`

	// Keys is the key management configuration. This is used to resolve values
	// that are encrypted via a KMS.
	Keys keys.Config `env:",prefix=DB_"`

	// The KMS managed KeyRing that per-realm certificate signing keys are
	// created on.
	CertificateSigningKeyRing string `env:"CERTIFICATE_SIGNING_KEYRING"`

	// MaxCertificateSigningKeyVersions is the maximum number of certificate
	// signing key versions per realm. This is enforced at the database layer, not
	// the upstream KMS.
	MaxCertificateSigningKeyVersions int64 `env:"MAX_CERTIFICATE_SIGNING_KEY_VERSIONS, default=5"`

	// EncryptionKey is the reference to an encryption/decryption key to use when
	// for application-layer encryption before values are persisted to the
	// database.
	EncryptionKey string `env:"DB_ENCRYPTION_KEY,required" json:"-"`

	// APIKeyDatabaseHMAC is the HMAC key to use for API keys before storing them
	// in the database.
	APIKeyDatabaseHMAC []envconfig.Base64Bytes `env:"DB_APIKEY_DATABASE_KEY,required" json:"-"`

	// APIKeySignatureHMAC is the HMAC key to sign API keys before returning them
	// to the requestor.
	APIKeySignatureHMAC []envconfig.Base64Bytes `env:"DB_APIKEY_SIGNATURE_KEY,required" json:"-"`

	// VerificationCodeDatabaseHMAC is the HMAC key to hash codes before storing
	// them in the database.
	VerificationCodeDatabaseHMAC []envconfig.Base64Bytes `env:"DB_VERIFICATION_CODE_DATABASE_KEY,required" json:"-"`

	// Secrets is the secret configuration. This is used to resolve values that
	// are actually pointers to secrets before returning them to the caller. The
	// table implementation is the source of truth for which values are secrets
	// and which are plaintext.
	Secrets secrets.Config
}

Config represents the env var based configuration for database connections.

func (*Config) ConnectionString

func (c *Config) ConnectionString() string

ConnectionString returns the postgresql connection string based on this config.

While this package could be adapted to different databases easily, this file and method in particular would need to change.

func (*Config) Load added in v0.4.0

func (c *Config) Load(ctx context.Context) (*Database, error)

Load loads the configuration and processes any dependencies like secret and key managers. It does NOT connect to the database.

type Database

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

Database is a handle to the database layer for the Exposure Notifications Verification Server.

func (*Database) AbusePreventionEnabledRealmIDs added in v0.9.0

func (db *Database) AbusePreventionEnabledRealmIDs() ([]uint64, error)

AbusePreventionEnabledRealmIDs returns the list of realm IDs that have abuse prevention enabled.

func (*Database) ClaimCleanup

func (db *Database) ClaimCleanup(current *CleanupStatus, lockTime time.Duration) (*CleanupStatus, error)

ClaimCleanup attempts to obtain a lock for the specified `lockTime` so that that type of cleanup can be performed exclusively by the owner.

func (*Database) ClaimModelerStatus added in v0.9.0

func (db *Database) ClaimModelerStatus() error

ClaimModelerStatus attempts to claim the modeler status lock. This acquires a 15min lock on the table to prevent concurrent modifications over subscription. If the function returns nil, it successfully claimed the lock. Otherwise, lock acqusition was not successful and the caller should NOT continue processing.

func (*Database) ClaimToken

func (db *Database) ClaimToken(authApp *AuthorizedApp, tokenID string, subject *Subject) error

ClaimToken looks up the token by ID, verifies that it is not expired and that the specified subject matches the parameters that were configured when issued.

func (*Database) Close

func (db *Database) Close() error

Close will close the database connection. Should be deferred right after Open.

func (*Database) CreateCleanup

func (db *Database) CreateCleanup(cType string) (*CleanupStatus, error)

CreateCleanup is used to create a new 'cleanup' type/row in the database.

func (*Database) CreateOrUpdateSMSFromNumbers added in v0.19.0

func (db *Database) CreateOrUpdateSMSFromNumbers(numbers []*SMSFromNumber) error

CreateOrUpdateSMSFromNumbers takes the list of SMS numbers and creates new records, updates existing records, and deletes records that are not present in the list.

func (*Database) DeleteUser

func (db *Database) DeleteUser(u *User, actor Auditable) error

DeleteUser deletes the user entry.

func (*Database) DeleteVerificationCode

func (db *Database) DeleteVerificationCode(code string) error

DeleteVerificationCode deletes the code if it exists. This is a hard delete.

func (*Database) ExpireCode added in v0.5.1

func (db *Database) ExpireCode(uuid string) (*VerificationCode, error)

ExpireCode saves a verification code as expired.

func (*Database) FindAuthorizedApp added in v0.18.0

func (db *Database) FindAuthorizedApp(id interface{}) (*AuthorizedApp, error)

FindAuthorizedApp finds the authorized app by the given id.

func (*Database) FindAuthorizedAppByAPIKey

func (db *Database) FindAuthorizedAppByAPIKey(apiKey string) (*AuthorizedApp, error)

FindAuthorizedAppByAPIKey located an authorized app based on API key.

func (*Database) FindCleanupStatus

func (db *Database) FindCleanupStatus(cType string) (*CleanupStatus, error)

FindCleanupStatus looks up the current cleanup state in the database by cleanup type.

func (*Database) FindRealm added in v0.5.0

func (db *Database) FindRealm(id interface{}) (*Realm, error)

func (*Database) FindRealmByName added in v0.5.0

func (db *Database) FindRealmByName(name string) (*Realm, error)

func (*Database) FindRealmByRegion added in v0.12.0

func (db *Database) FindRealmByRegion(region string) (*Realm, error)

func (*Database) FindSMSFromNumber added in v0.19.0

func (db *Database) FindSMSFromNumber(id interface{}) (*SMSFromNumber, error)

FindSMSFromNumber finds the given SMS from number by ID.

func (*Database) FindTokenByID

func (db *Database) FindTokenByID(tokenID string) (*Token, error)

func (*Database) FindUser

func (db *Database) FindUser(id interface{}) (*User, error)

FindUser finds a user by the given id, if one exists. The id can be a string or integer value. It returns an error if the record is not found.

func (*Database) FindUserByEmail added in v0.4.0

func (db *Database) FindUserByEmail(email string) (*User, error)

FindUserByEmail reads back a User struct by email address. It returns an error if the record is not found.

func (*Database) FindVerificationCode

func (db *Database) FindVerificationCode(code string) (*VerificationCode, error)

FindVerificationCode find a verification code by the code number (can be short code or long code).

func (*Database) GenerateAPIKey added in v0.3.0

func (db *Database) GenerateAPIKey(realmID uint) (string, error)

GenerateAPIKey generates a new API key that is bound to the given realm. This API key is NOT stored in the database. API keys are of the format:

key:realmID:hex(hmac)

func (*Database) GenerateAPIKeyHMAC added in v0.7.0

func (db *Database) GenerateAPIKeyHMAC(apiKey string) (string, error)

GenerateAPIKeyHMAC generates the HMAC of the provided API key using the latest HMAC key.

func (*Database) GenerateAPIKeySignature added in v0.3.0

func (db *Database) GenerateAPIKeySignature(apiKey string) ([]byte, error)

GenerateAPIKeySignature returns all possible signatures of the given key.

func (*Database) GenerateVerificationCodeHMAC added in v0.7.0

func (db *Database) GenerateVerificationCodeHMAC(verCode string) (string, error)

GenerateVerificationCodeHMAC generates the HMAC of the code using the latest key.

func (*Database) IsCodeExpired added in v0.5.0

func (db *Database) IsCodeExpired(v *VerificationCode, code string) (bool, CodeType, error)

IsCodeExpired checks to see if the actual code provided is the short or long code, and determines if it is expired based on that.

func (*Database) KeyManager added in v0.5.0

func (db *Database) KeyManager() keys.KeyManager

func (*Database) ListActiveApps added in v0.17.1

func (db *Database) ListActiveApps(realmID uint, scopes ...Scope) ([]*MobileApp, error)

ListActiveApps finds mobile apps by their realm.

func (*Database) ListActiveAppsWithRealm added in v0.16.0

func (db *Database) ListActiveAppsWithRealm(p *pagination.PageParams) ([]*ExtendedMobileApp, *pagination.Paginator, error)

ListActiveAppsWithRealm finds all active mobile apps with their associated realm.

func (*Database) ListAudits added in v0.16.0

func (db *Database) ListAudits(p *pagination.PageParams, scopes ...Scope) ([]*AuditEntry, *pagination.Paginator, error)

ListAudits returns the list audit events which match the given criteria. Warning: This list may be large. Use Realm.Audits() to get users scoped to a realm.

func (*Database) ListRealms added in v0.16.0

func (db *Database) ListRealms(p *pagination.PageParams, scopes ...Scope) ([]*Realm, *pagination.Paginator, error)

ListRealms lists all available realms in the system.

func (*Database) ListRecentCodes added in v0.12.0

func (db *Database) ListRecentCodes(realm *Realm, user *User) ([]*VerificationCode, error)

ListRecentCodes shows the last 5 recently issued codes for a given issuing user. The code and longCode are removed, this is only intended to show metadata.

func (*Database) ListUsers

func (db *Database) ListUsers(p *pagination.PageParams, scopes ...Scope) ([]*User, *pagination.Paginator, error)

ListUsers returns a list of all users sorted by name. Warning: This list may be large. Use Realm.ListUsers() to get users scoped to a realm.

func (*Database) MaxCertificateSigningKeyVersions added in v0.16.0

func (db *Database) MaxCertificateSigningKeyVersions() int64

MaxCertificateSigningKeyVersions returns the configured maximum.

func (*Database) MigrateTo

func (db *Database) MigrateTo(ctx context.Context, target string, rollback bool) error

MigrateTo migrates the database to a specific target migration ID.

func (*Database) Migrations added in v0.19.0

func (db *Database) Migrations(ctx context.Context) []*gormigrate.Migration

func (*Database) Open added in v0.4.0

func (db *Database) Open(ctx context.Context) error

Open creates a database connection. This should only be called once.

func (*Database) OpenWithCacher added in v0.5.0

func (db *Database) OpenWithCacher(ctx context.Context, cacher cache.Cacher) error

OpenWithCacher creates a database connection with the cacher. This should only be called once.

func (*Database) PasswordChanged added in v0.9.0

func (db *Database) PasswordChanged(email string, t time.Time) error

PasswordChanged updates the last password change timestamp of the user.

func (*Database) Ping added in v0.3.0

func (db *Database) Ping(ctx context.Context) error

Ping attempts a connection and closes it to the database.

func (*Database) PurgeAuditEntries added in v0.11.0

func (db *Database) PurgeAuditEntries(maxAge time.Duration) (int64, error)

PurgeAuditEntries will delete audit entries which were created longer than maxAge ago.

func (*Database) PurgeAuthorizedApps added in v0.15.0

func (db *Database) PurgeAuthorizedApps(maxAge time.Duration) (int64, error)

PurgeAuthorizedApps will delete authorized apps that have been deleted for more than the specified time.

func (*Database) PurgeMobileApps added in v0.10.0

func (db *Database) PurgeMobileApps(maxAge time.Duration) (int64, error)

PurgeMobileApps will delete mobile apps that have been deleted for more than the specified time.

func (*Database) PurgeTokens

func (db *Database) PurgeTokens(maxAge time.Duration) (int64, error)

PurgeTokens will delete tokens that have expired since at least the provided maxAge ago. This is a hard delete, not a soft delete.

func (*Database) PurgeUsers added in v0.17.0

func (db *Database) PurgeUsers(maxAge time.Duration) (int64, error)

PurgeUsers will delete users who are not a system admin, not a member of any realms and have not been modified before the expiry time.

func (*Database) PurgeVerificationCodes

func (db *Database) PurgeVerificationCodes(maxAge time.Duration) (int64, error)

PurgeVerificationCodes will delete verifications that have expired since at least the provided maxAge ago. This is a hard delete, not a soft delete.

func (*Database) RawDB added in v0.9.0

func (db *Database) RawDB() *gorm.DB

RawDB returns the underlying gorm database. This is publicly exposed for tests.

func (*Database) RecycleVerificationCodes added in v0.16.0

func (db *Database) RecycleVerificationCodes(maxAge time.Duration) (int64, error)

RecycleVerificationCodes sets to null code and long_code values so that status can be retained longer, but the codes are recycled into the pool.

func (*Database) SMSFromNumbers added in v0.19.0

func (db *Database) SMSFromNumbers(scopes ...Scope) ([]*SMSFromNumber, error)

SMSFromNumbers returns the list of SMS from numbers in the system.

func (*Database) SaveAuditEntry added in v0.17.0

func (db *Database) SaveAuditEntry(a *AuditEntry) error

SaveAuditEntry saves the audit entry.

func (*Database) SaveAuthorizedApp added in v0.3.0

func (db *Database) SaveAuthorizedApp(a *AuthorizedApp, actor Auditable) error

SaveAuthorizedApp saves the authorized app.

func (*Database) SaveEmailConfig added in v0.14.0

func (db *Database) SaveEmailConfig(s *EmailConfig) error

SaveEmailConfig creates or updates an email configuration record.

func (*Database) SaveMembership added in v0.19.0

func (db *Database) SaveMembership(m *Membership, actor Auditable) error

SaveMembership saves the membership details. Should have a userID and a realmID to identify it.

func (*Database) SaveMobileApp added in v0.10.0

func (db *Database) SaveMobileApp(a *MobileApp, actor Auditable) error

SaveMobileApp saves the mobile app.

func (*Database) SaveRealm

func (db *Database) SaveRealm(r *Realm, actor Auditable) error

func (*Database) SaveSMSConfig

func (db *Database) SaveSMSConfig(s *SMSConfig) error

SaveSMSConfig creates or updates an SMS configuration record.

func (*Database) SaveUser

func (db *Database) SaveUser(u *User, actor Auditable) error

func (*Database) SaveUserStat added in v0.18.0

func (db *Database) SaveUserStat(u *UserStat) error

SaveUserStat saves some UserStats to the database. This function is provided for testing only.

func (*Database) SaveVerificationCode

func (db *Database) SaveVerificationCode(vc *VerificationCode, realm *Realm) error

SaveVerificationCode created or updates a verification code in the database. Max age represents the maximum age of the test date [optional] in the record.

func (*Database) SearchActiveAppsWithRealm added in v0.16.0

func (db *Database) SearchActiveAppsWithRealm(p *pagination.PageParams, q string) ([]*ExtendedMobileApp, *pagination.Paginator, error)

SearchActiveAppsWithRealm finds all active mobile apps with their associated realm.

func (*Database) SetRawDB added in v0.19.0

func (db *Database) SetRawDB(tx *gorm.DB)

SetRawDB sets the underlying gorm database. This is publicly exposed for tests.

func (*Database) SupportsPerRealmSigning added in v0.5.0

func (db *Database) SupportsPerRealmSigning() bool

SupportsPerRealmSigning returns true if the configuration supports application managed signing keys.

func (*Database) SystemEmailConfig added in v0.14.0

func (db *Database) SystemEmailConfig() (*EmailConfig, error)

SystemEmailConfig returns the system email config, if one exists

func (*Database) SystemSMSConfig added in v0.10.0

func (db *Database) SystemSMSConfig() (*SMSConfig, error)

SystemSMSConfig returns the system SMS config, if one exists

func (*Database) TouchUserRevokeCheck added in v0.5.0

func (db *Database) TouchUserRevokeCheck(u *User) error

TouchUserRevokeCheck updates the revoke check time on the user. It updates the column directly and does not invoke callbacks.

func (*Database) UntouchUserRevokeCheck added in v0.17.0

func (db *Database) UntouchUserRevokeCheck(u *User) error

UntouchUserRevokeCheck removes the last revoke check, forcing it to occur on next auth.

func (*Database) VerifyAPIKeySignature added in v0.3.0

func (db *Database) VerifyAPIKeySignature(key string) (string, uint64, error)

VerifyAPIKeySignature verifies the signature matches the expected value for the key. It does this by computing the expected signature and then doing a constant-time comparison against the provided signature.

func (*Database) VerifyCodeAndIssueToken

func (db *Database) VerifyCodeAndIssueToken(authApp *AuthorizedApp, verCode string, acceptTypes api.AcceptTypes, expireAfter time.Duration) (*Token, error)

VerifyCodeAndIssueToken takes a previously issued verification code and exchanges it for a long term token. The verification code must not have expired and must not have been previously used. Both acctions are done in a single database transaction. The verCode can be the "short code" or the "long code" which impacts expiry time.

The long term token can be used later to sign keys when they are submitted.

type DurationSeconds added in v0.4.0

type DurationSeconds struct {
	Duration time.Duration

	// AsString allows this value to be updated and parsed using the Update() method.
	AsString string
}

DurationSeconds is a custom type for writing and reading a time.Duration to be stored as seconds in the database.

func FromDuration added in v0.5.0

func FromDuration(d time.Duration) DurationSeconds

func (*DurationSeconds) Days added in v0.11.0

func (d *DurationSeconds) Days() int64

func (*DurationSeconds) Scan added in v0.4.0

func (d *DurationSeconds) Scan(src interface{}) error

Scan takes a int64 value in seconds and converts that to a time.Duration

func (*DurationSeconds) Update added in v0.5.0

func (d *DurationSeconds) Update() error

Update attempts to parse the AsString value and set is as the duration

func (DurationSeconds) Value added in v0.4.0

func (d DurationSeconds) Value() (driver.Value, error)

Value converts the internal time.Duration value to seconds and returns that value as an int64 for saving to the database.

type EmailConfig added in v0.14.0

type EmailConfig struct {
	gorm.Model
	Errorable

	// email Config belongs to exactly one realm.
	RealmID uint `gorm:"type:integer"`

	// ProviderType is the email provider type - it's used to determine the
	// underlying configuration.
	ProviderType email.ProviderType `gorm:"type:varchar(100)"`

	SMTPAccount string `gorm:"type:varchar(250)"`
	SMTPHost    string `gorm:"type:varchar(250)"`
	SMTPPort    string `gorm:"type:varchar(250)"`

	// SMTPPassword is encrypted/decrypted automatically by callbacks. The
	// cache fields exist as optimizations.
	SMTPPassword                string `gorm:"type:varchar(250)" json:"-"` // ignored by zap's JSON formatter
	SMTPPasswordPlaintextCache  string `gorm:"-"`
	SMTPPasswordCiphertextCache string `gorm:"-"`

	// IsSystem determines if this is a system-level email configuration. There can
	// only be one system-level email configuration.
	IsSystem bool `gorm:"type:bool; not null; default:false;"`
}

EmailConfig represents and email configuration.

func (*EmailConfig) BeforeSave added in v0.14.0

func (e *EmailConfig) BeforeSave(tx *gorm.DB) error

func (*EmailConfig) Provider added in v0.14.0

func (e *EmailConfig) Provider() (email.Provider, error)

type Errorable added in v0.4.0

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

Errorable defines an embeddable struct for managing errors on models.

func (*Errorable) AddError added in v0.4.0

func (e *Errorable) AddError(key, err string)

AddError adds a new error to the list.

func (*Errorable) ErrorMessages added in v0.4.0

func (e *Errorable) ErrorMessages() []string

ErrorMessages returns the list of error messages.

func (*Errorable) ErrorOrNil added in v0.19.0

func (e *Errorable) ErrorOrNil() error

ErrorOrNil returns ErrValidationFailed if there are any errors, or nil if there are none.

func (*Errorable) Errors added in v0.4.0

func (e *Errorable) Errors() map[string][]string

Errors returns the list of errors.

func (*Errorable) ErrorsFor added in v0.4.0

func (e *Errorable) ErrorsFor(key string) []string

ErrorsFor returns the list of errors for the key

type ExtendedMobileApp added in v0.16.0

type ExtendedMobileApp struct {
	MobileApp
	Realm
}

ExtendedMobileApp combines a MobileApp with its Realm

type ExternalIssuerStat added in v0.17.1

type ExternalIssuerStat struct {
	Date        time.Time `gorm:"column:date; type:date;"`
	RealmID     uint      `gorm:"column:realm_id; type:int"`
	IssuerID    string    `gorm:"column:issuer_id; type:varchar(255)"`
	CodesIssued uint      `gorm:"column:codes_issued; type:int;"`
}

ExternalIssuerStat represents statistics related to a user in the database.

type ExternalIssuerStats added in v0.17.1

type ExternalIssuerStats []*ExternalIssuerStat

ExternalIssuerStats is a collection of external issuer stats.

func (ExternalIssuerStats) MarshalCSV added in v0.17.1

func (s ExternalIssuerStats) MarshalCSV() ([]byte, error)

MarshalCSV returns bytes in CSV format.

func (ExternalIssuerStats) MarshalJSON added in v0.17.1

func (s ExternalIssuerStats) MarshalJSON() ([]byte, error)

MarshalJSON is a custom JSON marshaller.

func (*ExternalIssuerStats) UnmarshalJSON added in v0.17.1

func (s *ExternalIssuerStats) UnmarshalJSON(b []byte) error

type Membership added in v0.19.0

type Membership struct {
	Errorable

	UserID uint
	User   *User

	RealmID uint
	Realm   *Realm

	// DefaultSMSTemplateLabel is the label of realm.SMSTextAlternateTemplates or "Default SMS template"
	// that the user last used to issue codes. This helps the UI remember the default user preference.
	// Note: This label may not exist if it has been deleted or modified on the realm.
	DefaultSMSTemplateLabel string `gorm:"type:varchar(255);"`

	Permissions rbac.Permission

	// CreatedAt is when the user was added to the realm. UpdatedAt is when the
	// user's permissions were last updated. Note that UpdatedAt only applies to
	// the membership's fields, not the user fields (e.g. email, name).
	CreatedAt time.Time
	UpdatedAt time.Time
}

Membership represents a user's membership in a realm.

func (*Membership) AfterFind added in v0.19.0

func (m *Membership) AfterFind() error

AfterFind does a sanity check to ensure the User and Realm properties were preloaded and the referenced values exist.

func (*Membership) Can added in v0.19.0

func (m *Membership) Can(p rbac.Permission) bool

Can returns true if the membership has the checked permission on the realm, false otherwise.

func (*Membership) Cannot added in v0.19.0

func (m *Membership) Cannot(p rbac.Permission) bool

Cannot returns the opposite of Can

type MobileApp added in v0.10.0

type MobileApp struct {
	gorm.Model
	Errorable

	// Name is the name of the app.
	Name string `gorm:"column:name; type:citext;"`

	// RealmID is the id of the mobile app.
	RealmID uint `gorm:"column:realm_id;"`

	// URL is the link to the app in it's appstore.
	URL    string  `gorm:"-"`
	URLPtr *string `gorm:"column:url; type:text"`

	// DisableRedirect disables URL redirection in the redirector service for this
	// app.
	DisableRedirect bool `gorm:"column:disable_redirect; type:bool; default:false; not null"`

	// OS is the type of the application we're using (eg, iOS, Android).
	OS OSType `gorm:"column:os; type:int;"`

	// AppID is a unique string representing the app.
	//
	// For iOS this should include the team ID or app ID prefix followed by
	// the bundle ID. eg. ABCD1234.com.google.test.application
	AppID string `gorm:"column:app_id; type:varchar(512);"`

	// SHA is a unique hash of the app.
	// It is only present for Android devices, and should be of the form:
	//   AA:BB:CC:DD...
	SHA string `gorm:"column:sha; type:text;"`
}

func (*MobileApp) AfterFind added in v0.11.0

func (a *MobileApp) AfterFind(tx *gorm.DB) error

func (*MobileApp) AuditDisplay added in v0.11.0

func (a *MobileApp) AuditDisplay() string

func (*MobileApp) AuditID added in v0.11.0

func (a *MobileApp) AuditID() string

func (*MobileApp) BeforeSave added in v0.10.0

func (a *MobileApp) BeforeSave(tx *gorm.DB) error

type ModelerStatus added in v0.9.0

type ModelerStatus struct {
	ID        uint `gorm:"primary_key"`
	NotBefore time.Time
}

type OSType added in v0.10.0

type OSType int
const (
	OSTypeInvalid OSType = iota
	OSTypeIOS
	OSTypeAndroid
)

func (OSType) Display added in v0.11.0

func (o OSType) Display() string

Display prints the name of the OSType. Note this CANNOT be named String() because, if it is, Go's text/template package will automatically call String() and cause you to lose hours upon hours of your life debuggin when forms are suddenly broken.

type Realm

type Realm struct {
	gorm.Model
	Errorable

	// Name is the name of the realm.
	Name string `gorm:"type:varchar(200);unique_index;"`

	// RegionCode is both a display attribute and required field for ENX. To
	// handle NULL and uniqueness, the field is converted from it's ptr type to a
	// concrete type in callbacks. Do not modify RegionCodePtr directly.
	RegionCode    string  `gorm:"-"`
	RegionCodePtr *string `gorm:"column:region_code; type:varchar(10);"`

	// WelcomeMessage is arbitrary realm-defined data to display to users after
	// selecting this realm. If empty, nothing is displayed. The format is
	// markdown. Do not modify WelcomeMessagePtr directly.
	WelcomeMessage    string  `gorm:"-"`
	WelcomeMessagePtr *string `gorm:"column:welcome_message; type:text;"`

	// AllowBulkUpload allows users to issue codes from a batch file of test results.
	AllowBulkUpload bool `gorm:"type:boolean; not null; default:false;"`

	// Code configuration
	CodeLength       uint            `gorm:"type:smallint; not null; default: 8;"`
	CodeDuration     DurationSeconds `gorm:"type:bigint; not null; default: 900;"` // default 15m (in seconds)
	LongCodeLength   uint            `gorm:"type:smallint; not null; default: 16;"`
	LongCodeDuration DurationSeconds `gorm:"type:bigint; not null; default: 86400;"` // default 24h

	// SMS configuration
	SMSTextTemplate           string          `` /* 136-byte string literal not displayed */
	SMSTextAlternateTemplates postgres.Hstore `gorm:"column:alternate_sms_templates; type:hstore;"`

	// SMSCountry is an optional field to hint the default phone picker country
	// code.
	SMSCountry    string  `gorm:"-"`
	SMSCountryPtr *string `gorm:"column:sms_country; type:varchar(5);"`

	// CanUseSystemSMSConfig is configured by system administrators to share the
	// system SMS config with this realm. Note that the system SMS config could be
	// empty and a local SMS config is preferred over the system value.
	CanUseSystemSMSConfig bool `gorm:"column:can_use_system_sms_config; type:bool; not null; default:false;"`

	// UseSystemSMSConfig is a realm-level configuration that lets a realm opt-out
	// of sending SMS messages using the system-provided SMS configuration.
	// Without this, a realm would always fallback to the system-level SMS
	// configuration, making it impossible to opt out of text message sending.
	UseSystemSMSConfig bool `gorm:"column:use_system_sms_config; type:bool; not null; default:false;"`

	// SMSFromNumberID is a realm-level configuration that only applies when using
	// the system SMS configuration. It determines which of the system SMS numbers
	// to use as the sender when sending text messages.
	SMSFromNumberID    uint  `gorm:"-"`
	SMSFromNumberIDPtr *uint `gorm:"column:sms_from_number_id; type:integer;"`

	// EmailInviteTemplate is the template for inviting new users.
	EmailInviteTemplate string `gorm:"type:text;"`

	// EmailPasswordResetTemplate is the template for resetting password.
	EmailPasswordResetTemplate string `gorm:"type:text;"`

	// EmailVerifyTemplate is the template used for email verification.
	EmailVerifyTemplate string `gorm:"type:text;"`

	// CanUseSystemEmailConfig is configured by system administrators to share the
	// system email config with this realm. Note that the system email config could be
	// empty and a local email config is preferred over the system value.
	CanUseSystemEmailConfig bool `gorm:"column:can_use_system_email_config; type:bool; not null; default:false;"`

	// UseSystemEmailConfig is a realm-level configuration that lets a realm opt-out
	// of sending email messages using the system-provided email configuration.
	// Without this, a realm would always fallback to the system-level email
	// configuration, making it impossible to opt out of text message sending.
	UseSystemEmailConfig bool `gorm:"column:use_system_email_config; type:bool; not null; default:false;"`

	// MFAMode represents the mode for Multi-Factor-Authorization requirements for the realm.
	MFAMode AuthRequirement `gorm:"type:smallint; not null; default: 0;"`

	// MFARequiredGracePeriod defines how long after creation a user may skip adding
	// a second auth factor before the server requires it.
	MFARequiredGracePeriod DurationSeconds `gorm:"type:bigint; not null; default: 0;"`

	// EmailVerifiedMode represents the mode for email verification requirements for the realm.
	EmailVerifiedMode AuthRequirement `gorm:"type:smallint; not null; default: 0;"`

	// PasswordRotationPeriodDays is the number of days before the user must
	// rotate their password.
	PasswordRotationPeriodDays uint `gorm:"type:smallint; not null; default: 0;"`

	// PasswordRotationWarningDays is the number of days before Password expiry
	// that the user should receive a warning.
	PasswordRotationWarningDays uint `gorm:"type:smallint; not null; default: 0;"`

	// AllowedCIDRs is the list of allowed IPs to the various services.
	AllowedCIDRsAdminAPI  pq.StringArray `gorm:"column:allowed_cidrs_adminapi; type:varchar(50)[];"`
	AllowedCIDRsAPIServer pq.StringArray `gorm:"column:allowed_cidrs_apiserver; type:varchar(50)[];"`
	AllowedCIDRsServer    pq.StringArray `gorm:"column:allowed_cidrs_server; type:varchar(50)[];"`

	// AllowedTestTypes is the type of tests that this realm permits. The default
	// value is to allow all test types.
	AllowedTestTypes TestType `gorm:"type:smallint; not null; default: 14;"`

	// RequireDate requires that verifications on this realm require a test or
	// symptom date (either). The default behavior is to not require a date.
	RequireDate bool `gorm:"type:boolean; not null; default:false;"`

	// Signing Key Settings
	UseRealmCertificateKey bool            `gorm:"type:boolean; default: false;"`
	CertificateIssuer      string          `gorm:"type:varchar(150); default: '';"`
	CertificateAudience    string          `gorm:"type:varchar(150); default: '';"`
	CertificateDuration    DurationSeconds `gorm:"type:bigint; default: 900;"` // 15m

	// EN Express
	EnableENExpress bool `gorm:"type:boolean; default: false;"`

	// AbusePreventionEnabled determines if abuse protection is enabled.
	AbusePreventionEnabled bool `gorm:"type:boolean; not null; default:false;"`

	// AbusePreventionLimit is the configured daily limit for the realm. This value is populated
	// by the nightly aggregation job and is based on a statistical model from
	// historical code issuance data.
	AbusePreventionLimit uint `gorm:"type:integer; not null; default:10;"`

	// AbusePreventionLimitFactor is the factor against the predicted model for the day which
	// determines the total number of codes that can be issued for the realm on
	// the day. For example, if the predicted value was 50 and this value was 1.5,
	// the realm could generate 75 codes today before triggering abuse prevention.
	// Similarly, if this value was 0.5, the realm could only generate 25 codes
	// before triggering abuse protections.
	AbusePreventionLimitFactor float32 `gorm:"type:numeric(6, 3); not null; default:1.0;"`

	// DailyActiveUsersEnabled determines if the realm collects and displays daily
	// active user metrics.
	DailyActiveUsersEnabled bool `gorm:"type:boolean; not null; default: false;"`

	// Relations to items that belong to a realm.
	Codes  []*VerificationCode `gorm:"PRELOAD:false; SAVE_ASSOCIATIONS:false; ASSOCIATION_AUTOUPDATE:false, ASSOCIATION_SAVE_REFERENCE:false;"`
	Tokens []*Token            `gorm:"PRELOAD:false; SAVE_ASSOCIATIONS:false; ASSOCIATION_AUTOUPDATE:false, ASSOCIATION_SAVE_REFERENCE:false;"`
}

Realm represents a tenant in the system. Typically this corresponds to a geography or a public health authority scope. This is used to manage user logins.

func NewRealmWithDefaults added in v0.4.0

func NewRealmWithDefaults(name string) *Realm

NewRealmWithDefaults initializes a new Realm with the default settings populated, and the provided name. It does NOT save the Realm to the database.

func (*Realm) AbusePreventionEffectiveLimit added in v0.9.0

func (r *Realm) AbusePreventionEffectiveLimit() uint

AbusePreventionEffectiveLimit returns the effective limit, multiplying the limit by the limit factor and rounding up.

func (*Realm) AfterFind added in v0.9.0

func (r *Realm) AfterFind(tx *gorm.DB) error

AfterFind runs after a realm is found.

func (*Realm) AuditDisplay added in v0.11.0

func (r *Realm) AuditDisplay() string

func (*Realm) AuditID added in v0.11.0

func (r *Realm) AuditID() string

func (*Realm) BeforeSave added in v0.4.0

func (r *Realm) BeforeSave(tx *gorm.DB) error

BeforeSave runs validations. If there are errors, the save fails.

func (*Realm) BuildInviteEmail added in v0.15.0

func (r *Realm) BuildInviteEmail(inviteLink string) string

BuildInviteEmail replaces certain strings with the right values for invitations.

func (*Realm) BuildPasswordResetEmail added in v0.15.0

func (r *Realm) BuildPasswordResetEmail(passwordResetLink string) string

BuildPasswordResetEmail replaces certain strings with the right values for password reset.

func (*Realm) BuildSMSText added in v0.4.0

func (r *Realm) BuildSMSText(code, longCode string, enxDomain, templateLabel string) (string, error)

BuildSMSText replaces certain strings with the right values.

func (*Realm) BuildVerifyEmail added in v0.15.0

func (r *Realm) BuildVerifyEmail(verifyLink string) string

BuildVerifyEmail replaces certain strings with the right values for email verification.

func (*Realm) CanUpgradeToRealmSigningKeys added in v0.5.0

func (r *Realm) CanUpgradeToRealmSigningKeys() bool

func (*Realm) CreateAuthorizedApp added in v0.4.0

func (r *Realm) CreateAuthorizedApp(db *Database, app *AuthorizedApp, actor Auditable) (string, error)

CreateAuthorizedApp generates a new API key and assigns it to the specified app. Note that the API key is NOT stored in the database, only a hash. The only time the API key is available is as the string return parameter from invoking this function.

func (*Realm) CreateSigningKeyVersion added in v0.5.1

func (r *Realm) CreateSigningKeyVersion(ctx context.Context, db *Database) (string, error)

CreateSigningKeyVersion creates a new signing key version on the key manager and saves a reference to the new key version in the database. If creating the key in the key manager fails, the database is not updated. However, if updating the signing key in the database fails, the key is NOT deleted from the key manager.

func (*Realm) DestroySigningKeyVersion added in v0.5.1

func (r *Realm) DestroySigningKeyVersion(ctx context.Context, db *Database, id interface{}) error

DestroySigningKeyVersion destroys the given key version in both the database and the key manager. ID is the primary key ID from the database. If the id does not exist, it does nothing.

func (*Realm) EffectiveMFAMode added in v0.11.0

func (r *Realm) EffectiveMFAMode(t time.Time) AuthRequirement

EffectiveMFAMode returns the realm's default MFAMode but first checks if the time is in the grace-period (if so, required becomes prompt).

func (*Realm) EmailConfig added in v0.14.0

func (r *Realm) EmailConfig(db *Database) (*EmailConfig, error)

EmailConfig returns the email configuration for this realm, if one exists. If the realm is configured to use the system email configuration, that configuration is preferred.

func (*Realm) EmailProvider added in v0.14.0

func (r *Realm) EmailProvider(db *Database) (email.Provider, error)

EmailProvider returns the email provider for the realm. If no email configuration exists, it returns nil. If any errors occur creating the provider, they are returned.

func (*Realm) ExternalIssuerStats added in v0.17.1

func (r *Realm) ExternalIssuerStats(db *Database) (ExternalIssuerStats, error)

ExternalIssuerStats returns the 30-day external issuer stats for this realm. If no stats exist, returns an empty slice.

func (*Realm) ExternalIssuerStatsCached added in v0.19.0

func (r *Realm) ExternalIssuerStatsCached(ctx context.Context, db *Database, cacher cache.Cacher) (ExternalIssuerStats, error)

ExternalIssuerStatsCached is stats, but cached.

func (*Realm) FindAuthorizedApp added in v0.3.0

func (r *Realm) FindAuthorizedApp(db *Database, id interface{}) (*AuthorizedApp, error)

FindAuthorizedApp finds the authorized app by the given id associated to the realm.

func (*Realm) FindMobileApp added in v0.10.0

func (r *Realm) FindMobileApp(db *Database, id interface{}) (*MobileApp, error)

FindMobileApp finds the mobile app by the given id associated with the realm.

func (*Realm) FindUser added in v0.4.0

func (r *Realm) FindUser(db *Database, id interface{}) (*User, error)

FindUser finds the given user in the realm by ID.

func (*Realm) FindVerificationCodeByUUID added in v0.16.0

func (r *Realm) FindVerificationCodeByUUID(db *Database, uuidStr string) (*VerificationCode, error)

FindVerificationCodeByUUID find a verification codes by UUID. It returns NotFound if the UUID is invalid.

func (*Realm) GetCodeDurationMinutes added in v0.4.0

func (r *Realm) GetCodeDurationMinutes() int

GetCodeDurationMinutes is a helper for the HTML rendering to get a round minutes value.

func (*Realm) GetCurrentSigningKey added in v0.5.0

func (r *Realm) GetCurrentSigningKey(db *Database) (*SigningKey, error)

GetCurrentSigningKey returns the currently active signing key, the one marked active in the database. If there is more than one active, the most recently created one wins. Should not occur due to transactional update.

func (*Realm) GetLongCodeDurationHours added in v0.4.0

func (r *Realm) GetLongCodeDurationHours() int

GetLongCodeDurationHours is a helper for the HTML rendering to get a round hours value.

func (*Realm) HasSMSConfig added in v0.3.0

func (r *Realm) HasSMSConfig(db *Database) (bool, error)

HasSMSConfig returns true if the realm has an SMS config, false otherwise. This does not perform the KMS encryption/decryption, so it's more efficient that loading the full SMS config.

func (*Realm) HistoricalCodesIssued added in v0.9.0

func (r *Realm) HistoricalCodesIssued(db *Database, limit uint64) ([]uint64, error)

HistoricalCodesIssued returns a slice of the historical codes issued for this realm by date descending.

func (*Realm) IncrementDailyActiveUsers added in v0.18.0

func (r *Realm) IncrementDailyActiveUsers(db *Database, now time.Time) error

IncrementDailyActiveUsers increments the daily active users for the realm by the provided amount.

func (*Realm) ListAudits added in v0.16.0

func (r *Realm) ListAudits(db *Database, p *pagination.PageParams, scopes ...Scope) ([]*AuditEntry, *pagination.Paginator, error)

ListAudits returns the list audit events which match the given criteria.

func (*Realm) ListAuthorizedApps added in v0.4.0

func (r *Realm) ListAuthorizedApps(db *Database, p *pagination.PageParams, scopes ...Scope) ([]*AuthorizedApp, *pagination.Paginator, error)

func (*Realm) ListMemberships added in v0.19.0

func (r *Realm) ListMemberships(db *Database, p *pagination.PageParams, scopes ...Scope) ([]*Membership, *pagination.Paginator, error)

ListMemberships lists the realm's memberships.

func (*Realm) ListMobileApps added in v0.10.0

func (r *Realm) ListMobileApps(db *Database, p *pagination.PageParams, scopes ...Scope) ([]*MobileApp, *pagination.Paginator, error)

ListMobileApps gets all the mobile apps for the realm.

func (*Realm) ListSigningKeys added in v0.5.0

func (r *Realm) ListSigningKeys(db *Database) ([]*SigningKey, error)

ListSigningKeys returns the non-deleted signing keys for a realm ordered by created_at desc.

func (*Realm) MembershipPermissionMap added in v0.19.0

func (r *Realm) MembershipPermissionMap(db *Database) (map[uint]rbac.Permission, error)

MembershipPermissionMap returns a map where the key is the ID of a user and the value is the permissions for that user.

func (*Realm) QuotaKey added in v0.12.1

func (r *Realm) QuotaKey(hmacKey []byte) (string, error)

QuotaKey returns the unique and consistent key to use for storing quota data for this realm, given the provided HMAC key.

func (*Realm) RenderWelcomeMessage added in v0.9.0

func (r *Realm) RenderWelcomeMessage() string

RenderWelcomeMessage message renders the realm's welcome message.

func (*Realm) SMSConfig

func (r *Realm) SMSConfig(db *Database) (*SMSConfig, error)

SMSConfig returns the SMS configuration for this realm, if one exists. If the realm is configured to use the system SMS configuration, that configuration is preferred.

func (*Realm) SMSProvider added in v0.3.0

func (r *Realm) SMSProvider(db *Database) (sms.Provider, error)

SMSProvider returns the SMS provider for the realm. If no sms configuration exists, it returns nil. If any errors occur creating the provider, they are returned.

func (*Realm) SetActiveSigningKey added in v0.5.0

func (r *Realm) SetActiveSigningKey(db *Database, id uint) (string, error)

SetActiveSigningKey sets a specific signing key to active=true for the realm, and transactionally sets all other signing keys to inactive. It accepts the database primary key ID but returns the KID of the now-active key.

func (*Realm) SigningKeyID added in v0.5.0

func (r *Realm) SigningKeyID() string

func (*Realm) Stats added in v0.8.0

func (r *Realm) Stats(db *Database) (RealmStats, error)

Stats returns the 30-day usage statistics for this realm. If no stats exist, returns an empty array.

func (*Realm) StatsCached added in v0.19.0

func (r *Realm) StatsCached(ctx context.Context, db *Database, cacher cache.Cacher) (RealmStats, error)

StatsCached is stats, but cached.

func (*Realm) UserStats added in v0.17.1

func (r *Realm) UserStats(db *Database) (RealmUserStats, error)

UserStats returns the 30-day stats by user.

func (*Realm) UserStatsCached added in v0.19.0

func (r *Realm) UserStatsCached(ctx context.Context, db *Database, cacher cache.Cacher) (RealmUserStats, error)

UserStatsCached is stats, but cached.

func (*Realm) ValidTestType added in v0.4.0

func (r *Realm) ValidTestType(typ string) bool

ValidTestType returns true if the given test type string is valid for this realm, false otherwise.

type RealmStat added in v0.17.1

type RealmStat struct {
	Date    time.Time `gorm:"column:date; type:date; not null;"`
	RealmID uint      `gorm:"column:realm_id; type:integer; not null;"`

	// CodesIssued is the total number of codes issued. CodesClaimed are
	// successful claims. CodesInvalid are codes that have failed to claim
	// (expired or not found).
	CodesIssued  uint `gorm:"column:codes_issued; type:integer; not null; default:0;"`
	CodesClaimed uint `gorm:"column:codes_claimed; type:integer; not null; default:0;"`
	CodesInvalid uint `gorm:"column:codes_invalid; type:integer; not null; default:0;"`

	// TokensClaimed is the number of tokens exchanged for a certificate.
	// TokensInvalid is the number of tokens which failed to exchange due to
	// a user error.
	TokensClaimed uint `gorm:"column:tokens_claimed; type:integer; not null; default:0;"`
	TokensInvalid uint `gorm:"column:tokens_invalid; type:integer; not null; default:0;"`

	// DailyActiveUsers is the total number of daily active users.
	DailyActiveUsers uint `gorm:"column:daily_active_users; type:integer; not null; default:0;"`
}

RealmStat represents statistics related to a user in the database.

type RealmStats added in v0.8.0

type RealmStats []*RealmStat

RealmStats represents a logical collection of stats of a realm.

func (RealmStats) MarshalCSV added in v0.17.1

func (s RealmStats) MarshalCSV() ([]byte, error)

MarshalCSV returns bytes in CSV format.

func (RealmStats) MarshalJSON added in v0.17.1

func (s RealmStats) MarshalJSON() ([]byte, error)

MarshalJSON is a custom JSON marshaller.

func (*RealmStats) UnmarshalJSON added in v0.17.1

func (s *RealmStats) UnmarshalJSON(b []byte) error

type RealmUserStat added in v0.17.1

type RealmUserStat struct {
	Date        time.Time
	RealmID     uint
	UserID      uint
	Name        string
	Email       string
	CodesIssued uint
}

RealmUserStat is an interim data structure representing a single date/user statistic. It does not correspond to a single database table, but is rather a join across multiple tables.

type RealmUserStats added in v0.12.1

type RealmUserStats []*RealmUserStat

RealmUserStats is a grouping collection of RealmUserStat.

func (RealmUserStats) MarshalCSV added in v0.17.1

func (s RealmUserStats) MarshalCSV() ([]byte, error)

MarshalCSV returns bytes in CSV format.

func (RealmUserStats) MarshalJSON added in v0.17.1

func (s RealmUserStats) MarshalJSON() ([]byte, error)

MarshalJSON is a custom JSON marshaller.

func (*RealmUserStats) UnmarshalJSON added in v0.17.1

func (s *RealmUserStats) UnmarshalJSON(b []byte) error

type SMSConfig

type SMSConfig struct {
	gorm.Model
	Errorable

	// SMS Config belongs to exactly one realm.
	RealmID uint

	// ProviderType is the SMS provider type - it's used to determine the
	// underlying configuration.
	ProviderType sms.ProviderType `gorm:"type:varchar(100)"`

	// Twilio configuration options.
	TwilioAccountSid string `gorm:"type:varchar(250)"`
	// E.164 format telephone number or
	// Twilio messaging service identifier see: https://support.twilio.com/hc/en-us/articles/223134387-What-is-a-Message-SID-
	TwilioFromNumber string `gorm:"type:varchar(255)"`

	// TwilioAuthToken is encrypted/decrypted automatically by callbacks. The
	// cache fields exist as optimizations.
	TwilioAuthToken                string `gorm:"type:varchar(250)" json:"-"` // ignored by zap's JSON formatter
	TwilioAuthTokenPlaintextCache  string `gorm:"-"`
	TwilioAuthTokenCiphertextCache string `gorm:"-"`

	// IsSystem determines if this is a system-level SMS configuration. There can
	// only be one system-level SMS configuration.
	IsSystem bool `gorm:"type:bool; not null; default:false;"`
}

SMSConfig represents and SMS configuration.

func (*SMSConfig) BeforeSave added in v0.3.0

func (s *SMSConfig) BeforeSave(tx *gorm.DB) error

type SMSFromNumber added in v0.19.0

type SMSFromNumber struct {
	Errorable

	ID    uint   `gorm:"primary_key;" json:"id,omitempty"`
	Label string `gorm:"column:label;" json:"label"`
	Value string `gorm:"column:value;" json:"value"`
}

SMSFromNumber represents a source number which can send SMS messages. The table only contains the system SMS from numbers.

func (*SMSFromNumber) BeforeSave added in v0.19.0

func (s *SMSFromNumber) BeforeSave(tx *gorm.DB) error

type Scope added in v0.16.0

type Scope = func(db *gorm.DB) *gorm.DB

Scope is a type alias to a gorm scope. It exists to reduce duplicate and function length. Note this is an ALIAS. It is NOT a new type.

func OnlySystemAdmins added in v0.16.0

func OnlySystemAdmins() Scope

OnlySystemAdmins returns a scope that restricts the query to system admins. It's only applicable to functions that query User.

func WithAppOS added in v0.17.1

func WithAppOS(os OSType) Scope

WithAppOS returns a scope that for querying MobileApps by Operating System type.

func WithAuditRealmID added in v0.17.0

func WithAuditRealmID(id uint) Scope

WithAuditRealmID returns a scope that adds querying for Audit events by realm. The provided ID is expected to be stringable (int, uint, string).

func WithAuditTime added in v0.17.0

func WithAuditTime(from, to string) Scope

WithAuditTime returns a scope that adds querying for Audit events by time.

func WithAuthorizedAppSearch added in v0.16.0

func WithAuthorizedAppSearch(q string) Scope

WithAuthorizedAppSearch returns a scope that adds querying for API keys by name and preview, case-insensitive. It's only applicable to functions that query AuthorizedApp.

func WithMobileAppSearch added in v0.16.0

func WithMobileAppSearch(q string) Scope

WithMobileAppSearch returns a scope that adds querying for mobile apps by name, case-insensitive. It's only applicable to functions that query MobileApp.

func WithPermissionSearch added in v0.19.1

func WithPermissionSearch(p rbac.Permission) Scope

WithPermissionSearch searches for memberships which have the given permission.

func WithRealmSearch added in v0.16.0

func WithRealmSearch(q string) Scope

WithRealmSearch returns a scope that adds querying for realms by name. It's only applicable to functions that query Realm.

func WithUserSearch added in v0.16.0

func WithUserSearch(q string) Scope

WithUserSearch returns a scope that adds querying for users by email and name, case-insensitive. It's only applicable to functions that query User.

func WithoutAuditTest added in v0.17.0

func WithoutAuditTest() Scope

WithoutAuditTest excludes audit entries related to test entries created from SystemTest.

func WithoutPermissionSearch added in v0.19.1

func WithoutPermissionSearch(p rbac.Permission) Scope

WithoutPermissionSearch searches for memberships which do not have the given permission.

type SigningKey added in v0.5.0

type SigningKey struct {
	gorm.Model
	Errorable

	// A signing key belongs to exactly one realm.
	RealmID uint `gorm:"index:realm"`

	// Reference to an exact version of a key in the KMS
	KeyID  string
	Active bool
}

SigningKey represents a reference to a KMS backed signing key version for verification certificate signing.

func (*SigningKey) GetKID added in v0.5.0

func (s *SigningKey) GetKID() string

GetKID returns the 'kid' field value to use in signing JWTs.

type Subject

type Subject struct {
	TestType    string
	SymptomDate *time.Time
	TestDate    *time.Time
}

Subject represents the data that is used in the 'sub' field of the token JWT.

func ParseSubject

func ParseSubject(sub string) (*Subject, error)

func (*Subject) String

func (s *Subject) String() string

func (*Subject) SymptomInterval

func (s *Subject) SymptomInterval() uint32

type TestInstance added in v0.17.1

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

TestInstance is a wrapper around the Docker-based database instance.

func MustTestInstance added in v0.17.1

func MustTestInstance() *TestInstance

MustTestInstance is NewTestInstance, except it prints errors to stderr and calls os.Exit when finished. Callers can call Close or MustClose().

func NewTestInstance added in v0.17.1

func NewTestInstance() (*TestInstance, error)

NewTestInstance creates a new Docker-based database instance. It also creates an initial database, runs the migrations, and sets that database as a template to be cloned by future tests.

This should not be used outside of testing, but it is exposed in the package so it can be shared with other packages. It should be called and instantiated in TestMain.

All database tests can be skipped by running `go test -short` or by setting the `SKIP_DATABASE_TESTS` environment variable.

func (*TestInstance) Close added in v0.17.1

func (i *TestInstance) Close() (retErr error)

Close terminates the test database instance, cleaning up any resources.

func (*TestInstance) MustClose added in v0.17.1

func (i *TestInstance) MustClose() error

MustClose is like Close except it prints the error to stderr and calls os.Exit.

func (*TestInstance) NewDatabase added in v0.17.1

func (i *TestInstance) NewDatabase(tb testing.TB, cacher cache.Cacher) (*Database, *Config)

NewDatabase creates a new database suitable for use in testing. It returns an established database connection and the configuration.

type TestType added in v0.4.0

type TestType int16

TestType is a test type in the database.

const (
	TestTypeConfirmed TestType
	TestTypeLikely
	TestTypeNegative
)

func (TestType) Display added in v0.11.0

func (t TestType) Display() string

type Token

type Token struct {
	gorm.Model
	// Tokens belong to one realm.
	RealmID     uint
	TokenID     string `gorm:"type:varchar(200); unique_index"`
	TestType    string `gorm:"type:varchar(20)"`
	SymptomDate *time.Time
	TestDate    *time.Time
	Used        bool `gorm:"default:false"`
	ExpiresAt   time.Time
}

Token represents an issued "long term" from a validated verification code.

func (*Token) FormatSymptomDate

func (t *Token) FormatSymptomDate() string

FormatSymptomDate returns YYYY-MM-DD formatted symptom date, or "" if nil.

func (*Token) FormatTestDate added in v0.14.0

func (t *Token) FormatTestDate() string

FormatTestDate returns YYYY-MM-DD formatted test date, or "" if nil.

func (*Token) Subject

func (t *Token) Subject() *Subject

type User

type User struct {
	gorm.Model
	Errorable

	Email       string `gorm:"type:varchar(250);unique_index"`
	Name        string `gorm:"type:varchar(100)"`
	SystemAdmin bool   `gorm:"column:system_admin; default:false;"`

	LastRevokeCheck    time.Time
	LastPasswordChange time.Time
}

User represents a user of the system

func (*User) AddToRealm added in v0.19.0

func (u *User) AddToRealm(db *Database, r *Realm, permissions rbac.Permission, actor Auditable) error

AddToRealm adds the current user to the realm with the given permissions. If a record already exists, the permissions are overwritten with the new permissions.

func (*User) AuditDisplay added in v0.11.0

func (u *User) AuditDisplay() string

AuditDisplay is how the user will be displayed in audit entries.

func (*User) AuditID added in v0.11.0

func (u *User) AuditID() string

AuditID is how the user is stored in the audit entry.

func (*User) BeforeSave added in v0.4.0

func (u *User) BeforeSave(tx *gorm.DB) error

BeforeSave runs validations. If there are errors, the save fails.

func (*User) DeleteFromRealm added in v0.19.0

func (u *User) DeleteFromRealm(db *Database, r *Realm, actor Auditable) error

DeleteFromRealm removes this user from the given realm. If the user does not exist in the realm, no action is taken.

func (*User) FindMembership added in v0.19.0

func (u *User) FindMembership(db *Database, realmID interface{}) (*Membership, error)

FindMembership finds the corresponding membership for the given realm ID, if one exists. If not does not exist, an error is returned that satisfies IsNotFound.

func (*User) ListMemberships added in v0.19.0

func (u *User) ListMemberships(db *Database) ([]*Membership, error)

ListMemberships lists the memberships for this user. Use ListMembershipsCached where possible.

func (*User) PasswordAgeString added in v0.9.0

func (u *User) PasswordAgeString() string

PasswordAgeString displays the age of the password in friendly text.

func (*User) PasswordChanged added in v0.10.0

func (u *User) PasswordChanged() time.Time

PasswordChanged returns password change time or account creation time if unset.

func (*User) SelectFirstMembership added in v0.19.0

func (u *User) SelectFirstMembership(db *Database) (*Membership, error)

SelectFirstMembership selects the first memberships for this user.

func (*User) Stats added in v0.5.0

func (u *User) Stats(db *Database, realm *Realm) (UserStats, error)

Stats returns the usage statistics for this user at the provided realm. If no stats exist, it returns an empty array.

func (*User) StatsCached added in v0.19.0

func (u *User) StatsCached(ctx context.Context, db *Database, cacher cache.Cacher, realm *Realm) (UserStats, error)

StatsCached is stats, but cached.

type UserStat added in v0.18.0

type UserStat struct {
	Date        time.Time `gorm:"date; not null;"`
	UserID      uint      `gorm:"user_id; not null;"`
	RealmID     uint      `gorm:"realm_id; default:0;"`
	CodesIssued uint      `gorm:"codes_issued; default:0;"`

	// Non-database fields, these are added via the stats lookup using the join
	// table.
	UserName  string `gorm:"-"`
	UserEmail string `gorm:"-"`
}

UserStat represents a single-date statistic for a user.

type UserStats added in v0.3.0

type UserStats []*UserStat

UserStats represents a logical collection of stats for a user.

func (UserStats) MarshalCSV added in v0.18.0

func (s UserStats) MarshalCSV() ([]byte, error)

MarshalCSV returns bytes in CSV format.

func (UserStats) MarshalJSON added in v0.18.0

func (s UserStats) MarshalJSON() ([]byte, error)

MarshalJSON is a custom JSON marshaller.

func (*UserStats) UnmarshalJSON added in v0.18.0

func (s *UserStats) UnmarshalJSON(b []byte) error

type VerificationCode

type VerificationCode struct {
	gorm.Model
	Errorable

	RealmID       uint   // VerificationCodes belong to exactly one realm when issued.
	Code          string `gorm:"type:varchar(512)"`
	LongCode      string `gorm:"type:varchar(512)"`
	UUID          string `gorm:"type:uuid;default:null"`
	Claimed       bool   `gorm:"default:false"`
	TestType      string `gorm:"type:varchar(20)"`
	SymptomDate   *time.Time
	TestDate      *time.Time
	ExpiresAt     time.Time
	LongExpiresAt time.Time

	// IssuingUserID is the ID of the user in the database that created this
	// verification code. This is only populated if the code was created via the
	// UI.
	IssuingUserID uint `gorm:"column:issuing_user_id; type:integer;"`

	// IssuingAppID is the ID of the app in the database that created this
	// verification code. This is only populated if the code was created via the
	// API.
	IssuingAppID uint `gorm:"column:issuing_app_id; type:integer;"`

	// IssuingExternalID is an optional ID to an external system that created this
	// verification code. This is only populated if the code was created via the
	// API AND the API caller supplied it in the request. This ID has no meaning
	// in this system. It can be up to 255 characters in length.
	IssuingExternalID string `gorm:"column:issuing_external_id; type:varchar(255);"`
}

VerificationCode represents a verification code in the database.

func (*VerificationCode) AfterCreate added in v0.5.0

func (v *VerificationCode) AfterCreate(scope *gorm.Scope)

AfterCreate runs after the verification code has been saved, primarily used to update statistics about usage. If the executions fail, an error is logged but the transaction continues. This is called automatically by gorm.

func (*VerificationCode) BeforeSave added in v0.17.1

func (v *VerificationCode) BeforeSave(tx *gorm.DB) error

BeforeSave is used by callbacks.

func (*VerificationCode) FormatSymptomDate

func (v *VerificationCode) FormatSymptomDate() string

FormatSymptomDate returns YYYY-MM-DD formatted test date, or "" if nil.

func (*VerificationCode) HasLongExpiration added in v0.7.0

func (v *VerificationCode) HasLongExpiration() bool

func (*VerificationCode) IsExpired

func (v *VerificationCode) IsExpired() bool

IsExpired returns true if a verification code has expired.

func (*VerificationCode) Validate

func (v *VerificationCode) Validate(realm *Realm) error

Validate validates a verification code before save.

Jump to

Keyboard shortcuts

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