service

package
v0.1.6 Latest Latest
Warning

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

Go to latest
Published: Mar 29, 2026 License: AGPL-3.0 Imports: 35 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrEnrollmentCapacity  = errors.New("enrollment capacity reached")
	ErrPendingNotFound     = errors.New("pending enrollment not found or expired")
	ErrSecretMismatch      = errors.New("credential secret mismatch")
	ErrDeviceAlreadyExists = errors.New("device with this EK already exists")
	ErrQuoteVerification   = errors.New("quote verification failed")
)

Functions

func ComputePCRCompositeHash added in v0.1.5

func ComputePCRCompositeHash(pcrValues map[string]string, group model.PCRGroup) string

ComputePCRCompositeHash computes a deterministic hash for a set of PCR values within a group.

func ComputeTrustLevel added in v0.1.5

func ComputeTrustLevel(identityClass string, pcrConsensus model.PCRConsensusStatus) model.TrustLevel

ComputeTrustLevel implements the trust matrix from RFC 003.

func EncodePCRValues added in v0.1.5

func EncodePCRValues(raw map[int][]byte) map[string]string

EncodePCRValues converts raw PCR digests to hex-encoded strings for storage.

func EvaluatePCRConsensus added in v0.1.5

func EvaluatePCRConsensus(
	pcrValues map[string]string,
	issuerFP, osVersion *string,
	lookupMajority func(groupKey string, group model.PCRGroup) (string, bool),
) model.PCRConsensusStatus

EvaluatePCRConsensus determines PCR consensus for a device by checking its PCR values against majority data. The lookupMajority function returns (compositeHash, found) for a given key/group.

func ExtractSubnet added in v0.1.5

func ExtractSubnet(ip net.IP) string

ExtractSubnet extracts the /24 subnet string from an IP address.

func PCRGroupingKey added in v0.1.5

func PCRGroupingKey(group model.PCRGroup, issuerFP *string, osVersion *string) string

PCRGroupingKey returns the census grouping key for a PCR group.

Types

type ACMEService

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

func NewACMEService

func NewACMEService(acmeStore *store.ACMEStore, deviceStore *store.DeviceStore, pdns *dns.PowerDNSClient, cfg *config.Config, logger *slog.Logger) *ACMEService

func (*ACMEService) CleanupLoop

func (s *ACMEService) CleanupLoop(ctx context.Context)

CleanupLoop removes expired ACME challenges.

func (*ACMEService) CreateChallenge

func (*ACMEService) DeleteChallenge

func (s *ACMEService) DeleteChallenge(ctx context.Context, challengeID uuid.UUID, deviceID uuid.UUID) error

type AccountService added in v0.1.4

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

func NewAccountService added in v0.1.4

func NewAccountService(
	accountStore *store.AccountStore,
	deviceStore *store.DeviceStore,
	inviteStore *store.InviteStore,
	auditStore *store.AuditStore,
	cfg *config.Config,
	logger *slog.Logger,
) *AccountService

func (*AccountService) CleanupExpiredInvites added in v0.1.4

func (s *AccountService) CleanupExpiredInvites(ctx context.Context)

CleanupExpiredInvites removes expired unconsumed invites.

func (*AccountService) CreateInvite added in v0.1.4

func (s *AccountService) CreateInvite(ctx context.Context, deviceID uuid.UUID) (*InviteResponse, error)

func (*AccountService) JoinAccount added in v0.1.4

func (s *AccountService) JoinAccount(ctx context.Context, deviceID uuid.UUID, inviteCode string) error

func (*AccountService) LeaveAccount added in v0.1.4

func (s *AccountService) LeaveAccount(ctx context.Context, deviceID uuid.UUID) error

func (*AccountService) SetVoucherCreator added in v0.1.4

func (s *AccountService) SetVoucherCreator(vc VoucherRequestCreator)

