store

package
v0.16.0 Latest Latest
Warning

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

Go to latest
Published: Sep 4, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotFound                       = errors.New("not found")
	ErrTokenUsed                      = errors.New("token already used")
	ErrTokenExpired                   = errors.New("token expired")
	ErrDuplicateEntry                 = errors.New("duplicate entry")
	ErrRekeyAlreadyPending            = errors.New("rekey already pending")
	ErrReplayedNonce                  = errors.New("replayed nonce")
	ErrIPTaken                        = errors.New("nebula ip already assigned in network")
	ErrTOTPReplayed                   = errors.New("totp timestep already used")
	ErrMeshImportInProgress           = errors.New("mesh import collection in progress")
	ErrMeshImportNotCollecting        = errors.New("mesh import is not collecting")
	ErrMeshImportTokenExpired         = errors.New("mesh import token expired")
	ErrMeshImportChallengeExpired     = errors.New("mesh import challenge expired")
	ErrMeshImportChallengeLimit       = errors.New("mesh import challenge limit reached")
	ErrMeshImportChallengeUsed        = errors.New("mesh import challenge already used")
	ErrMeshImportChallengeMismatch    = errors.New("mesh import challenge does not match registration")
	ErrMeshImportSigningKeyConflict   = errors.New("certificate fingerprint is bound to another signing key")
	ErrMeshImportPayloadConflict      = errors.New("certificate fingerprint is bound to another snapshot payload")
	ErrConfigAckUnsupported           = errors.New("config acknowledgement is not supported by this host")
	ErrConfigVersionMismatch          = errors.New("config acknowledgement version does not match pending delivery")
	ErrHostNotEnrolled                = errors.New("host is not enrolled")
	ErrIssuanceNotAllowed             = errors.New("certificate issuance is not allowed")
	ErrMeshImportExpectedHostsReached = errors.New("mesh import expected host count reached")
	ErrMeshImportScopeInvalid         = errors.New("mesh import scope is invalid")
	ErrMeshImportConflict             = errors.New("mesh import changed since preview")
	ErrCredentialHasherUnavailable    = errors.New("credential hasher unavailable")
	ErrCredentialCutoverBlocked       = errors.New("credential cutover blocked by a collecting mesh import")
	ErrCredentialCutoverGuardMissing  = errors.New("credential cutover master-key guard unavailable")
)

Functions

func ApplyHostEdit added in v0.11.0

func ApplyHostEdit(ctx context.Context, s Store, logger *slog.Logger, before, after *models.Host) error

ApplyHostEdit persists an edited host together with the follow-up writes a host edit implies. Both edit paths — the API's PATCH handler and the web UI's edit form — go through here so they cannot drift apart on what an edit means; they previously kept separate copies of these rules, and the copies disagreed about whether a group change needs a new certificate.

Callers are expected to have snapshotted `before`, merged their input into `after`, validated it, and established that something actually changed.

The pending-rekey flag is set on the host struct rather than through a separate SetPendingRekey write. UpdateHost commits it in the same transaction as the config_version reset (SEC-PERSIST-001), so a crash between the two cannot leave a host whose certificate-bound fields moved but whose re-issuance was never scheduled — which would strand an agent on a stale, possibly more permissive, certificate. Setting the flag when it is already set is a no-op, so retries stay idempotent.

The returned error is the one from persisting the host; callers map it to their own transport (ErrIPTaken → 409, ErrNotFound → 404). The network config-version bump is best-effort and only logged: it is a propagation hint for peers, and failing an otherwise-applied edit over it would be worse than a late peer update.

Types

type AuditFilter

type AuditFilter struct {
	Action string
	Limit  int
}

AuditFilter specifies filters for audit log queries.

type HostFilter

type HostFilter struct {
	NetworkID string
	Group     string
	Status    models.HostStatus
	// CAIDs scopes results to hosts under these CA ids. When non-empty the
	// scope is applied in SQL, so it composes correctly with Limit — the
	// limit applies after scoping, not before. Empty means no CA scoping.
	CAIDs []string
	Limit int // 0 = no limit
}

HostFilter specifies filters for listing hosts.

type MeshImportFinalizeHost added in v0.8.0

type MeshImportFinalizeHost struct {
	SnapshotID string
	Host       models.Host
}

type MeshImportFinalizeInput added in v0.8.0

type MeshImportFinalizeInput struct {
	ID           string
	Revision     int64
	Hosts        []MeshImportFinalizeHost
	FirewallJSON string
	Blocklist    []string
	Now          time.Time
}

type SQLiteStore

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

SQLiteStore implements Store using SQLite.

func NewSQLiteStore

func NewSQLiteStore(dbPath string, options ...SQLiteStoreOption) (*SQLiteStore, error)

NewSQLiteStore opens a SQLite database at the given path. Use ":memory:" for in-memory database.

func (*SQLiteStore) AcknowledgeHostConfigVersion added in v0.8.0

func (s *SQLiteStore) AcknowledgeHostConfigVersion(ctx context.Context, hostID string, version int) error

func (*SQLiteStore) AddAuditEntry

func (s *SQLiteStore) AddAuditEntry(ctx context.Context, actor, action, resource, details string) error

func (*SQLiteStore) AddPopNonce

func (s *SQLiteStore) AddPopNonce(ctx context.Context, hostID, nonce string, expiresAt time.Time) error

AddPopNonce records a (hostID, nonce) pair valid until expiresAt. Returns nil when the row was freshly inserted (or replaced an expired duplicate), and ErrReplayedNonce when a live duplicate exists. GHSA-v2jf-442r-6mjh.

The lazy DELETE prune clears any past-expiry rows; the subsequent INSERT OR IGNORE either lands fresh (RowsAffected == 1) or is swallowed by the (host_id, nonce) UNIQUE constraint (RowsAffected == 0 → replay). Both statements run inside a single transaction so the writer lock is acquired once per call instead of twice — matching the DELETE+INSERT shape used elsewhere in this package (e.g. CreateTokenForHost). SQLite's single-writer model linearizes concurrent same-key calls. expires_at is stored as unix-epoch INTEGER, so sub-second RFC3339 precision truncates down — harmless inside the ±5m skew that gates this call upstream.

func (*SQLiteStore) AddToBlocklist

func (s *SQLiteStore) AddToBlocklist(ctx context.Context, fingerprint, hostID, reason string) error

func (*SQLiteStore) BlockHostAndAddToBlocklist

func (s *SQLiteStore) BlockHostAndAddToBlocklist(ctx context.Context, id, reason string) (*models.Host, error)

