Documentation
¶
Overview ¶
Package auth holds backd's identity model: users, their sign-in identities and password handling. It is storage-neutral; MongoDB specifics live behind Store in internal/mongodb.
A user carries no credentials. Each way of signing in is an Identity (provider + subject), so adding login providers later only adds identities: a password user has a "password" identity, and a user who signs in only through another provider needs none.
Index ¶
- Constants
- Variables
- func ActorOf(ctx context.Context) string
- func CheckPassword(password string, minLength int) (string, error)
- func CleanProfile(in map[string]string) map[string]string
- func CompletionJobID(jobID string) string
- func DefaultHashConcurrency(p Argon2Params) int
- func ErasedEmail(id string) string
- func HashEmailToken(token string) string
- func HashToken(token string) string
- func HashUploadToken(token string) string
- func IPKey(ip string) string
- func IdempotencyID(database, name, callerSubject, key string) string
- func NewPKCE() (verifier, challenge string, err error)
- func NewSessionToken() (string, error)
- func NewUploadToken() (token, hash string)
- func PKCEChallenge(verifier string) string
- func ProfileValues(input json.RawMessage) []string
- func ScheduledJobID(database, function string, scheduledAt time.Time) string
- func SignCallback(key []byte, c CallbackClaims) string
- func ValidPKCEChallenge(s string) bool
- func WithAuditSource(ctx context.Context, source func() AuditSource) context.Context
- type APIKey
- type Argon2Params
- type Attempts
- type AuditFilter
- type AuditRecord
- type AuditSource
- type AuthChallenge
- type CallbackClaims
- type Caller
- type CheckJob
- type CheckProblem
- type CheckReport
- type CheckedDocument
- type ConsentContext
- type ConsentInput
- type ConsentNotice
- type ConsentRecord
- type ConsentRef
- type ConsentRequiredError
- type CustomEmail
- type Device
- type DeviceInput
- type EmailJob
- type EmailLimitedError
- type EmailRequest
- type EmailToken
- type EraseJob
- type ErrCheckRunning
- type FileDeletion
- type FileDeletionStats
- type FileJournalEntry
- type FuncCaller
- type Hasher
- type IdempotencyRecord
- type Identity
- type IdentityUpdate
- type ImageJob
- type InvalidCodeError
- type InvalidConsentsError
- type InvalidDeviceError
- type InvalidLocaleError
- type Invitation
- type InvocationFilter
- type InvocationRecord
- type IssuedChallenge
- type Job
- type JobFilter
- type JobResult
- type KeyOptions
- type KeyRole
- type LogLine
- type LoginCode
- type MFALockedError
- type MFARecord
- type MFAStatus
- type MagicLinkInput
- type OAuthState
- type OnSignupInput
- type PolicyError
- type Principal
- type ProviderLogin
- type ProviderResult
- type PushAudience
- type PushCounts
- type PushDelta
- type PushJob
- type PushOutboxEntry
- type PushRecipient
- type PushSend
- type PushSendFilter
- type PushSendInput
- type PushStarted
- type PushUserFilter
- type ReauthGrant
- type Redeemed
- type RefusedError
- type RevokeJob
- type RoleReport
- type ScheduleState
- type Scope
- type ScopeOp
- type Scopes
- type Secret
- type SecretCache
- type SecretCipher
- type SecretMeta
- type Session
- type SignupRequest
- type SignupResult
- type Step
- type StorageUsage
- type StorageUsageTotals
- type Store
- type TOTPSetup
- type ThrottledError
- type User
- type UserUpdate
- type UserUsage
- type Users
- func (s *Users) AbandonedUploads(ctx context.Context, limit int) ([]FileJournalEntry, error)
- func (s *Users) AcceptConsents(ctx context.Context, challenge string, given map[string]string, ...) (Verified, error)
- func (s *Users) AcceptConsentsOf(ctx context.Context, u User, given map[string]string, from ConsentContext) (User, error)
- func (s *Users) AcceptInvitation(ctx context.Context, token, password, locale string) (EmailToken, error)
- func (s *Users) AddRole(ctx context.Context, email, role string) error
- func (s *Users) ApplyRoleSeeds(ctx context.Context) (int, error)
- func (s *Users) Audit(ctx context.Context, action, target string, details map[string]any)
- func (s *Users) AuditAs(ctx context.Context, actor, action, target string, details map[string]any)
- func (s *Users) AuditTrail(ctx context.Context, f AuditFilter) ([]AuditRecord, bool, error)
- func (s *Users) Authenticate(ctx context.Context, token string) (Principal, error)
- func (s *Users) AuthenticateIgnoringConsents(ctx context.Context, token string) (Principal, error)
- func (s *Users) AuthenticateKey(ctx context.Context, key string) (APIKey, error)
- func (s *Users) BeginEnrollment(ctx context.Context, challenge string) (TOTPSetup, error)
- func (s *Users) BeginOAuth(ctx context.Context, st OAuthState) (state, nonce, verifier string, err error)
- func (s *Users) BeginTOTPSetup(ctx context.Context, u User) (TOTPSetup, error)
- func (s *Users) CallbackCaller(ctx context.Context, c CallbackClaims) (Caller, error)
- func (s *Users) CancelJob(ctx context.Context, id string) (Job, error)
- func (s *Users) ChangeEmailAsAdmin(ctx context.Context, userID, newAddress string) (User, error)
- func (s *Users) ChangePassword(ctx context.Context, p Principal, next string) error
- func (s *Users) CheckReauth(ctx context.Context, p Principal, token string) error
- func (s *Users) CheckReport(ctx context.Context, database, collection string) (CheckReport, error)
- func (s *Users) CheckReports(ctx context.Context, documents bool) ([]CheckReport, error)
- func (s *Users) ClaimDirectUpload(ctx context.Context, id, token string) (FileJournalEntry, error)
- func (s *Users) ClaimFileDeletions(ctx context.Context, limit int) ([]FileDeletion, error)
- func (s *Users) ClaimIdempotency(ctx context.Context, rec IdempotencyRecord) (IdempotencyRecord, bool, error)
- func (s *Users) ClaimJob(ctx context.Context, workerID string) (Job, bool, error)
- func (s *Users) ClaimPendingUpload(ctx context.Context, id, token, documentID string) (FileJournalEntry, error)
- func (s *Users) Clock() time.Time
- func (s *Users) CompleteEnrollment(ctx context.Context, challenge, setupID, code string) (Verified, []string, error)
- func (s *Users) CompleteIdempotency(ctx context.Context, id string, result *JobResult, jobID string) error
- func (s *Users) CompleteJob(ctx context.Context, id string, result JobResult) error
- func (s *Users) CompletePendingUpload(ctx context.Context, id, name, contentType, sha256sum string, size int64, ...) error
- func (s *Users) ConfirmEmailChange(ctx context.Context, token string) (EmailToken, error)
- func (s *Users) ConfirmTOTP(ctx context.Context, u User, keepSession, setupID, code string) ([]string, error)
- func (s *Users) ConsentHistory(ctx context.Context, userID string) ([]ConsentRecord, error)
- func (s *Users) ConsentPseudonym(ctx context.Context, address string) (string, error)
- func (s *Users) Create(ctx context.Context, email string, password *string) (User, error)
- func (s *Users) CreateAPIKey(ctx context.Context, name string, opts KeyOptions) (APIKey, string, error)
- func (s *Users) CreateInvitation(ctx context.Context, email string, ttl time.Duration, createdBy string) (Invitation, string, error)
- func (s *Users) DeactivateAccount(ctx context.Context, p Principal) error
- func (s *Users) Delete(ctx context.Context, email string) error
- func (s *Users) DeleteSecret(ctx context.Context, database, name string) error
- func (s *Users) Devices(ctx context.Context, userID string) ([]Device, error)
- func (s *Users) DisableMFA(ctx context.Context, u User) error
- func (s *Users) EnqueueCompletionJob(ctx context.Context, finished Job, target string, timeoutMS int64, ...) (Job, bool, error)
- func (s *Users) EnqueueImageJob(ctx context.Context, database string, e ImageJob, requestID string) error
- func (s *Users) EnqueueImageOp(ctx context.Context, database string, e ImageJob, requestID string) (Job, error)
- func (s *Users) EnqueueJob(ctx context.Context, j Job) (Job, error)
- func (s *Users) EnqueueJobID(ctx context.Context, j Job) (created bool, err error)
- func (s *Users) EnqueueScheduledJob(ctx context.Context, j Job, scheduledAt time.Time, skipOverlap bool) (Job, bool, error)
- func (s *Users) Erase(ctx context.Context, id, requestID string) (Job, error)
- func (s *Users) EraseJobFor(ctx context.Context, userID string) (Job, bool, error)
- func (s *Users) FileAdded(ctx context.Context, owner string, size int64) error
- func (s *Users) FileDeletionStats(ctx context.Context) (FileDeletionStats, error)
- func (s *Users) FileRemoved(ctx context.Context, owner string, size int64) error
- func (s *Users) Find(ctx context.Context, email string) (User, error)
- func (s *Users) FinishFileDeletion(ctx context.Context, key string) error
- func (s *Users) GetJob(ctx context.Context, id string) (Job, bool, error)
- func (s *Users) Identify(ctx context.Context, credential string) (Caller, error)
- func (s *Users) Identities(ctx context.Context, userID string) ([]Identity, error)
- func (s *Users) ImageDeclarations(ctx context.Context) (map[string]string, error)
- func (s *Users) InvitationByID(ctx context.Context, id string) (Invitation, bool, error)
- func (s *Users) Invitations(ctx context.Context) ([]Invitation, error)
- func (s *Users) Invocations(ctx context.Context, f InvocationFilter) ([]InvocationRecord, bool, error)
- func (s *Users) IsSeeded(email, role string) bool
- func (s *Users) IssueLoginCode(ctx context.Context, userID, method, challenge string, newUser bool, ...) (string, error)
- func (s *Users) Jobs(ctx context.Context, f JobFilter) ([]Job, bool, error)
- func (s *Users) JournalDirectUpload(ctx context.Context, e FileJournalEntry, ttl time.Duration) error
- func (s *Users) JournalPendingUpload(ctx context.Context, e FileJournalEntry, ttl time.Duration) error
- func (s *Users) JournalUpload(ctx context.Context, e FileJournalEntry) error
- func (s *Users) KeyCreatedBySession(ctx context.Context, p Principal)
- func (s *Users) List(ctx context.Context) ([]User, error)
- func (s *Users) ListAPIKeys(ctx context.Context) ([]APIKey, error)
- func (s *Users) ListPage(ctx context.Context, contains, after string, skip, limit int) ([]User, bool, error)
- func (s *Users) ListSecrets(ctx context.Context) ([]SecretMeta, error)
- func (s *Users) LocaleOf(u User) string
- func (s *Users) Login(ctx context.Context, email, password, ip string) (Principal, string, error)
- func (s *Users) Logout(ctx context.Context, p Principal) error
- func (s *Users) LogoutAll(ctx context.Context, p Principal) error
- func (s *Users) MFAStatusOf(ctx context.Context, u User) (MFAStatus, error)
- func (s *Users) MagicLinkByToken(ctx context.Context, token string) (AuthChallenge, error)
- func (s *Users) MagicLinkDestination(c AuthChallenge) string
- func (s *Users) MagicLinkEmailFor(ctx context.Context, challengeID string) (AuthChallenge, string, error)
- func (s *Users) MakeMagicLinkSecrets(ctx context.Context, challengeID string) (token, code string, expires time.Time, err error)
- func (s *Users) MakeReauthCode(ctx context.Context, challengeID string) (string, time.Time, error)
- func (s *Users) MaxSessionExpiry(u User, created time.Time) time.Time
- func (s *Users) NetworksInConfig(email string) bool
- func (s *Users) NewEmailToken(ctx context.Context, purpose, userID, redirectTo string, ttl time.Duration) (token string, expiresAt time.Time, err error)
- func (s *Users) NewEmailTokenFor(ctx context.Context, t EmailToken, ttl time.Duration) (token string, expiresAt time.Time, err error)
- func (s *Users) NotifyConsentUpdated(ctx context.Context, consent string) (ConsentNotice, error)
- func (s *Users) OnBehalfOf(ctx context.Context, c Caller, userID string) (Caller, error)
- func (s *Users) OpenPendingUploads(ctx context.Context, callerKey string) (int, error)
- func (s *Users) OpenToken(sealed string) (string, error)
- func (s *Users) PeekEmailToken(ctx context.Context, token, purpose string) (EmailToken, error)
- func (s *Users) PendingUpload(ctx context.Context, id string) (FileJournalEntry, error)
- func (s *Users) PlanPushAudience(ctx context.Context, job Job) error
- func (s *Users) PlanPushBatch(ctx context.Context, batchID, sendID string, users []string, ...) (PushCounts, error)
- func (s *Users) PlanPushBatchRequiring(ctx context.Context, batchID, sendID string, users []string, ...) (PushCounts, error)
- func (s *Users) PurgeUnverified(ctx context.Context) (int, error)
- func (s *Users) PushSendByID(ctx context.Context, id string) (PushSend, error)
- func (s *Users) PushSends(ctx context.Context, f PushSendFilter) ([]PushSend, bool, error)
- func (s *Users) QueueEmail(ctx context.Context, r EmailRequest) (Job, error)
- func (s *Users) QueueFileDeletion(ctx context.Context, key, reason string) error
- func (s *Users) RateLimit(ctx context.Context, key string, limit int, window time.Duration) error
- func (s *Users) ReauthMethodsOf(ctx context.Context, u User) ([]string, error)
- func (s *Users) Reauthenticate(ctx context.Context, p Principal, method, proof, ip string) (ReauthGrant, error)
- func (s *Users) RecordConsent(ctx context.Context, userID string, in ConsentInput) (ConsentRecord, error)
- func (s *Users) RecordConsentFor(ctx context.Context, userID string, in ConsentInput) (ConsentRecord, error)
- func (s *Users) RecordInvocation(ctx context.Context, rec InvocationRecord)
- func (s *Users) RedeemEmailToken(ctx context.Context, token, purpose string) (EmailToken, error)
- func (s *Users) RedeemLoginCode(ctx context.Context, code, verifier string) (Redeemed, error)
- func (s *Users) ReduceConsentRecords(ctx context.Context, userID, address string) (int64, error)
- func (s *Users) RegenerateRecoveryCodes(ctx context.Context, u User) ([]string, error)
- func (s *Users) RegisterDevice(ctx context.Context, p Principal, in DeviceInput) (Device, error)
- func (s *Users) ReleaseDirectUpload(ctx context.Context, id string) error
- func (s *Users) ReleaseIdempotency(ctx context.Context, id string) error
- func (s *Users) ReleasePendingUpload(ctx context.Context, id string) error
- func (s *Users) RemoveDevice(ctx context.Context, userID, id, by string) error
- func (s *Users) RemoveDevicesOfPlatform(ctx context.Context, platform string) (int64, error)
- func (s *Users) RemovePassword(ctx context.Context, p Principal) error
- func (s *Users) RemoveRole(ctx context.Context, email, role string) error
- func (s *Users) RenewJobLease(ctx context.Context, id string, attempt int, d time.Duration) (bool, error)
- func (s *Users) ReportRoles(ctx context.Context) (RoleReport, error)
- func (s *Users) RequestEmailChange(ctx context.Context, p Principal, newAddress, redirectTo, ip, requestID string) error
- func (s *Users) RequestMagicLink(ctx context.Context, in MagicLinkInput) (string, error)
- func (s *Users) RequestPasswordReset(ctx context.Context, address, redirectTo, ip, requestID string) error
- func (s *Users) RequestReauthCode(ctx context.Context, p Principal, ip, requestID string) error
- func (s *Users) RerunJob(ctx context.Context, id string, timeoutMS int64) (Job, error)
- func (s *Users) ResendVerification(ctx context.Context, address, redirectTo, ip, requestID string) error
- func (s *Users) ResetMFA(ctx context.Context, userID, actorID string) error
- func (s *Users) ResetPassword(ctx context.Context, token, password string) (EmailToken, error)
- func (s *Users) ResolveProviderLogin(ctx context.Context, in ProviderLogin) (ProviderResult, error)
- func (s *Users) ResolveSecrets(ctx context.Context, refs []registry.SecretRef, database string) (values map[string]string, missing []string, err error)
- func (s *Users) RetryFileDeletion(ctx context.Context, key string, wait time.Duration) error
- func (s *Users) RetryJob(ctx context.Context, id string, delay time.Duration) error
- func (s *Users) RevertEmailChange(ctx context.Context, token string) (EmailToken, error)
- func (s *Users) RevokeAPIKey(ctx context.Context, name string) error
- func (s *Users) RevokeInvitation(ctx context.Context, id string) error
- func (s *Users) RevokeSession(ctx context.Context, p Principal, id string) error
- func (s *Users) RevokeUserSession(ctx context.Context, userID, id string) error
- func (s *Users) SaveAppleToken(ctx context.Context, userID, clientID, refreshToken string) error
- func (s *Users) SaveCheckReport(ctx context.Context, r CheckReport) error
- func (s *Users) ScheduleStates(ctx context.Context) (map[string]ScheduleState, error)
- func (s *Users) SealToken(token string) (string, error)
- func (s *Users) SendInvitation(ctx context.Context, address string, ttl time.Duration, ...) (Invitation, error)
- func (s *Users) Sessions(ctx context.Context, p Principal) ([]Session, error)
- func (s *Users) SetDisabled(ctx context.Context, email string, disabled bool) error
- func (s *Users) SetEmailVerified(ctx context.Context, email string, verified bool) error
- func (s *Users) SetImageDeclaration(ctx context.Context, key, fingerprint string) error
- func (s *Users) SetJobSteps(ctx context.Context, id string, attempt int, steps []Step, omitted int) (bool, error)
- func (s *Users) SetLocale(ctx context.Context, userID, locale string) (User, error)
- func (s *Users) SetNetworks(ctx context.Context, email string, admin, login registry.Networks) (User, error)
- func (s *Users) SetPassword(ctx context.Context, email, password string) error
- func (s *Users) SetSchedulePaused(ctx context.Context, database, function string, paused bool, by string) (ScheduleState, error)
- func (s *Users) SetSecret(ctx context.Context, database, name, value, by string) error
- func (s *Users) SetUploadStatus(ctx context.Context, id, status, documentID string) error
- func (s *Users) SignIn(ctx context.Context, email, password, ip string) (Redeemed, error)
- func (s *Users) SignInMethods(ctx context.Context, u User) ([]string, error)
- func (s *Users) SignUp(ctx context.Context, r SignupRequest) (SignupResult, error)
- func (s *Users) Signup(ctx context.Context, email, password, invitation string, locales ...string) (Principal, string, error)
- func (s *Users) StartProviderSession(ctx context.Context, u User, provider string, newUser bool, ...) (Redeemed, error)
- func (s *Users) StartPushSend(ctx context.Context, in PushSendInput, requestID string) (PushStarted, error)
- func (s *Users) StartRegeneration(ctx context.Context, database string, e ImageJob, ...) (Job, error)
- func (s *Users) StartSchemaCheck(ctx context.Context, scope CheckJob, requestedBy, requestID string) (Job, error)
- func (s *Users) StorageUsage(ctx context.Context, limit int) (StorageUsage, error)
- func (s *Users) StorageUsageOf(ctx context.Context, owner string) (realm, user StorageUsageTotals, err error)
- func (s *Users) SweepDevices(ctx context.Context) (stale, orphaned int64, err error)
- func (s *Users) TakeOAuthState(ctx context.Context, state string) (OAuthState, error)
- func (s *Users) Unlink(ctx context.Context, userID, provider, by string) error
- func (s *Users) UploadEntry(ctx context.Context, id string) (FileJournalEntry, error)
- func (s *Users) UseMagicLink(ctx context.Context, token, ip string) (code, destination string, err error)
- func (s *Users) UserByID(ctx context.Context, id string) (User, error)
- func (s *Users) UserSessions(ctx context.Context, userID string) ([]Session, error)
- func (s *Users) UsersWithoutRequiredMFA(ctx context.Context, limit int) ([]User, int, error)
- func (s *Users) ValidateConsents(given map[string]string) error
- func (s *Users) VerifyEmail(ctx context.Context, token string) (EmailToken, error)
- func (s *Users) VerifyMFA(ctx context.Context, challenge, method, code, ip string) (Verified, error)
- func (s *Users) VerifyMagicLinkCode(ctx context.Context, requestID, code, verifier, ip string) (Redeemed, error)
- func (s *Users) WithdrawConsent(ctx context.Context, u User, consent string, from ConsentContext) (User, error)
- type Verified
Constants ¶
const ( // ProviderApple is the identity provider of Sign in with Apple. ProviderApple = "apple" // RevokeOrigin is the origin of a revoke job in the job list. RevokeOrigin = "backd:apple.revoke" )
const ( AuditUserCreate = "user.create" // by an administrator (or bootstrap) AuditUserSignup = "user.signup" // self-service sign-up AuditUserPassword = "user.password" // set by an administrator AuditPasswordChange = "user.password_change" AuditPasswordSet = "user.password_set" // the user set a password on an account that had none AuditPasswordRemoved = "user.password_removed" // the user removed their password AuditUserVerifyEmail = "user.verify_email" // details: verified AuditPasswordReset = "user.password_reset" // by the link in an email; details: verified_address AuditUserPurged = "user.purged_unverified" // details: count; never addresses AuditUserClaimed = "user.claimed" // an unverified account taken over by its mailbox's owner; details: methods, mfa AuditUserDisable = "user.disable" AuditUserEnable = "user.enable" AuditUserDelete = "user.delete" AuditAccountDelete = "user.delete_account" // self-service: the account is deactivated AuditUserErased = "user.erased" // details: job_id and counts, or needs_attention AuditUserNetworks = "user.networks" // details: admin_networks, login_networks AuditSessionRevoke = "session.revoke" // by an administrator; details: session AuditDeviceRemoved = "device.removed" // by an administrator; details: platform, device AuditAppConfig = "appconfig.change" // details: version, kind (set, rollback), paths; never values AuditPushTest = "push.test" // an administrator sent a test push; details: send, kind AuditPushDevices = "push.devices_removed" // an administrator removed every device of a platform (a rotated VAPID key); details: platform, count AuditRoleAdd = "role.add" // details: role AuditRoleRemove = "role.remove" // details: role AuditAPIKeyCreate = "apikey.create" // details: role, expires_at, networks AuditAPIKeyRevoke = "apikey.revoke" AuditEmailChanged = "user.email_changed" // details: by (self or admin) AuditEmailReverted = "user.email_change_reverted" // the old address undid a change AuditInviteSent = "invitation.sent" // details: expires_at AuditInviteCreate = "invitation.create" // details: bound_to_email, expires_at AuditInviteRevoke = "invitation.revoke" AuditAdminLogin = "admin.login" // login of a user holding an admin role AuditAdminRefused = "admin.refused" // details: reason AuditBootstrap = "realm.bootstrap" // Sign-in methods; the target is the user, details: provider, and by // (self or admin) for an unlink. AuditIdentityLinked = "identity.linked" AuditIdentityUnlinked = "identity.unlinked" // Apple revoked a user's tokens when their account went away or Apple was unlinked; // never the token itself. AuditAppleRevoked = "identity.apple_revoked" // A provider sign-in the account's state refused; details: provider, reason // (disabled, network, erased, …). AuditSignInRefused = "identity.signin_refused" // Second factors; the target is the user. user.mfa_reset: by an administrator (the // actor) or `instance`; user.mfa_locked: details retry_after_seconds; never codes. AuditMFAEnabled = "user.mfa_enabled" AuditMFADisabled = "user.mfa_disabled" AuditMFAReset = "user.mfa_reset" AuditRecoveryRegenerate = "user.recovery_codes_regenerated" AuditRecoveryCodeUsed = "user.recovery_code_used" // details: codes_left AuditMFALocked = "user.mfa_locked" // A fresh proof of identity before a sensitive action; details: method (never a code). AuditReauth = "user.reauth" // The admin data route (documents written past the collections' rules); // the target is database/collection/id, never content. AuditDataCreate = "data.create" AuditDataUpdate = "data.update" AuditDataDelete = "data.delete" AuditDataRestore = "data.restore" AuditDataPurge = "data.purge" // A schema check started by an administrator; the target is the scope // (<database>/<collection>, <database> or the realm), details: collections, limit. AuditDataCheck = "data.check" // A job cancelled or re-run by an administrator; the target is job:<id>, // details: function (and, for a re-run, the new job's id). AuditJobCancel = "job.cancel" AuditJobRerun = "job.rerun" // A scheduled function paused or resumed by an administrator; the target is // schedule:<database>/<function>. AuditSchedulePause = "schedule.pause" AuditScheduleResume = "schedule.resume" // An administrator ran `backd storage check`; details: ok, provider, bucket. AuditStorageCheck = "storage.check" // An administrator ran `backd storage reconcile`; details: delete, orphans, deleted. AuditStorageReconcile = "storage.reconcile" // An administrator ran `backd files regenerate`; details: version, missing_only, job_id. AuditVersionsRegenerate = "files.versions.regenerate" AuditSecretSet = "secret.set" // details: database ("": realm scope); never the value AuditSecretDelete = "secret.delete" // details: database AuditSecretsRotated = "secret.rotate_key" // by backd secret rotate-key; details: count )
Audit actions: security-sensitive changes and events, recorded in the realm's append-only audit trail.
const ( // ActorConfig applies realm.yaml's role and network seeds. ActorConfig = "config:realm.yaml" // ActorInstance is an operator with direct access to the instance's database and key // (`backd user mfa-reset --local`). ActorInstance = "instance" // ActorBootstrap is `backd bootstrap`. ActorBootstrap = "cli:bootstrap" // ActorSystem is backd itself, in the background (purging unverified accounts). ActorSystem = "system" // ActorAnonymous is a caller without credentials. ActorAnonymous = "anonymous" )
Actors that aren't a credential.
const ( ConsentAccepted = "accepted" ConsentWithdrawn = "withdrawn" ConsentMethodSignup = "signup" ConsentMethodPrompt = "prompt" ConsentMethodAPI = "api" ConsentMethodAdmin = "admin" )
Consent actions and the methods that give them (design/compliance.md §5.2).
const ( JournalWriting = "writing" // the upload started; the object may be partly stored JournalStored = "stored" // the object is stored; the document doesn't reference it yet JournalAttaching = "attaching" // a write is attaching a pending upload to a document JournalAttached = "attached" // a document references it JournalFailed = "failed" // it never became part of a document; its object was queued for deletion )
Journal states of an upload.
const ( // FileJournalGrace is how long an upload may stay writing or stored before a // worker treats it as abandoned. FileJournalGrace = time.Hour // FileDeletionLease is how long a worker owns a deletion it claimed. FileDeletionLease = 5 * time.Minute )
const ( IdempotencyRunning = "running" IdempotencyDone = "done" )
Idempotency record statuses.
const ( DefaultInvitationTTL = 7 * 24 * time.Hour MaxInvitationTTL = 90 * 24 * time.Hour )
Invitation lifetimes.
const ( JobQueued = "queued" JobRunning = "running" JobDone = "done" )
Job statuses.
const ( StepRunning = "running" StepDone = "done" StepFailed = "failed" StepTimedOut = "timed_out" StepCancelled = "cancelled" )
Step statuses.
const ( MagicLinkPurposeLink = "link" // a link and a code MagicLinkPurposeNoAccount = "no_account" // a message that there is no account for the address )
What a request sends.
const ( MagicLinkTTL = 10 * time.Minute MagicLinkCodeAttempts = MaxChallengeAttempts // ProviderEmail is the sign-in method of an address proved by a link or a code: an // identity of the user, recorded the first time, so that the rules about a user's last // way to sign in see it like any other. ProviderEmail = "email" )
MagicLinkTTL is how long a request's link and code work; MagicLinkCodeAttempts the wrong tries of its code.
const ( MethodTOTP = "totp" MethodRecovery = "recovery_code" )
The second factors.
const ( // ChallengeMFA waits for a second factor of a user who has one. ChallengeMFA = "mfa" // ChallengeEnroll waits for a user in a required role to set a second factor up. ChallengeEnroll = "enroll" // ChallengeTOTPSetup is a TOTP secret waiting for its first code (the user is // setting authenticator app up). ChallengeTOTPSetup = "totp_setup" // ChallengeReauth is the token a re-authentication gave, bound to a session; // ChallengeReauthCode a code emailed to a user with no other proof. ChallengeReauth = "reauth" ChallengeReauthCode = "reauth_code" // ChallengeMagicLink is a request for a sign-in link and code (see magiclink.go). ChallengeMagicLink = "magic_link" // ChallengeConsent waits for a user to accept consents (see consents_signin.go). ChallengeConsent = "consent" )
The kinds of AuthChallenge.
const ( ChallengeTTL = 5 * time.Minute MaxChallengeAttempts = 5 )
Challenge limits.
const ( OAuthStateTTL = 10 * time.Minute LoginCodeTTL = time.Minute )
The lifetimes of the two short-lived records of the redirect flow.
const ( IntentSignIn = "signin" IntentLink = "link" )
Intents of a sign-in attempt.
const ( PushPlan = "plan" PushBatch = "batch" PushDeliver = "deliver" )
The kinds of push job.
const ( PushBatchSize = 1000 PushUnitSize = 100 )
Sizes of what a send is split into.
const ( ReauthPassword = "password" ReauthEmailCode = "email_code" // ReauthTOTP and ReauthRecovery are the second factors' own names. ReauthTOTP = MethodTOTP ReauthRecovery = MethodRecovery )
The proofs (the method of a re-authentication).
const ( ReauthCodeTTL = 10 * time.Minute ReauthCodeAttempts = MaxChallengeAttempts )
ReauthCodeTTL and the attempts a code allows.
const ( // CheckOrigin is the origin of a schema check's job. CheckOrigin = "backd:schema.check" // CheckLock is the exclusive name of a schema check's job: one at a time. CheckLock = "schema-check" // CheckLease is how long a worker holds a check before another may claim it; the // worker renews it after every batch. CheckLease = 10 * time.Minute // CheckMaxDuration is the longest a check attempt runs before it stops and // says its report is incomplete. CheckMaxDuration = 6 * time.Hour // DefaultCheckLimit and MaxCheckLimit bound how many invalid documents a // report lists per collection. DefaultCheckLimit = 100 MaxCheckLimit = 1000 // MaxCheckProblems is how many problems a report lists per document. MaxCheckProblems = 5 )
const APIKeyPrefix = "bdk_"
APIKeyPrefix starts every API key; see SessionTokenPrefix.
const AuditConsentRecorded = "user.consent_recorded" // details: consent, version, action, evidence
AuditConsentRecorded is the audit action of an administrator recording a consent for a user.
const AuditConsentsNotified = "consents.notify"
AuditConsentsNotified is the audit action of an administrator asking users to review a consent; details: consent, version, queued, limited.
const CallbackTokenPrefix = "bdf_"
CallbackTokenPrefix starts every callback token: the credential a function uses to reach the realm's data (ctx.db, ctx.admin.db) for the duration of one invocation.
const ConsentPseudonymSecret = registry.ConsentPseudonymSecret
ConsentPseudonymSecret is the realm secret that keys the pseudonym consent records keep of an erased person. backd makes it the first time an erase needs it; changing it stops matching records to addresses made before.
const EmailNoConsent = "no_consent"
EmailNoConsent is the status a gated email or push answers for a user who doesn't hold the consent it requires.
const (
EraseOrigin = "backd:account.erase"
)
What an erase job is called in the job list and in the audit trail.
const ImageOrigin = "backd:image.versions"
ImageOrigin is the origin of the job that makes a file's image versions.
const InvitationPrefix = "bdi_"
InvitationPrefix starts every invitation token.
const MagicLinkLoginMethod = "link"
MagicLinkLoginMethod is the first factor a link or a code stands for in sessions and challenges.
const MaxDeviceTokenBytes = 4096
MaxDeviceTokenBytes is the largest token a device may register.
const MaxOpenPendingUploads = 20
MaxOpenPendingUploads is how many unused pending uploads one caller may hold.
const MaxPasswordLength = 128
MaxPasswordLength is the longest accepted password, in characters.
const MaxScopes = 32
MaxScopes bounds the grants of one key.
const MaxSteps = 100
MaxSteps is how many steps a job or an invocation record keeps: the first half and the latest half of what a function reported.
const OnSignupOrigin = "backd:account.on_signup"
OnSignupOrigin is the origin of the job that calls account.on_signup.
const ProviderPassword = "password"
ProviderPassword is the identity provider for email + password sign-in. Its subject is the user's id, so it doesn't depend on the email.
const PushOrigin = "backd:push"
PushOrigin is the origin of the jobs of a send.
const RecoveryCodeCount = 10
RecoveryCodeCount is how many recovery codes a user gets.
const ResultCancelled = "cancelled"
ResultCancelled is the result status of a job an administrator cancelled.
const ResultSkipped = "skipped"
ResultSkipped is the result status of a scheduled run that didn't happen because the function's previous run hadn't finished (overlap: skip).
const SessionTokenPrefix = "bds_"
SessionTokenPrefix starts every session token, so tokens are easy to recognize (e.g. by secret scanners) and to tell apart from API keys.
const TOTPSetupTTL = 15 * time.Minute
TOTPSetupTTL is how long a TOTP secret waits for its first code.
Variables ¶
var ( ErrKeyNameTaken = errors.New("an API key with this name already exists") ErrKeyNotFound = errors.New("API key not found") )
var ( ErrNotFound = errors.New("user not found") ErrEmailTaken = errors.New("email is already registered") // ErrIdentityExists means the user already has an identity of that provider, // or that provider account belongs to another user. ErrIdentityExists = errors.New("identity already exists") // ErrLastSignInMethod means unlinking would leave the user no way to sign in. ErrLastSignInMethod = errors.New("the last sign-in method can't be removed") // ErrBusy means no password-hashing slot freed up before the deadline. ErrBusy = errors.New("too many password operations in progress; try again later") )
var ( // ErrUnknownConsent: the realm declares no consent of that name. ErrUnknownConsent = errors.New("unknown consent") // ErrUnknownConsentVersion: the version isn't one the realm has a text for. ErrUnknownConsentVersion = errors.New("unknown consent version") // ErrConsentRequiredForAccount: a required consent can't be withdrawn without // deleting the account. ErrConsentRequiredForAccount = errors.New("a required consent can't be withdrawn: delete the account instead") )
var ( // ErrPushNotConfigured: the realm has no push: section. ErrPushNotConfigured = errors.New("push notifications are not configured in this realm") // ErrPlatformNotEnabled: the realm has no provider for the platform. ErrPlatformNotEnabled = errors.New("that platform is not enabled in this realm") ErrPushUnavailable = errors.New("push notifications are unavailable: a secret the providers need is not set") ErrWebKeyUnavailable = errors.New("web push is not enabled in this realm") )
var ( // ErrEmailChangeDisabled means the realm doesn't let users change their // own address (account.allow_email_change). ErrEmailChangeDisabled = errors.New("this realm doesn't allow changing the email address") // ErrSameEmail means the new address is the one the user already has. ErrSameEmail = errors.New("that is already the address of this account") )
var ( // ErrAlreadyErased means the user was erased and nothing is left to do. ErrAlreadyErased = errors.New("this user was already erased") // ErrUserErased means an operation that needs a user was asked of an // erased one: all that is left is a tombstone. ErrUserErased = errors.New("this user was erased") )
var ( // ErrInvitationRequired means the realm only accepts sign-ups with an invitation. ErrInvitationRequired = errors.New("sign-up requires an invitation") // ErrInvalidInvitation covers unknown, used, expired and mismatched // invitations alike. ErrInvalidInvitation = errors.New("invalid or expired invitation") )
var ( // ErrJobFinished means the job is done: there is nothing left to cancel. ErrJobFinished = errors.New("the job has already finished") // ErrJobNotFinished means a job can't be re-run while it may still run. ErrJobNotFinished = errors.New("the job hasn't finished: cancel it, or wait for it to end") // ErrJobNotFunction means the job isn't a function call: backd's own // emails and erasures are not cancelled or re-run by hand. ErrJobNotFunction = errors.New("only a function's job can be cancelled or re-run") )
var ( // ErrMagicLinkDisabled: the realm doesn't have magic links. ErrMagicLinkDisabled = errors.New("magic links are not enabled in this realm") // ErrInvalidMagicLink answers a link or a code that is unknown, used or expired. ErrInvalidMagicLink = errors.New("the link or the code is invalid or has expired") // ErrNoRedirect: the request has no place to send the browser (no redirect_to, and the // realm has no sign_in.app_url): the code is the way. ErrNoRedirect = errors.New("the request has nowhere to send the browser") )
var ( // ErrInvalidChallenge answers a challenge that is unknown, used, expired or out of // attempts: the same for all of them. ErrInvalidChallenge = errors.New("the challenge is invalid or expired") // ErrSecondStepRequired is what the single-step entry points answer when the user // needs a second step (the HTTP layer uses the full outcome instead). ErrSecondStepRequired = errors.New("a second factor is required") // ErrMFADisabled: the realm doesn't let users turn MFA on. ErrMFADisabled = errors.New("multi-factor authentication is not enabled in this realm") )
var ( // ErrMFARequiredByRole: a role of the user requires MFA, so it can't be turned off. ErrMFARequiredByRole = errors.New("a role of this user requires multi-factor authentication") ErrMFAUnavailable = errors.New("multi-factor authentication needs the instance's secrets key (BACKD_SECRETS_KEY)") // ErrMFAAlreadyEnabled: the user already has a second factor. ErrMFAAlreadyEnabled = errors.New("multi-factor authentication is already enabled") // ErrMFANotEnabled: the user has no second factor. ErrMFANotEnabled = errors.New("multi-factor authentication is not enabled") )
var ( // ErrAccountExists: an account has the provider's address, but it can't be // linked on the provider's word alone: sign in another way and link explicitly. ErrAccountExists = errors.New("an account with that address exists") // ErrLinkConflict: the provider account belongs to another user, or the user // already has an identity of that provider. ErrLinkConflict = errors.New("that provider account can't be linked to this user") // ErrSignInRefused: the account can't sign in (disabled, or from this network); // the caller is not told which. ErrSignInRefused = errors.New("sign-in refused") // ErrEmailRequired: the provider gave no address and accounts need one. ErrEmailRequired = errors.New("the provider gave no email address") )
var ( // ErrReauthRequired: the action needs a fresh proof the request didn't have. ErrReauthRequired = errors.New("a fresh proof of identity is required") // ErrReauthMethod: that proof isn't the kind this user gives. ErrReauthMethod = errors.New("that proof is not accepted for this user") )
var ( // ErrInvalidCredentials is the one answer to a failed login, whatever // the reason (unknown email, wrong password, no password, disabled). ErrInvalidCredentials = errors.New("invalid email or password") // ErrUnauthenticated means the token is unknown, expired, revoked or // belongs to a disabled user. ErrUnauthenticated = errors.New("invalid or expired token") // ErrSignupClosed means the realm doesn't allow self sign-up. ErrSignupClosed = errors.New("sign-up is not open in this realm") // ErrEmailNotVerified answers a login with the right password for an // address that isn't verified yet, in a realm that requires it. It is // only returned after the password was checked, so it reveals nothing // to someone who doesn't have it. ErrEmailNotVerified = errors.New("verify your email address before signing in") )
var DefaultArgon2Params = Argon2Params{Memory: 64 * 1024, Time: 3, Threads: 1}
DefaultArgon2Params follow RFC 9106's second recommendation (64 MiB, 3 passes), with one thread per hash: concurrency is capped per instance instead.
var ErrEmailNotConfigured = errors.New("this realm doesn't send email")
ErrEmailNotConfigured means the realm has no email section: it sends no email.
var ErrInvalidCallback = errors.New("invalid or expired callback token")
ErrInvalidCallback means a callback token is malformed, forged or expired.
var ErrInvalidToken = errors.New("invalid, expired or used token")
ErrInvalidToken is every way a token can be refused (unknown, expired, used, or for another purpose); callers answer them all the same.
var ErrInvitationNeedsAddress = errors.New("an invitation sent by email needs an email address")
ErrInvitationNeedsAddress means an invitation to be sent by email has no address to send it to.
var ErrJobExclusive = errors.New("an exclusive job is not finished yet")
ErrJobExclusive means a job with the same exclusive name is not finished yet.
var ErrJobExists = errors.New("job already exists")
ErrJobExists means a job with that id was already enqueued.
var ErrNetworksOutsideRealm = errors.New("admin networks must lie within the realm's admin.allowed_networks")
ErrNetworksOutsideRealm means a user's admin networks aren't all inside the realm's admin.allowed_networks.
var ErrNotAllowedOnBehalf = errors.New("only API keys can act on behalf of a user")
ErrNotAllowedOnBehalf means a caller other than an API key tried to act on behalf of a user.
var ( // ErrPushSendNotFound: no send has that id. ErrPushSendNotFound = errors.New("push send not found") )
var ErrRegenerateRunning = errors.New("a regeneration of this field's versions is already queued or running")
ErrRegenerateRunning means a regeneration of the same field is queued or running.
var ErrSecretNotFound = errors.New("secret not found")
ErrSecretNotFound means no secret is stored at that scope and name.
var ErrSecretsNotConfigured = errors.New("the secrets master key is not configured (BACKD_SECRETS_KEY)")
ErrSecretsNotConfigured means BACKD_SECRETS_KEY isn't set: secrets can be neither stored nor read.
var ErrSelfMFAReset = errors.New("an administrator can't reset their own second factor")
ErrSelfMFAReset: an administrator can't reset their own second factor.
var ErrUndeclaredRole = errors.New("role is not declared in realm.yaml")
ErrUndeclaredRole means a role isn't declared in the realm's realm.yaml.
var ErrUserDisabled = errors.New("user is disabled")
ErrUserDisabled means the user an API key acts for is disabled.
Functions ¶
func ActorOf ¶ added in v0.8.2
ActorOf is who the context's audit source says is acting: "user:<id>", "key:<name>", or an Actor* constant.
func CheckPassword ¶
CheckPassword applies the length policy and returns the password in Unicode NFKC form, which is what gets hashed. Lengths count characters.
func CleanProfile ¶ added in v0.8.2
CleanProfile keeps the known profile fields that are not empty, without control characters and cut to a sane length. It is what a provider (or the browser, for Apple's first authorization) says about the person: a hint for the app, never trusted.
func CompletionJobID ¶ added in v0.8.0
CompletionJobID is the deterministic id of the notification of a job's end.
func DefaultHashConcurrency ¶
func DefaultHashConcurrency(p Argon2Params) int
DefaultHashConcurrency is how many password hashes may run at once when PASSWORD_HASH_CONCURRENCY isn't set: no more than the Go scheduler's processors (GOMAXPROCS, which follows the container's CPU limit), and no more than fit in half the memory limit (the cgroup's, or GOMEMLIMIT), so a flood of logins can't get the process killed for running out of memory. runtime.NumCPU is not used: in a container it reports the host's CPUs.
func ErasedEmail ¶ added in v0.4.0
ErasedEmail is the unique, undeliverable address a tombstone gets: the .invalid domain is reserved, so it can't receive mail, and the id makes it unique. The real address is freed for a new registration.
func HashEmailToken ¶ added in v0.4.0
HashEmailToken is the hash a token is stored under.
func HashToken ¶
HashToken is the stored form of a token: hex SHA-256. Tokens are random and long, so a fast hash is enough.
func HashUploadToken ¶ added in v0.8.0
HashUploadToken is what is stored of an upload token.
func IPKey ¶
IPKey groups client addresses for throttling: IPv4 addresses one by one, IPv6 by /64, since one client usually controls a whole /64.
func IdempotencyID ¶
IdempotencyID builds a record's id: unique per function, per caller (Caller.Subject(), so ownership can never cross callers), per key.
func NewSessionToken ¶
NewSessionToken returns a new random session token (256 bits).
func NewUploadToken ¶ added in v0.8.0
func NewUploadToken() (token, hash string)
NewUploadToken makes the secret a pending upload's creator holds, and the hash that is stored instead of it.
func PKCEChallenge ¶ added in v0.8.2
PKCEChallenge is the S256 challenge of a verifier.
func ProfileValues ¶ added in v0.8.2
func ProfileValues(input json.RawMessage) []string
ProfileValues are the values of an on_signup job's profile, which the function's logs must not show.
func ScheduledJobID ¶
ScheduledJobID is the deterministic id of a scheduled run.
func SignCallback ¶
func SignCallback(key []byte, c CallbackClaims) string
SignCallback returns a callback token for c, signed with key.
func ValidPKCEChallenge ¶ added in v0.8.2
ValidPKCEChallenge says whether s looks like an S256 challenge (43 URL-safe characters).
func WithAuditSource ¶
func WithAuditSource(ctx context.Context, source func() AuditSource) context.Context
WithAuditSource returns a context whose audit records take their actor, request id and client address from source, called when a record is written (the actor may be known only after authentication).
Types ¶
type APIKey ¶
type APIKey struct {
Name string
Role KeyRole // "" (stored before roles existed) counts as data
Networks registry.Networks // where the key may be used from; empty: anywhere
Scopes Scopes // what the key reaches; empty: everything
Prefix string // first characters of the key, for recognizing it
Hash string
CreatedAt time.Time
LastUsedAt *time.Time
ExpiresAt *time.Time // nil: never expires
}
APIKey is a realm API key for server-side callers. Only a hash of the key is stored.
type Argon2Params ¶
Argon2Params are argon2id cost parameters.
type AuditFilter ¶
type AuditFilter struct {
Action, Actor, Target string
Since, Until time.Time // At >= Since, At < Until
Limit, Skip int
}
AuditFilter selects audit records. Zero fields match everything.
type AuditRecord ¶
type AuditRecord struct {
ID string
At time.Time
ExpiresAt time.Time // removed after this (the realm's retention)
Action string
Actor string // "user:<id>", "key:<name>", "anonymous", or an Actor* constant
Target string // "user:<id>", "key:<name>", "invitation:<id>", or ""
Details map[string]any
RequestID string
ClientIP string
}
AuditRecord is one entry of the audit trail. It names users by id, keys by name and invitations by id, and never holds secrets: no passwords or hashes, tokens, keys, emails or request bodies.
type AuditSource ¶
type AuditSource struct {
Actor, RequestID, ClientIP string
}
AuditSource says who is acting and from where. The HTTP layer puts it in the request context; commands set their own.
type AuthChallenge ¶ added in v0.8.2
type AuthChallenge struct {
ID string // HashToken of the value given to the caller
Kind string
UserID string
// Factor is the first factor that was proved: ProviderPassword, a provider's name, ...
Factor string
// NewUser and Profile are what a provider sign-in hands over with the session: kept
// until the second step ends it.
NewUser bool
Profile map[string]string
// Secret is a TOTP secret (SealToken form) of a ChallengeTOTPSetup.
Secret string
// SessionID is the session a re-authentication token or code is bound to; CodeHash is
// the keyed hash of the code of a ChallengeReauthCode (set when the email is made).
SessionID string
CodeHash string
// A magic-link request: TokenHash is the hash of the link's token and CodeHash the code's;
// CodeChallenge the PKCE challenge of the app that asked; RedirectTo where the link ends
// ("" for the realm's app_url); Email the address when it has no user yet (sealed);
// Purpose says what is sent (MagicLinkPurposeLink or MagicLinkPurposeNoAccount); Locale
// the language for a new user.
TokenHash string
CodeChallenge string
RedirectTo string
Email string
Purpose string
Locale string
// Methods are how the session will say it was made (a ChallengeConsent keeps them
// while the user accepts); Consents are the acceptances a magic-link request carried.
Methods []string
Consents map[string]string
Attempts int
CreatedAt time.Time
ExpiresAt time.Time
}
AuthChallenge is a pending step between a first factor and a session. Its key is the hash of the secret value the caller holds.
type CallbackClaims ¶
type CallbackClaims struct {
Realm string `json:"r"`
Function string `json:"f"` // <database>/<name>
UserID string `json:"u,omitempty"`
KeyHash string `json:"k,omitempty"`
Admin bool `json:"a,omitempty"`
Expires time.Time `json:"e"`
// Calls are the functions of the caller's database this invocation may
// ctx.call (its function.yaml `calls`); Depth counts the nested calls
// above it; Inv is its own invocation id, the parent of what it calls.
Calls []string `json:"c,omitempty"`
Depth int `json:"d,omitempty"`
Inv string `json:"i,omitempty"`
// Job and Attempt say which job attempt this run is, so it may report its
// steps (ctx.step): only for an async function's job.
Job string `json:"j,omitempty"`
Attempt int `json:"t,omitempty"`
// Email says the function may send custom emails (function.yaml `email: true`).
Email bool `json:"m,omitempty"`
// Push says the function may send push notifications (function.yaml `push:`).
Push bool `json:"p,omitempty"`
// Config says the function may change the app configuration (function.yaml `config: write`).
Config bool `json:"g,omitempty"`
// MFA and Methods are how the session of the user the call acts as was created, so that
// rules in the function's own data calls see the same `user.mfa` and `user.methods`.
MFA bool `json:"x,omitempty"`
Methods []string `json:"y,omitempty"`
}
CallbackClaims are what a callback token carries: the function, the caller it acts as (a user, an API key, both for a key acting on behalf of a user, or neither for an anonymous caller) or full access (Admin), and when it expires (the invocation's deadline).
func VerifyCallback ¶
VerifyCallback checks a callback token's signature and expiry.
type Caller ¶
type Caller struct {
User *Principal // the user whose rules apply
Key *APIKey // set for API key callers
Func *FuncCaller // set for a function's callbacks
}
Caller is whoever makes a request to a realm with auth enabled: a user with a session, a server-side caller with an API key, an API key acting on behalf of a user (both set), or anonymous (neither). A function calling back (Func set) acts as the caller that invoked it, or, with admin access, as itself.
func (Caller) Actor ¶
Actor names the caller for logs: the subject, and for an API key acting on behalf of a user, "key:<name> as user:<id>".
func (Caller) BypassesRules ¶
BypassesRules reports whether the caller has full access: an API key that isn't acting on behalf of a user, or a function's admin access.
func (Caller) SignInMethods ¶ added in v0.8.2
SignInMethods says how the user the caller acts as signed in, for rules (`user.mfa`, `user.methods`) and functions (`ctx.user`): the first factor and any second one, and whether a second one was used. An API key (also acting on behalf of a user) is ["key"] and never MFA. The list is never nil.
type CheckJob ¶ added in v0.8.0
type CheckJob struct {
Collections []string // "<database>/<collection>", resolved when the check started
Database string // the scope asked for: "" every database
Collection string // "" every collection of Database
Limit int // invalid documents listed per collection
}
CheckJob is what a schema check's job holds: what to check and how much to list.
type CheckProblem ¶ added in v0.8.0
CheckProblem is one way a document fails its schema: a JSON path and the rule that failed, never the value.
type CheckReport ¶ added in v0.8.0
type CheckReport struct {
Database, Collection string
JobID string
StartedAt time.Time
FinishedAt time.Time
Scanned int64
Invalid int64
// Complete is false when the scan stopped before the end: StoppedBy says why
// ("limit" when Limit invalid documents were found, "time" for CheckMaxDuration).
Complete bool
StoppedBy string
Limit int
// SchemaHash identifies the schema the documents were checked against.
SchemaHash string
Documents []CheckedDocument // up to Limit
}
CheckReport is the latest finished schema check of one collection.
type CheckedDocument ¶ added in v0.8.0
type CheckedDocument struct {
ID string
Deleted bool // soft-deleted (in the trash)
Problems []CheckProblem
// MoreProblems counts the problems left out past MaxCheckProblems.
MoreProblems int
}
CheckedDocument is a document that failed its collection's schema.
type ConsentContext ¶ added in v0.8.2
type ConsentContext struct{ IP, UserAgent string }
ConsentContext is where a person gave consents from: for the proof.
type ConsentInput ¶ added in v0.8.2
type ConsentInput struct {
Consent string
Version string // accepted: the version; withdrawn: ignored
Action string
Method string
Evidence string
// Locale is the language of the text the person saw; "" uses the user's, then the realm's.
Locale string
IP string
UserAgent string
}
ConsentInput is a consent given or withdrawn.
type ConsentNotice ¶ added in v0.8.2
type ConsentNotice struct {
Consent string
Version string
// Matched is the users who hold an older version of the consent (or, for a required
// one, none): the ones the message is for.
Matched int
// Queued messages were handed to the email worker; Limited were skipped because an email
// limit was reached; the rest could not be sent to (disabled or erased users).
Queued int
Limited int
}
ConsentNotice is what a notification run did.
type ConsentRecord ¶ added in v0.8.2
type ConsentRecord struct {
ID string
UserID string
Consent string
Version string
Locale string
TextHash string // SHA-256 of the text shown
Action string // ConsentAccepted or ConsentWithdrawn
Method string // ConsentMethodSignup, …
Evidence string // for the admin method: the reference given
At time.Time
// DeleteAt is when a retention removes the record: set at erasure, zero before.
DeleteAt time.Time
// IP and UserAgent are stored only when the realm lists them in compliance.consent_proof.
IP string
UserAgent string
}
ConsentRecord is one entry of a user's append-only consent history: the proof that a text was accepted, or the withdrawal of that acceptance.
type ConsentRef ¶ added in v0.8.2
type ConsentRef struct{ Consent, Version string }
ConsentRef is a consent and version a record refers to.
type ConsentRequiredError ¶ added in v0.8.2
type ConsentRequiredError struct {
Consents []registry.ConsentRef
// Session is true when it is an authenticated request that is refused.
Session bool
}
ConsentRequiredError says which consents a person has to accept: at sign-up they were missing or outdated (400), or an open session is past the reaccept_by date of a version it hasn't accepted (403).
func (*ConsentRequiredError) Error ¶ added in v0.8.2
func (e *ConsentRequiredError) Error() string
type CustomEmail ¶ added in v0.4.0
type CustomEmail struct {
Function string // <database>/<name> of the function that asked
To []string
CC []string
BCC []string
Data map[string]any
}
CustomEmail is what a function's email job carries.
type Device ¶ added in v0.8.2
type Device struct {
ID string
UserID string
SessionID string // the session that registered it
Platform string
Name string
TokenHash string // of the token, or of a web subscription's endpoint
Token string // sealed
CreatedAt time.Time
LastSeen time.Time
}
Device is a registered device of a user. Token is the token sealed with the realm's key; it never leaves the store and the senders.
type DeviceInput ¶ added in v0.8.2
DeviceInput is a registration: the platform, the token the provider gave the app (for web, the subscription as JSON) and an optional label.
type EmailJob ¶ added in v0.4.0
type EmailJob struct {
Kind string
UserID string
Locale string
RedirectTo string // checked when the request was made; bound to the token the worker creates
// To says whose address the message goes to: "" the user's current one,
// "pending" the address they asked to change to, "previous" the one
// before the last change.
To string
// Notice marks a message that only informs: no token, no link.
Notice bool
// InvitationID is the invitation an invitation email is for (there is no
// user yet): the worker takes the address from it.
InvitationID string
// Event and CodesLeft are what a security-notice says: which change it reports and, for
// a used recovery code, how many remain. Nothing secret.
Event string
CodesLeft int
// ChallengeID is the pending step the email is for (a re-authentication code): the
// worker makes the secret at send time and keeps only its hash there.
ChallengeID string
// Custom is set on an email a function asked for with ctx.email.send. Unlike
// the account emails it stores what the function gave: the recipients'
// addresses and the data for the template, for as long as jobs are kept.
Custom *CustomEmail
}
EmailJob is what an email job stores: which email, for whom, and nothing that works as a credential.
type EmailLimitedError ¶ added in v0.4.0
type EmailLimitedError struct {
RetryAfter time.Duration
// Scope says which limit it was: "recipient", "ip", "function" or
// "invocation".
Scope string
}
EmailLimitedError means an email limit was reached: nothing was queued.
func (*EmailLimitedError) Error ¶ added in v0.4.0
func (e *EmailLimitedError) Error() string
type EmailRequest ¶ added in v0.4.0
type EmailRequest struct {
Kind string // an email kind (verify-email, ...)
UserID string
Address string // the recipient, for the per-recipient limits only (never stored readable)
Locale string
RedirectTo string // already checked against the realm's allowed redirects
ClientIP string // who caused it, for the per-IP limit; "" when nobody did
RequestID string
// Event and CodesLeft are the fields of the same name of EmailJob.
Event string
CodesLeft int
ChallengeID string
// To, Notice and InvitationID are the fields of the same name of EmailJob.
To string
Notice bool
InvitationID string
// Custom marks an email a function asked for; Invocation is the
// invocation that asked (the parent of the job, and what the per-invocation
// cap counts). Address is then the user's, for to_user; Custom holds the
// addresses of the others.
Custom *CustomEmail
Invocation string
Depth int
}
EmailRequest asks for one email to be sent to a user.
type EmailToken ¶ added in v0.4.0
type EmailToken struct {
Hash string // hex SHA-256 of the token; the record's id
Purpose string // verify-email, reset-password, change-email, revert-email-change or invitation
UserID string
RedirectTo string // where the page after the link may send the user (already checked)
// Address is the address the token acts on: the new one for change-email,
// the previous one for revert-email-change, the invited one for an
// invitation. Empty for the others.
Address string
// InvitationID is the invitation an invitation token accepts (UserID is empty then).
InvitationID string
CreatedAt time.Time
ExpiresAt time.Time
UsedAt time.Time // zero until redeemed
}
EmailToken is the record of a token sent in an email link (verifying an address, resetting a password, ...). backd stores only the SHA-256 hash of the token: the token itself exists only in memory and in the message handed to the delivery function.
type EraseJob ¶ added in v0.4.0
type EraseJob struct {
UserID string
Email string
Counts map[string]int64 // "<database>/<collection>/<operation>" → documents
}
EraseJob is what an erase job carries: whose data to erase, the email to match fields that hold it (cleared when the job finishes), and what has been done so far.
An erase job is not a function: it has no executor, a worker applies the collections' policies itself.
type ErrCheckRunning ¶ added in v0.8.0
type ErrCheckRunning struct{ JobID string }
ErrCheckRunning means a schema check is already queued or running in the realm; JobID is its job.
func (*ErrCheckRunning) Error ¶ added in v0.8.0
func (e *ErrCheckRunning) Error() string
type FileDeletion ¶ added in v0.8.0
type FileDeletion struct {
Key string
Reason string // replaced, cleared, removed, abandoned…
Attempts int
NotBefore time.Time // not claimed before this
CreatedAt time.Time
}
FileDeletion is an object to delete from the bucket.
type FileDeletionStats ¶ added in v0.8.0
type FileDeletionStats struct {
Queued int // objects waiting to be deleted
Retrying int // of them, the ones that failed at least once
Oldest time.Time // when the oldest was queued; zero when empty
}
FileDeletionStats describes the deletion queue.
type FileJournalEntry ¶ added in v0.8.0
type FileJournalEntry struct {
ID string // the file's id (fl_…)
Database string
Collection string
Field string
DocumentID string // "" for an upload no document references yet
Key string // the object's key
Caller string // who uploaded it, for display (user:<id>, key:<name>, func:…)
Size int64
Status string
CreatedAt time.Time
UpdatedAt time.Time
ExpiresAt time.Time
// A pending upload is one made before the document that will hold it exists
// (or without the document being touched): it is attached by naming it, with
// its token, in a write. Its details are kept here until then.
Pending bool
Direct bool // a direct upload: the client sends the bytes to the bucket and completes it
TokenHash string // SHA-256 of the secret token the creator holds
Owner string // the user who made it; "" for an anonymous caller
CallerKey string // who the open-uploads limit counts it for
PendingUntil time.Time // unused, it expires then (also set for a direct upload to a document)
Name string
Type string
SHA256 string
UploadedAt time.Time
// Image is a pending upload's image details as JSON (width, height and the state of each
// declared version), for the document that will hold it.
Image string
// A multipart direct upload (a file above one signed PUT): the storage's upload id, the
// part size and the SHA-256 of each part as declared at the start. SHA256 is then their
// composite, which storage can verify.
MultipartID string
PartSize int64
PartSHA256 []string
}
FileJournalEntry is one upload.
type FuncCaller ¶
type FuncCaller struct {
Name string // <realm>/<database>/<function>
Admin bool // ctx.admin.db: full access, recorded as the function
// What the invocation behind the token may do next (see CallbackClaims).
Calls []string
Depth int
Invocation string
Email bool // ctx.email.send
Push bool // ctx.push.send
Config bool // ctx.admin.config: may change the app configuration
Job string // the job attempt behind the token, if any (see CallbackClaims)
Attempt int
Expires time.Time
}
FuncCaller marks a caller as a function acting through a callback token.
func FuncCallerOf ¶ added in v0.4.0
func FuncCallerOf(c CallbackClaims) *FuncCaller
FuncCallerOf is the function behind a verified callback token.
type Hasher ¶
type Hasher struct {
Params Argon2Params
// contains filtered or unexported fields
}
Hasher hashes and verifies passwords with argon2id. At most a fixed number of hashes run at once; callers queue for a slot until their context ends, which bounds memory under a flood of requests.
func NewHasher ¶
func NewHasher(concurrency int, params Argon2Params) *Hasher
NewHasher returns a Hasher running at most concurrency hashes at once (DefaultHashConcurrency when concurrency < 1).
func (*Hasher) Concurrency ¶
Concurrency is how many hashes may run at once.
type IdempotencyRecord ¶
type IdempotencyRecord struct {
ID string // see IdempotencyID
Function string // <database>/<name>, for display
CallerActor string
InputHash string // sha256 of the exact input bytes
Mode string // sync | async
Status string // running | done
Result *JobResult // nil until done; a sync call's outcome
JobID string // set once done, for async; "" for sync
CreatedAt time.Time
ExpiresAt time.Time
}
IdempotencyRecord ties one Idempotency-Key to its outcome, scoped to the function and the caller: two different callers can never collide on the same client-chosen key, even if they happen to pick the same string. Never stores input or output for keyless calls — this is the one deliberate exception, for calls that declare a key.
type Identity ¶
type Identity struct {
ID string
UserID string
Provider string
Subject string // unique per provider
PasswordHash string // ProviderPassword only: argon2id, PHC string format
// Email and EmailVerified are what an external provider last reported.
Email string
EmailVerified bool
// LastUsedAt is the last successful sign-in with this identity; zero if
// none was recorded yet.
LastUsedAt time.Time
// AppleRefreshToken is Apple's refresh token, sealed with the realm's secrets cipher
// (see SealToken) and kept only to revoke it when the account goes away; AppleClientID
// is the client id it was issued to.
AppleRefreshToken string
AppleClientID string
CreatedAt time.Time
UpdatedAt time.Time
}
Identity is one way a user signs in.
A user has at most one identity per provider (the store enforces it) and any number of providers. The password identity has no email of its own: the user's is the one that counts.
type IdentityUpdate ¶ added in v0.8.2
type IdentityUpdate struct {
Email *string
EmailVerified *bool
LastUsedAt *time.Time
AppleRefreshToken *string
AppleClientID *string
}
IdentityUpdate changes the set fields of an identity.
type ImageJob ¶ added in v0.8.1
type ImageJob struct {
Collection string
Field string
DocumentID string
FileID string
// Version, when set, makes just that version, whatever its state: a function asked
// for it. Params are the parameters to make it with, as JSON ("" means the declared
// ones); the job's result carries the outcome for the function waiting on it.
Version string
Params string
// Scan makes this a job over a whole field (backd files regenerate): every file
// whose copies no longer match what the field declares is made again, for Version only
// when it is set. MissingOnly leaves the copies that exist alone. Rate is how many files
// a second at most (0 for the default). DocumentID and FileID are empty.
Scan bool
MissingOnly bool
Rate int
}
ImageJob is what an image-versions job carries: the file, and where it is. The job's Database is the file's database and its Function the collection.
type InvalidCodeError ¶ added in v0.8.2
type InvalidCodeError struct{ AttemptsLeft int }
InvalidCodeError is a second-factor code that is wrong; AttemptsLeft counts what the challenge still allows.
func (*InvalidCodeError) Error ¶ added in v0.8.2
func (e *InvalidCodeError) Error() string
type InvalidConsentsError ¶ added in v0.8.2
type InvalidConsentsError struct{ Reasons []string }
InvalidConsentsError is a request that names consents or versions the realm doesn't have.
func (*InvalidConsentsError) Error ¶ added in v0.8.2
func (e *InvalidConsentsError) Error() string
type InvalidDeviceError ¶ added in v0.8.2
type InvalidDeviceError struct{ Reason string }
InvalidDeviceError says why a token isn't acceptable.
func (*InvalidDeviceError) Error ¶ added in v0.8.2
func (e *InvalidDeviceError) Error() string
type InvalidLocaleError ¶ added in v0.4.0
type InvalidLocaleError struct{ Allowed []string }
InvalidLocaleError means a language the realm doesn't list was asked for.
func (*InvalidLocaleError) Error ¶ added in v0.4.0
func (e *InvalidLocaleError) Error() string
type Invitation ¶
type Invitation struct {
ID string
TokenHash string
Email string // "" if anyone holding the token may use it
CreatedBy string // "key:<name>"
CreatedAt time.Time
ExpiresAt time.Time
}
Invitation lets one person sign up in a realm with `signup: invite`. Only a hash of its token is stored.
type InvocationFilter ¶
InvocationFilter selects invocation records. Zero fields match everything.
type InvocationRecord ¶
type InvocationRecord struct {
ID string
At time.Time
ExpiresAt time.Time // removed after this (the realm's log retention)
Function string // <database>/<name>
Actor string // "user:<id>", "key:<name>", "anonymous", or "func:<name> as ..."
Mode string // sync today; async, webhook later
Status string // executor.Status* (ok, function_error, timeout, memory, cpu, crash, ...)
Code string // the function's own error code, when Status is function_error
DurationMS int64
RequestID string
JobID string // async jobs (roadmap F11); empty until then
ParentID string // the invocation that called this one (ctx.call); empty otherwise
Origin string // http, function, cron, admin or backd:<event>
Logs []LogLine
// Steps are what the call reported with ctx.step and ctx.progress, closed
// when it ended; StepsOmitted counts those dropped from the middle.
Steps []Step
StepsOmitted int
}
InvocationRecord is one function call, recorded in the realm's system database (roadmap F10). Inputs and outputs are never stored — only what's needed to debug what happened and read the function's own logs.
type IssuedChallenge ¶ added in v0.8.2
type IssuedChallenge struct {
Token string
Kind string
Methods []string
// Consents are the consents and versions a ChallengeConsent waits for.
Consents []registry.ConsentRef
}
IssuedChallenge is a challenge handed to the caller: the value to send back and what it accepts.
type Job ¶
type Job struct {
ID string
Database string
Function string // name only; Database plus this is the function
Input json.RawMessage
CallerActor string // for display: "user:<id>", "key:<name>", "anonymous"
CallerUserID string // "" unless the caller was a signed-in user
CallerKeyHash string // "" unless the caller was an API key
Scheduled bool // created by the function's cron schedule, acts as the function itself
ActsAsFunction bool // run as the function itself, with full access (a scheduled function run by hand)
Origin string // http, function (ctx.call), cron, admin or backd:<event>
ParentID string // the invocation that queued it with ctx.call; empty otherwise
RerunOf string // the finished job an administrator re-ran to make this one; empty otherwise
Depth int // nested calls above it
// Email is set on an email job: backd's own request to send a message, which
// a worker renders and hands to the realm's delivery function. It holds no
// message and no token.
Email *EmailJob
// Erase is set on an erase job (origin backd:account.erase).
Erase *EraseJob
// Check is set on a schema check's job (origin CheckOrigin).
Check *CheckJob
// Image is set on the job that makes a file's image versions (origin ImageOrigin).
Image *ImageJob
// Revoke is set on a job that revokes a user's Apple refresh token (origin RevokeOrigin).
Revoke *RevokeJob
// Push is set on the jobs of a push send (origin PushOrigin): planning an audience, a batch
// of users, or a delivery unit.
Push *PushJob
// Exclusive, when set, lets only one job of that name be unfinished at a
// time: enqueuing another fails with ErrJobExclusive.
Exclusive string
TimeoutMS int64 // the function's timeout at enqueue time, for the worker's lease
RequestID string
Status string // queued | running | done
Attempts int // times a worker claimed it
Failures int // attempts that ended in a failure worth retrying
NextAttemptAt time.Time // when a retry may be claimed; zero unless one is waiting
CreatedAt time.Time
CompletedAt time.Time // zero until done
ExpiresAt time.Time
Result *JobResult // nil until done
// Steps are what the running (or last) attempt reported with ctx.step and
// ctx.progress, the last being the current one; StepsOmitted counts those
// left out of the middle when there were more than MaxSteps. A new attempt
// starts with none.
Steps []Step
StepsOmitted int
}
Job is one async function call (roadmap F11), stored in the realm's system database until it's claimed, run, and its result read or expired. Unlike sync calls, whose input and output are never stored, a job's input and result are — there's nowhere else to keep them until the caller reads them back.
type JobFilter ¶
type JobFilter struct {
Database, Function string // Function is the name only; "" matches every function
Origin string // exact origin, such as function:main/ship; "" matches every one
EraseUser string // the erase jobs of this user
Status string // queued, running or done
Scheduled *bool // nil: both; true: cron runs only; false: called ones only
Since, Until time.Time // on created_at: from Since, before Until
Limit, Skip int
}
JobFilter selects jobs to list. Zero fields match everything.
type JobResult ¶
type JobResult struct {
Status string
Output json.RawMessage
Code string
Message string
Details json.RawMessage
DurationMS int64
// HTTPStatus is the function's own chosen status (ctx.error's first
// argument) when Status is "function_error"; unused otherwise. A
// job never answers HTTP itself, but an idempotent sync replay
// (roadmap F12) needs it to reconstruct the original response.
HTTPStatus int
}
JobResult is how a job's run ended: the same vocabulary as a sync call's executor.Result (executor.Status*), flattened here so this package doesn't need to import the executor.
type KeyOptions ¶
type KeyOptions struct {
TTL time.Duration // 0: never expires
Role KeyRole // "" means data
Networks registry.Networks // where the key may be used from; empty: anywhere
Scopes Scopes // what a data key reaches; empty: everything
}
KeyOptions are the settings of a new API key.
type KeyRole ¶
type KeyRole string
KeyRole is what an API key may do.
const ( // KeyRoleData keys reach data routes, bypassing rules, and may act on // behalf of a user. The default: what services need. KeyRoleData KeyRole = "data" // KeyRoleAdmin keys also reach the admin API (/_admin): users, roles, // invitations and API keys. For management tooling only. KeyRoleAdmin KeyRole = "admin" )
func ParseKeyRole ¶
ParseKeyRole returns the role named s ("" means data).
type LogLine ¶
LogLine is one line of a function's captured console output, already masked by the executor.
type LoginCode ¶ added in v0.8.2
type LoginCode struct {
ID string // HashToken(code)
UserID string
// Method is the first factor the code stands for: the provider's name (magic links will
// add their own), so that a second step can be asked for after the code is redeemed.
Method string
CodeChallenge string
// NewUser says the sign-in made the user, and Profile is what the provider said of them:
// the redemption hands both over once.
NewUser bool
Profile map[string]string
CreatedAt time.Time
ExpiresAt time.Time
}
LoginCode is the one-time code the app gets in place of a session: it is redeemed with the PKCE verifier its challenge came from.
type MFALockedError ¶ added in v0.8.2
MFALockedError means too many second factors failed for the user: nothing is tried until RetryAfter has passed.
func (*MFALockedError) Error ¶ added in v0.8.2
func (e *MFALockedError) Error() string
type MFARecord ¶ added in v0.8.2
type MFARecord struct {
UserID string
Secret string // SealToken form
EnabledAt time.Time
LastStep int64
RecoveryCodes []string
}
MFARecord is a user's second-factor state: the TOTP secret (sealed), the last time step accepted and the unused recovery codes (keyed hashes).
type MFAStatus ¶ added in v0.8.2
type MFAStatus struct {
// Available says the realm lets users turn TOTP on (it may be off with users who
// still have it).
Available bool
Enabled bool
Methods []string
RecoveryCodesLeft int
// Required says a role of the user requires MFA.
Required bool
}
MFAStatus is what a user can see of their second factor.
type MagicLinkInput ¶ added in v0.8.2
type MagicLinkInput struct {
Email string
// RedirectTo is where the link ends (already checked against the realm's allowed
// redirects); "" for the realm's sign_in.app_url.
RedirectTo string
// CodeChallenge is the S256 PKCE challenge of a verifier only the asking app holds.
CodeChallenge string
Locales []string
IP, RequestID string
// Consents are accepted for the account a new address gets when the link is used.
Consents map[string]string
}
MagicLinkInput is a request for a link and a code.
type OAuthState ¶ added in v0.8.2
type OAuthState struct {
ID string // HashToken(state)
Provider string
Intent string
CodeChallenge string // the app's PKCE challenge (S256)
Verifier string // backd's own PKCE verifier, for the provider
Nonce string
RedirectTo string
InvitationID string // HashToken of the invitation token, if one was passed
LinkUserID string // IntentLink: whose identity is being added
Locales []string
// Consents are the consents the app accepted for a sign-up through this attempt.
Consents map[string]string
CreatedAt time.Time
ExpiresAt time.Time
}
OAuthState is a sign-in attempt in progress: what backd must remember between sending the user to the provider and the provider sending them back. Its key is the hash of the state value the provider echoes.
type OnSignupInput ¶ added in v0.8.2
type OnSignupInput struct {
UserID string `json:"user_id"`
Provider string `json:"provider"`
Profile map[string]string `json:"profile,omitempty"`
}
OnSignupInput is what account.on_signup receives: the new user's id, how they signed up ("password", or a provider's name) and, from a provider, the profile it gave.
type PolicyError ¶
type PolicyError struct{ Reason string }
PolicyError is a password that doesn't meet the realm's policy.
func (*PolicyError) Error ¶
func (e *PolicyError) Error() string
type ProviderLogin ¶ added in v0.8.2
type ProviderLogin struct {
Provider string
Subject string // the provider's stable id for the person
Email string
EmailVerified bool // as the provider asserts it
// TrustsEmail: the provider's verified addresses may link an existing account
// and mark a new one verified (Google and Apple).
TrustsEmail bool
Intent string
LinkUserID string // IntentLink: the signed-in user
// Invitation is the hash of the invitation token the attempt carried.
Invitation string
Locales []string
IP string
// Consents and UserAgent: what a sign-up through the login accepted, and the proof's context.
Consents map[string]string
UserAgent string
// Profile is what the provider says of the person (CleanProfile's fields): handed to
// the app and to account.on_signup when the login makes a new user, and kept nowhere else.
Profile map[string]string
}
ProviderLogin is a person an external provider has vouched for.
type ProviderResult ¶ added in v0.8.2
type ProviderResult struct {
User User
NewUser bool
Linked bool // an identity was added to an existing user
// Profile is what the provider said of a new user (empty for anyone else).
Profile map[string]string
}
ProviderResult is the outcome of a provider login.
type PushAudience ¶ added in v0.8.2
type PushAudience struct {
All bool
Roles []string // any of
EmailVerified *bool
Locale string
CreatedBefore time.Time
CreatedAfter time.Time
// Consent: only users who hold this consent (any version).
Consent string
}
PushAudience is who a send reaches when it names no users.
type PushCounts ¶ added in v0.8.2
type PushCounts struct {
Queued, Limited, NoDevices, NoConsent int
// Units is the delivery units of the batch, those made now and those that existed.
Units int
}
PushCounts is what planning a batch decided.
type PushDelta ¶ added in v0.8.2
type PushDelta struct {
Units, Queued, Limited, NoDevices, NoConsent int
Sent, Invalid, Failed int
DoneBatch, DoneUnit string
}
PushDelta is what to add to a send's totals. DoneBatch and DoneUnit name the batch or unit that finished: it is counted once, however many times the same update runs.
type PushJob ¶ added in v0.8.2
type PushJob struct {
Kind string
SendID string
// Messages are the message in each language of the realm.
Messages map[string]push.Message
// Batch: the users. Plan: the audience, the last user id it paged to and the next batch.
Users []string
Audience *PushAudience
After string
NextBatch int
// RequiresConsent skips users who don't hold the consent, in a batch or a plan.
RequiresConsent string
// Deliver: who gets it, and how many users of the unit's chunk were not delivered to.
Recipients []PushRecipient
Limited int
NoDevices int
NoConsent int
}
PushJob is what a push job carries.
type PushOutboxEntry ¶ added in v0.8.2
type PushOutboxEntry struct {
ID string
SendID string
UserID string
DeviceID string
Platform string
Status string // push.Status*
Attempt int
Message push.Message
CreatedAt time.Time
ExpiresAt time.Time
}
PushOutboxEntry is a delivery the capture provider stored instead of sending: development only. Unlike a send's record it holds the message.
type PushRecipient ¶ added in v0.8.2
type PushRecipient struct {
UserID string
Locale string
Devices []string // device ids: tokens are loaded when the unit is delivered
}
PushRecipient is a user of a delivery unit with the devices to deliver to.
type PushSend ¶ added in v0.8.2
type PushSend struct {
ID string
Kind string // the template kind, or push.RawKind
Sender string // function:<database>/<name>, or admin:<id>
CreatedAt time.Time
ExpiresAt time.Time
// Users is the number of users named; -1 when the send has an audience.
Users int
// Planned says every batch exists (Batches is final).
Planned bool
Batches int
// Units is the delivery units made so far (final once Planned and every batch is done).
Units int
BatchesDone int
UnitsDone int
// Totals, by what became of each user or device.
Queued int // users handed to delivery
Limited int // users over their limits
NoDevices int // users with no device to reach
NoConsent int // users who don't hold the consent the send requires
Sent int // devices
Invalid int // devices removed as dead
Failed int // devices not delivered to
// CompletedAt is zero until everything is done.
CompletedAt time.Time
}
PushSend is the record of one send: totals, never content.
type PushSendFilter ¶ added in v0.8.2
PushSendFilter selects sends to list. Sender is "function:<database>/<name>" or "admin:<id>"; zero fields match everything.
type PushSendInput ¶ added in v0.8.2
type PushSendInput struct {
Kind string
Sender string
Messages map[string]push.Message
Users []string
Audience *PushAudience
// RequiresConsent names a consent a user must hold to be sent to; the others are
// counted as no_consent.
RequiresConsent string
}
PushSendInput is a send, validated and rendered by the caller.
type PushStarted ¶ added in v0.8.2
type PushStarted struct {
SendID string
// Users is the number named (-1 for an audience); Jobs the jobs created.
Users, Jobs int
// Known says Queued, Limited and NoDevices are final: a send that fits one batch is
// planned at once.
Known bool
Queued, Limited, NoDevice, NoConsent int
}
PushStarted is what starting a send reports.
type PushUserFilter ¶ added in v0.8.2
type PushUserFilter = PushAudience
PushUserFilter selects users for an audience page.
type ReauthGrant ¶ added in v0.8.2
ReauthGrant is a re-authentication token.
type Redeemed ¶ added in v0.8.2
type Redeemed struct {
Principal Principal
Token string
NewUser bool
Profile map[string]string
// Challenge is set instead of a session when the user needs a second step.
Challenge *IssuedChallenge
// RecoveryCodesLeft is set when a recovery code ended the sign-in: how many remain.
RecoveryCodesLeft *int
}
Redeemed is the outcome of redeeming a login code: the session, whether the sign-in made the user and, if so, what the provider said of them.
type RefusedError ¶ added in v0.8.2
RefusedError is a sign-in the account's state refuses; it is ErrSignInRefused to the caller, who is not told why, and says why to the audit.
func (*RefusedError) Error ¶ added in v0.8.2
func (e *RefusedError) Error() string
func (*RefusedError) Is ¶ added in v0.8.2
func (e *RefusedError) Is(target error) bool
type RevokeJob ¶ added in v0.8.2
type RevokeJob struct {
UserID string
ClientID string // the client id the token was issued to
Token string // sealed (SealToken)
}
RevokeJob is a job that revokes an Apple refresh token. It holds the token sealed, and a worker drops it once Apple has revoked it.
type RoleReport ¶
type RoleReport struct {
// DBOnly maps emails to roles assigned only in the database, which a
// rebuild from realm.yaml wouldn't restore.
DBOnly map[string][]string
// Undeclared maps emails to roles realm.yaml no longer declares.
Undeclared map[string][]string
// NetworksDBOnly lists users with network restrictions that realm.yaml
// doesn't set, which a rebuild from realm.yaml wouldn't restore.
NetworksDBOnly []string
// Admins counts the people who can use the admin API with a session:
// emails seeded into an admin role in realm.yaml, and users holding
// one in the database, each counted once.
Admins int
}
RoleReport lists role assignments that realm.yaml doesn't account for.
type ScheduleState ¶ added in v0.8.0
type ScheduleState struct {
Database, Function string
Paused bool
ChangedAt time.Time
ChangedBy string // the actor that last paused or resumed it
}
ScheduleState is the runtime state of a scheduled function: whether an administrator paused it. A function with no state is running. The state is kept after a resume, because ChangedAt keeps a run that fell inside the pause from being made up at the moment of the resume.
type Scope ¶ added in v0.5.0
type Scope struct {
Op ScopeOp
Database string // "" is every database
Name string // a collection (read, write) or a function (call); "" is all of the database
}
Scopes limit what a data API key reaches, so a leaked key exposes only what it was made for. A key without scopes keeps full access (every key made before scopes existed); a key with scopes may do exactly what they grant and nothing else. A grant is `ops` or `ops:target`:
read read every collection read:blog read the collections of the database blog write:blog/posts create, update and delete in blog/posts call call every function call:main call the functions of the database main call:main/export call that function (and read its jobs)
write means create, update and delete; it doesn't include read. The targets are relative to the key's realm.
func ParseScope ¶ added in v0.5.0
ParseScope parses one grant.
type Scopes ¶ added in v0.5.0
type Scopes []Scope
Scopes is the list of grants of a key.
func ParseScopes ¶ added in v0.5.0
ParseScopes parses grants; duplicates collapse, and the order is kept.
func (Scopes) Allows ¶ added in v0.5.0
Allows reports whether op on database/name is granted. A key without scopes allows everything.
type Secret ¶
type Secret struct {
Database string // "": realm scope
Name string
Ciphertext string // base64
Nonce string // base64
KeyID string // fingerprint of the key it was encrypted with
CreatedAt time.Time
UpdatedAt time.Time
UpdatedBy string
}
Secret is one encrypted value, bound to a realm (implicitly, by which Users it's stored through), a scope and a name. Database empty means the realm scope; otherwise it's the database scope.
type SecretCache ¶
type SecretCache struct {
// contains filtered or unexported fields
}
SecretCache holds decrypted secret values (and confirmed-missing lookups) for secretCacheTTL, shared across every realm's Users: NewSecretCache once, assigned to each Users.Cache. Each key includes the realm, so it's safe for every realm to share one instance.
type SecretCipher ¶
type SecretCipher struct {
KeyID string
// contains filtered or unexported fields
}
SecretCipher encrypts and decrypts secret values with AES-256-GCM, under a key derived from the operator's master key (never the master key's raw bytes directly, so an accidental log of the derived key alone can't be turned back into the configured secret). KeyID is a fingerprint safe to store and log: it identifies which master key a value was encrypted with, for rotation, without revealing it.
func NewSecretCipher ¶
func NewSecretCipher(raw []byte) (*SecretCipher, error)
NewSecretCipher derives a cipher from raw master key material (any length, at least 32 characters is enforced by settings). The same raw material always derives the same cipher and KeyID.
func (*SecretCipher) MAC ¶ added in v0.8.2
func (c *SecretCipher) MAC(parts ...string) string
MAC is a keyed hash (hex HMAC-SHA-256) of the parts, under a key derived from the master key and kept apart from the encryption key: for values that must be compared but never read back, such as recovery codes. The parts are length-prefixed, so ("a","bc") and ("ab","c") differ.
type SecretMeta ¶
type SecretMeta struct {
Database string
Name string
CreatedAt time.Time
UpdatedAt time.Time
UpdatedBy string
}
SecretMeta is a secret without its value, as listed: names, scope and who last changed it, never the value.
type Session ¶
type Session struct {
ID string // public id, used to list and revoke sessions
UserID string
TokenHash string
CreatedAt time.Time
LastUsedAt time.Time
ExpiresAt time.Time
// Methods are how the session was created: the first factor, plus "totp" or "recovery"
// when a second factor was used; MFA says it was. Empty for sessions from before
// they were recorded.
Methods []string
MFA bool
}
Session is a signed-in session. Only a hash of its token is stored.
type SignupRequest ¶ added in v0.4.0
type SignupRequest struct {
Email, Password, Invitation string
Locales []string // most wanted first
RedirectTo string // already checked against the realm's allowed redirects
ClientIP, RequestID string
// Consents are the consents accepted at sign-up: name to version. Every required
// consent of the realm must be there at its current version.
Consents map[string]string
UserAgent string
}
SignupRequest is a sign-up from a client.
type SignupResult ¶ added in v0.4.0
type SignupResult struct {
Principal Principal
Token string
Pending bool
// Challenge is set instead of a session when the new user has to set a second factor
// up first (their roles require it).
Challenge *IssuedChallenge
}
SignupResult is what a sign-up gives back: a session, or (Pending) none because the realm wants the address verified first.
type Step ¶ added in v0.8.0
type Step struct {
N int
Name string
Status string // StepRunning, StepDone, StepFailed, StepTimedOut or StepCancelled
StartedAt time.Time
EndedAt time.Time // zero while running
DurationMS int64
Current float64
Total *float64 // nil when the step has no known size
Message string
UpdatedAt time.Time
}
Step is one named step of an attempt, with how far it got.
type StorageUsage ¶ added in v0.8.0
type StorageUsage struct {
Realm StorageUsageTotals
Users []UserUsage
}
StorageUsage is a realm's running totals: all of it, and the users holding the most.
type StorageUsageTotals ¶ added in v0.8.0
StorageUsageTotals is bytes and files a scope holds.
type Store ¶
type Store interface {
// CreateUser inserts a user; ErrEmailTaken if the email exists.
CreateUser(ctx context.Context, u User) error
UserByEmail(ctx context.Context, email string) (User, error)
// UserByID returns the user with that id; ErrNotFound if none.
UserByID(ctx context.Context, id string) (User, error)
ListUsers(ctx context.Context) ([]User, error)
// ListUsersPage returns one page of users sorted by email: the users whose
// email sorts after `after` (all when empty), skipping skip of them, at most
// limit; hasMore says whether more follow. Emails are unique, so `after` is
// an exact position. It never reads more than the page. A non-empty contains
// keeps the users whose email holds it (emails are stored lower-case, so
// pass it lower-case): a scan of the email index, not of the documents.
ListUsersPage(ctx context.Context, contains, after string, skip, limit int) (users []User, hasMore bool, err error)
// AddRoles adds roles the user doesn't have yet, setting UpdatedAt.
AddRoles(ctx context.Context, userID string, roles []string, now time.Time) error
// RemoveRole removes a role from the user, setting UpdatedAt.
RemoveRole(ctx context.Context, userID, role string, now time.Time) error
// UpdateUser applies upd and sets UpdatedAt to now.
UpdateUser(ctx context.Context, id string, upd UserUpdate, now time.Time) error
// ListUnverifiedUsers returns up to limit users whose address is still
// unverified and who were created before the given time, oldest first.
ListUnverifiedUsers(ctx context.Context, createdBefore time.Time, limit int) ([]User, error)
// EraseUser turns the user into a tombstone: it deletes their sessions and
// sign-in methods, and sets email (the unique placeholder), ErasedAt,
// disabled and verified, with no roles, locale, networks or pending and
// previous addresses. Repeating it is harmless.
EraseUser(ctx context.Context, id, placeholderEmail string, now time.Time) error
// DeleteEmailTokensOfUser removes the user's email tokens.
DeleteEmailTokensOfUser(ctx context.Context, userID string) error
// DeleteEmailJobsOfUser removes the email jobs addressed to the user.
DeleteEmailJobsOfUser(ctx context.Context, userID string) error
// AddEraseCount adds n to the erase job's count under key
// ("<database>/<collection>/<operation>"), atomically.
AddEraseCount(ctx context.Context, jobID, key string, n int64) error
// PutChallenge stores a pending step. GetChallenge returns the unexpired one with that
// id (ErrNotFound if none); ClaimChallenge does too and deletes it, in one atomic step,
// so a challenge works once; CountChallengeAttempt adds an attempt and returns the new
// state; DeleteChallenge and DeleteChallengesOfUser remove them.
PutChallenge(ctx context.Context, c AuthChallenge) error
GetChallenge(ctx context.Context, id string, now time.Time) (AuthChallenge, error)
ClaimChallenge(ctx context.Context, id string, now time.Time) (AuthChallenge, error)
CountChallengeAttempt(ctx context.Context, id string, now time.Time) (AuthChallenge, error)
DeleteChallenge(ctx context.Context, id string) error
DeleteChallengesOfUser(ctx context.Context, userID string, kinds ...string) error
// ChallengeOfUser returns the newest unexpired challenge of a kind that a user has
// (ErrNotFound if none); ChallengeByToken the unexpired challenge of a kind whose link
// token has that hash; SetChallengeSecrets stores the hashes of a challenge's link token
// ("" leaves it) and code, and returns the unexpired challenge.
ChallengeOfUser(ctx context.Context, userID, kind string, now time.Time) (AuthChallenge, error)
ChallengeByToken(ctx context.Context, tokenHash, kind string, now time.Time) (AuthChallenge, error)
SetChallengeSecrets(ctx context.Context, id, tokenHash, codeHash string, now time.Time) (AuthChallenge, error)
// MFAOf returns a user's second-factor record (ErrNotFound if none); PutMFA stores it,
// replacing; DeleteMFA removes it; MFAUserIDs lists the users that have one.
MFAOf(ctx context.Context, userID string) (MFARecord, error)
PutMFA(ctx context.Context, rec MFARecord) error
DeleteMFA(ctx context.Context, userID string) error
MFAUserIDs(ctx context.Context) ([]string, error)
// AdvanceMFAStep moves the last accepted TOTP step forward to step, atomically; false
// when step is not greater than it (a replay).
AdvanceMFAStep(ctx context.Context, userID string, step int64) (bool, error)
// UseRecoveryCode removes the recovery code with that keyed hash, atomically, and says
// how many are left; ok is false when the user has no such code.
UseRecoveryCode(ctx context.Context, userID, hash string) (left int, ok bool, err error)
// ClearJobInput replaces a job's input with an empty object: what it held (a new user's
// profile) is not kept after the job has run.
ClearJobInput(ctx context.Context, jobID string) error
// ClearRevokeToken removes the sealed token a revoke job held.
ClearRevokeToken(ctx context.Context, jobID string) error
// ClearEraseEmail removes the email an erase job held.
ClearEraseEmail(ctx context.Context, jobID string) error
// ReopenJob queues a job that ended in failure again, with a fresh
// attempt count and expiry; false when it isn't a failed job.
ReopenJob(ctx context.Context, id string, expiresAt time.Time) (bool, error)
// DeleteUser removes the user with their identities and sessions.
DeleteUser(ctx context.Context, id string) error
// PutIdentity creates the identity, or, when one with the same provider
// and subject exists, updates its credentials and UpdatedAt (keeping its
// ID and CreatedAt). ErrIdentityExists when the user already has another
// identity of the provider, or the provider account belongs to another user.
PutIdentity(ctx context.Context, id Identity) error
Identity(ctx context.Context, provider, subject string) (Identity, error)
// ListIdentities returns a user's identities, oldest first.
ListIdentities(ctx context.Context, userID string) ([]Identity, error)
// IdentityOf returns a user's identity of a provider; ErrNotFound if none.
IdentityOf(ctx context.Context, userID, provider string) (Identity, error)
// UpdateIdentity applies upd to the identity with that id and sets UpdatedAt
// to now; ErrNotFound if none.
UpdateIdentity(ctx context.Context, id string, upd IdentityUpdate, now time.Time) error
// DeleteIdentity removes a user's identity of a provider; ErrNotFound if none.
DeleteIdentity(ctx context.Context, userID, provider string) error
// PutOAuthState stores a sign-in attempt; ClaimOAuthState deletes and returns the
// unexpired attempt with that id (ErrNotFound if none), so a state works once.
PutOAuthState(ctx context.Context, st OAuthState) error
ClaimOAuthState(ctx context.Context, id string, now time.Time) (OAuthState, error)
// PutLoginCode and ClaimLoginCode are the same for the one-time login codes.
PutLoginCode(ctx context.Context, lc LoginCode) error
ClaimLoginCode(ctx context.Context, id string, now time.Time) (LoginCode, error)
// DeleteSessions revokes every session of the user and says how many.
DeleteSessions(ctx context.Context, userID string) (int64, error)
CreateSession(ctx context.Context, s Session) error
// SessionByTokenHash returns the session and its user; ErrNotFound if
// either doesn't exist.
SessionByTokenHash(ctx context.Context, hash string) (Session, User, error)
// TouchSession records a use of the session and its new expiry.
TouchSession(ctx context.Context, id string, lastUsed, expires time.Time) error
// ListSessions returns the user's sessions, newest first.
ListSessions(ctx context.Context, userID string) ([]Session, error)
// DeleteSession revokes one session of the user; ErrNotFound if the
// user has no session with that id.
DeleteSession(ctx context.Context, userID, id string) error
// DeleteOtherSessions revokes every session of the user except keepID
// and says how many.
DeleteOtherSessions(ctx context.Context, userID, keepID string) (int64, error)
// PutDevice registers a device: a new one, or, when the token's hash exists, that device
// moved to this user and session (a new id, so the earlier owner's id is dead) with the
// new token and name. It returns what is stored and whether it moved from another user.
PutDevice(ctx context.Context, d Device) (Device, bool, error)
// ListDevices returns the user's devices, most recently seen first.
ListDevices(ctx context.Context, userID string) ([]Device, error)
// DeleteDevice removes one of the user's devices; ErrNotFound if it isn't theirs.
DeleteDevice(ctx context.Context, userID, id string) error
// DeleteOldestDevices removes the user's least recently seen devices beyond keep, never
// the device keepID, and says how many.
DeleteOldestDevices(ctx context.Context, userID string, keep int, keepID string) (int64, error)
// DeleteStaleDevices removes the devices last seen before the time.
DeleteStaleDevices(ctx context.Context, before time.Time) (int64, error)
// DeleteOrphanedDevices removes the devices whose session doesn't exist or has expired.
DeleteOrphanedDevices(ctx context.Context, now time.Time) (int64, error)
// The realm's app configuration state and history (internal/appconfig).
appconfig.Store
// AppendConsentRecord adds a record to the user's append-only consent history and
// ListConsentRecords returns it, oldest first.
AppendConsentRecord(ctx context.Context, r ConsentRecord) error
ListConsentRecords(ctx context.Context, userID string) ([]ConsentRecord, error)
// ReduceConsentRecords is what an erase leaves of a user's consent records: it removes
// their IP address and user agent and replaces the user id with a pseudonym, and, when
// deleteAt isn't zero, sets the time a retention will remove them. It says how many.
// DeleteConsentRecordsOf removes them all (a realm that keeps none after an erase).
ReduceConsentRecords(ctx context.Context, userID, pseudonym string, deleteAt time.Time) (int64, error)
DeleteConsentRecordsOf(ctx context.Context, userID string) (int64, error)
// SetUserConsent sets the version of a consent the user holds ("" removes it: withdrawn).
SetUserConsent(ctx context.Context, userID, consent, version string) error
// ConsentVersionsInUse lists the distinct consent and version pairs records refer to.
ConsentVersionsInUse(ctx context.Context) ([]ConsentRef, error)
// DevicesByIDs returns the devices that exist among the ids. LiveDevicesOf returns the
// devices of the users whose registering session exists and hasn't expired, by user id,
// most recently seen first. DeleteDeviceByID removes a device whatever its owner.
DevicesByIDs(ctx context.Context, ids []string) ([]Device, error)
LiveDevicesOf(ctx context.Context, userIDs []string, now time.Time) (map[string][]Device, error)
DeleteDeviceByID(ctx context.Context, id string) error
// DeleteDevicesOfPlatform removes every device of a platform, and says how many.
DeleteDevicesOfPlatform(ctx context.Context, platform string) (int64, error)
// UsersByIDs returns the users that exist among the ids. AudienceUserIDs returns the ids
// of up to limit active users (not disabled, not erased) matching the audience, after the
// id `after`, in id order.
UsersByIDs(ctx context.Context, ids []string) ([]User, error)
AudienceUserIDs(ctx context.Context, a PushAudience, after string, limit int) ([]string, error)
// The record of a push send. AddPushSend adds the delta atomically (a finished batch or
// unit named in it counts once), sets CompletedAt when everything is done and returns the
// record. SetPushPlanned says every batch exists, and how many; SetPushPlanPosition keeps
// a planner job's place; UpdatePushRecipients replaces what a delivery unit still has to do.
CreatePushSend(ctx context.Context, p PushSend) error
PushSendByID(ctx context.Context, id string) (PushSend, error)
// PutPushOutbox stores a delivery the capture provider took; ListPushOutbox returns the
// newest ones.
PutPushOutbox(ctx context.Context, e PushOutboxEntry) error
ListPushOutbox(ctx context.Context, limit int) ([]PushOutboxEntry, error)
// ListPushSends returns sends newest first, and whether more follow.
ListPushSends(ctx context.Context, f PushSendFilter) ([]PushSend, bool, error)
AddPushSend(ctx context.Context, id string, d PushDelta, now time.Time) (PushSend, error)
SetPushPlanned(ctx context.Context, id string, batches int, now time.Time) error
SetPushPlanPosition(ctx context.Context, jobID, after string, nextBatch int) error
UpdatePushRecipients(ctx context.Context, jobID string, recipients []PushRecipient) error
// CreateAPIKey stores a key; ErrKeyNameTaken if the name exists.
CreateAPIKey(ctx context.Context, k APIKey) error
// APIKeyByHash returns the key with that hash; ErrKeyNotFound if none.
APIKeyByHash(ctx context.Context, hash string) (APIKey, error)
ListAPIKeys(ctx context.Context) ([]APIKey, error)
// DeleteAPIKey removes the named key; ErrKeyNotFound if none.
DeleteAPIKey(ctx context.Context, name string) error
// TouchAPIKey records a use of the key.
TouchAPIKey(ctx context.Context, hash string, at time.Time) error
// AppendAudit adds a record to the audit trail, which is never
// modified: records are only removed when they expire.
AppendAudit(ctx context.Context, rec AuditRecord) error
// ListAudit returns records matching f, newest first, and whether
// more follow.
ListAudit(ctx context.Context, f AuditFilter) ([]AuditRecord, bool, error)
CreateInvitation(ctx context.Context, inv Invitation) error
// ClaimInvitation atomically deletes and returns the unexpired
// invitation with that token hash; ErrNotFound if none.
ClaimInvitation(ctx context.Context, hash string, now time.Time) (Invitation, error)
// ClaimInvitationByID is ClaimInvitation for an invitation known by its
// id (one sent by email: nobody holds its own token).
ClaimInvitationByID(ctx context.Context, id string, now time.Time) (Invitation, error)
// ListInvitations returns all invitations, newest first.
ListInvitations(ctx context.Context) ([]Invitation, error)
// DeleteInvitation removes an invitation by id; ErrNotFound if none.
DeleteInvitation(ctx context.Context, id string) error
// LoginAttempts returns the failure counter of key (zero if none).
LoginAttempts(ctx context.Context, key string) (Attempts, error)
// RecordLoginFailure increments key's counter atomically, setting its
// last failure to at; the counter is deleted at expires.
RecordLoginFailure(ctx context.Context, key string, at, expires time.Time) error
// ClearLoginAttempts deletes key's counter.
ClearLoginAttempts(ctx context.Context, key string) error
// AcquireLoginLock takes the lock of key for owner until the given time,
// atomically: it is free when nobody holds it or its lease ended at or
// before now. false means another owner holds it. The lock serializes the
// password checks of one account across every instance.
AcquireLoginLock(ctx context.Context, key, owner string, now, until time.Time) (bool, error)
// ReleaseLoginLock frees the lock if owner still holds it.
ReleaseLoginLock(ctx context.Context, key, owner string) error
// IncrementCounter atomically increments key's counter (creating it,
// or restarting it at 1 if its window has already ended) and returns
// the new count and when it resets. The same generic "N events per
// window" primitive login throttling uses, reused for function rate
// limits (roadmap F9), which is why it lives in the same collection.
IncrementCounter(ctx context.Context, key string, at, expires time.Time) (count int, resetAt time.Time, err error)
// RecordInvocation appends a function call record (roadmap F10).
// backd never updates or deletes them; MongoDB removes them when
// they expire.
RecordInvocation(ctx context.Context, r InvocationRecord) error
// ListInvocations returns records matching f, newest first, and
// whether more follow.
ListInvocations(ctx context.Context, f InvocationFilter) ([]InvocationRecord, bool, error)
// EnqueueJob stores a new async job (roadmap F11), queued for a worker.
EnqueueJob(ctx context.Context, j Job) error
// ClaimJob atomically claims the oldest job that's never been claimed,
// or whose lease has expired, leasing it to workerID until at plus
// the job's own timeout plus margin. found is false when there is
// none to claim.
ClaimJob(ctx context.Context, workerID string, at time.Time, margin time.Duration) (j Job, found bool, err error)
// RetryJob counts a failed attempt and queues the job again, not to be
// claimed before notBefore (it is still the same job: same id, same input).
RetryJob(ctx context.Context, id string, notBefore time.Time) error
// CompleteJob records a job's result; expiresAt starts its retention
// countdown (MongoDB removes it once past).
CompleteJob(ctx context.Context, id string, result JobResult, completedAt, expiresAt time.Time) error
// CancelJob ends a job that isn't done yet with the given result (status
// "cancelled"), clearing its lease. It reports whether it did: false when
// the job was already done (or is unknown).
CancelJob(ctx context.Context, id string, result JobResult, steps []Step, completedAt, expiresAt time.Time) (bool, error)
// ListJobs returns the jobs matching f, newest first, and whether
// more follow.
ListJobs(ctx context.Context, f JobFilter) ([]Job, bool, error)
// JournalFile records an upload; SetFileJournalStatus moves it to a new status
// (with the document that references it, if any) and sets when the record
// expires; StaleFileJournal lists uploads still writing or stored that were
// last updated before the given time.
JournalFile(ctx context.Context, e FileJournalEntry) error
SetFileJournalStatus(ctx context.Context, id, status, documentID string, at, expiresAt time.Time) error
StaleFileJournal(ctx context.Context, before, now time.Time, limit int) ([]FileJournalEntry, error)
// FileJournalEntry returns one upload's record (ErrNotFound); the others are
// the bookkeeping of pending uploads: completing one, claiming it once by its
// token hash (stored → attaching, ErrNotFound when it can't be taken), giving
// a claim back, and counting a caller's open ones.
FileJournalEntry(ctx context.Context, id string) (FileJournalEntry, error)
CompletePendingUpload(ctx context.Context, id, name, contentType, sha256sum string, size int64, uploadedAt time.Time, image string, at time.Time) error
ClaimPendingUpload(ctx context.Context, id, tokenHash, documentID string, now time.Time) (FileJournalEntry, error)
// ClaimDirectUpload is the same for a direct upload waiting for its bytes (writing →
// attaching); ReleaseUpload moves a claimed upload back to the given status.
ClaimDirectUpload(ctx context.Context, id, tokenHash string, now time.Time) (FileJournalEntry, error)
ReleaseUpload(ctx context.Context, id, status string, at time.Time) error
CountOpenPendingUploads(ctx context.Context, callerKey string, now time.Time) (int, error)
// QueueFileDeletion adds an object to delete (one per key); ClaimFileDeletions
// returns up to limit due ones and holds them until lease; CompleteFileDeletion
// removes one; RetryFileDeletion counts a failed attempt and holds it until
// notBefore.
QueueFileDeletion(ctx context.Context, d FileDeletion) error
// AddStorageUsage adds to the realm's running totals and, for a non-empty owner,
// the user's; StorageUsage reads them; FileDeletionStats describes the queue.
AddStorageUsage(ctx context.Context, owner string, bytes, files int64) error
StorageUsage(ctx context.Context, limit int) (StorageUsage, error)
// StorageUsageOf returns the realm's totals and one user's (zero for an owner of "").
StorageUsageOf(ctx context.Context, owner string) (realm, user StorageUsageTotals, err error)
FileDeletionStats(ctx context.Context) (FileDeletionStats, error)
ClaimFileDeletions(ctx context.Context, now, lease time.Time, limit int) ([]FileDeletion, error)
CompleteFileDeletion(ctx context.Context, key string) error
RetryFileDeletion(ctx context.Context, key string, notBefore time.Time) error
// RenewJobLease moves the lease of a running job's attempt to until; false
// when the job no longer runs that attempt.
RenewJobLease(ctx context.Context, id string, attempt int, until time.Time) (bool, error)
// SetCheckReport stores a collection's latest schema check report, replacing
// the previous one; ListCheckReports and GetCheckReport read them (documents
// false leaves the lists of invalid documents out).
SetCheckReport(ctx context.Context, r CheckReport) error
ListCheckReports(ctx context.Context, documents bool) ([]CheckReport, error)
GetCheckReport(ctx context.Context, database, collection string) (CheckReport, bool, error)
// ImageDeclarations returns, by "<database>/<collection>.<field>/<version>", the
// fingerprint of each declared image version as it was when a worker last looked;
// SetImageDeclaration records one.
ImageDeclarations(ctx context.Context) (map[string]string, error)
SetImageDeclaration(ctx context.Context, key, fingerprint string) error
// SetJobSteps replaces the steps of a running job's attempt; false when the
// job is not running that attempt (so a late write changes nothing).
SetJobSteps(ctx context.Context, id string, attempt int, steps []Step, omitted int) (bool, error)
// GetJob returns one job by id; found is false if there is none.
GetJob(ctx context.Context, id string) (j Job, found bool, err error)
// CreateEmailToken stores a token's hash with its purpose and user.
CreateEmailToken(ctx context.Context, t EmailToken) error
// GetEmailToken returns the token with this hash whatever its state, or
// ErrInvalidToken when there is none.
GetEmailToken(ctx context.Context, hash string) (EmailToken, error)
// RedeemEmailToken atomically marks the token with this hash and purpose
// used, if it is unused and unexpired at now, and returns it; otherwise
// ErrInvalidToken.
RedeemEmailToken(ctx context.Context, hash, purpose string, now time.Time) (EmailToken, error)
// InvalidateEmailTokens marks used every unused token of the user and
// purpose.
InvalidateEmailTokens(ctx context.Context, userID, purpose string, now time.Time) error
// ClaimIdempotency (roadmap F12) atomically inserts rec if its id
// isn't already used, or returns the existing record (running or
// done) if it is. claimed is false in the second case.
ClaimIdempotency(ctx context.Context, rec IdempotencyRecord) (existing IdempotencyRecord, claimed bool, err error)
// CompleteIdempotency stores a claimed key's outcome: result for a
// sync call, jobID for async (mutually exclusive). expiresAt starts
// its retention countdown.
CompleteIdempotency(ctx context.Context, id string, result *JobResult, jobID string, completedAt, expiresAt time.Time) error
// ReleaseIdempotency removes a claim that shouldn't be remembered
// (an infrastructure failure, not a real outcome), so a retry can
// go through cleanly instead of being stuck "running" forever.
ReleaseIdempotency(ctx context.Context, id string) error
// SetScheduleState stores a scheduled function's state, replacing any.
SetScheduleState(ctx context.Context, st ScheduleState) error
// ListScheduleStates returns every stored state.
ListScheduleStates(ctx context.Context) ([]ScheduleState, error)
// UpsertSecret creates or replaces the secret at (database, name),
// keeping its original CreatedAt on an update.
UpsertSecret(ctx context.Context, s Secret) error
// SecretByScope returns one secret; ErrSecretNotFound if none.
SecretByScope(ctx context.Context, database, name string) (Secret, error)
// ListSecrets returns every secret's metadata, sorted by database
// (realm scope, "", first) then name.
ListSecrets(ctx context.Context) ([]Secret, error)
// DeleteSecret removes one; ErrSecretNotFound if none.
DeleteSecret(ctx context.Context, database, name string) error
}
Store persists users, identities and sessions of one realm.
type TOTPSetup ¶ added in v0.8.2
type TOTPSetup struct {
SetupID string
Secret string // base32, for typing in
URI string // otpauth://
QR string // a PNG data URI of the URI
Expires time.Time
}
TOTPSetup is a secret an authenticator app is to be given.
type ThrottledError ¶
ThrottledError means the caller must wait before trying again.
func (*ThrottledError) Error ¶
func (e *ThrottledError) Error() string
type User ¶
type User struct {
ID string
Email string // normalized: trimmed, lowercased
EmailVerified bool
// PendingEmail is an address the user asked to change to and hasn't
// confirmed yet; PreviousEmail is the one before the last change, kept
// so the old address can be told and can undo it.
PendingEmail string
PreviousEmail string
// ErasedAt is when an administrator erased the user: what is left is a
// tombstone, the id with an anonymized email and no way to sign in.
ErasedAt time.Time
Roles []string
Disabled bool
// Locale is the user's language: one the realm lists (see
// RealmSettings.Languages). Empty for users from before languages existed;
// those use the realm's default.
Locale string
// AdminNetworks restrict the user's admin API requests; LoginNetworks
// their login and every request with their session. Empty: no
// restriction beyond the realm's.
AdminNetworks registry.Networks
LoginNetworks registry.Networks
// Consents is the version of each consent the user has accepted and not
// withdrawn: the summary of their consent records, for rules and sign-in.
Consents map[string]string
CreatedAt time.Time
UpdatedAt time.Time
}
User is a realm user. It holds only identity data; profiles belong in application collections.
type UserUpdate ¶
type UserUpdate struct {
// Email changes the address (ErrEmailTaken when another user has it).
Email *string
PendingEmail *string // set; an empty string clears it
PreviousEmail *string // set; an empty string clears it
EmailVerified *bool
Disabled *bool
Locale *string
AdminNetworks *registry.Networks // set (empty clears)
LoginNetworks *registry.Networks // set (empty clears)
}
UserUpdate changes the set fields of a user.
type UserUsage ¶ added in v0.8.0
type UserUsage struct {
UserID string
StorageUsageTotals
}
UserUsage is what the files of the documents a user owns add up to.
type Users ¶
type Users struct {
Store Store
Hasher *Hasher
Settings registry.RealmSettings
Now func() time.Time // defaults to time.Now
Realm string // the realm's name, for logs
Log *slog.Logger // audit records are also logged here; nil: not logged
// Cipher encrypts and decrypts secrets (roadmap F5); nil when
// BACKD_SECRETS_KEY isn't configured, in which case every secret
// resolves as missing. Cache holds decrypted values briefly, shared
// across every realm's Users (NewSecretCache); nil disables caching.
Cipher *SecretCipher
Cache *SecretCache
// Metrics counts sessions and limits; nil turns it off.
Metrics *metrics.Metrics
// contains filtered or unexported fields
}
Users manages the users of one realm.
func (*Users) AbandonedUploads ¶ added in v0.8.0
AbandonedUploads returns uploads left writing, stored or attaching for longer than the grace period, and pending uploads nobody used before they expired.
func (*Users) AcceptConsents ¶ added in v0.8.2
func (s *Users) AcceptConsents(ctx context.Context, challenge string, given map[string]string, from ConsentContext) (Verified, error)
AcceptConsents trades a consent challenge and the consents accepted (name to version) for the session the sign-in was waiting for. Every consent the challenge named must be accepted at its current version; optional consents may come with them. A challenge that isn't satisfied stays valid, so the person can try again.
func (*Users) AcceptConsentsOf ¶ added in v0.8.2
func (s *Users) AcceptConsentsOf(ctx context.Context, u User, given map[string]string, from ConsentContext) (User, error)
AcceptConsentsOf records consents a signed-in user gives (method api): an app showing the prompt after a version changed, or a user opting in to an optional consent.
func (*Users) AcceptInvitation ¶ added in v0.4.0
func (s *Users) AcceptInvitation(ctx context.Context, token, password, locale string) (EmailToken, error)
AcceptInvitation uses the link of an emailed invitation: it creates the account with the chosen password and the invited address, already verified (only its owner received the link). It starts no session. The password is checked first, so a refused one leaves the link usable. Every way the link can be wrong, or the address being registered meanwhile, is ErrInvalidToken.
func (*Users) ApplyRoleSeeds ¶
ApplyRoleSeeds adds the roles realm.yaml assigns to existing users. It never removes roles. Users who don't exist yet get theirs when created. It returns how many users were updated.
func (*Users) Audit ¶
Audit appends a record to the realm's audit trail and writes it to the log. A record that can't be stored is logged as an error; the action it describes has already happened, so it isn't undone.
func (*Users) AuditAs ¶
AuditAs is Audit with an explicit actor (when not empty), for events whose actor isn't the caller yet, such as a login.
func (*Users) AuditTrail ¶
func (s *Users) AuditTrail(ctx context.Context, f AuditFilter) ([]AuditRecord, bool, error)
AuditTrail returns records matching f, newest first, and whether more follow.
func (*Users) Authenticate ¶
Authenticate resolves a session token to its user. It extends the session's idle timeout, writing at most once per minute.
func (*Users) AuthenticateIgnoringConsents ¶ added in v0.8.2
AuthenticateIgnoringConsents is Authenticate without the consent deadline: for the few routes a person needs to accept what is missing, or to leave (see consents_signin.go).
func (*Users) AuthenticateKey ¶
AuthenticateKey resolves an API key. It records the use at most once a minute.
func (*Users) BeginEnrollment ¶ added in v0.8.2
BeginEnrollment starts the TOTP setup of a user whose sign-in is waiting for one (their role requires MFA): the same secret and QR as BeginTOTPSetup, asked for with the challenge the first factor gave instead of a session.
func (*Users) BeginOAuth ¶ added in v0.8.2
func (s *Users) BeginOAuth(ctx context.Context, st OAuthState) (state, nonce, verifier string, err error)
BeginOAuth records a sign-in attempt and returns the state value to send to the provider and the nonce and PKCE verifier to use with it.
func (*Users) BeginTOTPSetup ¶ added in v0.8.2
BeginTOTPSetup makes a TOTP secret for the user, held for 15 minutes until a first code from the app proves it was received. A new setup replaces any pending one.
func (*Users) CallbackCaller ¶
CallbackCaller resolves a verified token into the caller it acts as, checking the user and key still exist and may act: a user disabled or a key revoked during the invocation loses access at once.
func (*Users) CancelJob ¶ added in v0.8.0
CancelJob ends a queued or running function job: it is done, with the result "cancelled", at once. A worker running it notices and stops the run (what the function already did stays done). ErrJobFinished if it ended first, ErrNotFound if there is no such job.
func (*Users) ChangeEmailAsAdmin ¶ added in v0.4.0
ChangeEmailAsAdmin changes a user's address at once, as an administrator vouching for it: the new address counts as verified, every session of the user ends, the old address gets the message with the link to undo it and the new one is told. It needs the realm to send email (the notifications).
func (*Users) ChangePassword ¶
ChangePassword replaces the caller's password and ends all of their other sessions. The caller has checked that the user proved who they are just now (CheckReauth).
func (*Users) CheckReauth ¶ added in v0.8.2
CheckReauth says whether token is a re-authentication of this session (ErrReauthRequired otherwise). A user who gives no proof (ReauthMethodsOf is empty) always passes.
func (*Users) CheckReport ¶ added in v0.8.0
CheckReport returns one collection's latest report; ErrNotFound if it was never checked.
func (*Users) CheckReports ¶ added in v0.8.0
CheckReports returns the latest report of every collection checked, sorted by database and collection. With documents false the lists of invalid documents are left out.
func (*Users) ClaimDirectUpload ¶ added in v0.8.0
ClaimDirectUpload takes a direct upload to verify and complete it, once: held as attaching until it is done or released. ErrNotFound when the token doesn't match, the upload isn't one that waits for its bytes, or it expired.
func (*Users) ClaimFileDeletions ¶ added in v0.8.0
ClaimFileDeletions returns up to limit deletions that are due, holding them for FileDeletionLease so no other worker takes them meanwhile.
func (*Users) ClaimIdempotency ¶
func (s *Users) ClaimIdempotency(ctx context.Context, rec IdempotencyRecord) (IdempotencyRecord, bool, error)
ClaimIdempotency atomically claims a key for a new call, or returns the existing record (running or done) if one already exists.
func (*Users) ClaimJob ¶
ClaimJob atomically claims the oldest claimable job: never claimed, or whose lease has expired (a dead worker's jobs are picked up again), leasing it to workerID for the function's own timeout plus a margin.
func (*Users) ClaimPendingUpload ¶ added in v0.8.0
func (s *Users) ClaimPendingUpload(ctx context.Context, id, token, documentID string) (FileJournalEntry, error)
ClaimPendingUpload takes a completed, unexpired pending upload whose token matches, once: it is held as attaching to the document until it is attached or released. ErrNotFound when there is none to take.
func (*Users) Clock ¶ added in v0.4.0
Clock is the service's current time (its Now, or the real one).
func (*Users) CompleteEnrollment ¶ added in v0.8.2
func (s *Users) CompleteEnrollment(ctx context.Context, challenge, setupID, code string) (Verified, []string, error)
CompleteEnrollment confirms the TOTP setup of a waiting sign-in with its first code, and finishes the sign-in: the outcome is the session the first factor was waiting for, with the second one recorded, and the recovery codes, shown once. Five wrong codes end the challenge.
func (*Users) CompleteIdempotency ¶
func (s *Users) CompleteIdempotency(ctx context.Context, id string, result *JobResult, jobID string) error
CompleteIdempotency stores a claimed key's outcome.
func (*Users) CompleteJob ¶
CompleteJob records a job's result and starts its retention countdown.
func (*Users) CompletePendingUpload ¶ added in v0.8.0
func (s *Users) CompletePendingUpload(ctx context.Context, id, name, contentType, sha256sum string, size int64, uploadedAt time.Time, image string) error
CompletePendingUpload records what was stored: the upload is now ready to be attached.
func (*Users) ConfirmEmailChange ¶ added in v0.4.0
ConfirmEmailChange uses the link sent to the new address: the address changes (and counts as verified: the owner just read that mailbox), every session of the user ends, and the old address is told, with a link to undo it. Every way the token can be wrong, or the address having been taken meanwhile, is ErrInvalidToken.
func (*Users) ConfirmTOTP ¶ added in v0.8.2
func (s *Users) ConfirmTOTP(ctx context.Context, u User, keepSession, setupID, code string) ([]string, error)
ConfirmTOTP turns TOTP on for the user with the first code of the setup, and returns the recovery codes: shown once, kept only as keyed hashes. Every other session of the user ends, so a session from before can't pass a rule that asks for MFA; keepSession is the one that stays ("" for none). A wrong code is an *InvalidCodeError; five end the setup.
func (*Users) ConsentHistory ¶ added in v0.8.2
ConsentHistory returns the user's consent records, oldest first.
func (*Users) ConsentPseudonym ¶ added in v0.8.2
ConsentPseudonym is HMAC-SHA-256 over the normalized address under the realm's key: it lets a later dispute from that address be matched to the records without keeping the address. "" when the realm has no secrets key (nothing can be keyed).
func (*Users) Create ¶
Create adds a user, as an administrator, with the address already verified. With password nil the user has no password identity and can't sign in with a password until one is set.
func (*Users) CreateAPIKey ¶
func (s *Users) CreateAPIKey(ctx context.Context, name string, opts KeyOptions) (APIKey, string, error)
CreateAPIKey creates a key named name with opts. The key itself is returned only here.
func (*Users) CreateInvitation ¶
func (s *Users) CreateInvitation(ctx context.Context, email string, ttl time.Duration, createdBy string) (Invitation, string, error)
CreateInvitation creates an invitation valid for ttl (0: the default), optionally bound to email. The token is returned only here.
func (*Users) DeactivateAccount ¶ added in v0.4.0
DeactivateAccount handles a user deleting their own account: it is disabled and its sessions end. The caller has checked that the user proved who they are just now (CheckReauth). Nothing is erased: that is an administrator's action (Erase).
func (*Users) Delete ¶
Delete removes the user, their identities and sessions. Documents they own are kept.
func (*Users) DeleteSecret ¶
DeleteSecret removes the value at scope and name; ErrSecretNotFound if none. Functions that declare it start answering secret_missing again.
func (*Users) Devices ¶ added in v0.8.2
Devices lists a user's devices, most recently seen first, without tokens' meaning to the caller (the sealed value is in each one: the HTTP layer never returns it).
func (*Users) DisableMFA ¶ added in v0.8.2
DisableMFA removes the user's second factor and recovery codes; refused while a role of the user requires one.
func (*Users) EnqueueCompletionJob ¶ added in v0.8.0
func (s *Users) EnqueueCompletionJob(ctx context.Context, finished Job, target string, timeoutMS int64, input json.RawMessage) (Job, bool, error)
EnqueueCompletionJob queues the notification of a job's end (on_complete): a job of function target in the same database, with input as its input, run with no caller (it has whatever its own function.yaml gives it). Its id comes from the finished job, so a second attempt to queue it for the same job does nothing; it returns false then. timeoutMS is the target's timeout.
func (*Users) EnqueueImageJob ¶ added in v0.8.1
func (s *Users) EnqueueImageJob(ctx context.Context, database string, e ImageJob, requestID string) error
EnqueueImageJob queues the making of a file's pending versions. A file has at most one such job at a time: asking again while one is queued or running is not an error.
func (*Users) EnqueueImageOp ¶ added in v0.8.1
func (s *Users) EnqueueImageOp(ctx context.Context, database string, e ImageJob, requestID string) (Job, error)
EnqueueImageOp queues the making of one version for a function that waits for it. It returns ErrJobExclusive while another job of the file is queued or running: the caller waits and asks again.
func (*Users) EnqueueJob ¶
EnqueueJob stores a new job, queued for a worker to claim, and returns it with its id and timestamps filled in.
func (*Users) EnqueueJobID ¶ added in v0.8.2
EnqueueJobID is EnqueueJob for a job that has its id already: a job with that id existing is not an error (created is false), so work that runs again doesn't make it twice.
func (*Users) EnqueueScheduledJob ¶
func (s *Users) EnqueueScheduledJob(ctx context.Context, j Job, scheduledAt time.Time, skipOverlap bool) (Job, bool, error)
EnqueueScheduledJob enqueues the run of a scheduled function for scheduledAt, under an id derived from the function and that time, so however many workers try, exactly one job is created (roadmap F18). It returns the job, and false when the run already exists.
With skipOverlap, a function that still has an unfinished job (queued, waiting for a retry, or running) doesn't get a new run: the scheduled time is recorded as a job that is done at once with the result "skipped", so the job list shows it and no worker claims it.
func (*Users) Erase ¶ added in v0.4.0
Erase starts erasing a user, as an administrator: it queues the erase job (which holds the id and the email the policies match by), then turns the user into a tombstone and deletes their email tokens and email jobs at once. A worker applies the collections' policies. Repeating it for a user whose erase job failed queues that job again; for one whose job is still going it returns the job; otherwise it is ErrAlreadyErased.
func (*Users) EraseJobFor ¶ added in v0.4.0
EraseJobFor returns the latest erase job of a user.
func (*Users) FileAdded ¶ added in v0.8.0
FileAdded counts a file a document now references, for the realm and, when the document has an owner, for them.
func (*Users) FileDeletionStats ¶ added in v0.8.0
func (s *Users) FileDeletionStats(ctx context.Context) (FileDeletionStats, error)
FileDeletionStats describes what waits to be deleted.
func (*Users) FileRemoved ¶ added in v0.8.0
FileRemoved counts a file no document references any more.
func (*Users) FinishFileDeletion ¶ added in v0.8.0
FinishFileDeletion removes a deletion that was carried out.
func (*Users) Identify ¶
Identify resolves a bearer credential (a session token or an API key) to its caller. An empty credential is the anonymous caller.
func (*Users) Identities ¶ added in v0.8.2
Identities returns the user's sign-in methods, oldest first.
func (*Users) ImageDeclarations ¶ added in v0.8.1
ImageDeclarations returns the fingerprints recorded for the declared image versions.
func (*Users) InvitationByID ¶ added in v0.4.0
InvitationByID returns an unexpired invitation by id.
func (*Users) Invitations ¶
func (s *Users) Invitations(ctx context.Context) ([]Invitation, error)
Invitations lists the realm's unexpired invitations, newest first.
func (*Users) Invocations ¶
func (s *Users) Invocations(ctx context.Context, f InvocationFilter) ([]InvocationRecord, bool, error)
Invocations returns invocation records matching f, newest first, and whether more follow.
func (*Users) IssueLoginCode ¶ added in v0.8.2
func (s *Users) IssueLoginCode(ctx context.Context, userID, method, challenge string, newUser bool, profile map[string]string) (string, error)
IssueLoginCode makes the one-time code that lets the app, holding the PKCE verifier of challenge, get a session for the user; method is the first factor that proved them.
func (*Users) JournalDirectUpload ¶ added in v0.8.0
func (s *Users) JournalDirectUpload(ctx context.Context, e FileJournalEntry, ttl time.Duration) error
JournalDirectUpload records a direct upload that is starting: the client will send the bytes to the bucket and complete it before it expires after ttl. A pending one (e.Pending) is attached later by a write; the others belong to a document.
func (*Users) JournalPendingUpload ¶ added in v0.8.0
func (s *Users) JournalPendingUpload(ctx context.Context, e FileJournalEntry, ttl time.Duration) error
JournalPendingUpload records a pending upload that is starting; unused, it expires after ttl.
func (*Users) JournalUpload ¶ added in v0.8.0
func (s *Users) JournalUpload(ctx context.Context, e FileJournalEntry) error
JournalUpload records an upload that is starting.
func (*Users) KeyCreatedBySession ¶ added in v0.8.2
KeyCreatedBySession tells the signed-in administrator who made an API key that they did, by email: a key outlives the session, so a stolen session making one is noticed.
func (*Users) ListAPIKeys ¶
ListAPIKeys returns the realm's API keys, sorted by name.
func (*Users) ListPage ¶ added in v0.5.0
func (s *Users) ListPage(ctx context.Context, contains, after string, skip, limit int) ([]User, bool, error)
ListPage is List for one page, sorted by email; see Store.ListUsersPage.
func (*Users) ListSecrets ¶
func (s *Users) ListSecrets(ctx context.Context) ([]SecretMeta, error)
ListSecrets returns every secret's metadata (never a value), sorted by database then name (realm-scope secrets, database "", first).
func (*Users) LocaleOf ¶ added in v0.4.0
LocaleOf is the language of a user: theirs, or the realm's default for users from before languages existed.
func (*Users) Login ¶
Login checks an email and password and starts a session. Every failure returns ErrInvalidCredentials after the same amount of hashing work, so neither the answer nor its timing reveals whether the email exists. Repeated failures for the email or from the client ip (may be empty) are throttled with a *ThrottledError.
func (*Users) MFAStatusOf ¶ added in v0.8.2
MFAStatusOf reports a user's second-factor state.
func (*Users) MagicLinkByToken ¶ added in v0.8.2
MagicLinkByToken finds the request a link token belongs to, without using it up: opening a link in a mail scanner must not spoil it.
func (*Users) MagicLinkDestination ¶ added in v0.8.2
func (s *Users) MagicLinkDestination(c AuthChallenge) string
MagicLinkDestination is where a request's link sends the browser: its redirect_to, else the realm's sign_in.app_url, else "" (then the code is the way).
func (*Users) MagicLinkEmailFor ¶ added in v0.8.2
func (s *Users) MagicLinkEmailFor(ctx context.Context, challengeID string) (AuthChallenge, string, error)
MagicLinkEmailFor is what the worker needs to write a request's email: the address it goes to and, for a request that has a user, who they are.
func (*Users) MakeMagicLinkSecrets ¶ added in v0.8.2
func (s *Users) MakeMagicLinkSecrets(ctx context.Context, challengeID string) (token, code string, expires time.Time, err error)
MakeMagicLinkSecrets makes the link token and the code of a request when its email is written, keeps their hashes only, and returns them with when they stop working. A retried job gets new ones, and the earlier pair stops working.
func (*Users) MakeReauthCode ¶ added in v0.8.2
MakeReauthCode is what the worker calls when it writes the email: it makes a fresh code, keeps its hash on the challenge and returns the code and when it stops working. A job that is tried again gets a new code, and the earlier one stops working.
func (*Users) MaxSessionExpiry ¶ added in v0.5.0
MaxSessionExpiry is the latest a session started at created can last for this user: the absolute limit, whatever the idle timeout slides to.
func (*Users) NetworksInConfig ¶
NetworksInConfig reports whether realm.yaml sets network restrictions for email; seeding would then overwrite changes made elsewhere.
func (*Users) NewEmailToken ¶ added in v0.4.0
func (s *Users) NewEmailToken(ctx context.Context, purpose, userID, redirectTo string, ttl time.Duration) (token string, expiresAt time.Time, err error)
NewEmailToken creates a token of 256 random bits for userID and purpose, valid for ttl, stores its hash, and returns the token itself. Whoever receives it must not store it.
func (*Users) NewEmailTokenFor ¶ added in v0.4.0
func (s *Users) NewEmailTokenFor(ctx context.Context, t EmailToken, ttl time.Duration) (token string, expiresAt time.Time, err error)
NewEmailTokenFor is NewEmailToken for a token that also carries an address or an invitation: t's Hash, CreatedAt and ExpiresAt are filled in.
func (*Users) NotifyConsentUpdated ¶ added in v0.8.2
NotifyConsentUpdated queues the consent-updated email for every user who holds an older version of the consent than the current one (and, for a required consent, who holds none). It never runs by itself: publishing a version sends nothing. The email limits apply, so a large realm may need more than one run; users already told are not told again until the version changes, because the run only goes by what each user holds.
func (*Users) OnBehalfOf ¶
OnBehalfOf makes an API key caller act as the user with id: that user's rules and ownership apply. It returns ErrNotFound for unknown users.
func (*Users) OpenPendingUploads ¶ added in v0.8.0
OpenPendingUploads counts the unused pending uploads a caller holds.
func (*Users) PeekEmailToken ¶ added in v0.4.0
PeekEmailToken checks a token for purpose without using it, so a page can show its form before the person acts. Every failure is ErrInvalidToken.
func (*Users) PendingUpload ¶ added in v0.8.0
PendingUpload returns a pending upload's record, or ErrNotFound.
func (*Users) PlanPushAudience ¶ added in v0.8.2
PlanPushAudience pages an audience into batches. It records its position in the job, so a planner that runs again continues where it stopped; the batches' ids make a repeat harmless.
func (*Users) PlanPushBatch ¶ added in v0.8.2
func (s *Users) PlanPushBatch(ctx context.Context, batchID, sendID string, users []string, messages map[string]push.Message, requestID string) (PushCounts, error)
PlanPushBatch applies the limits, resolves the devices and makes the delivery units of one batch of users. Unit ids derive from the batch's, so a batch that runs again continues where it was and makes nothing twice; the batch's totals are added once, when it ends.
func (*Users) PlanPushBatchRequiring ¶ added in v0.8.2
func (s *Users) PlanPushBatchRequiring(ctx context.Context, batchID, sendID string, users []string, messages map[string]push.Message, requestID, requiresConsent string) (PushCounts, error)
PlanPushBatchRequiring is PlanPushBatch for a send that requires a consent: users who don't hold it are counted as no_consent and get nothing (before the limits are applied, so they don't count against them).
func (*Users) PurgeUnverified ¶ added in v0.4.0
PurgeUnverified deletes accounts that never verified their address and are older than account.purge_unverified_after, and returns how many. Accounts with roles are never purged. Documents the accounts created stay, as with any deletion of a user.
func (*Users) PushSendByID ¶ added in v0.8.2
PushSendByID returns a send's record.
func (*Users) QueueEmail ¶ added in v0.4.0
QueueEmail applies the limits and queues an email job. The job holds the kind, the user, the locale and the redirect: no address, no message and no token. A worker creates the token, renders the message and calls the delivery function. It returns ErrEmailNotConfigured in a realm without email, and *EmailLimitedError when a limit is reached: callers without a signed-in user skip the send silently, so the answer reveals nothing; callers with one answer 429. Without a UserID nothing is queued, but the limits are counted all the same, so a request about an address that has no account does the same work as one that has.
func (*Users) QueueFileDeletion ¶ added in v0.8.0
QueueFileDeletion queues an object for deletion; queueing the same key twice is one deletion.
func (*Users) RateLimit ¶
RateLimit increments key's counter and returns *ThrottledError if the resulting count is over limit within window: shared across every backd instance (roadmap F9), unlike concurrency limits (F8), because the counter lives in Store, not in process memory. Reuses the same "N events per window" primitive as login throttling (Store's IncrementCounter), under its own key namespace so the two never collide.
func (*Users) ReauthMethodsOf ¶ added in v0.8.2
ReauthMethodsOf says which proofs a user gives: the second factor's when they have one (a password alone is not enough then), else the password, else a code sent by email. A user with none of them (no password, no second factor, and a realm that sends no email) has no way to prove anything more than their session, and sensitive actions don't ask.
func (*Users) Reauthenticate ¶ added in v0.8.2
func (s *Users) Reauthenticate(ctx context.Context, p Principal, method, proof, ip string) (ReauthGrant, error)
Reauthenticate checks one proof of the signed-in user and gives a token bound to their session, good for the realm's reauth.ttl and for any number of actions in it. proof is the code, or for ReauthPassword the password. Wrong proofs count against the same limits as signing in.
func (*Users) RecordConsent ¶ added in v0.8.2
func (s *Users) RecordConsent(ctx context.Context, userID string, in ConsentInput) (ConsentRecord, error)
RecordConsent appends a record for the user and updates their summary. Accepting needs a version the realm has a text for in the person's language; the record keeps that text's hash, so the proof names the exact words.
func (*Users) RecordConsentFor ¶ added in v0.8.2
func (s *Users) RecordConsentFor(ctx context.Context, userID string, in ConsentInput) (ConsentRecord, error)
RecordConsentFor records a consent given or withdrawn outside the app (on paper, by phone) by an administrator, with the reference that proves it. Audited.
func (*Users) RecordInvocation ¶
func (s *Users) RecordInvocation(ctx context.Context, rec InvocationRecord)
RecordInvocation stores one function call. A record that can't be stored is logged as an error; the call already happened and isn't undone by a failed write, the same philosophy as Audit.
func (*Users) RedeemEmailToken ¶ added in v0.4.0
RedeemEmailToken uses a token for purpose: it hashes it, finds it, checks purpose, expiry and use, and marks it used in one atomic step, so of two parallel redemptions exactly one succeeds. A success also invalidates the user's other outstanding tokens of the same purpose. Every failure is ErrInvalidToken.
func (*Users) RedeemLoginCode ¶ added in v0.8.2
RedeemLoginCode trades a login code and the PKCE verifier for a session. The code is used up whether or not the verifier fits, so a stolen code can't be tried again. Every failure is ErrInvalidCredentials, and the answer is the same for an unknown, expired or used code.
func (*Users) ReduceConsentRecords ¶ added in v0.8.2
ReduceConsentRecords is what an erase leaves of a person's consent records (design/compliance.md §8): the IP address and the user agent go, the user id becomes an HMAC of the normalized address under a realm secret, and what proves consent stays (names, versions, text hashes, actions, methods, times) until `compliance.consent_retention` has passed, when the database removes them. With a retention of 0 they go at once. Safe to repeat. It returns how many records it touched.
func (*Users) RegenerateRecoveryCodes ¶ added in v0.8.2
RegenerateRecoveryCodes replaces every recovery code of the user and returns the new ones, shown once.
func (*Users) RegisterDevice ¶ added in v0.8.2
RegisterDevice registers or refreshes a device of the signed-in user and returns it. A token that exists moves to this user and session; above the cap the least recently seen device goes.
func (*Users) ReleaseDirectUpload ¶ added in v0.8.0
ReleaseDirectUpload gives a claimed direct upload back, to wait for its bytes again.
func (*Users) ReleaseIdempotency ¶
ReleaseIdempotency removes a claim that shouldn't be remembered (the executor was unreachable or busy — nothing about the call's own outcome to replay), so a retry can go through cleanly.
func (*Users) ReleasePendingUpload ¶ added in v0.8.0
ReleasePendingUpload gives a claimed pending upload back, when the write that claimed it didn't happen.
func (*Users) RemoveDevice ¶ added in v0.8.2
RemoveDevice removes one of the user's devices; ErrNotFound when it isn't theirs. An administrator's removal (by != "") is audited.
func (*Users) RemoveDevicesOfPlatform ¶ added in v0.8.2
RemoveDevicesOfPlatform removes every device of a platform, for an administrator: rotating a realm's VAPID key makes every web subscription useless (browsers made them under the old key), so they go at once and apps subscribe again at their next launch. It is audited.
func (*Users) RemovePassword ¶ added in v0.8.2
RemovePassword removes the user's password, so that they sign in with a link or a provider only. It refuses when nothing else would be left (ErrLastSignInMethod), and ends every other session: whoever knew the password may have a session. The caller has checked a fresh proof of identity.
func (*Users) RemoveRole ¶
RemoveRole takes a role away from a user. An assignment seeded in realm.yaml comes back at the next seeding.
func (*Users) RenewJobLease ¶ added in v0.8.0
func (s *Users) RenewJobLease(ctx context.Context, id string, attempt int, d time.Duration) (bool, error)
RenewJobLease keeps a running job's lease for another d, for the worker's attempt; false when it no longer runs that attempt.
func (*Users) ReportRoles ¶
func (s *Users) ReportRoles(ctx context.Context) (RoleReport, error)
ReportRoles compares the stored assignments with realm.yaml.
func (*Users) RequestEmailChange ¶ added in v0.4.0
func (s *Users) RequestEmailChange(ctx context.Context, p Principal, newAddress, redirectTo, ip, requestID string) error
RequestEmailChange starts a change of the signed-in user's own address: it needs the current password, remembers the new address as pending and sends a confirmation link to it. Nothing changes until that link is used. An address someone else already has is answered like any other (the request is accepted and nothing is sent), so this can't be used to find out who is registered. A reached email limit is an *EmailLimitedError: the caller is signed in, so it may be told.
func (*Users) RequestMagicLink ¶ added in v0.8.2
RequestMagicLink makes a request and asks for its email, returning the request id the asking app keeps to redeem the code. It answers the same, in about the same work, for every address: a known one, one without an account (a message says so) and one that can't sign in (nothing is sent), so it says nothing about who is registered. An email limit that is reached changes nothing for the caller either: the message is skipped.
func (*Users) RequestPasswordReset ¶ added in v0.4.0
func (s *Users) RequestPasswordReset(ctx context.Context, address, redirectTo, ip, requestID string) error
RequestPasswordReset asks for a reset email. It answers nothing about the account: an unknown or disabled address does the same work as a known one, minus the queued job. Requests are counted per address and per client (a *ThrottledError once past the limit, for every address alike), and the email limits apply on top.
func (*Users) RequestReauthCode ¶ added in v0.8.2
RequestReauthCode makes a code and emails it to a user whose proof is one (no second factor, no password): the code is made when the message is, kept only as a hash, and good for 10 minutes and 5 attempts. A new request replaces the earlier code.
func (*Users) RerunJob ¶ added in v0.8.0
RerunJob queues a new job for a finished function job: the same function, input and caller, as a job of its own (RerunOf says which). timeoutMS is the function's timeout now, for the new job's lease.
func (*Users) ResendVerification ¶ added in v0.4.0
func (s *Users) ResendVerification(ctx context.Context, address, redirectTo, ip, requestID string) error
ResendVerification asks again for the verification email of an address. It answers nothing about the account: an unknown, disabled or already verified address does the same work, minus the queued job, and every limit counts the same.
func (*Users) ResetMFA ¶ added in v0.8.2
ResetMFA removes a user's second factor and recovery codes and ends all of their sessions, on an administrator's say-so (or an operator's, with direct access): the user is asked to set one up again at their next sign-in when a role requires it, and is told by email. actorID is the administrator's user id (""), who can't reset themselves; ErrMFANotEnabled when the user has none.
func (*Users) ResetPassword ¶ added in v0.4.0
ResetPassword uses a reset token to set a new password. The password is checked first, so a refused one (*PolicyError) leaves the token usable. Success ends every session of the user, marks the address verified (the token proves the person reads that mailbox) and sends password-changed. It never starts a session. Every way the token can be wrong is ErrInvalidToken.
func (*Users) ResolveProviderLogin ¶ added in v0.8.2
func (s *Users) ResolveProviderLogin(ctx context.Context, in ProviderLogin) (ProviderResult, error)
ResolveProviderLogin decides who a provider's person is, under the rules of the design: an identity already linked signs that user in; an address that matches an account links only when the provider is trusted, says the address is verified and the account's is too; otherwise a new account is made if the realm's sign-up allows it. It does not start a session.
func (*Users) ResolveSecrets ¶
func (s *Users) ResolveSecrets(ctx context.Context, refs []registry.SecretRef, database string) (values map[string]string, missing []string, err error)
ResolveSecrets decrypts the values a function declared (refs), for database (its own). It returns values keyed exactly as declared (SecretRef.String(): NAME or realm.NAME) and, separately, the refs with no stored value, so the caller can answer secret_missing. Decrypted values are cached for a short time, so a rotation or a changed value applies within a minute without restarting anything.
func (*Users) RetryFileDeletion ¶ added in v0.8.0
RetryFileDeletion keeps a deletion that failed, to be claimed again after wait.
func (*Users) RetryJob ¶ added in v0.4.0
RetryJob puts a job whose attempt failed back in the queue, to be claimed again once delay has passed.
func (*Users) RevertEmailChange ¶ added in v0.4.0
RevertEmailChange uses the link sent to the old address: it restores that address, ends every session of the user and makes their password unusable, since whoever changed the address may know it, and sends a password reset link to the restored address. Every way the token can be wrong is ErrInvalidToken.
func (*Users) RevokeAPIKey ¶
RevokeAPIKey deletes a key; it stops working at once.
func (*Users) RevokeInvitation ¶
RevokeInvitation deletes an invitation; ErrNotFound if none has that id.
func (*Users) RevokeSession ¶
RevokeSession ends one of the caller's sessions; ErrNotFound if the caller has no session with that id.
func (*Users) RevokeUserSession ¶ added in v0.7.0
RevokeUserSession ends one session of a user, on an administrator's say-so; ErrNotFound if the user has no session with that id.
func (*Users) SaveAppleToken ¶ added in v0.8.2
SaveAppleToken keeps Apple's refresh token on the user's Apple identity, sealed, unless the provider is configured with revoke_on_delete: false (then nothing is stored).
func (*Users) SaveCheckReport ¶ added in v0.8.0
func (s *Users) SaveCheckReport(ctx context.Context, r CheckReport) error
SaveCheckReport stores r as the collection's latest report, replacing the last.
func (*Users) ScheduleStates ¶ added in v0.8.0
ScheduleStates returns the state of every function that has ever been paused, keyed by "<database>/<function>".
func (*Users) SealToken ¶ added in v0.8.2
SealToken encrypts a token for storage with the realm's secrets cipher. The result names the key it was sealed under, so a rotated key is noticed.
func (*Users) SendInvitation ¶ added in v0.4.0
func (s *Users) SendInvitation(ctx context.Context, address string, ttl time.Duration, createdBy, redirectTo, locale, ip, requestID string) (Invitation, error)
SendInvitation is CreateInvitation for an invitation that backd emails to the address it is bound to: the person gets a link to a page where they choose a password. Nobody holds the invitation's own token, so no token is returned; the link's token is made by a worker when it sends the message, and only its hash is stored. A reached email limit removes the invitation again and is an *EmailLimitedError.
func (*Users) SetDisabled ¶
SetDisabled disables or re-enables the user. Disabling revokes all of their sessions.
func (*Users) SetEmailVerified ¶
SetEmailVerified marks the user's email as verified or not.
func (*Users) SetImageDeclaration ¶ added in v0.8.1
SetImageDeclaration records a declared version's fingerprint.
func (*Users) SetJobSteps ¶ added in v0.8.0
func (s *Users) SetJobSteps(ctx context.Context, id string, attempt int, steps []Step, omitted int) (bool, error)
SetJobSteps stores the steps the attempt numbered attempt reported, replacing what the job held. It does nothing (false) when the job is not running that attempt any more: finished, cancelled, or claimed again by another worker.
func (*Users) SetLocale ¶ added in v0.4.0
SetLocale changes a user's language to one the realm lists (ignoring case; es-mx sets es-MX). Any other value is an *InvalidLocaleError naming the allowed ones: unlike sign-up, an explicit change isn't silently mapped.
func (*Users) SetNetworks ¶
func (s *Users) SetNetworks(ctx context.Context, email string, admin, login registry.Networks) (User, error)
SetNetworks replaces the user's network restrictions: admin limits their admin API requests (within the realm's allowed networks), login their login and session use. Empty lists remove the restriction. Settings realm.yaml doesn't hold live only in the database.
func (*Users) SetPassword ¶
SetPassword sets or replaces the user's password and revokes all of their sessions.
func (*Users) SetSchedulePaused ¶ added in v0.8.0
func (s *Users) SetSchedulePaused(ctx context.Context, database, function string, paused bool, by string) (ScheduleState, error)
SetSchedulePaused pauses or resumes a scheduled function's runs. Asking for the state it already has changes nothing.
func (*Users) SetSecret ¶
SetSecret creates or replaces the value at scope (database, or "" for the realm) and name, encrypting it with Cipher. by is the actor for UpdatedBy (see Caller.Actor).
func (*Users) SetUploadStatus ¶ added in v0.8.0
SetUploadStatus moves an upload through its states (JournalStored, then JournalAttached or JournalFailed).
func (*Users) SignIn ¶ added in v0.8.2
SignIn is Login for callers that can answer a second step: the outcome is a session, or a challenge the user trades for one with VerifyMFA.
func (*Users) SignInMethods ¶ added in v0.8.2
SignInMethods lists the ways the user can sign in now: "password", "magic_link" and the provider names, in that order.
func (*Users) SignUp ¶ added in v0.4.0
func (s *Users) SignUp(ctx context.Context, r SignupRequest) (SignupResult, error)
SignUp creates the account like Signup, and in a realm with email asks for the verification email. The realm may also require the address to be verified before any session: then there is none (Pending).
func (*Users) Signup ¶
func (s *Users) Signup(ctx context.Context, email, password, invitation string, locales ...string) (Principal, string, error)
Signup creates a user with a password and signs them in. Realms with `signup: open` accept anyone; `signup: invite` needs a valid invitation token (used up by a successful sign-up); `signup: closed` refuses.
locales are the languages the person asked for, most wanted first (the request's locale, then Accept-Language); the user gets the best one the realm lists, or its default, silently.
func (*Users) StartProviderSession ¶ added in v0.8.2
func (s *Users) StartProviderSession(ctx context.Context, u User, provider string, newUser bool, profile map[string]string) (Redeemed, error)
StartProviderSession starts a session for a user a provider login resolved (the native flow, which has no login code to redeem).
func (*Users) StartPushSend ¶ added in v0.8.2
func (s *Users) StartPushSend(ctx context.Context, in PushSendInput, requestID string) (PushStarted, error)
StartPushSend records a send and starts it. A send of one batch or less is planned here, so its answer has the limits applied; a larger one is left to jobs.
func (*Users) StartRegeneration ¶ added in v0.8.1
func (s *Users) StartRegeneration(ctx context.Context, database string, e ImageJob, requestedBy, requestID string) (Job, error)
StartRegeneration queues the making again of the versions of a file field that no longer match what it declares (a scan job; see ImageJob.Scan). A field has at most one at a time.
func (*Users) StartSchemaCheck ¶ added in v0.8.0
func (s *Users) StartSchemaCheck(ctx context.Context, scope CheckJob, requestedBy, requestID string) (Job, error)
StartSchemaCheck queues a schema check of collections (each "<database>/<collection>"), or *ErrCheckRunning when one is already queued or running in the realm. scope is what was asked for (database and collection, either may be "").
func (*Users) StorageUsage ¶ added in v0.8.0
StorageUsage returns the running totals: the realm's and the limit users holding the most.
func (*Users) StorageUsageOf ¶ added in v0.8.1
func (s *Users) StorageUsageOf(ctx context.Context, owner string) (realm, user StorageUsageTotals, err error)
StorageUsageOf returns the realm's totals and those of one user, for the quotas.
func (*Users) SweepDevices ¶ added in v0.8.2
SweepDevices removes the devices not seen for push.devices.stale_after and those whose session ended without anyone calling anything (it expired). Running it in every worker is harmless.
func (*Users) TakeOAuthState ¶ added in v0.8.2
TakeOAuthState returns the attempt a state value belongs to, and forgets it: a state is good for one callback. ErrNotFound when it is unknown, used or expired.
func (*Users) Unlink ¶ added in v0.8.2
Unlink removes the user's sign-in method of a provider, never the last one: ErrLastSignInMethod. ErrNotFound when the user has none of that provider. by says who did it for the audit ("self" or "admin").
func (*Users) UploadEntry ¶ added in v0.8.0
UploadEntry returns an upload's record whatever kind it is, or ErrNotFound.
func (*Users) UseMagicLink ¶ added in v0.8.2
func (s *Users) UseMagicLink(ctx context.Context, token, ip string) (code, destination string, err error)
UseMagicLink is what opening the link does, once the person pressed the button: it uses up the request and signs the user in as far as a login code, which the browser carries to the asking app (bound to its PKCE challenge). It returns the code. Errors are those of a provider sign-in: a *RefusedError for an account that can't sign in, ErrSignupClosed.
func (*Users) UserSessions ¶ added in v0.7.0
UserSessions lists a user's unexpired sessions, newest first (an administrator's view of someone else's).
func (*Users) UsersWithoutRequiredMFA ¶ added in v0.8.2
UsersWithoutRequiredMFA lists, up to limit, the users whose role requires a second factor and who have none, oldest first by address, and says how many there are in all. Erased and disabled users are not counted: they can't sign in.
func (*Users) ValidateConsents ¶ added in v0.8.2
ValidateConsents checks that the consents a request names exist with a text, without asking for the required ones: for requests that carry them for later (a magic link, a provider sign-in), where whether an account is made isn't known yet.
func (*Users) VerifyEmail ¶ added in v0.4.0
VerifyEmail uses a verification token: it marks the address verified and, if the realm wants it, asks for the welcome email. It never starts a session. Every way the token can be wrong is ErrInvalidToken.
func (*Users) VerifyMFA ¶ added in v0.8.2
func (s *Users) VerifyMFA(ctx context.Context, challenge, method, code, ip string) (Verified, error)
VerifyMFA trades a challenge and a second-factor code for the session the first factor was waiting for. method is MethodTOTP or MethodRecovery. ip is the caller's address, for the login throttle. The answer to an unknown, used, expired or exhausted challenge is always ErrInvalidChallenge.
func (*Users) VerifyMagicLinkCode ¶ added in v0.8.2
func (s *Users) VerifyMagicLinkCode(ctx context.Context, requestID, code, verifier, ip string) (Redeemed, error)
VerifyMagicLinkCode is the code typed in the asking app: with the request id and the verifier of its PKCE challenge it signs the user in like the link would, answering a session or the MFA challenge. Five wrong codes end the request.
func (*Users) WithdrawConsent ¶ added in v0.8.2
func (s *Users) WithdrawConsent(ctx context.Context, u User, consent string, from ConsentContext) (User, error)
WithdrawConsent records the withdrawal of an optional consent by the user. A required consent can't be withdrawn without deleting the account (ErrConsentRequiredForAccount).
Source Files
¶
- apikeys.go
- apple.go
- audit.go
- auth.go
- callback.go
- concurrency.go
- consents.go
- consents_signin.go
- devices.go
- email.go
- emailchange.go
- emailtoken.go
- erase.go
- files.go
- idempotency.go
- identities.go
- invitations.go
- invocations.go
- jobs.go
- magiclink.go
- mfa.go
- mfa_manage.go
- oauth.go
- onsignup.go
- password.go
- push.go
- ratelimit.go
- reauth.go
- reset.go
- roles.go
- schedules.go
- schemacheck.go
- scope.go
- secrets.go
- sessions.go
- throttle.go
- users.go
- verify.go