SetVoucherCreator sets the voucher request creator for triggering voucher exchange after join/leave. Set after construction to break circular init.

type AttestRequest

type AttestRequest struct {
	Nonce          string
	Secret         []byte
	QuoteB64       string
	OSVersion      string
	PCRValues      map[int][]byte
	ClientIP       net.IP
	RecoveryBundle *RecoveryBundle // optional, for recovery enrollment
}

type AttestResponse

type AttestResponse struct {
	DeviceID       uuid.UUID `json:"device_id"`
	Hostname       string    `json:"hostname"`
	IdentityClass  string    `json:"identity_class"`
	TrustLevel     string    `json:"trust_level"`
	NexusEndpoints []string  `json:"nexus_endpoints"`
	Reenrolled     bool      `json:"reenrolled,omitempty"`
	// Recovery replay hints — returned when recovery_bundle was processed,
	// so the client knows what state to replay via separate API calls.
	ReplayCustomHostname string   `json:"replay_custom_hostname,omitempty"`
	ReplayAliasDomains   []string `json:"replay_alias_domains,omitempty"`
}

type CensusService added in v0.1.5

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

func NewCensusService added in v0.1.5

func NewCensusService(censusStore *store.CensusStore, deviceStore *store.DeviceStore, auditStore *store.AuditStore, pool *pgxpool.Pool, cfg *config.Config, logger *slog.Logger) *CensusService

func (*CensusService) Analyze added in v0.1.5

func (s *CensusService) Analyze(ctx context.Context) error

Analyze runs a single census analysis pass with advisory lock protection.

func (*CensusService) Run added in v0.1.5

func (s *CensusService) Run(ctx context.Context)

Run starts the periodic census analysis loop.

type CompleteVoucher added in v0.1.4

type CompleteVoucher struct {
	Data           string `json:"data"`
	Quote          string `json:"quote"`
	IssuerAKPubKey string `json:"issuer_ak_public_key"`
	IssuerEKCert   string `json:"issuer_ek_cert,omitempty"`
}

CompleteVoucher is the API response format for a signed voucher.

type CreateChallengeRequest

type CreateChallengeRequest struct {
	DeviceID uuid.UUID
	Digest   string
	Hostname string // optional: defaults to canonical hostname
}

type CreateChallengeResponse

type CreateChallengeResponse struct {
	ID   uuid.UUID `json:"id"`
	FQDN string    `json:"fqdn"`
}

type DeviceService

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

func NewDeviceService

func NewDeviceService(deviceStore *store.DeviceStore, accountStore *store.AccountStore, auditStore *store.AuditStore, censusStore *store.CensusStore, pool *pgxpool.Pool, cfg *config.Config, logger *slog.Logger) *DeviceService

func (*DeviceService) CleanupPending

func (s *DeviceService) CleanupPending()

CleanupPending removes expired pending enrollments.

func (*DeviceService) CompleteEnrollment

func (s *DeviceService) CompleteEnrollment(ctx context.Context, req AttestRequest, verifier tpm.Verifier, nexusEndpoints []string) (*AttestResponse, error)

func (*DeviceService) PendingCount added in v0.1.6

func (s *DeviceService) PendingCount() int

PendingCount returns the number of pending enrollments.

func (*DeviceService) SetCustomHostname

func (s *DeviceService) SetCustomHostname(ctx context.Context, deviceID uuid.UUID, hostname string) error

func (*DeviceService) SetRecoveryProcessor added in v0.1.4

func (s *DeviceService) SetRecoveryProcessor(rp RecoveryProcessor)

SetRecoveryProcessor sets the recovery processor for handling recovery bundles.

func (*DeviceService) StartEnrollment

func (s *DeviceService) StartEnrollment(ctx context.Context, req EnrollRequest, verifier tpm.Verifier) (*EnrollResponse, error)

type DomainService added in v0.1.1

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

func NewDomainService added in v0.1.1