BlockHostAndAddToBlocklist atomically blocks a host and adds its cert to the blocklist. Every network under the host CA is bumped whenever a fingerprint enters the blocklist so every peer under that CA receives a re-rendered config.yml carrying the new pki.blocklist entry (GHSA-cm26-5974-52h8). An additional bump for enrolled lighthouses is redundant — the single bump below already covers blocklist propagation — but the lighthouse-specific path is kept so peers also stop directing traffic at the blocked lighthouse.

func (*SQLiteStore) BumpNetworkConfigVersion

func (s *SQLiteStore) BumpNetworkConfigVersion(ctx context.Context, networkID string) error

func (*SQLiteStore) CancelMeshImport added in v0.8.0

func (s *SQLiteStore) CancelMeshImport(ctx context.Context, id, reason string, now time.Time) error

func (*SQLiteStore) ClearPendingRekey

func (s *SQLiteStore) ClearPendingRekey(ctx context.Context, hostID string) error

ClearPendingRekey resets the pending_rekey flag, typically after the agent has redeemed the rekey token and the new keypair has been bound to the existing host row.

func (*SQLiteStore) ClearPrevFingerprint

func (s *SQLiteStore) ClearPrevFingerprint(ctx context.Context, hostID string) error

ClearPrevFingerprint drops the rotation overlap state once the agent has successfully polled under the new fingerprint or the wall-clock window expired.

func (*SQLiteStore) Close

func (s *SQLiteStore) Close() error

Close closes the database.

func (*SQLiteStore) ConsumeOperatorRecoveryCode

func (s *SQLiteStore) ConsumeOperatorRecoveryCode(ctx context.Context, id, rawCode string) error

ConsumeOperatorRecoveryCode marks the given hash as consumed if it exists and is unused. Returns ErrNotFound otherwise.

func (*SQLiteStore) ConsumeOperatorTOTPTimestep added in v0.4.0

func (s *SQLiteStore) ConsumeOperatorTOTPTimestep(ctx context.Context, id string, ts int64) error

ConsumeOperatorTOTPTimestep advances the operator's last-accepted TOTP timestep to ts, but only if ts is strictly greater than the stored value — the same atomic verify-and-mark shape as ConsumeOperatorRecoveryCode, so two concurrent logins presenting the same code cannot both win. Returns ErrTOTPReplayed when ts has already been used (or an older one accepted after it), which the caller must treat as an authentication failure (RFC 6238 §5.2).

func (*SQLiteStore) ConsumeToken

func (s *SQLiteStore) ConsumeToken(ctx context.Context, token string) (*models.EnrollmentToken, error)

ConsumeToken accepts the raw token from the caller, derives its keyed verifier, and marks the matching row used on success.

func (*SQLiteStore) ConsumeTokenAndEnrollHost

func (s *SQLiteStore) ConsumeTokenAndEnrollHost(ctx context.Context, hostID, token string, certPEM []byte, fp string, notBefore, notAfter time.Time) error

ConsumeTokenAndEnrollHost atomically consumes the single-use enrollment token and enrolls the host with its freshly-signed certificate in one transaction, so the token is marked used IFF the certificate is persisted and the host enrolled. A transient failure anywhere in the caller before this call (CA signing error, DB blip) therefore leaves the token usable for a clean retry, while a concurrent second enrollment racing the same token loses the used=0 CAS and receives ErrTokenUsed -- preserving single-use. This closes the burn-on-failure window left by consuming the token up front in its own transaction. The caller is expected to have validated the token via GetEnrollmentToken first, so a zero-row CAS here means the race was lost.

func (*SQLiteStore) ConsumeTokenAndEnrollHostWithProfile added in v0.8.0

func (s *SQLiteStore) ConsumeTokenAndEnrollHostWithProfile(
	ctx context.Context, hostID, token string, certPEM []byte, fp string,
	notBefore, notAfter time.Time, signingPubPEM string, profile models.AgentProfile, signedIdentity *models.CertificateIdentity,
) (int, error)

func (*SQLiteStore) CountEmptyCAIDRows

func (s *SQLiteStore) CountEmptyCAIDRows(ctx context.Context) (int, error)

CountEmptyCAIDRows counts the total number of rows across networks, hosts, certificates, and blocklist tables that have an empty ca_id. This is used at startup to detect rows from the pre-multi-CA era that have not been backfilled with a CA owner.

func (*SQLiteStore) CreateCA

func (s *SQLiteStore) CreateCA(ctx context.Context, c *models.CA) error

func (*SQLiteStore) CreateHost

func (s *SQLiteStore) CreateHost(ctx context.Context, h *models.Host) error

func (*SQLiteStore) CreateHostAndToken

func (s *SQLiteStore) CreateHostAndToken(ctx context.Context, h *models.Host, t *models.EnrollmentToken, rawToken string) error

CreateHostAndToken atomically creates a host and its enrollment token.

func (*SQLiteStore) CreateMeshImport added in v0.8.0

func (s *SQLiteStore) CreateMeshImport(ctx context.Context, item *models.MeshImport, rawToken string) error

func (*SQLiteStore) CreateMeshImportChallenge added in v0.8.0

func (s *SQLiteStore) CreateMeshImportChallenge(ctx context.Context, challenge *models.MeshImportChallenge, now time.Time) error

func (*SQLiteStore) CreateNetwork

func (s *SQLiteStore) CreateNetwork(ctx context.Context, n *models.Network) error

func (*SQLiteStore) CreateOperator

func (s *SQLiteStore) CreateOperator(ctx context.Context, op *models.Operator) error

CreateOperator inserts a new operator. Caller fills in PasswordHash.

func (*SQLiteStore) CreateOperatorAPIKey

func (s *SQLiteStore) CreateOperatorAPIKey(ctx context.Context, k *models.OperatorAPIKey, rawKey string) error

func (*SQLiteStore) CreateOperatorSession

func (s *SQLiteStore) CreateOperatorSession(ctx context.Context, sess *models.OperatorSession) error

func (*SQLiteStore) CreateToken

func (s *SQLiteStore) CreateToken(ctx context.Context, t *models.EnrollmentToken, rawToken string) error

func (*SQLiteStore) CreateTokenForHost

func (s *SQLiteStore) CreateTokenForHost(ctx context.Context, hostID, token string, expiresAt time.Time) error

CreateTokenForHost atomically invalidates any active enrollment tokens for the host and writes a fresh single-use one. Used by the regenerate-token, reenroll, and rekey flows (ADR 0004) where the host row must be preserved. The `token` argument is the raw value handed back to the caller; the store only ever persists its keyed verifier (SEC-CREDENTIAL-001).

func (*SQLiteStore) CreateWebhookSubscription added in v0.6.0

func (s *SQLiteStore) CreateWebhookSubscription(ctx context.Context, sub *models.WebhookSubscription) error

