service

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 3, 2026 License: GPL-3.0 Imports: 35 Imported by: 0

Documentation

Overview

Package service holds the application business logic.

Index

Constants

View Source
const DefaultEnrollmentTTL = 15 * time.Minute

DefaultEnrollmentTTL is how long an unused enrollment token stays valid.

View Source
const DefaultInvitationTTL = 72 * time.Hour

DefaultInvitationTTL is how long an unaccepted invitation stays valid.

View Source
const DefaultProxyImage = app.AgentImageLatest

DefaultProxyImage is the container image install artifacts default to.

View Source
const MinPasswordLength = 8

Variables

View Source
var (
	// ErrNoAgentSupport is returned when a connection's plugin declares no agent.
	ErrNoAgentSupport = errors.New("service: plugin does not support agent transport")
	// ErrEnrollmentInvalid is returned for an unknown, expired, or revoked token.
	ErrEnrollmentInvalid = errors.New("service: invalid enrollment token")
)
View Source
var (
	// ErrInvalidCode is returned for a wrong TOTP or recovery code.
	ErrInvalidCode = errors.New("twofactor: invalid code")
	// ErrTOTPNotEnrolled is returned when a confirm/verify is attempted with no secret.
	ErrTOTPNotEnrolled = errors.New("twofactor: no enrollment in progress")
	// ErrTOTPNotEnabled is returned when an action requires active 2FA.
	ErrTOTPNotEnabled = errors.New("twofactor: not enabled")
	// ErrTOTPAlreadyEnabled prevents replacing active 2FA without verification.
	ErrTOTPAlreadyEnabled = errors.New("twofactor: already enabled")
)
View Source
var ErrInvitationInvalid = errors.New("service: invalid or expired invitation")

ErrInvitationInvalid is returned for an unknown, expired, or consumed token.

View Source
var ErrWrongPassword = errors.New("service: current password is incorrect")

ErrWrongPassword is returned when a self password change supplies the wrong current password.

Functions

func SaveConnectionFolderOrder

func SaveConnectionFolderOrder(ctx context.Context, folderStore store.ConnectionFolderStore, userID string, in []ConnectionFolderOrderInput) error

SaveConnectionFolderOrder validates and persists a user's folder ordering.

func SaveConnectionLayout

func SaveConnectionLayout(ctx context.Context, placements store.ConnectionPlacementStore, userID string, accessible map[string]bool, folders map[string]bool, in []ConnectionPlacementInput) error

SaveConnectionLayout validates and persists a user's connection placements.

func ValidatePassword

func ValidatePassword(password string) error

Types

type AgentState

type AgentState struct {
	Status  string `json:"status"`
	Message string `json:"message,omitempty"`
}

AgentState is the polled status the UI shows in the enroll panel.

type ArtifactURLFunc

type ArtifactURLFunc func(enrollmentID, kind string) (string, error)

ArtifactURLFunc mints a single-use signed fetch URL for a URL-delivered artifact (supplied by the server, which owns ticket minting and the host).

type ConnectionDetail

type ConnectionDetail struct {
	ID                 string                        `json:"id"`
	Name               string                        `json:"name"`
	Protocol           string                        `json:"protocol"`
	Transport          string                        `json:"transport"`
	OwnerID            string                        `json:"ownerId"`
	Config             map[string]any                `json:"config"`
	Secrets            map[string]string             `json:"secrets"`
	Credentials        map[string]CredentialRefState `json:"credentials,omitempty"`
	Recording          map[string]string             `json:"recording"`
	AIMode             string                        `json:"aiMode"`
	AIAllowDestructive bool                          `json:"aiAllowDestructive"`
}

ConnectionDetail is the client edit/detail view; it never carries secret values.

type ConnectionFolderDTO

type ConnectionFolderDTO struct {
	ID        string `json:"id"`
	ParentID  string `json:"parentId,omitempty"`
	Name      string `json:"name"`
	Color     string `json:"color"`
	SortOrder int    `json:"sortOrder"`
}

ConnectionFolderDTO is the client-facing folder record.

func FolderDTO

FolderDTO projects a folder for the browser.

type ConnectionFolderInput

type ConnectionFolderInput struct {
	Name     string
	Color    string
	ParentID string
}

ConnectionFolderInput is a sidebar folder create/update request.

type ConnectionFolderOrderInput

type ConnectionFolderOrderInput struct {
	FolderID  string `json:"folderId"`
	ParentID  string `json:"parentId"`
	SortOrder int    `json:"sortOrder"`
}

ConnectionFolderOrderInput is one sidebar folder position.

type ConnectionInput

