Help us shape the future of Go! Take the 2026 Go Developer Survey

localowner

package
v0.54.10 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2026 License: Apache-2.0 Imports: 35 Imported by: 0

Documentation

Overview

Package localowner realizes and verifies the init-owned human identity in the local PocketID runtime without exposing its bootstrap credential.

Index

Constants

View Source
const KombifyLinkClientID = "stackkit-kombify-link"

KombifyLinkClientID is the public PKCE client a Techstack-connected node registers so a household member can link their kombify account to their Pocket ID user. It matches Techstack's household link client id.

View Source
const StepUpCallbackPath = "/api/v1/identity/step-up/callback"
View Source
const StepUpClientID = "stackkits-owner-step-up"

Variables

View Source
var ErrStepUpRejected = errors.New("localowner: current PocketID owner approval required")

Functions

func ApplicationOIDCClientID added in v0.47.3

func ApplicationOIDCClientID(workloadRef string) string

ApplicationOIDCClientID is the stable Pocket ID client ID of a workload.

func ApplicationOIDCClientSecretRef added in v0.47.3

func ApplicationOIDCClientSecretRef(workloadRef string) string

ApplicationOIDCClientSecretRef is the custody ref of a workload's issued Pocket ID client secret.

func ConsumeRemoteActionApproval

func ConsumeRemoteActionApproval(workspaceRoot string, receipt json.RawMessage, expected RemoteActionApprovalBinding, trust StepUpTrust, now time.Time) error

ConsumeRemoteActionApproval is a cross-process no-replace replay journal in existing local custody. A crash after consumption leaves the approval spent; resume through the executor's existing operation journal, never replay it.

func NormalizeStepUpOrigin

func NormalizeStepUpOrigin(origin string) (string, error)

NormalizeStepUpOrigin keeps registration, the browser Origin and OAuth callback on one canonical HTTPS origin. Unsupported host forms fail during startup.

func StepUpNonce

func StepUpNonce(binding RemoteActionApprovalBinding) (string, error)

func VerifyRemoteActionApproval

func VerifyRemoteActionApproval(ctx context.Context, workspaceRoot, origin string, receipt json.RawMessage, expected RemoteActionApprovalBinding) error

VerifyRemoteActionApproval requires the live Home owner/client projection and consumes the exact approval before the caller dispatches any mutation.

func VerifyRemoteActionApprovalClaims

func VerifyRemoteActionApprovalClaims(receipt json.RawMessage, expected RemoteActionApprovalBinding, trust StepUpTrust, now time.Time) error

VerifyRemoteActionApprovalClaims verifies the independent human signature. It performs no mutation. The executor must consume the approval durably before its first side effect, using ConsumeRemoteActionApproval or its existing replay journal, after all action, device, target and current Home-trust admission.

Types

type ApplicationOIDCClient added in v0.47.3

type ApplicationOIDCClient struct {
	ClientID string
	Issuer   string
}

ApplicationOIDCClient is the secret-free result: the client ID and the issuer URL the application discovers Pocket ID at.

type ApplicationOIDCClientRequest added in v0.47.3

type ApplicationOIDCClientRequest struct {
	// RequiredPrivilege comes from the validated catalog endpoint. Empty keeps
	// the existing household application policy; vault always requires vault.
	RequiredPrivilege string
	// Public is admitted only for the governed Smart Home and kombify account
	// link PKCE clients.
	Public   bool
	ClientID string
	Name     string
	// CallbackURL keeps the single-callback contract for existing callers.
	// CallbackURLs is used by applications such as Immich that own several
	// exact browser and mobile callbacks. Callers set exactly one form.
	CallbackURL  string
	CallbackURLs []string
	SecretRef    string
}

ApplicationOIDCClientRequest names one application's governed Pocket ID client. The client ID is stable per workload; SecretRef is the custody ref the issued client secret is stored under.

type CloudSessionIntent added in v0.53.9

type CloudSessionIntent interface {
	Candidate([]byte) ([]byte, error)
	Persist(string, string, []byte, []byte) error
	Restore(string, string, []byte, []byte) error
}