CreateWebhookSubscription inserts a new subscription.

func (*SQLiteStore) DB

func (s *SQLiteStore) DB() *sql.DB

DB returns the underlying *sql.DB for advanced usage.

func (*SQLiteStore) DeleteCA

func (s *SQLiteStore) DeleteCA(ctx context.Context, id string) error

DeleteCA removes a CA row. ca_id is a plain column on networks, hosts, certificates, and blocklist with no DB-level foreign key (it defaults to the empty string for pre-multi-CA rows), so referential integrity is enforced here: the call refuses while any of those tables still references the CA. Without checking all four, deleting a CA orphans rows whose ca_id no longer resolves, surfacing later as a silent failure in caForHost (ErrNotFound, then 500). Each table is checked independently because they can reference a CA in isolation, e.g. a blocklist row whose host was deleted via ON DELETE SET NULL, or a host whose ca_id diverged from its network's.

func (*SQLiteStore) DeleteExpiredOperatorSessions

func (s *SQLiteStore) DeleteExpiredOperatorSessions(ctx context.Context, before time.Time) error

func (*SQLiteStore) DeleteHost

func (s *SQLiteStore) DeleteHost(ctx context.Context, id string) error

func (*SQLiteStore) DeleteHostAndBlockCert

func (s *SQLiteStore) DeleteHostAndBlockCert(ctx context.Context, id, reason string) error

DeleteHostAndBlockCert atomically deletes a host and adds its cert to the blocklist. Every network under the host CA is bumped whenever a fingerprint enters the blocklist so peers receive the updated pki.blocklist (GHSA-cm26-5974-52h8).

func (*SQLiteStore) DeleteOperatorSession

func (s *SQLiteStore) DeleteOperatorSession(ctx context.Context, token string) error

func (*SQLiteStore) DeleteOperatorSessionsByOperator

func (s *SQLiteStore) DeleteOperatorSessionsByOperator(ctx context.Context, operatorID string) error

func (*SQLiteStore) DeleteOperatorSessionsByOperatorExcept added in v0.7.0

func (s *SQLiteStore) DeleteOperatorSessionsByOperatorExcept(ctx context.Context, operatorID, keepToken string) error

DeleteOperatorSessionsByOperatorExcept removes every session of an operator except the one identified by keepToken, used by self-service password change to revoke other (possibly compromised) sessions while keeping the caller's current session alive (#259). keepToken is the raw cookie value; it is hashed here, mirroring DeleteOperatorSession.

func (*SQLiteStore) DeleteWebhookSubscription added in v0.6.0

func (s *SQLiteStore) DeleteWebhookSubscription(ctx context.Context, id string) error

DeleteWebhookSubscription removes a subscription.

func (*SQLiteStore) DisableOperator

func (s *SQLiteStore) DisableOperator(ctx context.Context, id string) error

DisableOperator marks operator as disabled and atomically deletes their sessions and revokes all of their non-revoked API keys.

func (*SQLiteStore) EnableOperator

func (s *SQLiteStore) EnableOperator(ctx context.Context, id string) error

func (*SQLiteStore) FinalizeMeshImport added in v0.8.0

func (s *SQLiteStore) FinalizeMeshImport(ctx context.Context, input MeshImportFinalizeInput) error

func (*SQLiteStore) FindCAByPredecessor

func (s *SQLiteStore) FindCAByPredecessor(ctx context.Context, predecessorID string) (*models.CA, error)

func (*SQLiteStore) GetBlocklist

func (s *SQLiteStore) GetBlocklist(ctx context.Context) ([]string, error)

func (*SQLiteStore) GetBlocklistForCA added in v0.3.8

func (s *SQLiteStore) GetBlocklistForCA(ctx context.Context, caID string) ([]string, error)

GetBlocklistForCA returns the revoked fingerprints scoped to a single CA — the set an agent under that CA needs to reject peers, without leaking other operators' revocations across the tenant boundary (#203). Rows with an empty ca_id (legacy/orphan entries from before the column was populated, whose owning host is already deleted so the CA can't be recovered) are included as a fail-safe so revocation is never silently weakened.

func (*SQLiteStore) GetCA

func (s *SQLiteStore) GetCA(ctx context.Context, id string) (*models.CA, error)

func (*SQLiteStore) GetCAByFingerprint

func (s *SQLiteStore) GetCAByFingerprint(ctx context.Context, fp string) (*models.CA, error)

func (*SQLiteStore) GetCertAlert

func (s *SQLiteStore) GetCertAlert(ctx context.Context, hostID string) (time.Time, error)

GetCertAlert returns the alerted_not_after recorded for hostID, or ErrNotFound when no alert has been recorded yet.

func (*SQLiteStore) GetCertificateInfo

func (s *SQLiteStore) GetCertificateInfo(ctx context.Context, hostID string) (*models.CertificateInfo, error)

func (*SQLiteStore) GetCurrentCertificate

func (s *SQLiteStore) GetCurrentCertificate(ctx context.Context, hostID string) ([]byte, error)

func (*SQLiteStore) GetEnrollmentToken

func (s *SQLiteStore) GetEnrollmentToken(ctx context.Context, token string) (*models.EnrollmentToken, error)

GetEnrollmentToken resolves a raw enrollment token by its keyed verifier WITHOUT consuming it, applying the same validity checks as ConsumeToken (ErrNotFound / ErrTokenUsed / ErrTokenExpired). It lets the enrollment handler resolve the target host and fail fast before the expensive CA signature; the actual single-use consume then happens atomically with the certificate save in ConsumeTokenAndEnrollHost.

func (*SQLiteStore) GetHost

func (s *SQLiteStore) GetHost(ctx context.Context, id string) (*models.Host, error)

func (*SQLiteStore) GetHostAgentProfile added in v0.8.0

func (s *SQLiteStore) GetHostAgentProfile(ctx context.Context, hostID string) (*models.HostAgentProfile, error)

func (*SQLiteStore) GetHostByFingerprint

func (s *SQLiteStore) GetHostByFingerprint(ctx context.Context, fingerprint string) (*models.Host, error)

GetHostByFingerprint resolves the host by either its current or previous cert fingerprint. The previous-fingerprint match window exists so cert auto-rotation does not lock the agent out between server-side cert update and on-disk cert write (ADR 0004 §7.1 cert rotation overlap).

The returned host's CertFingerprint always reflects the row's current value; callers that need to know which fingerprint matched can compare against the input.

func (*SQLiteStore) GetHostConfigVersion

func (s *SQLiteStore) GetHostConfigVersion(ctx context.Context, hostID string) (int, error)

func (*SQLiteStore) GetMeshImport added in v0.8.0