func NewDomainService(
	domainStore *store.DomainStore,
	deviceStore *store.DeviceStore,
	auditStore *store.AuditStore,
	resolver dns.CNAMEResolver,
	cfg *config.Config,
	logger *slog.Logger,
) *DomainService

func (*DomainService) AssignDomain added in v0.1.1

func (s *DomainService) AssignDomain(ctx context.Context, deviceID uuid.UUID, domainID uuid.UUID, targetDeviceIDs []uuid.UUID) ([]*model.DomainAssignment, error)

func (*DomainService) CleanupLoop added in v0.1.1

func (s *DomainService) CleanupLoop(ctx context.Context)

CleanupLoop removes expired pending domains.

func (*DomainService) DeleteDomain added in v0.1.1

func (s *DomainService) DeleteDomain(ctx context.Context, deviceID uuid.UUID, domainID uuid.UUID) error

func (*DomainService) GetDeviceAliasDomains added in v0.1.1

func (s *DomainService) GetDeviceAliasDomains(ctx context.Context, deviceID uuid.UUID) ([]string, error)

GetDeviceAliasDomains returns verified alias domain strings for a device.

func (*DomainService) ListAssignments added in v0.1.1

func (s *DomainService) ListAssignments(ctx context.Context, deviceID uuid.UUID, domainID uuid.UUID) ([]*model.DomainAssignment, error)

func (*DomainService) ListDomains added in v0.1.1

func (s *DomainService) ListDomains(ctx context.Context, deviceID uuid.UUID) ([]*model.AccountDomain, error)

func (*DomainService) RegisterDomain added in v0.1.1

func (s *DomainService) RegisterDomain(ctx context.Context, deviceID uuid.UUID, domain string) (*model.AccountDomain, error)

func (*DomainService) UnassignDomain added in v0.1.1

func (s *DomainService) UnassignDomain(ctx context.Context, deviceID uuid.UUID, domainID uuid.UUID, targetDeviceID uuid.UUID) error

func (*DomainService) VerifyDomain added in v0.1.1

func (s *DomainService) VerifyDomain(ctx context.Context, deviceID uuid.UUID, domainID uuid.UUID) (*model.AccountDomain, error)

type EnrollRequest

type EnrollRequest struct {
	EKCertDER []byte // optional: DER-encoded EK certificate
	EKPubDER  []byte // optional: PKIX DER-encoded EK public key (fallback when no cert)
	AKParams  []byte
	ClientIP  net.IP
}

type EnrollResponse

type EnrollResponse struct {
	Nonce         string `json:"nonce"`
	EncCredential []byte `json:"enc_credential"`
}

type ErrValidation

type ErrValidation struct {
	Message string
}

ErrValidation is a typed error for validation failures safe to return to clients.

func (*ErrValidation) Error

func (e *ErrValidation) Error() string

type InviteResponse added in v0.1.4

type InviteResponse struct {
	InviteCode string    `json:"invite_code"`
	AccountID  uuid.UUID `json:"account_id"`
	ExpiresAt  time.Time `json:"expires_at"`
}

type IssueTokenRequest

type IssueTokenRequest struct {
	DeviceID     uuid.UUID
	Stage        int
	SessionNonce string
}

type NexusService

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

func NewNexusService

func NewNexusService(nexusStore *store.NexusStore, auditStore *store.AuditStore, pdns *dns.PowerDNSClient, cfg *config.Config, logger *slog.Logger) *NexusService

func (*NexusService) GetActiveEndpoints

func (s *NexusService) GetActiveEndpoints(ctx context.Context) ([]string, error)

GetActiveEndpoints returns WebSocket URLs for all active Nexus instances.

func (*NexusService) GetActiveRelayServices added in v0.1.6

func (s *NexusService) GetActiveRelayServices() map[string][]string

GetActiveRelayServices returns aggregated relay service endpoints from the in-memory map. Returns nil when no services are available (ensures omitempty omits the field).