type DomainMigration added in v0.47.7

type DomainMigration struct {
	From   string   `json:"from"`
	To     string   `json:"to"`
	Status string   `json:"status"`
	Next   []string `json:"next"`
}

DomainMigration reports local preparation, never runtime deployment or login.

type DomainMigrationIntent added in v0.47.7

type DomainMigrationIntent interface {
	Candidate([]byte) ([]byte, error)
	Persist(workspace, specPath string, before, after []byte) error
}

MigrateBasementDomain requires the caller's explicit owner approval and idle lifecycle mutation lock. All local writes are authenticated and replayable. The existing user subjects, client secrets, CA and signing keys stay intact.

type HouseholdAppAccess added in v0.53.9

type HouseholdAppAccess struct {
	Scoped bool
	Apps   []string
}

HouseholdAppAccess is a member's app grant. The zero value is open: every user-tier app, as before per-app grants. Scoped admits only Apps.

type HouseholdProjection added in v0.54.10

type HouseholdProjection struct {
	Key      string
	Revision uint64
	Action   string
	User     HouseholdUserSpec
}

HouseholdProjection binds the Cloud owner/person generation to the node's actual identity mutation. Key is SHA-256(owner subject + newline + member subject), produced by Techstack after verifying Cloud's delegated owner.

type HouseholdUser

type HouseholdUser struct {
	Username    string
	Email       string
	DisplayName string
	Status      string
	ExpiresAt   time.Time
	SetupURL    string
	// Access is the member's app grant; the zero value admits every app.
	Access HouseholdAppAccess
}

HouseholdUser is one non-owner PocketID subject in the household group.

type HouseholdUserSpec

type HouseholdUserSpec struct {
	Username    string
	Email       string
	DisplayName string
	// Access defaults to every app, as before per-app grants.
	Access HouseholdAppAccess
}

HouseholdUserSpec is the owner-supplied identity for one household member.

type OwnerActivation

type OwnerActivation struct {
	Status    string
	Origin    string
	ExpiresAt time.Time
	SetupURL  string
}

OwnerActivation is the owner-bound passkey enrollment state. SetupURL is returned only by the explicit activation operation and must remain transient.

type OwnerEmailVerification added in v0.47.7

type OwnerEmailVerification struct {
	Status string
}

OwnerEmailVerification records only the current PocketID readback. Pending means the owner must request and consume the mailed token in their own authenticated PocketID session; administrator custody cannot perform that confirmation on the owner's behalf.

type RemoteActionApproval

type RemoteActionApproval struct {
	IDToken string `json:"idToken"`
}

RemoteActionApproval preserves the actual PocketID signature. A lifecycle owner-key signature cannot replace this token or satisfy human approval. Treat this structure as a credential: never put it in logs or public receipts.

type RemoteActionApprovalBinding

type RemoteActionApprovalBinding struct {
	ActionDigest  string    `json:"actionDigest"`
	PlanHash      string    `json:"planHash"`
	Action        string    `json:"action"`
	OwnerRef      string    `json:"ownerRef"`
	HomeSiteRef   string    `json:"homeSiteRef"`
	TargetSiteRef string    `json:"targetSiteRef"`
	TargetNodeRef string    `json:"targetNodeRef"`
	IssuedAt      time.Time `json:"issuedAt"`
	ExpiresAt     time.Time `json:"expiresAt"`
}

RemoteActionApprovalBinding is supplied by the admitted action receiver, never copied from the receipt. ActionDigest covers the unsigned action envelope, including its nonce and idempotency key, but excludes the approval itself.

type Result

type Result struct {
	Binding        localevidence.OwnerRuntimeBinding
	EnrollmentPath string
}

type Service

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

func NewService

func NewService(workspaceRoot string) (*Service, error)

func (*Service) AbortCloudSessionRoutes added in v0.53.9

func (s *Service) AbortCloudSessionRoutes(ctx context.Context, specPath string, intent CloudSessionIntent, runtime CloudSessionRuntime) (localevidence.CloudSessionRouting, error)