func (s *SQLiteStore) GetMeshImport(ctx context.Context, id string) (*models.MeshImport, error)

func (*SQLiteStore) GetMeshImportByToken added in v0.12.0

func (s *SQLiteStore) GetMeshImportByToken(ctx context.Context, rawToken string, now time.Time) (*models.MeshImport, error)

func (*SQLiteStore) GetMeshImportChallenge added in v0.8.0

func (s *SQLiteStore) GetMeshImportChallenge(ctx context.Context, id string) (*models.MeshImportChallenge, error)

func (*SQLiteStore) GetMeshImportTombstone added in v0.8.0

func (s *SQLiteStore) GetMeshImportTombstone(ctx context.Context, fingerprint string) (*models.MeshImportTombstone, error)

func (*SQLiteStore) GetNetwork

func (s *SQLiteStore) GetNetwork(ctx context.Context, id string) (*models.Network, error)

func (*SQLiteStore) GetNetworkConfig

func (s *SQLiteStore) GetNetworkConfig(ctx context.Context, networkID, key string) (string, error)

func (*SQLiteStore) GetNetworkConfigVersion

func (s *SQLiteStore) GetNetworkConfigVersion(ctx context.Context, networkID string) (int, error)

func (*SQLiteStore) GetOperator

func (s *SQLiteStore) GetOperator(ctx context.Context, id string) (*models.Operator, error)

func (*SQLiteStore) GetOperatorAPIKey

func (s *SQLiteStore) GetOperatorAPIKey(ctx context.Context, keyID string) (*models.OperatorAPIKey, error)

GetOperatorAPIKey returns the API key by its ID regardless of revoked state. Callers that need ownership verification compare the returned .OperatorID against the expected operator.

func (*SQLiteStore) GetOperatorByAPIKey added in v0.12.0

func (s *SQLiteStore) GetOperatorByAPIKey(ctx context.Context, rawKey string) (*models.Operator, *models.OperatorAPIKey, error)

GetOperatorByAPIKey returns the operator associated with a non-revoked raw API key, ensuring the operator is active.

func (*SQLiteStore) GetOperatorByOIDC

func (s *SQLiteStore) GetOperatorByOIDC(ctx context.Context, issuer, subject string) (*models.Operator, error)

GetOperatorByOIDC returns the operator matching the issuer+subject pair, if any. Used to look up federated operators after a successful OIDC callback.

func (*SQLiteStore) GetOperatorBySession

func (s *SQLiteStore) GetOperatorBySession(ctx context.Context, token string) (*models.Operator, error)

GetOperatorBySession returns the operator associated with a non-expired, fully-authenticated session whose operator is still active. Sessions in pending_totp state are NOT returned here.

func (*SQLiteStore) GetOperatorByUsername

func (s *SQLiteStore) GetOperatorByUsername(ctx context.Context, username string) (*models.Operator, error)

func (*SQLiteStore) GetPendingTwoFactorOperator

func (s *SQLiteStore) GetPendingTwoFactorOperator(ctx context.Context, token string) (*models.Operator, error)

GetPendingTwoFactorOperator returns the operator associated with a session that is awaiting a second factor (`pending_totp`). The operator must still be active. Sessions already authenticated are not returned.

func (*SQLiteStore) GetServerSetting

func (s *SQLiteStore) GetServerSetting(ctx context.Context, key string) (string, error)

GetServerSetting returns the stored value for key, or "" + ErrNotFound when the key has never been set.

func (*SQLiteStore) GetWebhookSubscription added in v0.6.0

func (s *SQLiteStore) GetWebhookSubscription(ctx context.Context, id string) (*models.WebhookSubscription, error)

GetWebhookSubscription returns one subscription by id.

func (*SQLiteStore) ListActiveWebhookSubscriptionsForCA added in v0.8.0

func (s *SQLiteStore) ListActiveWebhookSubscriptionsForCA(ctx context.Context, caID string) ([]*models.WebhookSubscription, error)

ListActiveWebhookSubscriptionsForCA returns active subscriptions owned by the operator that owns caID. An unknown or empty CA id matches no owner.

func (*SQLiteStore) ListAuditEntries

func (s *SQLiteStore) ListAuditEntries(ctx context.Context, filter AuditFilter) ([]*models.AuditEntry, error)

func (*SQLiteStore) ListCAs

func (s *SQLiteStore) ListCAs(ctx context.Context) ([]*models.CA, error)

func (*SQLiteStore) ListCAsApproachingExpiry

func (s *SQLiteStore) ListCAsApproachingExpiry(ctx context.Context, thresholdRatio float64) ([]*models.CA, error)

func (*SQLiteStore) ListCAsByOwner

func (s *SQLiteStore) ListCAsByOwner(ctx context.Context, ownerID string) ([]*models.CA, error)

func (*SQLiteStore) ListEnrolledHostCerts

func (s *SQLiteStore) ListEnrolledHostCerts(ctx context.Context) ([]*models.CertificateInfo, error)

func (*SQLiteStore) ListHosts

func (s *SQLiteStore) ListHosts(ctx context.Context, filter HostFilter) ([]*models.Host, error)

func (*SQLiteStore) ListMeshImportSnapshots added in v0.8.0

func (s *SQLiteStore) ListMeshImportSnapshots(ctx context.Context, meshImportID string) ([]*models.MeshImportSnapshot, error)

func (*SQLiteStore) ListMeshImports added in v0.8.0

func (s *SQLiteStore) ListMeshImports(ctx context.Context) ([]*models.MeshImport, error)

func (*SQLiteStore) ListMeshImportsByOwner added in v0.8.0

func (s *SQLiteStore) ListMeshImportsByOwner(ctx context.Context, ownerID string) ([]*models.MeshImport, error)

func (*SQLiteStore) ListNetworks

func (s *SQLiteStore) ListNetworks(ctx context.Context) ([]*models.Network, error)

func (*SQLiteStore) ListOperatorAPIKeys

func (s *SQLiteStore) ListOperatorAPIKeys(ctx context.Context, operatorID string) ([]*models.OperatorAPIKey, error)

func (*SQLiteStore) ListOperatorRecoveryCodes

func (s *SQLiteStore) ListOperatorRecoveryCodes(ctx context.Context, id string) ([]string, error)

ListOperatorRecoveryCodes returns the hashes of all non-consumed recovery codes for the operator. Used by tests and integrity checks.

func (*SQLiteStore) ListOperators

func (s *SQLiteStore) ListOperators(ctx context.Context) ([]*models.Operator, error)

func (*SQLiteStore) ListWebhookSubscriptions added in v0.6.0

func (s *SQLiteStore) ListWebhookSubscriptions(ctx context.Context) ([]*models.WebhookSubscription, error)