func (*NexusService) HealthCheckLoop

func (s *NexusService) HealthCheckLoop(ctx context.Context)

HealthCheckLoop periodically checks for inactive Nexus instances.

func (*NexusService) Register

type NexusServicesInfo added in v0.1.6

type NexusServicesInfo struct {
	StunPort int
}

type PendingEnrollment

type PendingEnrollment struct {
	EKPubKey         crypto.PublicKey
	EKCertDER        []byte
	AKPubKeyDER      []byte
	AKName           []byte
	ChallengeSecret  []byte
	IdentityClass    string
	EKFingerprint    string
	EKVerifyResult   *tpm.EKVerifyResult
	ClientIP         net.IP
	ExpiresAt        time.Time
	ExistingDeviceID *uuid.UUID // non-nil for re-enrollment of active devices
}

type PendingVoucherRequest added in v0.1.4

type PendingVoucherRequest struct {
	RequestID   uuid.UUID `json:"request_id"`
	VoucherData string    `json:"voucher_data"`
	Nonce       string    `json:"nonce"`
}

PendingVoucherRequest is the API response format for pending voucher requests.

type RecoveryBundle added in v0.1.4

type RecoveryBundle struct {
	AccountID      string         `json:"account_id"`
	Vouchers       []VoucherProof `json:"vouchers"`
	CustomHostname string         `json:"custom_hostname,omitempty"`
	AliasDomains   []string       `json:"alias_domains,omitempty"`
}

RecoveryBundle represents a recovery bundle from the enrollment request.

type RecoveryProcessor added in v0.1.4

type RecoveryProcessor interface {
	ValidateRecoveryBundle(bundle *RecoveryBundle) error
	ProcessRecoveryBundle(ctx context.Context, deviceID uuid.UUID, ekFingerprint string, bundle *RecoveryBundle) error
	AttributeClaimsForDevice(ctx context.Context, ekFingerprint string, akPublicKey []byte) error
}

RecoveryProcessor handles recovery bundle processing and claim attribution.

type RecoveryService added in v0.1.4

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

func NewRecoveryService added in v0.1.4

func NewRecoveryService(
	recoveryStore *store.RecoveryStore,
	accountStore *store.AccountStore,
	deviceStore *store.DeviceStore,
	auditStore *store.AuditStore,
	tpmVerifier tpm.Verifier,
	cfg *config.Config,
	logger *slog.Logger,
) *RecoveryService

func (*RecoveryService) AttributeClaimsForDevice added in v0.1.4

func (s *RecoveryService) AttributeClaimsForDevice(ctx context.Context, ekFingerprint string, akPublicKey []byte) error

AttributeClaimsForDevice attributes unattributed claims where this device is the issuer. Called during enrollment after a device re-enrolls.

func (*RecoveryService) CleanupLoop added in v0.1.4

func (s *RecoveryService) CleanupLoop(ctx context.Context)

CleanupLoop periodically cleans up old recovery claims.

func (*RecoveryService) DissolveAccount added in v0.1.4

func (s *RecoveryService) DissolveAccount(ctx context.Context, accountID uuid.UUID)

DissolveAccount moves each device in a pending_recovery account to its own standalone account, marks the original as dissolved, and logs the event.

func (*RecoveryService) EvaluateQuorum added in v0.1.4

func (s *RecoveryService) EvaluateQuorum(ctx context.Context, accountID uuid.UUID) (bool, error)

EvaluateQuorum checks if an account has reached quorum and promotes it to active.

func (*RecoveryService) ProcessRecoveryBundle added in v0.1.4

func (s *RecoveryService) ProcessRecoveryBundle(ctx context.Context, deviceID uuid.UUID, ekFingerprint string, bundle *RecoveryBundle) error

ProcessRecoveryBundle validates vouchers and stores recovery claims. Errors are logged but do not block enrollment (non-blocking).