AbortCloudSessionRoutes restores only the source topology retained by the signed transition. It never changes the issuer, user, passkeys or secrets.

func (*Service) ActivateHouseholdUser added in v0.47.7

func (s *Service) ActivateHouseholdUser(ctx context.Context, username string) (HouseholdUser, error)

ActivateHouseholdUser reissues enrollment for the same non-owner subject. It preserves memberships and data and refuses owner/admin identity changes.

func (*Service) AddHouseholdUser

func (s *Service) AddHouseholdUser(ctx context.Context, spec HouseholdUserSpec) (HouseholdUser, error)

AddHouseholdUser creates a non-admin PocketID subject in the household group and returns a one-time passkey enrollment URL. Owners, admins and break-glass identities are refused.

func (*Service) CheckCloudSessionRoutes added in v0.53.9

func (s *Service) CheckCloudSessionRoutes(ctx context.Context, specPath string, intent CloudSessionIntent, runtime CloudSessionRuntime) (addressplan.SessionTopology, error)

func (*Service) ConfigureOwnerEmailVerification added in v0.47.7

func (s *Service) ConfigureOwnerEmailVerification(ctx context.Context, email string, smtp pocketid.SMTPConfiguration) (OwnerEmailVerification, error)

ConfigureOwnerEmailVerification configures authenticated SMTP delivery for the exact bound owner and reports whether PocketID has observed a real email confirmation. It deliberately works before passkey activation so automatic application setup cannot prevent the owner from reaching activation.

func (*Service) EnsureApplicationOIDCClient added in v0.47.3

func (s *Service) EnsureApplicationOIDCClient(ctx context.Context, request ApplicationOIDCClientRequest) (ApplicationOIDCClient, error)

EnsureApplicationOIDCClient registers or converges a governed, PKCE-enabled Pocket ID client for one application, restricted to the same owner groups as the TinyAuth gate, and keeps its secret in local custody as an issued secret. An existing client keeps its secret while custody holds it; a client whose secret custody was lost receives a new secret. The exact public Smart Home client never issues or custodies a secret.

func (*Service) EnsureImmichUserClaims added in v0.47.7

func (s *Service) EnsureImmichUserClaims(ctx context.Context) error

EnsureImmichUserClaims converges the application role of the exact signed owner and every household subject before Photos is applied. It preserves unrelated per-user claims, memberships, credentials and Pocket ID admin flags. Verify never calls this mutating operation. Callers hold the lifecycle lock.

func (*Service) ExchangeStepUpCode

func (s *Service) ExchangeStepUpCode(ctx context.Context, origin, code, verifier string, expected RemoteActionApprovalBinding) (json.RawMessage, error)

ExchangeStepUpCode uses only the fixed local PocketID endpoint. Neither an incoming token nor discovery metadata may redirect a request to another host.

func (*Service) ExchangeStepUpIDToken added in v0.53.14

func (s *Service) ExchangeStepUpIDToken(ctx context.Context, origin, code, verifier string) (string, error)

ExchangeStepUpIDToken redeems a step-up authorization code for its PocketID ID token without an action binding. The caller must verify the token against its own purpose (issuer, Owner subject, audience StepUpClientID, its flow nonce, passkey amr and freshness) before acting; the Home device-enroll ceremony does so in identity.IssueHomePairingWithOwnerStepUp. The token is a credential and never leaves the server.

func (*Service) IssueOwnerActivation

func (s *Service) IssueOwnerActivation(ctx context.Context) (OwnerActivation, error)

IssueOwnerActivation mints a fresh one-time URL for an owner who has not registered a passkey and retires the previously issued link first, so an owner who opened a link without finishing enrollment is never handed the consumed code again and at most one activation link stays redeemable. It never mints a link for an active owner.

func (*Service) ListHouseholdUsers

func (s *Service) ListHouseholdUsers(ctx context.Context) ([]HouseholdUser, error)

ListHouseholdUsers returns non-admin PocketID subjects in the household group.

func (*Service) MigrateBasementDomain added in v0.47.7

func (s *Service) MigrateBasementDomain(ctx context.Context, specPath string, intent DomainMigrationIntent, quiesceRuntime bool) (DomainMigration, error)