ListWebhookSubscriptions returns every subscription (admin view).

func (*SQLiteStore) ListWebhookSubscriptionsByOwner added in v0.6.0

func (s *SQLiteStore) ListWebhookSubscriptionsByOwner(ctx context.Context, ownerID string) ([]*models.WebhookSubscription, error)

ListWebhookSubscriptionsByOwner returns subscriptions owned by ownerID.

func (*SQLiteStore) Migrate

func (s *SQLiteStore) Migrate(ctx context.Context) error

Migrate applies all pending migrations. Each migration file is executed at most once per database — its name is recorded in `schema_migrations` once applied. This fixes two latent issues:

  • Destructive recreate-style migrations (e.g. 004_blocklist_fk, which rebuilds `blocklist` via blocklist_new + RENAME) used to run on every start, silently dropping columns that later migrations had added.
  • Multi-statement migration files used to be Exec'd as one string; `modernc.org/sqlite` stops processing the remainder of the blob on the first error (e.g. a duplicate-column ALTER), so the trailing statements were skipped. We now split each file by top-level `;` boundaries and Exec one statement at a time.

See https://github.com/forgekeep/nebula-mesh/issues/37.

The entire run is pinned to a single pooled connection. PRAGMA foreign_keys is connection-scoped, and migration 014 turns it OFF, drops and recreates tables, then turns it back ON across separate statements — if those statements were dispatched to different pool connections (every connection opens with foreign_keys ON via the DSN), the DROP TABLE would run with FK enforcement live and cascade-delete every child row (certificates, host_addresses, enrollment_tokens, cert_alerts).

func (*SQLiteStore) Ping

func (s *SQLiteStore) Ping(ctx context.Context) error

Ping verifies the database connection is alive.

func (*SQLiteStore) PromoteOperatorSession

func (s *SQLiteStore) PromoteOperatorSession(ctx context.Context, token string, newExpiry time.Time) error

PromoteOperatorSession upgrades a pending_totp session to authenticated and resets the expiry to a fresh 24h window. Returns ErrNotFound if the session does not exist or is not pending.

func (*SQLiteStore) RecordCertAlert

func (s *SQLiteStore) RecordCertAlert(ctx context.Context, hostID string, alertedNotAfter time.Time) error

RecordCertAlert upserts the (host_id, alerted_not_after) tuple so subsequent scans for the same cert do not re-emit the alert. Update alerted_at to now on every call so dashboards can show "last fired" times.

func (*SQLiteStore) RecordFailedLoginAttempt added in v0.7.0

func (s *SQLiteStore) RecordFailedLoginAttempt(ctx context.Context, id string, maxAttempts int, lockUntil time.Time) (bool, error)