type ConnectionInput struct {
	Name      string
	Protocol  string
	Transport string
	Config    map[string]any
	ActorID   string
	// PreserveCredentials names credential_ref fields whose existing stored
	// credential ID must be kept because the editor cannot read that credential.
	PreserveCredentials []string
	// Recording is the per-class policy (class -> disabled|manual|auto). A nil map
	// on update preserves the stored policy; on create it means recording is off.
	Recording map[string]string
	// AIMode gates the AI agent (disabled|read_only|read_write); AIAllowDestructive
	// is honored only with read_write.
	AIMode             string
	AIAllowDestructive bool
}

ConnectionInput is a create/update request.

type ConnectionPlacementInput

type ConnectionPlacementInput struct {
	ConnectionID string `json:"connectionId"`
	FolderID     string `json:"folderId"`
	SortOrder    int    `json:"sortOrder"`
}

ConnectionPlacementInput is one row of the user's sidebar layout.

type ConnectionService

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

ConnectionService owns connection config validation, secret encryption, and write-only secret update semantics.

func NewConnectionService

func NewConnectionService(conns store.ConnectionStore, plugins *plugin.Registry, creds *CredentialService, vault secrets.SecretStore) *ConnectionService

func (*ConnectionService) Create

Create validates, encrypts inline secrets, and persists a new connection.

func (*ConnectionService) CreateFolder

CreateFolder creates one user-owned sidebar folder.

func (*ConnectionService) Delete

func (s *ConnectionService) Delete(ctx context.Context, id string) error

func (*ConnectionService) Detail

Detail projects a connection to its non-secret edit view, marking each secret field as "set" or "not set" without revealing any value.

func (*ConnectionService) ReferencesCredential

func (s *ConnectionService) ReferencesCredential(ctx context.Context, credentialID string) (bool, error)

ReferencesCredential reports whether any connection config uses credentialID.

func (*ConnectionService) Update

Update re-validates and persists connection changes. Blank secrets keep the stored ciphertext.

func (*ConnectionService) UpdateFolder

UpdateFolder updates a user-owned sidebar folder.

type Connector

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

Connector assembles a plugin.ConnectConfig for a connection: it decrypts inline secrets, resolves any referenced credential (authorized for the acting user), and wires the transport for the connection's mode. Secret material lives only in the returned ConnectConfig — it is never serialized back to the client.

func NewConnector

func NewConnector(plugins *plugin.Registry, creds *CredentialService, vault secrets.SecretStore, tunnels transport.TunnelRegistry) *Connector

func (*Connector) Build

Build produces the ConnectConfig + plugin for a connection on behalf of user.

func (*Connector) Plugin

func (c *Connector) Plugin(conn models.Connection) (plugin.Plugin, bool)

Plugin resolves the plugin singleton for a connection's protocol.

func (*Connector) SetSecretAccessHook

func (c *Connector) SetSecretAccessHook(fn func())

SetSecretAccessHook registers a callback for successful inline secret decryptions.

type CredentialRefState

type CredentialRefState struct {
	State    string                    `json:"state"`
	Readable bool                      `json:"readable"`
	Summary  *models.CredentialSummary `json:"summary,omitempty"`
}

type CredentialService

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

CredentialService owns reusable credential encryption, resolution, and non-secret summaries.

func (*CredentialService) Create

Create encrypts the secret material and persists the credential.

func (*CredentialService) Delete

func (s *CredentialService) Delete(ctx context.Context, id string) error

Delete removes a credential after callers enforce reference checks.

func (*CredentialService) EnsureUsable

func (s *CredentialService) EnsureUsable(ctx context.Context, userID, credentialID string) error

EnsureUsable verifies owner/use access to a credential.

func (*CredentialService) EnsureUsableFor

func (s *CredentialService) EnsureUsableFor(ctx context.Context, userID, credentialID string, kinds []string, protocol string) error

EnsureUsableFor verifies that userID may use credentialID and that the credential matches the selector constraints for the connection protocol.

func (*CredentialService) ListUsable

func (s *CredentialService) ListUsable(ctx context.Context, userID string, kinds []string, protocol string) ([]models.CredentialSummary, error)

ListUsable returns the non-secret summaries the user may select for a credential_ref field, filtered by accepted kinds and an optional protocol.

func (*CredentialService) Resolve

func (s *CredentialService) Resolve(ctx context.Context, userID, credentialID string) ([]byte, error)

Resolve returns decrypted material for connect-time injection after use access.

func (*CredentialService) ResolveWithMetadata

func (s *CredentialService) ResolveWithMetadata(ctx context.Context, userID, credentialID string) (models.Credential, []byte, error)

ResolveWithMetadata returns metadata plus decrypted material after use access.

func (*CredentialService) SetSecretAccessHook

func (s *CredentialService) SetSecretAccessHook(fn func())

SetSecretAccessHook registers a callback for successful secret decryptions.

func (*CredentialService) SummaryIfUsable