func (*RecoveryService) QuorumReEvaluationLoop added in v0.1.4

func (s *RecoveryService) QuorumReEvaluationLoop(ctx context.Context)

QuorumReEvaluationLoop periodically re-evaluates quorum for pending_recovery accounts.

func (*RecoveryService) ValidateRecoveryBundle added in v0.1.4

func (s *RecoveryService) ValidateRecoveryBundle(bundle *RecoveryBundle) error

ValidateRecoveryBundle performs structural and consistency checks on the bundle.

type RegisterNexusRequest

type RegisterNexusRequest struct {
	Hostname    string
	Region      *string
	BackendPort int
	Services    *NexusServicesInfo
}

type RegisterNexusResponse

type RegisterNexusResponse struct {
	HeartbeatInterval int `json:"heartbeat_interval"`
}

type TokenService

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

func NewTokenService

func NewTokenService(deviceStore *store.DeviceStore, domainStore *store.DomainStore, issuer *token.Issuer, cfg *config.Config, logger *slog.Logger) *TokenService

func (*TokenService) IssueNexusToken

func (s *TokenService) IssueNexusToken(ctx context.Context, req IssueTokenRequest) (string, error)

func (*TokenService) VerifyToken

func (s *TokenService) VerifyToken(tokenString string) *VerifyResult

type VerifyResult

type VerifyResult struct {
	Valid  bool               `json:"valid"`
	Claims *token.NexusClaims `json:"claims"`
	Error  string             `json:"error"`
}

type VoucherProof added in v0.1.4

type VoucherProof struct {
	Data              string `json:"data"`
	Quote             string `json:"quote"`
	IssuerAKPublicKey string `json:"issuer_ak_public_key"`
	IssuerEKCert      string `json:"issuer_ek_cert,omitempty"`
}

VoucherProof is a single voucher in a recovery bundle.

type VoucherRequestCreator added in v0.1.4

type VoucherRequestCreator interface {
	CreateVoucherRequests(ctx context.Context, accountID uuid.UUID) error
}

VoucherRequestCreator is an interface to decouple AccountService from VoucherService.

type VoucherService added in v0.1.4

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

func NewVoucherService added in v0.1.4

func NewVoucherService(
	voucherStore *store.VoucherStore,
	deviceStore *store.DeviceStore,
	accountStore *store.AccountStore,
	auditStore *store.AuditStore,
	tpmVerifier tpm.Verifier,
	cfg *config.Config,
	logger *slog.Logger,
) *VoucherService

func (*VoucherService) CleanupExpiredRequests added in v0.1.4

func (s *VoucherService) CleanupExpiredRequests(ctx context.Context)

CleanupExpiredRequests expires unfulfilled voucher requests older than 30 days.

func (*VoucherService) CreateVoucherRequests added in v0.1.4

func (s *VoucherService) CreateVoucherRequests(ctx context.Context, accountID uuid.UUID) error

CreateVoucherRequests creates all-pairs voucher requests for devices in an account. Called after join/leave to trigger voucher exchange.

func (*VoucherService) GetNewVouchers added in v0.1.4

func (s *VoucherService) GetNewVouchers(ctx context.Context, deviceID uuid.UUID) ([]CompleteVoucher, error)

GetNewVouchers returns signed vouchers where the device is the subject.

func (*VoucherService) GetPendingRequests added in v0.1.4

func (s *VoucherService) GetPendingRequests(ctx context.Context, deviceID uuid.UUID) ([]PendingVoucherRequest, error)

GetPendingRequests returns pending voucher requests for a device (as issuer).

func (*VoucherService) SignVoucher added in v0.1.4

func (s *VoucherService) SignVoucher(ctx context.Context, deviceID uuid.UUID, requestID uuid.UUID, quoteB64 string) error

SignVoucher verifies a TPM quote and marks a voucher request as signed.

Jump to

Keyboard shortcuts

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