RecordFailedLoginAttempt increments the operator's consecutive failed-login counter and, when the count reaches maxAttempts, sets locked_until to lockUntil — atomically in one UPDATE so concurrent failures can't race past the threshold (#263). It reports whether the account is now locked.

func (*SQLiteStore) RecordWebhookDelivery added in v0.6.0

func (s *SQLiteStore) RecordWebhookDelivery(ctx context.Context, id string, ok bool, errMsg string, at time.Time) error

RecordWebhookDelivery updates a subscription's delivery-status columns after an attempt. On success it clears the failure counter and error; on failure it increments the counter and stores the (truncated) error.

func (*SQLiteStore) RegisterImportedHost added in v0.8.0

func (s *SQLiteStore) RegisterImportedHost(ctx context.Context, registration *models.MeshImportRegistration, now time.Time) (*models.MeshImportRegistrationResult, error)

func (*SQLiteStore) RemoveFromBlocklist

func (s *SQLiteStore) RemoveFromBlocklist(ctx context.Context, fingerprint string) error

func (*SQLiteStore) ReplaceOperatorRecoveryCodes

func (s *SQLiteStore) ReplaceOperatorRecoveryCodes(ctx context.Context, id string, rawCodes []string) error

ReplaceOperatorRecoveryCodes deletes any existing codes for the operator and inserts the provided list of hashes (atomic).

func (*SQLiteStore) ResetFailedLoginAttempts added in v0.7.0

func (s *SQLiteStore) ResetFailedLoginAttempts(ctx context.Context, id string) error

ResetFailedLoginAttempts clears the failed-login counter and any active lock, called on a successful login and when an expired lock is observed (#263).

func (*SQLiteStore) ResetOperatorTOTPBreakGlass added in v0.12.0

func (s *SQLiteStore) ResetOperatorTOTPBreakGlass(ctx context.Context, username string) error

ResetOperatorTOTPBreakGlass disables TOTP for one operator, removes its recovery codes and sessions, and records the local recovery action in the same transaction. The operator status is deliberately unchanged.

func (*SQLiteStore) RevokeOperatorAPIKey

func (s *SQLiteStore) RevokeOperatorAPIKey(ctx context.Context, keyID string) error

func (*SQLiteStore) RotateMeshImportToken added in v0.8.0

func (s *SQLiteStore) RotateMeshImportToken(ctx context.Context, id, rawToken string, expiresAt, now time.Time) error

func (*SQLiteStore) SaveCertificate

func (s *SQLiteStore) SaveCertificate(ctx context.Context, hostID string, certPEM []byte, fp string, notBefore, notAfter time.Time) error

func (*SQLiteStore) SaveCertificateAndEnrollHost

func (s *SQLiteStore) SaveCertificateAndEnrollHost(ctx context.Context, hostID string, certPEM []byte, fp string, notBefore, notAfter time.Time) error

SaveCertificateAndEnrollHost atomically saves a certificate and marks the host as enrolled. Used by token-less enrollment paths (e.g. mobile-bundle generation). The agent token flow uses ConsumeTokenAndEnrollHost, which folds the single-use token consume into the same transaction.

func (*SQLiteStore) SaveCertificateAndUpdateHostCert

func (s *SQLiteStore) SaveCertificateAndUpdateHostCert(ctx context.Context, hostID string, certPEM []byte, fp string, notBefore, notAfter time.Time) error

SaveCertificateAndUpdateHostCert atomically saves a certificate and updates the host's cert metadata. The previous fingerprint (if non-empty) is parked in prev_cert_fingerprint with cert_rotated_at = now() so the poll handler can accept either fingerprint during the rotation overlap window (ADR 0004 §7.1).

func (*SQLiteStore) SaveCertificateIfIssuanceAllowed added in v0.9.0

func (s *SQLiteStore) SaveCertificateIfIssuanceAllowed(
	ctx context.Context, hostID string, expectedStatus models.HostStatus,
	certPEM []byte, fp string, notBefore, notAfter time.Time,
) error

SaveCertificateIfIssuanceAllowed atomically re-checks durable Host and owner state and persists a mobile certificate only when both still authorize the transition. expectedStatus prevents a stale builder from changing a Host whose lifecycle state changed while the bundle was being rendered.

func (*SQLiteStore) SeedInitialAdminOperator

func (s *SQLiteStore) SeedInitialAdminOperator(ctx context.Context, op *models.Operator, key *models.OperatorAPIKey, rawKey string) (bool, error)

SeedInitialAdminOperator atomically inserts op (and key, if non-nil) only when the operators table is empty. The check-then-write is wrapped in a single transaction whose INSERT is guarded by `WHERE NOT EXISTS (SELECT 1 FROM operators)`, so two concurrent first-boot seed calls cannot both succeed: the loser sees `RowsAffected() == 0` and returns (false, nil) without touching the API-key table.

Returns (true, nil) if this call performed the seed; (false, nil) if the operators table already had at least one row (either because the caller ran a second time on a populated DB, or because a concurrent boot won the race). Any non-nil error indicates a real failure.

func (*SQLiteStore) SetNetworkConfig

func (s *SQLiteStore) SetNetworkConfig(ctx context.Context, networkID, key, value string) error

func (*SQLiteStore) SetNetworkConfigAndBumpVersion

func (s *SQLiteStore) SetNetworkConfigAndBumpVersion(ctx context.Context, networkID, key, value string) error

SetNetworkConfigAndBumpVersion atomically sets a config value and bumps the config version.

func (*SQLiteStore) SetOperatorTOTP

func (s *SQLiteStore) SetOperatorTOTP(ctx context.Context, id, secret string, enabled bool) error

SetOperatorTOTP records the operator's TOTP secret and enabled flag. Passing enabled=false with secret="" clears 2FA entirely.

func (*SQLiteStore) SetPendingHostConfigVersion added in v0.8.0

func (s *SQLiteStore) SetPendingHostConfigVersion(ctx context.Context, hostID string, version int) error

func (*SQLiteStore) SetPendingRekey

func (s *SQLiteStore) SetPendingRekey(ctx context.Context, hostID string) error

SetPendingRekey flips the pending_rekey flag atomically. If the flag is already set on this host the call returns ErrRekeyAlreadyPending so a duplicate force-rotate request can be rejected with 409.

func (*SQLiteStore) SetPrevFingerprint

func (s *SQLiteStore) SetPrevFingerprint(ctx context.Context, hostID, prev string, rotatedAt time.Time) error

SetPrevFingerprint records the previous cert fingerprint and the rotation timestamp on the host row. Called from SaveCertificateAndUpdateHostCert before the new fingerprint is written so the overlap window is preserved.

func (*SQLiteStore) SetServerSetting

func (s *SQLiteStore) SetServerSetting(ctx context.Context, key, value string) error

SetServerSetting upserts a key/value pair into server_settings.

func (*SQLiteStore) TouchOperatorAPIKey

func (s *SQLiteStore) TouchOperatorAPIKey(ctx context.Context, keyID string, t time.Time) error

func (*SQLiteStore) UnblockHostAndRemoveFromBlocklist

func (s *SQLiteStore) UnblockHostAndRemoveFromBlocklist(ctx context.Context, id string) (*models.Host, error)

UnblockHostAndRemoveFromBlocklist atomically marks a blocked host as pending and removes its certificate fingerprint from the blocklist. The host must re-enroll to obtain a new certificate after unblocking.

func (*SQLiteStore) UpdateCAStatus

func (s *SQLiteStore) UpdateCAStatus(ctx context.Context, id string, status models.CAStatus) error

func (*SQLiteStore) UpdateHost

func (s *SQLiteStore) UpdateHost(ctx context.Context, h *models.Host) error

UpdateHost persists all host fields. NOTE: mutates h.UpdatedAt to current time.

func (*SQLiteStore) UpdateHostCert

func (s *SQLiteStore) UpdateHostCert(ctx context.Context, id, fingerprint string, expiresAt time.Time) error

func (*SQLiteStore) UpdateHostConfigVersion

func (s *SQLiteStore) UpdateHostConfigVersion(ctx context.Context, hostID string, version int) error

func (*SQLiteStore) UpdateHostLastSeen

func (s *SQLiteStore) UpdateHostLastSeen(ctx context.Context, id string, t time.Time) error

func (*SQLiteStore) UpdateHostSigningPub

func (s *SQLiteStore) UpdateHostSigningPub(ctx context.Context, hostID, signingPubPEM string) error

UpdateHostSigningPub stores the Ed25519 PEM public key bound to the host's signing identity at enrollment / re-enrollment time.

func (*SQLiteStore) UpdateHostStatus

func (s *SQLiteStore) UpdateHostStatus(ctx context.Context, id string, status models.HostStatus) error

func (*SQLiteStore) UpdateNetwork

func (s *SQLiteStore) UpdateNetwork(ctx context.Context, n *models.Network) error

func (*SQLiteStore) UpdateOperatorLastLogin

func (s *SQLiteStore) UpdateOperatorLastLogin(ctx context.Context, id string, t time.Time) error

func (*SQLiteStore) UpdateOperatorPassword

func (s *SQLiteStore) UpdateOperatorPassword(ctx context.Context, id, passwordHash string) error

func (*SQLiteStore) UpdateWebhookSubscription added in v0.6.0

func (s *SQLiteStore) UpdateWebhookSubscription(ctx context.Context, sub *models.WebhookSubscription) error

UpdateWebhookSubscription writes the mutable fields (url, events, active, allow_private, secret envelope) and bumps updated_at. Delivery-status columns are left to RecordWebhookDelivery.

type SQLiteStoreOption added in v0.12.0

type SQLiteStoreOption func(*SQLiteStore)

SQLiteStoreOption configures a SQLiteStore.

func WithCredentialCutoverGuard added in v0.12.0

func WithCredentialCutoverGuard(guard func(context.Context, *SQLiteStore) error) SQLiteStoreOption

WithCredentialCutoverGuard verifies that the configured master key can decrypt persisted CA material before migration 027 destroys legacy credential verifiers.

func WithCredentialHasher added in v0.12.0

func WithCredentialHasher(hasher *credentialhash.Hasher) SQLiteStoreOption

WithCredentialHasher configures the HMAC boundary for persisted credentials.

type Store

type Store interface {
	// CAs
	CreateCA(ctx context.Context, c *models.CA) error
	GetCA(ctx context.Context, id string) (*models.CA, error)
	GetCAByFingerprint(ctx context.Context, fp string) (*models.CA, error)
	ListCAs(ctx context.Context) ([]*models.CA, error)
	ListCAsByOwner(ctx context.Context, ownerID string) ([]*models.CA, error)
	ListCAsApproachingExpiry(ctx context.Context, thresholdRatio float64) ([]*models.CA, error)
	FindCAByPredecessor(ctx context.Context, predecessorID string) (*models.CA, error)
	UpdateCAStatus(ctx context.Context, id string, status models.CAStatus) error
	DeleteCA(ctx context.Context, id string) error

	// Webhook subscriptions
	CreateWebhookSubscription(ctx context.Context, sub *models.WebhookSubscription) error
	GetWebhookSubscription(ctx context.Context, id string) (*models.WebhookSubscription, error)
	ListWebhookSubscriptions(ctx context.Context) ([]*models.WebhookSubscription, error)
	ListWebhookSubscriptionsByOwner(ctx context.Context, ownerID string) ([]*models.WebhookSubscription, error)
	ListActiveWebhookSubscriptionsForCA(ctx context.Context, caID string) ([]*models.WebhookSubscription, error)
	UpdateWebhookSubscription(ctx context.Context, sub *models.WebhookSubscription) error
	DeleteWebhookSubscription(ctx context.Context, id string) error
	RecordWebhookDelivery(ctx context.Context, id string, ok bool, errMsg string, at time.Time) error

	// Networks
	CreateNetwork(ctx context.Context, n *models.Network) error
	GetNetwork(ctx context.Context, id string) (*models.Network, error)
	ListNetworks(ctx context.Context) ([]*models.Network, error)
	UpdateNetwork(ctx context.Context, n *models.Network) error

	// Existing mesh adoption.
	CreateMeshImport(ctx context.Context, item *models.MeshImport, rawToken string) error
	GetMeshImport(ctx context.Context, id string) (*models.MeshImport, error)
	GetMeshImportByToken(ctx context.Context, rawToken string, now time.Time) (*models.MeshImport, error)
	ListMeshImports(ctx context.Context) ([]*models.MeshImport, error)
	ListMeshImportsByOwner(ctx context.Context, ownerID string) ([]*models.MeshImport, error)
	RotateMeshImportToken(ctx context.Context, id, rawToken string, expiresAt, now time.Time) error
	CancelMeshImport(ctx context.Context, id, reason string, now time.Time) error
	CreateMeshImportChallenge(ctx context.Context, challenge *models.MeshImportChallenge, now time.Time) error
	GetMeshImportChallenge(ctx context.Context, id string) (*models.MeshImportChallenge, error)
	RegisterImportedHost(ctx context.Context, registration *models.MeshImportRegistration, now time.Time) (*models.MeshImportRegistrationResult, error)
	ListMeshImportSnapshots(ctx context.Context, meshImportID string) ([]*models.MeshImportSnapshot, error)
	FinalizeMeshImport(ctx context.Context, input MeshImportFinalizeInput) error
	GetHostAgentProfile(ctx context.Context, hostID string) (*models.HostAgentProfile, error)
	SetPendingHostConfigVersion(ctx context.Context, hostID string, version int) error
	AcknowledgeHostConfigVersion(ctx context.Context, hostID string, version int) error
	GetMeshImportTombstone(ctx context.Context, fingerprint string) (*models.MeshImportTombstone, error)

	// Hosts
	CreateHost(ctx context.Context, h *models.Host) error
	GetHost(ctx context.Context, id string) (*models.Host, error)
	GetHostByFingerprint(ctx context.Context, fingerprint string) (*models.Host, error)
	ListHosts(ctx context.Context, filter HostFilter) ([]*models.Host, error)
	// UpdateHost persists the host row and atomically resets its
	// config_version to 0 in the same transaction (SEC-PERSIST-001), so the
	// agent re-renders its config on the next poll.
	UpdateHost(ctx context.Context, h *models.Host) error
	UpdateHostLastSeen(ctx context.Context, id string, t time.Time) error
	UpdateHostCert(ctx context.Context, id, fingerprint string, expiresAt time.Time) error
	UpdateHostStatus(ctx context.Context, id string, status models.HostStatus) error
	DeleteHost(ctx context.Context, id string) error
	BlockHostAndAddToBlocklist(ctx context.Context, id, reason string) (*models.Host, error)
	UnblockHostAndRemoveFromBlocklist(ctx context.Context, id string) (*models.Host, error)
	DeleteHostAndBlockCert(ctx context.Context, id, reason string) error

	// Agent authorization (ADR 0004 / #75).
	//
	// SetPrevFingerprint records the prior cert fingerprint and the time of
	// rotation; SaveCertificateAndUpdateHostCert is the natural caller.
	// ClearPrevFingerprint drops the overlap window once the agent has
	// successfully polled under the new fingerprint.
	//
	// SetPendingRekey is a compare-and-swap that succeeds only when the host
	// is not already mid-rekey; the second concurrent call returns
	// ErrRekeyAlreadyPending so the API layer can answer 409.
	SetPrevFingerprint(ctx context.Context, hostID, prev string, rotatedAt time.Time) error
	ClearPrevFingerprint(ctx context.Context, hostID string) error
	SetPendingRekey(ctx context.Context, hostID string) error
	ClearPendingRekey(ctx context.Context, hostID string) error
	UpdateHostSigningPub(ctx context.Context, hostID, signingPubPEM string) error

	// AddPopNonce records a (hostID, nonce) pair valid until expiresAt.
	// Returns nil when the row was freshly inserted (or replaced an expired
	// duplicate); returns ErrReplayedNonce when a live duplicate exists.
	// Rows past expiresAt are pruned lazily on the next call; callers must
	// not infer freshness from the row's age alone. GHSA-v2jf-442r-6mjh.
	AddPopNonce(ctx context.Context, hostID, nonce string, expiresAt time.Time) error

	// Enrollment tokens
	CreateHostAndToken(ctx context.Context, h *models.Host, t *models.EnrollmentToken, rawToken string) error
	CreateToken(ctx context.Context, t *models.EnrollmentToken, rawToken string) error
	CreateTokenForHost(ctx context.Context, hostID, token string, expiresAt time.Time) error
	ConsumeToken(ctx context.Context, token string) (*models.EnrollmentToken, error)
	GetEnrollmentToken(ctx context.Context, token string) (*models.EnrollmentToken, error)

	// Certificates
	SaveCertificate(ctx context.Context, hostID string, certPEM []byte, fp string, notBefore, notAfter time.Time) error
	SaveCertificateAndEnrollHost(ctx context.Context, hostID string, certPEM []byte, fp string, notBefore, notAfter time.Time) error
	SaveCertificateIfIssuanceAllowed(ctx context.Context, hostID string, expectedStatus models.HostStatus, certPEM []byte, fp string, notBefore, notAfter time.Time) error
	ConsumeTokenAndEnrollHost(ctx context.Context, hostID, token string, certPEM []byte, fp string, notBefore, notAfter time.Time) error
	// ConsumeTokenAndEnrollHostWithProfile atomically binds an enrollment to a
	// signed certificate identity snapshot. If Name, NebulaIPs, or Groups changed after
	// signing, the transaction keeps pending_rekey set so a stale certificate is
	// never treated as satisfying the newer identity.
	ConsumeTokenAndEnrollHostWithProfile(ctx context.Context, hostID, token string, certPEM []byte, fp string, notBefore, notAfter time.Time, signingPubPEM string, profile models.AgentProfile, signedIdentity *models.CertificateIdentity) (int, error)
	SaveCertificateAndUpdateHostCert(ctx context.Context, hostID string, certPEM []byte, fp string, notBefore, notAfter time.Time) error
	GetCurrentCertificate(ctx context.Context, hostID string) ([]byte, error)
	GetCertificateInfo(ctx context.Context, hostID string) (*models.CertificateInfo, error)
	ListEnrolledHostCerts(ctx context.Context) ([]*models.CertificateInfo, error)

	// Blocklist
	AddToBlocklist(ctx context.Context, fingerprint, hostID, reason string) error
	RemoveFromBlocklist(ctx context.Context, fingerprint string) error
	GetBlocklist(ctx context.Context) ([]string, error)
	GetBlocklistForCA(ctx context.Context, caID string) ([]string, error)

	// Config versioning
	BumpNetworkConfigVersion(ctx context.Context, networkID string) error
	GetNetworkConfigVersion(ctx context.Context, networkID string) (int, error)
	GetHostConfigVersion(ctx context.Context, hostID string) (int, error)
	UpdateHostConfigVersion(ctx context.Context, hostID string, version int) error

	// Network config (key-value)
	GetNetworkConfig(ctx context.Context, networkID, key string) (string, error)
	SetNetworkConfig(ctx context.Context, networkID, key, value string) error
	SetNetworkConfigAndBumpVersion(ctx context.Context, networkID, key, value string) error

	// Audit log
	AddAuditEntry(ctx context.Context, actor, action, resource, details string) error
	ListAuditEntries(ctx context.Context, filter AuditFilter) ([]*models.AuditEntry, error)

	// Cert-expiry alert dedup state. RecordCertAlert remembers that an
	// alert was emitted for the given host whose current cert expires at
	// alertedNotAfter; GetCertAlert returns the previously alerted
	// not_after, or ErrNotFound if no alert has been recorded yet.
	RecordCertAlert(ctx context.Context, hostID string, alertedNotAfter time.Time) error
	GetCertAlert(ctx context.Context, hostID string) (time.Time, error)

	// Server-wide key/value settings (e.g. enforce_2fa). Empty string is
	// returned when the key has never been set — callers convert to typed
	// defaults via the helpers in the consuming package.
	GetServerSetting(ctx context.Context, key string) (string, error)
	SetServerSetting(ctx context.Context, key, value string) error

	// Operators
	CreateOperator(ctx context.Context, op *models.Operator) error
	// SeedInitialAdminOperator atomically inserts op (and optionally key,
	// when key is non-nil) only if the operators table is empty. Returns
	// (true, nil) when this call performed the seed, (false, nil) when
	// another caller already populated the table. The check + insert run
	// in a single transaction, so concurrent boots cannot both seed.
	SeedInitialAdminOperator(ctx context.Context, op *models.Operator, key *models.OperatorAPIKey, rawKey string) (bool, error)
	GetOperator(ctx context.Context, id string) (*models.Operator, error)
	GetOperatorByUsername(ctx context.Context, username string) (*models.Operator, error)
	GetOperatorByOIDC(ctx context.Context, issuer, subject string) (*models.Operator, error)
	ListOperators(ctx context.Context) ([]*models.Operator, error)
	UpdateOperatorPassword(ctx context.Context, id, passwordHash string) error
	UpdateOperatorLastLogin(ctx context.Context, id string, t time.Time) error
	RecordFailedLoginAttempt(ctx context.Context, id string, maxAttempts int, lockUntil time.Time) (bool, error)
	ResetFailedLoginAttempts(ctx context.Context, id string) error
	DisableOperator(ctx context.Context, id string) error
	EnableOperator(ctx context.Context, id string) error

	// Operator TOTP / recovery codes
	SetOperatorTOTP(ctx context.Context, id, secret string, enabled bool) error
	// ConsumeOperatorTOTPTimestep atomically records the TOTP timestep a
	// code was accepted at, rejecting (ErrTOTPReplayed) any timestep at or
	// below the last accepted one so an observed code cannot be replayed
	// within its validity window (RFC 6238 §5.2).
	ConsumeOperatorTOTPTimestep(ctx context.Context, id string, ts int64) error
	ReplaceOperatorRecoveryCodes(ctx context.Context, id string, rawCodes []string) error
	ConsumeOperatorRecoveryCode(ctx context.Context, id, rawCode string) error
	ListOperatorRecoveryCodes(ctx context.Context, id string) ([]string, error)
	ResetOperatorTOTPBreakGlass(ctx context.Context, username string) error

	// Operator API keys
	CreateOperatorAPIKey(ctx context.Context, k *models.OperatorAPIKey, rawKey string) error
	GetOperatorAPIKey(ctx context.Context, keyID string) (*models.OperatorAPIKey, error)
	GetOperatorByAPIKey(ctx context.Context, rawKey string) (*models.Operator, *models.OperatorAPIKey, error)
	ListOperatorAPIKeys(ctx context.Context, operatorID string) ([]*models.OperatorAPIKey, error)
	RevokeOperatorAPIKey(ctx context.Context, keyID string) error
	TouchOperatorAPIKey(ctx context.Context, keyID string, t time.Time) error

	// Operator sessions
	CreateOperatorSession(ctx context.Context, s *models.OperatorSession) error
	GetOperatorBySession(ctx context.Context, token string) (*models.Operator, error)
	GetPendingTwoFactorOperator(ctx context.Context, token string) (*models.Operator, error)
	PromoteOperatorSession(ctx context.Context, token string, newExpiry time.Time) error
	DeleteOperatorSession(ctx context.Context, token string) error
	DeleteOperatorSessionsByOperator(ctx context.Context, operatorID string) error
	DeleteOperatorSessionsByOperatorExcept(ctx context.Context, operatorID, keepToken string) error
	DeleteExpiredOperatorSessions(ctx context.Context, before time.Time) error

	// Lifecycle
	Migrate(ctx context.Context) error
	Ping(ctx context.Context) error
	Close() error
}

Store defines the persistence interface for the management server.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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