func (s *CredentialService) SummaryIfUsable(ctx context.Context, userID, credentialID string) (models.CredentialSummary, bool)

SummaryIfUsable returns a non-secret summary only when userID has use access.

func (*CredentialService) Update

Update applies metadata changes and rotates the encrypted material when set.

type CredentialServiceOption

type CredentialServiceOption func(*CredentialService)

func WithCredentialKindCatalog

func WithCredentialKindCatalog(kinds plugin.CredentialKindCatalog) CredentialServiceOption

WithCredentialKindCatalog makes credential validation use the effective plugin registry catalog instead of only the core built-in kinds.

type Enrollment

type Enrollment struct {
	EnrollmentID string            `json:"enrollmentId"`
	ExpiresAt    time.Time         `json:"expiresAt"`
	Artifacts    []InstallArtifact `json:"artifacts"`
	// DownloadURL is where host-run installs fetch the agent binary.
	DownloadURL string `json:"downloadUrl"`
}

type EnrollmentService

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

EnrollmentService issues connection-scoped agent enrollment tokens.

func NewEnrollmentService

func NewEnrollmentService(s store.EnrollmentStore, conns store.ConnectionStore, plugins *plugin.Registry) *EnrollmentService

func (*EnrollmentService) Create

func (s *EnrollmentService) Create(ctx context.Context, connectionID, connectURL string, artifactURL ArtifactURLFunc) (Enrollment, error)

Create issues an enrollment and renders install artifacts.

func (*EnrollmentService) MarkOffline

func (s *EnrollmentService) MarkOffline(ctx context.Context, connectionID string)

MarkOffline flips a connection's online enrollment to offline (tunnel closed).

func (*EnrollmentService) Redeem

func (s *EnrollmentService) Redeem(ctx context.Context, token string) (connectionID string, proxy plugin.ProxyTarget, err error)

Redeem validates an agent-presented token and returns the connection it binds to plus the target the agent should proxy. An unused pending token must still be within its install window; an already-enrolled agent may reconnect with the same token until that enrollment is revoked.

func (*EnrollmentService) RenderArtifactContent

func (s *EnrollmentService) RenderArtifactContent(ctx context.Context, connectionID, enrollmentID, kind, connectURL string) (string, error)

RenderArtifactContent mints the token and renders a URL-delivered artifact.

func (*EnrollmentService) State

func (s *EnrollmentService) State(ctx context.Context, connectionID string) AgentState

State returns the latest agent status for a connection (for the enroll panel).

type InstallArtifact

type InstallArtifact struct {
	Label   string `json:"label"`
	Kind    string `json:"kind"`
	Command string `json:"command,omitempty"`
	URL     string `json:"url,omitempty"`
	// Content is an inline file body shown in the panel; Filename names it.
	Content  string `json:"content,omitempty"`
	Filename string `json:"filename,omitempty"`
}

InstallArtifact is a rendered launch recipe shown to the user.

type InvitationService

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

InvitationService issues account invitations, sends the link when email is configured, and consumes a token to create the account on acceptance.

func NewInvitationService

func NewInvitationService(invites store.InvitationStore, users *UserService, mailer Mailer) *InvitationService

func (*InvitationService) Accept

func (s *InvitationService) Accept(ctx context.Context, token, username, password string) (models.User, error)

Accept consumes an invitation, creating the account under the chosen username with the invitation's email and role.

func (*InvitationService) Create

func (s *InvitationService) Create(ctx context.Context, email string, role models.Role, inviterID, acceptURL string) (models.Invitation, string, bool, error)

Create issues an invitation. It returns the stored record and the raw token, which appears only here (in the acceptURL link) and as a stored hash.

func (*InvitationService) EmailEnabled

func (s *InvitationService) EmailEnabled() bool

EmailEnabled reports whether invitations are also delivered by email.

func (*InvitationService) List

func (*InvitationService) Lookup

func (s *InvitationService) Lookup(ctx context.Context, token string) (models.Invitation, error)

Lookup validates a raw token and returns the pending invitation behind it.

func (*InvitationService) Revoke

func (s *InvitationService) Revoke(ctx context.Context, id string) error

type Mailer

type Mailer interface {
	Enabled() bool
	Send(to, subject, body string) error
}

Mailer sends invitation emails; satisfied by internal/email.Mailer.

type NewCredentialInput

type NewCredentialInput struct {
	OwnerID  string
	Name     string
	Kind     string
	Identity string
	Secret   string
}

NewCredentialInput describes a credential to create.

type NewUserInput

type NewUserInput struct {
	Username    string
	Email       string
	DisplayName string
	Roles       []models.Role
	Password    string
	Protected   bool
}

NewUserInput describes an account to create (password in plaintext).

type RecordingService

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

