Documentation
¶
Overview ¶
Package service holds the application business logic.
Index ¶
- Constants
- Variables
- func SaveConnectionFolderOrder(ctx context.Context, folderStore store.ConnectionFolderStore, userID string, ...) error
- func SaveConnectionLayout(ctx context.Context, placements store.ConnectionPlacementStore, userID string, ...) error
- func ValidatePassword(password string) error
- type AgentState
- type ArtifactURLFunc
- type ConnectionDetail
- type ConnectionFolderDTO
- type ConnectionFolderInput
- type ConnectionFolderOrderInput
- type ConnectionInput
- type ConnectionPlacementInput
- type ConnectionService
- func (s *ConnectionService) Create(ctx context.Context, ownerID string, in ConnectionInput) (models.Connection, error)
- func (s *ConnectionService) CreateFolder(ctx context.Context, folders store.ConnectionFolderStore, userID string, ...) (models.ConnectionFolder, error)
- func (s *ConnectionService) Delete(ctx context.Context, id string) error
- func (s *ConnectionService) Detail(ctx context.Context, userID string, conn models.Connection) ConnectionDetail
- func (s *ConnectionService) ReferencesCredential(ctx context.Context, credentialID string) (bool, error)
- func (s *ConnectionService) Update(ctx context.Context, existing models.Connection, in ConnectionInput) (models.Connection, error)
- func (s *ConnectionService) UpdateFolder(ctx context.Context, folders store.ConnectionFolderStore, ...) (models.ConnectionFolder, error)
- type Connector
- type CredentialRefState
- type CredentialService
- func (s *CredentialService) Create(ctx context.Context, in NewCredentialInput) (models.Credential, error)
- func (s *CredentialService) Delete(ctx context.Context, id string) error
- func (s *CredentialService) EnsureUsable(ctx context.Context, userID, credentialID string) error
- func (s *CredentialService) EnsureUsableFor(ctx context.Context, userID, credentialID string, kinds []string, ...) error
- func (s *CredentialService) ListUsable(ctx context.Context, userID string, kinds []string, protocol string) ([]models.CredentialSummary, error)
- func (s *CredentialService) Resolve(ctx context.Context, userID, credentialID string) ([]byte, error)
- func (s *CredentialService) ResolveWithMetadata(ctx context.Context, userID, credentialID string) (models.Credential, []byte, error)
- func (s *CredentialService) SetSecretAccessHook(fn func())
- func (s *CredentialService) SummaryIfUsable(ctx context.Context, userID, credentialID string) (models.CredentialSummary, bool)
- func (s *CredentialService) Update(ctx context.Context, id string, in UpdateCredentialInput) (models.Credential, error)
- type CredentialServiceOption
- type Enrollment
- type EnrollmentService
- func (s *EnrollmentService) Create(ctx context.Context, connectionID, connectURL string, ...) (Enrollment, error)
- func (s *EnrollmentService) MarkOffline(ctx context.Context, connectionID string)
- func (s *EnrollmentService) Redeem(ctx context.Context, token string) (connectionID string, proxy plugin.ProxyTarget, err error)
- func (s *EnrollmentService) RenderArtifactContent(ctx context.Context, connectionID, enrollmentID, kind, connectURL string) (string, error)
- func (s *EnrollmentService) State(ctx context.Context, connectionID string) AgentState
- type InstallArtifact
- type InvitationService
- func (s *InvitationService) Accept(ctx context.Context, token, username, password string) (models.User, error)
- func (s *InvitationService) Create(ctx context.Context, email string, role models.Role, ...) (models.Invitation, string, bool, error)
- func (s *InvitationService) EmailEnabled() bool
- func (s *InvitationService) List(ctx context.Context) ([]models.InvitationSummary, error)
- func (s *InvitationService) Lookup(ctx context.Context, token string) (models.Invitation, error)
- func (s *InvitationService) Revoke(ctx context.Context, id string) error
- type Mailer
- type NewCredentialInput
- type NewUserInput
- type RecordingService
- func (s *RecordingService) Cleanup(ctx context.Context, now time.Time) (int, error)
- func (s *RecordingService) Content(ctx context.Context, actor models.User, id string) (io.ReadCloser, models.Recording, error)
- func (s *RecordingService) Create(ctx context.Context, r *models.Recording) error
- func (s *RecordingService) Delete(ctx context.Context, actor models.User, id string) (models.Recording, error)
- func (s *RecordingService) Get(ctx context.Context, actor models.User, id string) (models.Recording, error)
- func (s *RecordingService) List(ctx context.Context, actor models.User, f store.RecordingFilter) ([]models.Recording, error)
- type TOTPEnrollment
- type TwoFactorService
- func (s *TwoFactorService) BeginEnrollment(ctx context.Context, user models.User) (TOTPEnrollment, error)
- func (s *TwoFactorService) ConfirmEnrollment(ctx context.Context, user models.User, code string) ([]string, error)
- func (s *TwoFactorService) Disable(ctx context.Context, user models.User, code string) error
- func (s *TwoFactorService) RegenerateRecoveryCodes(ctx context.Context, user models.User, code string) ([]string, error)
- func (s *TwoFactorService) Remind(ctx context.Context, userID string) error
- func (s *TwoFactorService) Reset(ctx context.Context, userID string) error
- func (s *TwoFactorService) ShouldRemind(user models.User) bool
- func (s *TwoFactorService) Verify(ctx context.Context, user models.User, code string) (bool, error)
- type UpdateCredentialInput
- type UpdateUserInput
- type UserService
- func (s *UserService) ChangePassword(ctx context.Context, id, current, next string) error
- func (s *UserService) Create(ctx context.Context, in NewUserInput) (models.User, error)
- func (s *UserService) Delete(ctx context.Context, id string) error
- func (s *UserService) Get(ctx context.Context, id string) (models.User, error)
- func (s *UserService) List(ctx context.Context) ([]models.User, error)
- func (s *UserService) Update(ctx context.Context, id string, in UpdateUserInput) (models.User, error)
- func (s *UserService) UpdateProfile(ctx context.Context, id, email, displayName string) (models.User, error)
Constants ¶
const DefaultEnrollmentTTL = 15 * time.Minute
DefaultEnrollmentTTL is how long an unused enrollment token stays valid.
const DefaultInvitationTTL = 72 * time.Hour
DefaultInvitationTTL is how long an unaccepted invitation stays valid.
const DefaultProxyImage = app.AgentImageLatest
DefaultProxyImage is the container image install artifacts default to.
const MinPasswordLength = 8
Variables ¶
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") )
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") )
var ErrInvitationInvalid = errors.New("service: invalid or expired invitation")
ErrInvitationInvalid is returned for an unknown, expired, or consumed token.
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 ¶
Types ¶
type AgentState ¶
AgentState is the polled status the UI shows in the enroll panel.
type ArtifactURLFunc ¶
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 ¶
func FolderDTO(f models.ConnectionFolder) ConnectionFolderDTO
FolderDTO projects a folder for the browser.
type ConnectionFolderInput ¶
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 ¶
func (s *ConnectionService) Create(ctx context.Context, ownerID string, in ConnectionInput) (models.Connection, error)
Create validates, encrypts inline secrets, and persists a new connection.
func (*ConnectionService) CreateFolder ¶
func (s *ConnectionService) CreateFolder(ctx context.Context, folders store.ConnectionFolderStore, userID string, in ConnectionFolderInput) (models.ConnectionFolder, error)
CreateFolder creates one user-owned sidebar folder.
func (*ConnectionService) Delete ¶
func (s *ConnectionService) Delete(ctx context.Context, id string) error
func (*ConnectionService) Detail ¶
func (s *ConnectionService) Detail(ctx context.Context, userID string, conn models.Connection) ConnectionDetail
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 ¶
func (s *ConnectionService) Update(ctx context.Context, existing models.Connection, in ConnectionInput) (models.Connection, error)
Update re-validates and persists connection changes. Blank secrets keep the stored ciphertext.
func (*ConnectionService) UpdateFolder ¶
func (s *ConnectionService) UpdateFolder(ctx context.Context, folders store.ConnectionFolderStore, existing models.ConnectionFolder, in ConnectionFolderInput) (models.ConnectionFolder, error)
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 ¶
func (c *Connector) Build(ctx context.Context, _ models.User, conn models.Connection) (plugin.ConnectConfig, plugin.Plugin, error)
Build produces the ConnectConfig + plugin for a connection on behalf of user.
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 NewCredentialService ¶
func NewCredentialService(creds store.CredentialStore, grants store.CredentialGrantStore, vault secrets.SecretStore, opts ...CredentialServiceOption) *CredentialService
func (*CredentialService) Create ¶
func (s *CredentialService) Create(ctx context.Context, in NewCredentialInput) (models.Credential, error)
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 ¶
func (s *CredentialService) Update(ctx context.Context, id string, in UpdateCredentialInput) (models.Credential, error)
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 (s *InvitationService) List(ctx context.Context) ([]models.InvitationSummary, error)
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.
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 ¶
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 ¶
func (s *RecordingService) Content(ctx context.Context, actor models.User, id string) (io.ReadCloser, models.Recording, error)
Content opens the recording's blob for a finalized recording the actor may see.
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.
type TOTPEnrollment ¶
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) 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.
type UpdateCredentialInput ¶
UpdateCredentialInput updates metadata and optionally rotates the secret.
type UpdateUserInput ¶
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) 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.