func (*Service) OwnerActivationStatus

func (s *Service) OwnerActivationStatus(ctx context.Context) (OwnerActivation, error)

OwnerActivationStatus verifies the exact owner runtime binding and reports completion from PocketID's passkey records.

func (*Service) PrepareStepUp

func (s *Service) PrepareStepUp(ctx context.Context, origin string) (StepUpTrust, error)

PrepareStepUp binds a dedicated confidential PKCE client to an explicitly configured HTTPS server origin. Existing clients are verified, never silently rewritten.

func (*Service) ProjectHouseholdUser added in v0.54.10

func (s *Service) ProjectHouseholdUser(ctx context.Context, request HouseholdProjection) (HouseholdUser, error)

ProjectHouseholdUser must execute under the node lifecycle mutation lock. The provider UUID is signed before POST /users. Only that UUID can recover an uncertain creation; a username, email or mutable profile is not custody.

func (*Service) ReadStepUpTrust

func (s *Service) ReadStepUpTrust(ctx context.Context, origin string) (StepUpTrust, error)

ReadStepUpTrust verifies current owner, client and public signing keys without creating or changing identity resources. The remote peer enrollment owner may project this trust only through its existing authenticated custody contract.

func (*Service) Realize

func (s *Service) Realize(ctx context.Context) (Result, error)

Realize creates the exact desired PocketID owner once, persists a private one-time passkey-enrollment URL, and records a secret-free signed binding to ownerRef and the step-ca certificate chain.

A reset host answers as an empty PocketID: reachable, unbootstrapped, and without the subject, groups, or client the workspace recorded. Realize treats that as work to redo rather than as a reason to refuse, so re-running an install rebuilds the owner from the custody that survived on disk.

func (*Service) ReconcileTinyAuthPKCE added in v0.53.9

func (s *Service) ReconcileTinyAuthPKCE(ctx context.Context, approved bool) (TinyAuthReconciliation, error)

ReconcileTinyAuthPKCE repairs only legacy PKCE drift against the existing signed Owner/client binding. The caller holds the native mutation lock. Unlike Realize it cannot recreate identities, seed groups or issue links.

func (*Service) RemoveHouseholdUser

func (s *Service) RemoveHouseholdUser(ctx context.Context, username string) error

RemoveHouseholdUser deletes one household subject. Owner and admin identities are refused.

func (*Service) SetHouseholdUserApps added in v0.53.9

func (s *Service) SetHouseholdUserApps(ctx context.Context, username string, access HouseholdAppAccess) (HouseholdUser, error)

SetHouseholdUserApps changes which node apps one existing household member may sign into. It is idempotent.

func (*Service) TransitionCloudSessionRoutes added in v0.53.9

func (s *Service) TransitionCloudSessionRoutes(ctx context.Context, specPath string, intent CloudSessionIntent, runtime CloudSessionRuntime) (localevidence.CloudSessionRouting, error)

TransitionCloudSessionRoutes runs beneath the existing lifecycle mutation lock. Each uncertain mutation is observed on resume before it is repeated.

func (*Service) Verify

Verify performs only authenticated readback. It verifies custody and the signed binding before any network request and never creates or updates a PocketID resource.

type StepUpTrust

type StepUpTrust struct {
	Issuer      string
	Subject     string
	OwnerRef    string
	HomeSiteRef string
	Keys        jose.JSONWebKeySet
}

StepUpTrust must come from admitted Home identity custody. A caller must never accept issuer, subject, or keys supplied alongside an untrusted approval. Remote consumers also need a current admitted client/owner projection: offline verification alone cannot discover a disabled owner or changed client policy.

type TinyAuthReconciliation added in v0.53.9

type TinyAuthReconciliation struct {
	Status          string `json:"status"`
	Changed         bool   `json:"changed"`
	PKCEEnabled     bool   `json:"pkceEnabled"`
	BindingVerified bool   `json:"bindingVerified"`
}

TinyAuthReconciliation contains public policy results, never identity credentials or enrollment links.

Jump to

Keyboard shortcuts

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