RecordingService is the control-plane read/lifecycle side of recordings: authorized listing, retrieval, deletion, blob content access, and retention cleanup. Read scope is role-aware — admins see everything, others see their own recordings only.

func NewRecordingService

func NewRecordingService(recs store.RecordingStore, blobs recording.BlobStore) *RecordingService

func (*RecordingService) Cleanup

func (s *RecordingService) Cleanup(ctx context.Context, now time.Time) (int, error)

Cleanup deletes the blobs of recordings expired as of now and marks their metadata discarded. It is a no-op for already-discarded rows.

func (*RecordingService) Content

Content opens the recording's blob for a finalized recording the actor may see.

func (*RecordingService) Create

Create persists initial recording metadata.

func (*RecordingService) Delete

func (s *RecordingService) Delete(ctx context.Context, actor models.User, id string) (models.Recording, error)

Delete removes a recording's blob and metadata if the actor may manage it.

func (*RecordingService) Get

Get returns one recording if the actor may see it.

func (*RecordingService) List

List returns the actor's own recordings; the query is always scoped to them.

type TOTPEnrollment

type TOTPEnrollment struct {
	Secret      string
	OTPAuthURL  string
	QRDataURL   string
	AccountName string
}

TOTPEnrollment is the provisioning material for an authenticator app.

type TwoFactorService

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

TwoFactorService owns TOTP enrollment, verification, and recovery codes. The secret is vault-encrypted at rest; only recovery-code hashes are stored.

func NewTwoFactorService

func NewTwoFactorService(users store.UserStore, vault secrets.SecretStore, issuer string) *TwoFactorService

func (*TwoFactorService) BeginEnrollment

func (s *TwoFactorService) BeginEnrollment(ctx context.Context, user models.User) (TOTPEnrollment, error)

BeginEnrollment stores a fresh, not-yet-confirmed secret and returns its QR.

func (*TwoFactorService) ConfirmEnrollment

func (s *TwoFactorService) ConfirmEnrollment(ctx context.Context, user models.User, code string) ([]string, error)

ConfirmEnrollment validates the first code and returns one-time recovery codes.

func (*TwoFactorService) Disable

func (s *TwoFactorService) Disable(ctx context.Context, user models.User, code string) error

Disable turns off 2FA after verifying a current code.

func (*TwoFactorService) RegenerateRecoveryCodes

func (s *TwoFactorService) RegenerateRecoveryCodes(ctx context.Context, user models.User, code string) ([]string, error)

RegenerateRecoveryCodes verifies a code, then replaces the recovery codes.

func (*TwoFactorService) Remind

func (s *TwoFactorService) Remind(ctx context.Context, userID string) error

Remind records that the user was just nudged.

func (*TwoFactorService) Reset

func (s *TwoFactorService) Reset(ctx context.Context, userID string) error

Reset clears a user's 2FA without a code (admin break-glass); callers gate it.

func (*TwoFactorService) ShouldRemind

func (s *TwoFactorService) ShouldRemind(user models.User) bool

ShouldRemind reports whether to nudge the user to enable 2FA.

func (*TwoFactorService) Verify

func (s *TwoFactorService) Verify(ctx context.Context, user models.User, code string) (bool, error)

Verify checks a TOTP or single-use recovery code.

type UpdateCredentialInput

type UpdateCredentialInput struct {
	Name     string
	Kind     string
	Identity string
	Secret   string
}

UpdateCredentialInput updates metadata and optionally rotates the secret.

type UpdateUserInput

type UpdateUserInput struct {
	Email       string
	DisplayName string
	Roles       []models.Role
	Disabled    bool
}

UpdateUserInput changes an account's profile, roles, and enabled state.

type UserService

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

UserService manages platform accounts: it hashes passwords on write and never returns hashes (the store clears them on read).

func NewUserService

func NewUserService(users store.UserStore) *UserService

func (*UserService) ChangePassword

func (s *UserService) ChangePassword(ctx context.Context, id, current, next string) error

ChangePassword verifies the current password before setting a new one.

func (*UserService) Create

func (s *UserService) Create(ctx context.Context, in NewUserInput) (models.User, error)

func (*UserService) Delete

func (s *UserService) Delete(ctx context.Context, id string) error

func (*UserService) Get

func (s *UserService) Get(ctx context.Context, id string) (models.User, error)

func (*UserService) List

func (s *UserService) List(ctx context.Context) ([]models.User, error)

func (*UserService) Update

func (s *UserService) Update(ctx context.Context, id string, in UpdateUserInput) (models.User, error)

func (*UserService) UpdateProfile

func (s *UserService) UpdateProfile(ctx context.Context, id, email, displayName string) (models.User, error)

UpdateProfile changes only a user's own profile fields (display name + email). Username, roles, and enabled state are intentionally left untouched.

Jump to

Keyboard shortcuts

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