Documentation
¶
Index ¶
- Constants
- Variables
- func GetCheckInterval() time.Duration
- func IdempotencyStatus(o IdempotencyOutcome) int
- func UnverifiedCleanupDisabledReason(smtpConfigured, oidcEnabled bool) string
- type AircraftService
- func (s *AircraftService) CountAircraft(ctx context.Context, userID uuid.UUID) (int, error)
- func (s *AircraftService) CreateAircraft(ctx context.Context, aircraft *models.Aircraft) error
- func (s *AircraftService) DeleteAircraft(ctx context.Context, id, userID uuid.UUID) error
- func (s *AircraftService) GetAircraft(ctx context.Context, id, userID uuid.UUID) (*models.Aircraft, error)
- func (s *AircraftService) GetAircraftStats(ctx context.Context, userID uuid.UUID) (*AircraftStatsResult, error)
- func (s *AircraftService) ListAircraft(ctx context.Context, userID uuid.UUID) ([]*models.Aircraft, error)
- func (s *AircraftService) ListAircraftUpdatedSince(ctx context.Context, userID uuid.UUID, updatedSince time.Time) ([]*models.Aircraft, error)
- func (s *AircraftService) UpdateAircraft(ctx context.Context, aircraft *models.Aircraft, userID uuid.UUID, ...) (int, error)
- type AircraftStatsResult
- type AuthService
- func (s *AuthService) ChangePassword(ctx context.Context, userID uuid.UUID, currentPassword, newPassword string) error
- func (s *AuthService) CreateEmailVerificationToken(ctx context.Context, userID uuid.UUID) (string, error)
- func (s *AuthService) DeleteUser(ctx context.Context, userID uuid.UUID, password string) error
- func (s *AuthService) DeleteUserConfirmed(ctx context.Context, userID uuid.UUID) error
- func (s *AuthService) GenerateTokensForUser(ctx context.Context, userID uuid.UUID) (*TokenPair, error)
- func (s *AuthService) GetUserByID(ctx context.Context, userID uuid.UUID) (*models.User, error)
- func (s *AuthService) Login(ctx context.Context, input LoginInput) (*models.User, *TokenPair, error)
- func (s *AuthService) Logout(ctx context.Context, refreshToken string) error
- func (s *AuthService) MarkEmailVerified(ctx context.Context, userID uuid.UUID) error
- func (s *AuthService) RecordLogin(ctx context.Context, user *models.User)
- func (s *AuthService) RefreshToken(ctx context.Context, refreshToken string) (*TokenPair, error)
- func (s *AuthService) Register(ctx context.Context, input RegisterInput) (*models.User, string, error)
- func (s *AuthService) RequestPasswordReset(ctx context.Context, email string) (*PasswordResetRequest, error)
- func (s *AuthService) ResendVerification(ctx context.Context, email string) (token, userEmail, userName, locale string, err error)
- func (s *AuthService) ResetPassword(ctx context.Context, token, newPassword, twoFactorCode string) (*PasswordResetResult, error)
- func (s *AuthService) RevokeAllSessions(ctx context.Context, userID uuid.UUID) error
- func (s *AuthService) UpdateUser(ctx context.Context, user *models.User) error
- func (s *AuthService) VerifyEmail(ctx context.Context, token string) (*models.User, *TokenPair, error)
- func (s *AuthService) VerifyPassword(ctx context.Context, userID uuid.UUID, password string) error
- type ClassRatingRepository
- type ClassRatingService
- func (s *ClassRatingService) CreateClassRating(ctx context.Context, cr *models.ClassRating, userID uuid.UUID) error
- func (s *ClassRatingService) DeleteClassRating(ctx context.Context, ratingID, userID uuid.UUID) error
- func (s *ClassRatingService) GetClassRating(ctx context.Context, ratingID, userID uuid.UUID) (*models.ClassRating, error)
- func (s *ClassRatingService) ListClassRatings(ctx context.Context, licenseID, userID uuid.UUID) ([]*models.ClassRating, error)
- func (s *ClassRatingService) UpdateClassRating(ctx context.Context, cr *models.ClassRating, userID uuid.UUID) error
- type ContactService
- func (s *ContactService) CreateContact(ctx context.Context, contact *models.Contact) error
- func (s *ContactService) DeleteContact(ctx context.Context, id, userID uuid.UUID) error
- func (s *ContactService) ExportVCard(ctx context.Context, userID uuid.UUID) ([]byte, error)
- func (s *ContactService) FindOrCreateContact(ctx context.Context, userID uuid.UUID, name string) (*models.Contact, bool, error)
- func (s *ContactService) GetContact(ctx context.Context, id, userID uuid.UUID) (*models.Contact, error)
- func (s *ContactService) LinkCrewMembers(ctx context.Context, userID uuid.UUID, members []models.FlightCrewMember) (int, error)
- func (s *ContactService) ListContacts(ctx context.Context, userID uuid.UUID) ([]*models.Contact, error)
- func (s *ContactService) ListContactsUpdatedSince(ctx context.Context, userID uuid.UUID, updatedSince time.Time) ([]*models.Contact, error)
- func (s *ContactService) NewCrewLinker(userID uuid.UUID) *CrewLinker
- func (s *ContactService) SearchContacts(ctx context.Context, userID uuid.UUID, query string, limit int) ([]*models.Contact, error)
- func (s *ContactService) UpdateContact(ctx context.Context, contact *models.Contact, userID uuid.UUID) (int, error)
- type CredentialService
- func (s *CredentialService) CreateCredential(ctx context.Context, credential *models.Credential) error
- func (s *CredentialService) DeleteCredential(ctx context.Context, id, userID uuid.UUID) error
- func (s *CredentialService) GetCredential(ctx context.Context, id, userID uuid.UUID) (*models.Credential, error)
- func (s *CredentialService) ListCredentials(ctx context.Context, userID uuid.UUID) ([]*models.Credential, error)
- func (s *CredentialService) ListCredentialsUpdatedSince(ctx context.Context, userID uuid.UUID, updatedSince time.Time) ([]*models.Credential, error)
- func (s *CredentialService) UpdateCredential(ctx context.Context, credential *models.Credential, userID uuid.UUID) error
- type CrewLinker
- type CurrencyResult
- type DeletionPage
- type DeletionService
- type DocumentFileService
- func (s *DocumentFileService) Delete(ctx context.Context, userID uuid.UUID, subject models.DocumentSubjectType, ...) error
- func (s *DocumentFileService) Enabled() bool
- func (s *DocumentFileService) Get(ctx context.Context, userID uuid.UUID, subject models.DocumentSubjectType, ...) (*models.DocumentFile, error)
- func (s *DocumentFileService) List(ctx context.Context, userID uuid.UUID, subject models.DocumentSubjectType, ...) ([]*models.DocumentFile, error)
- func (s *DocumentFileService) Upload(ctx context.Context, userID uuid.UUID, subject models.DocumentSubjectType, ...) (*models.DocumentFile, error)
- type EmailDeliveryService
- func (s *EmailDeliveryService) CountSuppressions(ctx context.Context) (int, error)
- func (s *EmailDeliveryService) IsSuppressed(ctx context.Context, recipient string) bool
- func (s *EmailDeliveryService) ListEvents(ctx context.Context, recipient string, limit int) ([]*models.EmailDeliveryEvent, error)
- func (s *EmailDeliveryService) ListSuppressions(ctx context.Context, limit int) ([]*models.EmailSuppression, error)
- func (s *EmailDeliveryService) RecordAttempt(ctx context.Context, a emailpkg.Attempt)
- func (s *EmailDeliveryService) RefreshSuppressionGauge(ctx context.Context)
- func (s *EmailDeliveryService) Unsuppress(ctx context.Context, email string) error
- func (s *EmailDeliveryService) UserIDForEmail(ctx context.Context, email string) (uuid.UUID, error)
- type FlightService
- func (s *FlightService) CountFlights(ctx context.Context, userID uuid.UUID, opts *repository.FlightQueryOptions) (int, error)
- func (s *FlightService) CreateFlight(ctx context.Context, flight *models.Flight) error
- func (s *FlightService) DeleteAllFlights(ctx context.Context, userID uuid.UUID) (int64, error)
- func (s *FlightService) DeleteBaseline(ctx context.Context, userID uuid.UUID) error
- func (s *FlightService) DeleteFlight(ctx context.Context, flightID, userID uuid.UUID) error
- func (s *FlightService) GetBaseline(ctx context.Context, userID uuid.UUID) (*models.FlightBaseline, error)
- func (s *FlightService) GetCurrency(ctx context.Context, userID uuid.UUID) (*CurrencyResult, error)
- func (s *FlightService) GetFlight(ctx context.Context, flightID, userID uuid.UUID) (*models.Flight, error)
- func (s *FlightService) GetStatsByUserID(ctx context.Context, userID uuid.UUID, startDate, endDate *time.Time, ...) (*models.FlightStatistics, *models.FlightBaseline, error)
- func (s *FlightService) ListFlights(ctx context.Context, userID uuid.UUID, opts *repository.FlightQueryOptions) ([]*models.Flight, error)
- func (s *FlightService) UpdateFlight(ctx context.Context, flight *models.Flight, userID uuid.UUID) error
- func (s *FlightService) UpsertBaseline(ctx context.Context, baseline *models.FlightBaseline) error
- type FlightSessionEventInput
- type FlightSessionService
- func (s *FlightSessionService) Discard(ctx context.Context, userID uuid.UUID) error
- func (s *FlightSessionService) GetCurrent(ctx context.Context, userID uuid.UUID) (*models.FlightSession, error)
- func (s *FlightSessionService) RecordEvent(ctx context.Context, userID uuid.UUID, input FlightSessionEventInput) (*models.FlightSession, bool, error)
- type FlightSignatureService
- func (s *FlightSignatureService) CompleteFromToken(ctx context.Context, token, signerName string, credentialNo *string, ...) (sig *models.FlightSignature, ownerEmail, ownerName string, err error)
- func (s *FlightSignatureService) CreateRequest(ctx context.Context, flightID, userID uuid.UUID, instructorEmail *string, ...) (sig *models.FlightSignature, rawToken string, err error)
- func (s *FlightSignatureService) ExpirePendingRequests(ctx context.Context) (int64, error)
- func (s *FlightSignatureService) Get(ctx context.Context, flightID, userID, signatureID uuid.UUID) (*models.FlightSignature, error)
- func (s *FlightSignatureService) List(ctx context.Context, flightID, userID uuid.UUID) ([]*models.FlightSignature, error)
- func (s *FlightSignatureService) MarkEmailSent(ctx context.Context, sig *models.FlightSignature) error
- func (s *FlightSignatureService) Resend(ctx context.Context, flightID, userID, signatureID uuid.UUID, ...) (sig *models.FlightSignature, rawToken string, err error)
- func (s *FlightSignatureService) ResolveToken(ctx context.Context, token string) (*models.FlightSignature, *models.Flight, error)
- func (s *FlightSignatureService) Revoke(ctx context.Context, flightID, userID, signatureID uuid.UUID) error
- func (s *FlightSignatureService) SignLive(ctx context.Context, flightID, userID uuid.UUID, signerName string, ...) (*models.FlightSignature, error)
- func (s *FlightSignatureService) Void(ctx context.Context, flightID, userID, signatureID uuid.UUID, reason string) error
- type IdempotencyClaim
- type IdempotencyOutcome
- type IdempotencyService
- func (s *IdempotencyService) Abandon(ctx context.Context, userID uuid.UUID, key string, claimedAt time.Time) error
- func (s *IdempotencyService) Begin(ctx context.Context, userID uuid.UUID, key string, requestHash []byte) (IdempotencyClaim, error)
- func (s *IdempotencyService) Finish(ctx context.Context, userID uuid.UUID, key string, claimedAt time.Time, ...) error
- func (s *IdempotencyService) MaxResponseBytes() int
- func (s *IdempotencyService) StartReaper(ctx context.Context, interval time.Duration)
- type IdempotentResponse
- type LicenseService
- func (s *LicenseService) CreateLicense(ctx context.Context, license *models.License) error
- func (s *LicenseService) DeleteLicense(ctx context.Context, licenseID, userID uuid.UUID) error
- func (s *LicenseService) GetLicense(ctx context.Context, licenseID, userID uuid.UUID) (*models.License, error)
- func (s *LicenseService) ListLicenses(ctx context.Context, userID uuid.UUID) ([]*models.License, error)
- func (s *LicenseService) ListLicensesUpdatedSince(ctx context.Context, userID uuid.UUID, updatedSince time.Time) ([]*models.License, error)
- func (s *LicenseService) UpdateLicense(ctx context.Context, license *models.License, userID uuid.UUID) error
- type LoginInput
- type NotificationService
- func (s *NotificationService) GetNotificationHistory(ctx context.Context, userID uuid.UUID, limit, offset int) ([]*models.NotificationLog, int, error)
- func (s *NotificationService) GetPreferences(ctx context.Context, userID uuid.UUID) (*models.NotificationPreferences, error)
- func (s *NotificationService) StartBackgroundChecker(ctx context.Context, interval time.Duration)
- func (s *NotificationService) TriggerCheck(ctx context.Context)
- func (s *NotificationService) UpdatePreferences(ctx context.Context, prefs *models.NotificationPreferences) error
- type OIDCAuthorization
- type OIDCConfig
- type OIDCService
- func (s *OIDCService) BeginLogin(ctx context.Context) (*OIDCAuthorization, error)
- func (s *OIDCService) CompleteCallback(ctx context.Context, code, state, browserToken string) (string, error)
- func (s *OIDCService) Config() OIDCConfig
- func (s *OIDCService) ExchangeHandoff(ctx context.Context, handoff string) (*models.User, *TokenPair, error)
- func (s *OIDCService) PostLoginRedirect() string
- func (s *OIDCService) StartStateReaper(ctx context.Context, interval time.Duration)
- type PasswordResetRequest
- type PasswordResetResult
- type RegisterInput
- type TokenPair
- type TwoFactorService
- func (s *TwoFactorService) Disable(ctx context.Context, userID uuid.UUID, password string) error
- func (s *TwoFactorService) IsEnabled(ctx context.Context, userID uuid.UUID) (bool, error)
- func (s *TwoFactorService) SetupTOTP(ctx context.Context, userID uuid.UUID) (string, string, error)
- func (s *TwoFactorService) ValidateTOTP(ctx context.Context, userID uuid.UUID, code string) (bool, error)
- func (s *TwoFactorService) VerifyAndEnable(ctx context.Context, userID uuid.UUID, code string) ([]string, error)
- type TwoFactorValidator
- type UnverifiedAccountConfig
- type UnverifiedAccountService
- type UploadInput
- type WebAuthnService
- func (s *WebAuthnService) BeginLogin(ctx context.Context, email string) (handle string, options *protocol.CredentialAssertion, err error)
- func (s *WebAuthnService) BeginRegistration(ctx context.Context, userID uuid.UUID) (handle string, options *protocol.CredentialCreation, err error)
- func (s *WebAuthnService) DeleteCredential(ctx context.Context, userID, credentialID uuid.UUID) error
- func (s *WebAuthnService) FinishLogin(ctx context.Context, handle string, responseJSON []byte) (*models.User, *TokenPair, error)
- func (s *WebAuthnService) FinishRegistration(ctx context.Context, userID uuid.UUID, handle string, label *string, ...) (*models.WebAuthnCredential, error)
- func (s *WebAuthnService) ListCredentials(ctx context.Context, userID uuid.UUID) ([]*models.WebAuthnCredential, error)
- func (s *WebAuthnService) StartSessionReaper(ctx context.Context, interval time.Duration)
Constants ¶
const ( // DefaultTombstoneRetention bounds how long a deletion stays reportable. DefaultTombstoneRetention = 90 * 24 * time.Hour // DefaultDeletionPageSize / MaxDeletionPageSize bound the feed. DefaultDeletionPageSize = 100 MaxDeletionPageSize = 500 )
const ( DefaultDeliveryEventLimit = 100 MaxDeliveryEventLimit = 500 )
DefaultDeliveryEventLimit / MaxDeliveryEventLimit bound the admin listing.
const ( // DefaultIdempotencyTTL is how long a key stays replayable. DefaultIdempotencyTTL = 24 * time.Hour // DefaultIdempotencyLease is how long an in-progress claim is honoured // before another request may take it over. Must exceed the request // timeout (15s). DefaultIdempotencyLease = 60 * time.Second // DefaultIdempotencyMaxResponseBytes caps what is stored per record. DefaultIdempotencyMaxResponseBytes = 256 << 10 )
Defaults for idempotent-write bookkeeping. All three are overridable at startup (IDEMPOTENCY_TTL, IDEMPOTENCY_LEASE, IDEMPOTENCY_MAX_RESPONSE_BYTES).
const ( // DefaultOIDCLoginStateTTL bounds how long a pending authorization // request stays usable. DefaultOIDCLoginStateTTL = 10 * time.Minute // DefaultOIDCHandoffTTL bounds the window between the provider // redirecting the browser back and the SPA exchanging its code for // tokens. DefaultOIDCHandoffTTL = 60 * time.Second )
OIDC login mode. NinerLog runs in exactly one authentication mode: setting OIDC_ISSUER switches the deployment to OIDC and turns off every local credential path — passwords, registration, password reset, TOTP and passkeys.
const ( // PasswordMinLength is the shortest accepted password. PasswordMinLength = 12 // PasswordMaxLength is the longest accepted password (bcrypt's 72-byte // input limit). PasswordMaxLength = 72 )
Local password policy, shared by every flow that sets a password: registration, password reset and password change.
const ( DefaultVerificationReminderAfter = 24 * time.Hour DefaultUnverifiedRetention = 30 * 24 * time.Hour DefaultUnverifiedSweepInterval = time.Hour )
Defaults for the unverified-account lifecycle: one reminder a day after signup, and that reminder starts a 30-day deletion clock.
const ( // CleanupDisabledByOIDC: OIDC mode refuses the feature outright; it is // not configurable. CleanupDisabledByOIDC = "oidc_mode" // CleanupDisabledNoSMTP: without SMTP, registration marks accounts // verified on the spot. CleanupDisabledNoSMTP = "smtp_not_configured" // CleanupDisabledByConfig: UNVERIFIED_CLEANUP_ENABLED=false. CleanupDisabledByConfig = "disabled_by_configuration" )
Reasons the reaper is not running, reported to administrators.
const ( // DefaultWebAuthnSessionTTL is used when WEBAUTHN_SESSION_TTL is unset. DefaultWebAuthnSessionTTL = 5 * time.Minute // DefaultWebAuthnMaxOpenCeremonies is used when // WEBAUTHN_MAX_OPEN_CEREMONIES is unset. DefaultWebAuthnMaxOpenCeremonies = 10 )
Variables ¶
var ( ErrAircraftNotFound = errors.New("aircraft not found") ErrDuplicateRegistration = errors.New("aircraft registration already exists") )
var ( ErrUserAlreadyExists = errors.New("user already exists") ErrInvalidCredentials = errors.New("invalid credentials") ErrInvalidToken = errors.New("invalid token") ErrTokenExpired = errors.New("token expired") ErrTokenRevoked = errors.New("token revoked") ErrTokenUsed = errors.New("token already used") ErrAccountLocked = errors.New("account temporarily locked due to too many failed login attempts") ErrAccountDisabled = errors.New("account disabled by administrator") ErrEmailNotVerified = errors.New("email address not verified") ErrPasswordTooShort = errors.New("password must be at least 12 characters") ErrPasswordTooLong = errors.New("password must not exceed 72 characters") ErrPasswordTooWeak = errors.New("password must contain at least one lowercase letter, one uppercase letter, one digit and one special character") ErrEmailRequired = errors.New("email is required") ErrPasswordRequired = errors.New("password is required") ErrNameRequired = errors.New("name is required") ErrInvalidEmail = errors.New("invalid email format") ErrEmailTooLong = errors.New("email must not exceed 255 characters") // ErrPasswordNotSet marks an account that has no local password (an OIDC // account). ErrPasswordNotSet = errors.New("account has no local password") // ErrTwoFactorRequired is returned by ResetPassword when the account has 2FA // enabled and the caller supplied no code; the reset token is left unused. ErrTwoFactorRequired = errors.New("two-factor authentication code required") // but no validator is wired. ErrTwoFactorUnavailable = errors.New("two-factor verification is unavailable") )
var ( ErrClassRatingNotFound = errors.New("class rating not found") ErrInvalidClassType = errors.New("invalid class type") )
var ( ErrContactNotFound = errors.New("contact not found") // ErrContactNameExists is returned when a create or rename would give the // user two contacts with the same name. ErrContactNameExists = errors.New("a contact with this name already exists") // ErrContactNameRequired is returned for an empty or whitespace-only name. ErrContactNameRequired = errors.New("contact name is required") )
var ( ErrCredentialNotFound = errors.New("credential not found") ErrExpiryBeforeIssue = errors.New("expiry date must be after issue date") )
var ( // ErrDocumentFilesDisabled is returned from every image endpoint — reads // included — when the feature is switched off (DOCUMENT_FILES_ENABLED= // false). Stored rows are left untouched and become reachable again when // it is turned back on. ErrDocumentFilesDisabled = errors.New("document image uploads are disabled on this server") // ErrDocumentFileNotFound covers both "no such image" and "that image // belongs to a different document or user"; the caller cannot tell them // apart. ErrDocumentFileNotFound = errors.New("document image not found") // ErrDocumentSubjectNotFound means the licence or credential the image // would hang off does not exist or is not the caller's. ErrDocumentSubjectNotFound = errors.New("document not found") ErrDocumentFileEmpty = errors.New("image file is empty") ErrDocumentFileTooLarge = errors.New("image exceeds the maximum size") ErrDocumentFileUnsupported = errors.New("unsupported image format") ErrDocumentFileCorrupt = errors.New("image could not be decoded") ErrDocumentFileTooManyPixel = errors.New("image resolution is too large") ErrDocumentFileLimitReached = errors.New("maximum number of images for this document reached") )
var ( ErrFlightNotFound = errors.New("flight not found") ErrInvalidFlight = errors.New("invalid flight data") // ErrFlightLocked is returned when attempting to update or delete a // flight that carries a completed, non-voided instructor signature. The // signature must be voided (see FlightSignatureService.Void) before the // flight can be edited or deleted again. ErrFlightLocked = errors.New("flight is locked by a completed signature") )
var ( // ErrSignatureNotFound covers both "no signature with this ID" and, for // the public token flow, "no signature with this token"; the latter is // aliased to ErrSignatureTokenInvalid. ErrSignatureNotFound = errors.New("signature request not found") // ErrSignaturePendingExists is returned when creating a new deferred // request while one is already pending for the flight. ErrSignaturePendingExists = errors.New("a pending signature request already exists for this flight") // ErrSignatureTokenInvalid covers an unknown, revoked, voided, or // already-completed token, indistinguishably. ErrSignatureTokenInvalid = errors.New("signature link is invalid") // ErrSignatureTokenExpired means the token's expiry has passed. ErrSignatureTokenExpired = errors.New("signature link has expired") // ErrSignatureNotPending is returned by Resend/Revoke when the target // signature is not (or no longer) in the 'pending' state. ErrSignatureNotPending = errors.New("signature request is not pending") // ErrSignatureNotCompleted is returned by Void when the target // signature is not in the 'completed' state. ErrSignatureNotCompleted = errors.New("signature is not completed") ErrSignatureImageTooLarge = errors.New("signature image exceeds maximum size") ErrSignatureImageRequired = errors.New("a signature image is required") ErrSignerNameRequired = errors.New("signer name is required") ErrSignatureReasonRequired = errors.New("a reason is required to void a signature") // ErrSignatureEmailQuota is returned once a user has triggered too many // signature-request emails in a day. ErrSignatureEmailQuota = errors.New("daily limit for signature request emails reached") )
var ( ErrLicenseNotFound = errors.New("license not found") ErrInvalidLicense = errors.New("invalid license data") ErrLicenseAlreadyExists = errors.New("license already exists") )
var ( // NotificationCheckRunsTotal counts total background notification check runs. NotificationCheckRunsTotal = prometheus.NewCounter( prometheus.CounterOpts{ Name: "notification_check_runs_total", Help: "Total number of background notification check runs.", }, ) // NotificationCheckDurationSeconds tracks how long each notification check takes. NotificationCheckDurationSeconds = prometheus.NewHistogram( prometheus.HistogramOpts{ Name: "notification_check_duration_seconds", Help: "Duration of each background notification check run in seconds.", Buckets: prometheus.DefBuckets, }, ) // NotificationsSentTotal counts notifications sent by type. NotificationsSentTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "notifications_sent_total", Help: "Total number of notifications sent.", }, []string{"type"}, ) // NotificationCheckErrorsTotal counts notification check runs that aborted // early due to an error (e.g. failing to load user preferences). NotificationCheckErrorsTotal = prometheus.NewCounter( prometheus.CounterOpts{ Name: "notification_check_errors_total", Help: "Total number of background notification check runs that failed.", }, ) // NotificationLastSuccessTimestampSeconds records the Unix timestamp of the // last successfully completed notification check. Use it to alert when the // background checker stops running (staleness). NotificationLastSuccessTimestampSeconds = prometheus.NewGauge( prometheus.GaugeOpts{ Name: "notification_last_success_timestamp_seconds", Help: "Unix timestamp of the last successfully completed notification check.", }, ) )
var ( // not be fetched. ErrOIDCProviderUnavailable = errors.New("oidc provider is unavailable") // ErrOIDCInvalidState covers every unusable authorization response, // indistinguishably: an unknown, expired or already-consumed state, and a // state presented by a different browser than the one that started the // login. ErrOIDCInvalidState = errors.New("oidc login state is invalid or has expired") // ErrOIDCExchangeFailed means the provider rejected the authorization code // or returned a token response without an ID token. ErrOIDCExchangeFailed = errors.New("oidc token exchange failed") // ErrOIDCInvalidToken means the ID token failed signature, issuer, // audience, expiry or nonce validation. ErrOIDCInvalidToken = errors.New("oidc id token is invalid") // ErrOIDCEmailMissing means the ID token carried no usable email address; // an account cannot be provisioned without one. ErrOIDCEmailMissing = errors.New("oidc id token contains no email address") // ErrOIDCEmailConflict means the address belongs to an existing local // account that this identity is not allowed to adopt. ErrOIDCEmailConflict = errors.New("an account with this email address already exists") // ErrOIDCHandoffInvalid means the single-use handoff code was unknown, // expired or already redeemed. ErrOIDCHandoffInvalid = errors.New("oidc handoff code is invalid or has expired") )
OIDC-specific sentinel errors. Handlers map these to status codes; none of them are ever echoed back to the browser verbatim.
var ( ErrTwoFactorAlreadyEnabled = errors.New("two-factor authentication is already enabled") ErrTwoFactorNotEnabled = errors.New("two-factor authentication is not enabled") ErrInvalidTOTPCode = errors.New("invalid TOTP code") ErrInvalid2FAToken = errors.New("invalid two-factor token") )
var ( // UnverifiedRemindersTotal counts follow-up verification emails by outcome. // // Results: // sent — the reminder was delivered; the deletion clock started. // undeliverable — the address refused mail permanently; the clock // started anyway. // deferred — a transient failure; the account is retried next sweep. // error — the token could not be minted; nothing was sent. UnverifiedRemindersTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "unverified_account_reminders_total", Help: "Follow-up email-verification reminders by outcome.", }, []string{"result"}, ) // UnverifiedAccountsDeletedTotal counts accounts reaped for never having // verified their address. UnverifiedAccountsDeletedTotal = prometheus.NewCounter( prometheus.CounterOpts{ Name: "unverified_accounts_deleted_total", Help: "Accounts deleted after failing to verify their email address within the retention window.", }, ) )
var ( ErrWebAuthnNotConfigured = errors.New("webauthn is not configured") // ErrWebAuthnSessionNotFound is returned, indistinguishably, for every // unusable ceremony handle: expired, already consumed, wrong ceremony, // scoped to another user, or never issued. ErrWebAuthnSessionNotFound = errors.New("webauthn session not found or expired") ErrWebAuthnInvalidResponse = errors.New("invalid webauthn response") ErrWebAuthnUnknownCredential = errors.New("unknown webauthn credential") ErrWebAuthnVerification = errors.New("webauthn verification failed") )
var ( // WebAuthnSessionsCreatedTotal counts ceremony sessions opened, split by // ceremony ("registration" | "login"). WebAuthnSessionsCreatedTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "webauthn_sessions_created_total", Help: "Total number of WebAuthn ceremony sessions opened.", }, []string{"ceremony"}, ) // WebAuthnSessionsConsumedTotal counts finish attempts by ceremony and // result ("ok" | "rejected"). A rejection covers every unusable handle: // expired, already consumed, wrong ceremony, or forged. WebAuthnSessionsConsumedTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "webauthn_sessions_consumed_total", Help: "Total number of WebAuthn ceremony finish attempts by result.", }, []string{"ceremony", "result"}, ) // WebAuthnSessionsEvictedTotal counts sessions dropped by the per-user // open ceremony cap. WebAuthnSessionsEvictedTotal = prometheus.NewCounter( prometheus.CounterOpts{ Name: "webauthn_sessions_evicted_total", Help: "Total number of WebAuthn sessions evicted by the per-user open ceremony cap.", }, ) // WebAuthnSessionsExpiredTotal counts rows removed by the cleanup reaper. WebAuthnSessionsExpiredTotal = prometheus.NewCounter( prometheus.CounterOpts{ Name: "webauthn_sessions_expired_total", Help: "Total number of expired WebAuthn sessions removed by the cleanup job.", }, ) )
ErrIdempotencyUnavailable is returned when the replay store cannot be reached. Callers must fail the request rather than execute it.
var ErrInvalidDeletionEntity = errors.New("unknown deletion entity type")
ErrInvalidDeletionEntity is returned for an entity filter outside the enum.
var ErrInvalidSessionEvent = errors.New("invalid flight session event")
var ErrOIDCNotConfigured = errors.New("oidc is not configured")
ErrOIDCNotConfigured is returned by every OIDC operation on a deployment that has not set OIDC_ISSUER.
Functions ¶
func GetCheckInterval ¶
GetCheckInterval reads NOTIFICATION_CHECK_INTERVAL env var, defaults to 1h
func IdempotencyStatus ¶ added in v1.3.2
func IdempotencyStatus(o IdempotencyOutcome) int
IdempotencyStatus maps an outcome to the HTTP status a client should see.
func UnverifiedCleanupDisabledReason ¶ added in v1.3.2
UnverifiedCleanupDisabledReason reports why the reaper must not run, or "" if it may.
Types ¶
type AircraftService ¶
type AircraftService struct {
// contains filtered or unexported fields
}
func NewAircraftService ¶
func NewAircraftService(aircraftRepo repository.AircraftRepository) *AircraftService
func (*AircraftService) CountAircraft ¶
func (*AircraftService) CreateAircraft ¶
func (*AircraftService) DeleteAircraft ¶
func (*AircraftService) GetAircraft ¶
func (*AircraftService) GetAircraftStats ¶ added in v1.3.1
func (s *AircraftService) GetAircraftStats(ctx context.Context, userID uuid.UUID) (*AircraftStatsResult, error)
GetAircraftStats returns flight statistics aggregated per registration and per aircraft type, including informational 90-day landing recency
func (*AircraftService) ListAircraft ¶
func (*AircraftService) ListAircraftUpdatedSince ¶ added in v1.3.2
func (s *AircraftService) ListAircraftUpdatedSince(ctx context.Context, userID uuid.UUID, updatedSince time.Time) ([]*models.Aircraft, error)
ListAircraftUpdatedSince returns the user's aircraft that changed strictly after the given instant, for delta-syncing clients.
func (*AircraftService) UpdateAircraft ¶
func (s *AircraftService) UpdateAircraft(ctx context.Context, aircraft *models.Aircraft, userID uuid.UUID, renameFlights bool) (int, error)
UpdateAircraft updates an aircraft. When renameFlights is true and the registration changes, flights logged under the old registration are repointed to the new one; the returned count is the number of flights updated.
type AircraftStatsResult ¶ added in v1.3.1
type AircraftStatsResult struct {
ByRegistration []*models.AircraftStats
ByType []*models.AircraftTypeStats
}
AircraftStatsResult bundles per-registration and per-type flight statistics
type AuthService ¶
type AuthService struct {
// contains filtered or unexported fields
}
func NewAuthService ¶
func NewAuthService( userRepo repository.UserRepository, refreshTokenRepo repository.RefreshTokenRepository, passwordResetRepo repository.PasswordResetTokenRepository, emailVerificationRepo repository.EmailVerificationTokenRepository, jwtManager *jwt.Manager, twoFactor TwoFactorValidator, ) *AuthService
NewAuthService constructs the service. twoFactor may be nil, in which case a password reset for an account with 2FA enabled fails with ErrTwoFactorUnavailable.
func (*AuthService) ChangePassword ¶
func (s *AuthService) ChangePassword(ctx context.Context, userID uuid.UUID, currentPassword, newPassword string) error
ChangePassword changes the user's password after verifying the current password
func (*AuthService) CreateEmailVerificationToken ¶ added in v1.3.1
func (s *AuthService) CreateEmailVerificationToken(ctx context.Context, userID uuid.UUID) (string, error)
CreateEmailVerificationToken mints a fresh verification token for a user whose address has just changed.
func (*AuthService) DeleteUser ¶
DeleteUser permanently deletes a user account after verifying the password
func (*AuthService) DeleteUserConfirmed ¶ added in v1.3.2
DeleteUserConfirmed permanently deletes an account whose identity has been confirmed by means other than a password; the confirmation itself happens in the handler.
func (*AuthService) GenerateTokensForUser ¶
func (s *AuthService) GenerateTokensForUser(ctx context.Context, userID uuid.UUID) (*TokenPair, error)
GenerateTokensForUser generates access and refresh tokens for a user (used after 2FA verification)
func (*AuthService) GetUserByID ¶
GetUserByID retrieves a user by ID
func (*AuthService) Login ¶
func (s *AuthService) Login(ctx context.Context, input LoginInput) (*models.User, *TokenPair, error)
Login authenticates a user and returns tokens
func (*AuthService) Logout ¶
func (s *AuthService) Logout(ctx context.Context, refreshToken string) error
Logout revokes a refresh token
func (*AuthService) MarkEmailVerified ¶ added in v1.2.6
MarkEmailVerified marks a user as verified and clears any outstanding verification tokens. Used for environments where email delivery is disabled.
func (*AuthService) RecordLogin ¶ added in v1.3.2
func (s *AuthService) RecordLogin(ctx context.Context, user *models.User)
RecordLogin stamps a successful sign-in on the account and mirrors the value onto the in-memory user. Called by every path that hands a session to a user: password login, the 2FA second factor, passkeys, OIDC, and the sign-up verification link. A refresh is not a login. Failure is logged and swallowed.
func (*AuthService) RefreshToken ¶
RefreshToken generates a new access token using a refresh token
func (*AuthService) Register ¶
func (s *AuthService) Register(ctx context.Context, input RegisterInput) (*models.User, string, error)
Register creates a new user account with EmailVerified=false, stores an email-verification token, and returns the plaintext token for the handler to deliver via email. No JWT tokens are issued; the user must consume the verification token (see VerifyEmail) before logging in.
func (*AuthService) RequestPasswordReset ¶
func (s *AuthService) RequestPasswordReset(ctx context.Context, email string) (*PasswordResetRequest, error)
RequestPasswordReset creates a password reset token. On success it returns the reset token together with the recipient details loaded from the database, never from the HTTP request.
func (*AuthService) ResendVerification ¶ added in v1.2.5
func (s *AuthService) ResendVerification(ctx context.Context, email string) (token, userEmail, userName, locale string, err error)
ResendVerification issues a fresh verification token for the given email if (and only if) the address belongs to a known, not-yet-verified user. The returned values are empty when nothing should be sent; "unknown email" and "already verified" are indistinguishable to callers.
func (*AuthService) ResetPassword ¶
func (s *AuthService) ResetPassword(ctx context.Context, token, newPassword, twoFactorCode string) (*PasswordResetResult, error)
ResetPassword resets a user's password using a reset token. A reset does NOT disable two-factor authentication: an account with 2FA enabled must prove the second factor here too — twoFactorCode is a TOTP code or one of the account's recovery codes. The reset token is consumed only on success, so a wrong or missing code can be retried with the same link.
func (*AuthService) RevokeAllSessions ¶ added in v1.3.4
RevokeAllSessions deletes every refresh token a user holds, forcing a fresh login on all devices. Used when an admin disables an account, so a disabled user cannot keep an existing session alive.
func (*AuthService) UpdateUser ¶
UpdateUser updates user information
func (*AuthService) VerifyEmail ¶ added in v1.2.5
func (s *AuthService) VerifyEmail(ctx context.Context, token string) (*models.User, *TokenPair, error)
VerifyEmail consumes a verification token and, on success, marks the user's email as verified and returns a fresh access/refresh token pair.
func (*AuthService) VerifyPassword ¶ added in v1.3.1
VerifyPassword checks a plaintext password against the stored hash for the given user. Used to re-authenticate before security-sensitive profile changes.
type ClassRatingRepository ¶
type ClassRatingRepository interface {
Create(ctx context.Context, cr *models.ClassRating) error
GetByID(ctx context.Context, id uuid.UUID) (*models.ClassRating, error)
GetByLicenseID(ctx context.Context, licenseID uuid.UUID) ([]*models.ClassRating, error)
Update(ctx context.Context, cr *models.ClassRating) error
Delete(ctx context.Context, id uuid.UUID) error
}
ClassRatingRepository defines the interface for class rating data access
type ClassRatingService ¶
type ClassRatingService struct {
// contains filtered or unexported fields
}
func NewClassRatingService ¶
func NewClassRatingService(crRepo ClassRatingRepository, licRepo repository.LicenseRepository) *ClassRatingService
func (*ClassRatingService) CreateClassRating ¶
func (s *ClassRatingService) CreateClassRating(ctx context.Context, cr *models.ClassRating, userID uuid.UUID) error
func (*ClassRatingService) DeleteClassRating ¶
func (*ClassRatingService) GetClassRating ¶ added in v1.3.2
func (s *ClassRatingService) GetClassRating(ctx context.Context, ratingID, userID uuid.UUID) (*models.ClassRating, error)
func (*ClassRatingService) ListClassRatings ¶
func (s *ClassRatingService) ListClassRatings(ctx context.Context, licenseID, userID uuid.UUID) ([]*models.ClassRating, error)
func (*ClassRatingService) UpdateClassRating ¶
func (s *ClassRatingService) UpdateClassRating(ctx context.Context, cr *models.ClassRating, userID uuid.UUID) error
type ContactService ¶
type ContactService struct {
// contains filtered or unexported fields
}
func NewContactService ¶
func NewContactService(contactRepo repository.ContactRepository) *ContactService
func (*ContactService) CreateContact ¶
func (*ContactService) DeleteContact ¶
DeleteContact removes a contact from the address book. It does not touch any flight: flight_crew_members.contact_id is ON DELETE SET NULL and the crew row keeps the name it was logged with. Deleting is always allowed, even for a contact referenced by signed flights.
func (*ContactService) ExportVCard ¶ added in v1.3.3
ExportVCard renders the user's contacts as a single vCard 3.0 stream, in the same name order as the contact list. Contacts the pilot has flown with carry their crew roles as CATEGORIES.
func (*ContactService) FindOrCreateContact ¶
func (s *ContactService) FindOrCreateContact(ctx context.Context, userID uuid.UUID, name string) (*models.Contact, bool, error)
FindOrCreateContact finds an existing contact by exact name (case-insensitive) or creates a new one. Returns the contact and whether it was newly created.
func (*ContactService) GetContact ¶
func (*ContactService) LinkCrewMembers ¶ added in v1.3.3
func (s *ContactService) LinkCrewMembers(ctx context.Context, userID uuid.UUID, members []models.FlightCrewMember) (int, error)
LinkCrewMembers links a single flight's crew and reports how many contacts it created. Callers processing many flights should hold a CrewLinker instead.
func (*ContactService) ListContacts ¶
func (*ContactService) ListContactsUpdatedSince ¶ added in v1.3.2
func (s *ContactService) ListContactsUpdatedSince(ctx context.Context, userID uuid.UUID, updatedSince time.Time) ([]*models.Contact, error)
ListContactsUpdatedSince returns the user's contacts that changed strictly after the given instant, for delta-syncing clients.
func (*ContactService) NewCrewLinker ¶ added in v1.3.3
func (s *ContactService) NewCrewLinker(userID uuid.UUID) *CrewLinker
NewCrewLinker returns a linker for one user.
func (*ContactService) SearchContacts ¶
func (*ContactService) UpdateContact ¶
func (s *ContactService) UpdateContact(ctx context.Context, contact *models.Contact, userID uuid.UUID) (int, error)
UpdateContact updates a contact and returns the number of logbook crew entries whose name was rewritten to match. Entries on flights carrying a completed instructor signature, and entries not linked to the contact, are excluded; the repository enforces that boundary in SQL.
type CredentialService ¶
type CredentialService struct {
// contains filtered or unexported fields
}
func NewCredentialService ¶
func NewCredentialService(credentialRepo repository.CredentialRepository) *CredentialService
func (*CredentialService) CreateCredential ¶
func (s *CredentialService) CreateCredential(ctx context.Context, credential *models.Credential) error
func (*CredentialService) DeleteCredential ¶
func (*CredentialService) GetCredential ¶
func (s *CredentialService) GetCredential(ctx context.Context, id, userID uuid.UUID) (*models.Credential, error)
func (*CredentialService) ListCredentials ¶
func (s *CredentialService) ListCredentials(ctx context.Context, userID uuid.UUID) ([]*models.Credential, error)
func (*CredentialService) ListCredentialsUpdatedSince ¶ added in v1.3.2
func (s *CredentialService) ListCredentialsUpdatedSince(ctx context.Context, userID uuid.UUID, updatedSince time.Time) ([]*models.Credential, error)
ListCredentialsUpdatedSince returns the user's credentials that changed strictly after the given instant, for delta-syncing clients.
func (*CredentialService) UpdateCredential ¶
func (s *CredentialService) UpdateCredential(ctx context.Context, credential *models.Credential, userID uuid.UUID) error
type CrewLinker ¶ added in v1.3.3
type CrewLinker struct {
// contains filtered or unexported fields
}
CrewLinker resolves crew-member names to a single user's contacts across any number of flights, remembering the names it has already looked up. Every path that writes crew rows goes through it: flight create, flight update, spreadsheet import and backup restore.
Not safe for concurrent use; take one per request.
func (*CrewLinker) Created ¶ added in v1.3.3
func (l *CrewLinker) Created() int
Created reports how many contacts this linker has had to create.
func (*CrewLinker) Link ¶ added in v1.3.3
func (l *CrewLinker) Link(ctx context.Context, members []models.FlightCrewMember) error
Link resolves one flight's crew members to contacts, updating them in place.
A caller-supplied ContactID is honoured only if the caller owns that contact; otherwise it is discarded and the name is resolved like any other. A member with a blank or over-length name is left unlinked; the crew row is still written with the name as logged. Only infrastructure failures abort.
type CurrencyResult ¶
type CurrencyResult struct {
IsCurrent bool
DaysCurrent bool
NightsCurrent bool
Flights90Days int
TotalLandings int
DayLandings int
NightLandings int
RequiredDay int
RequiredNight int
}
CurrencyResult holds the calculated currency status
type DeletionPage ¶ added in v1.3.2
type DeletionPage struct {
Deletions []*models.Deletion
Total int
// WatermarkExpired is true when `since` predates the retention horizon;
// the feed may be incomplete and the client must fall back to a full
// ID-set reconciliation.
WatermarkExpired bool
}
DeletionPage is one page of the feed plus how many deletions match and whether the client's watermark predates the retention horizon.
type DeletionService ¶ added in v1.3.2
type DeletionService struct {
// contains filtered or unexported fields
}
DeletionService serves the tombstone feed and sweeps it.
func NewDeletionService ¶ added in v1.3.2
func NewDeletionService(repo repository.DeletionRepository, retention time.Duration) *DeletionService
func (*DeletionService) ListDeletions ¶ added in v1.3.2
func (s *DeletionService) ListDeletions( ctx context.Context, userID uuid.UUID, since time.Time, entity *models.DeletionEntityType, page, pageSize int, ) (*DeletionPage, error)
ListDeletions returns the deletions recorded for the user after `since`. The result is always user-scoped; the filter is applied in SQL.
func (*DeletionService) Retention ¶ added in v1.3.2
func (s *DeletionService) Retention() time.Duration
Retention is how long a tombstone is kept; reported to clients.
func (*DeletionService) StartReaper ¶ added in v1.3.2
func (s *DeletionService) StartReaper(ctx context.Context, interval time.Duration)
StartReaper sweeps tombstones past the retention horizon — the same horizon WatermarkExpired is computed from.
type DocumentFileService ¶ added in v1.3.2
type DocumentFileService struct {
// contains filtered or unexported fields
}
DocumentFileService owns reference photos attached to licences and credentials: the feature switch, upload validation, ownership checks and the per-document cap. Every method resolves the subject through the licence/credential repository first; an image is only addressable through the document it belongs to.
func NewDocumentFileService ¶ added in v1.3.2
func NewDocumentFileService( imageRepo repository.DocumentFileRepository, licenseRepo repository.LicenseRepository, credentialRepo repository.CredentialRepository, enabled bool, ) *DocumentFileService
func (*DocumentFileService) Delete ¶ added in v1.3.2
func (s *DocumentFileService) Delete(ctx context.Context, userID uuid.UUID, subject models.DocumentSubjectType, subjectID, imageID uuid.UUID) error
Delete removes one image from a document.
func (*DocumentFileService) Enabled ¶ added in v1.3.2
func (s *DocumentFileService) Enabled() bool
Enabled reports whether the feature is switched on. Handlers use it to answer GET /features.
func (*DocumentFileService) Get ¶ added in v1.3.2
func (s *DocumentFileService) Get(ctx context.Context, userID uuid.UUID, subject models.DocumentSubjectType, subjectID, imageID uuid.UUID) (*models.DocumentFile, error)
Get returns a single image including its bytes, for the authenticated download endpoint.
func (*DocumentFileService) List ¶ added in v1.3.2
func (s *DocumentFileService) List(ctx context.Context, userID uuid.UUID, subject models.DocumentSubjectType, subjectID uuid.UUID) ([]*models.DocumentFile, error)
List returns the metadata for a document's images, oldest first.
func (*DocumentFileService) Upload ¶ added in v1.3.2
func (s *DocumentFileService) Upload(ctx context.Context, userID uuid.UUID, subject models.DocumentSubjectType, subjectID uuid.UUID, in UploadInput) (*models.DocumentFile, error)
Upload validates and stores one image against a licence or credential.
type EmailDeliveryService ¶ added in v1.3.2
type EmailDeliveryService struct {
// contains filtered or unexported fields
}
EmailDeliveryService records the outcome of every send and maintains the suppression list. It implements pkg/email.DeliveryRecorder.
func NewEmailDeliveryService ¶ added in v1.3.2
func NewEmailDeliveryService(repo repository.EmailDeliveryRepository) *EmailDeliveryService
func (*EmailDeliveryService) CountSuppressions ¶ added in v1.3.2
func (s *EmailDeliveryService) CountSuppressions(ctx context.Context) (int, error)
CountSuppressions reports how many addresses are currently suppressed.
func (*EmailDeliveryService) IsSuppressed ¶ added in v1.3.2
func (s *EmailDeliveryService) IsSuppressed(ctx context.Context, recipient string) bool
IsSuppressed reports whether the address has hard-bounced before. It fails open: a lookup error returns false and the send proceeds.
func (*EmailDeliveryService) ListEvents ¶ added in v1.3.2
func (s *EmailDeliveryService) ListEvents(ctx context.Context, recipient string, limit int) ([]*models.EmailDeliveryEvent, error)
ListEvents returns recent delivery events, newest first. An empty recipient means all recipients.
func (*EmailDeliveryService) ListSuppressions ¶ added in v1.3.2
func (s *EmailDeliveryService) ListSuppressions(ctx context.Context, limit int) ([]*models.EmailSuppression, error)
ListSuppressions returns suppressed addresses, most recently bounced first.
func (*EmailDeliveryService) RecordAttempt ¶ added in v1.3.2
func (s *EmailDeliveryService) RecordAttempt(ctx context.Context, a emailpkg.Attempt)
RecordAttempt appends the attempt to the delivery log and, for a permanent recipient-level refusal, adds the address to the suppression list. It swallows its own storage errors.
func (*EmailDeliveryService) RefreshSuppressionGauge ¶ added in v1.3.2
func (s *EmailDeliveryService) RefreshSuppressionGauge(ctx context.Context)
RefreshSuppressionGauge re-reads the suppression count into the metric. Called at startup.
func (*EmailDeliveryService) Unsuppress ¶ added in v1.3.2
func (s *EmailDeliveryService) Unsuppress(ctx context.Context, email string) error
Unsuppress lifts a suppression; mail to the address is attempted again.
func (*EmailDeliveryService) UserIDForEmail ¶ added in v1.3.2
UserIDForEmail is exposed for callers that want attribution outside the send path.
type FlightService ¶
type FlightService struct {
// contains filtered or unexported fields
}
func NewFlightService ¶
func NewFlightService(flightRepo repository.FlightRepository, baselineRepo repository.FlightBaselineRepository) *FlightService
func (*FlightService) CountFlights ¶
func (s *FlightService) CountFlights(ctx context.Context, userID uuid.UUID, opts *repository.FlightQueryOptions) (int, error)
CountFlights counts flights for a user with optional filters
func (*FlightService) CreateFlight ¶
CreateFlight creates a new flight log entry
func (*FlightService) DeleteAllFlights ¶
DeleteAllFlights deletes all flights for a user
func (*FlightService) DeleteBaseline ¶ added in v1.2.3
DeleteBaseline removes the user's initial-hours snapshot.
func (*FlightService) DeleteFlight ¶
DeleteFlight deletes a flight and verifies user ownership
func (*FlightService) GetBaseline ¶ added in v1.2.3
func (s *FlightService) GetBaseline(ctx context.Context, userID uuid.UUID) (*models.FlightBaseline, error)
GetBaseline returns the user's initial-hours snapshot, or repository.ErrNotFound.
func (*FlightService) GetCurrency ¶
func (s *FlightService) GetCurrency(ctx context.Context, userID uuid.UUID) (*CurrencyResult, error)
GetCurrency calculates currency status for a user based on EASA/FAA rules. FAA 14 CFR 61.57: 3 takeoffs and landings in the preceding 90 days EASA FCL.060: Recent experience — 3 takeoffs and landings in the preceding 90 days (simplified)
func (*FlightService) GetFlight ¶
func (s *FlightService) GetFlight(ctx context.Context, flightID, userID uuid.UUID) (*models.Flight, error)
GetFlight retrieves a flight by ID and verifies user ownership
func (*FlightService) GetStatsByUserID ¶
func (s *FlightService) GetStatsByUserID(ctx context.Context, userID uuid.UUID, startDate, endDate *time.Time, applyBaseline bool) (*models.FlightStatistics, *models.FlightBaseline, error)
GetStatsByUserID returns aggregated statistics for a user. The optional initial-hours snapshot (baseline) is added on top when:
- the user has a baseline, AND
- applyBaseline is true, AND
- startDate is nil OR startDate <= baseline_date AND endDate is nil OR endDate >= baseline_date.
When the baseline is applied, it is also returned so callers can surface a breakdown to the client. baseline is nil otherwise.
func (*FlightService) ListFlights ¶
func (s *FlightService) ListFlights(ctx context.Context, userID uuid.UUID, opts *repository.FlightQueryOptions) ([]*models.Flight, error)
ListFlights retrieves flights for a user with optional filters
func (*FlightService) UpdateFlight ¶
func (s *FlightService) UpdateFlight(ctx context.Context, flight *models.Flight, userID uuid.UUID) error
UpdateFlight updates a flight and verifies user ownership
func (*FlightService) UpsertBaseline ¶ added in v1.2.3
func (s *FlightService) UpsertBaseline(ctx context.Context, baseline *models.FlightBaseline) error
UpsertBaseline validates and stores the user's initial-hours snapshot.
type FlightSessionEventInput ¶ added in v1.2.8
type FlightSessionEventInput struct {
Type string
OccurredAt *time.Time
AircraftReg *string
ICAO *string
Lat *float64
Lon *float64
// UserName is the authenticated user's display name, forwarded to
// flight auto-calculations when the session is converted into a flight.
UserName string
}
FlightSessionEventInput carries one tap-to-log event.
type FlightSessionService ¶ added in v1.2.8
type FlightSessionService struct {
// contains filtered or unexported fields
}
FlightSessionService manages live tap-to-log flight sessions: opening a session on off-block, stamping takeoff/landing, and converting the session into a regular flight log entry when the pilot goes on blocks.
func NewFlightSessionService ¶ added in v1.2.8
func NewFlightSessionService( sessionRepo repository.FlightSessionRepository, aircraftRepo repository.AircraftRepository, flightService *FlightService, ) *FlightSessionService
func (*FlightSessionService) Discard ¶ added in v1.2.8
Discard marks the user's open session as discarded without creating a flight. Returns models.ErrNoOpenFlightSession when there is none.
func (*FlightSessionService) GetCurrent ¶ added in v1.2.8
func (s *FlightSessionService) GetCurrent(ctx context.Context, userID uuid.UUID) (*models.FlightSession, error)
GetCurrent returns the user's open session or models.ErrNoOpenFlightSession.
func (*FlightSessionService) RecordEvent ¶ added in v1.2.8
func (s *FlightSessionService) RecordEvent(ctx context.Context, userID uuid.UUID, input FlightSessionEventInput) (*models.FlightSession, bool, error)
RecordEvent applies one tap-to-log event. It returns the resulting session and whether a new session was opened (offblock on a user with no open session). Repeating an event type already recorded on the session is a no-op returning the unchanged session. An onblock event completes the session and creates the flight log entry.
type FlightSignatureService ¶ added in v1.2.9
type FlightSignatureService struct {
// contains filtered or unexported fields
}
FlightSignatureService implements the instructor sign-off workflow: live (in-person, synchronous), deferred-by-email, and deferred-by-shareable-link (all deferred requests share the same token mechanism; email is just an optional delivery channel for it). See models.FlightSignature for the lifecycle and internal/service/flight.go's ErrFlightLocked for the edit-lock this feature imposes on signed flights.
func NewFlightSignatureService ¶ added in v1.2.9
func NewFlightSignatureService(sigRepo repository.FlightSignatureRepository, flightRepo repository.FlightRepository, userRepo repository.UserRepository) *FlightSignatureService
func (*FlightSignatureService) CompleteFromToken ¶ added in v1.2.9
func (s *FlightSignatureService) CompleteFromToken(ctx context.Context, token, signerName string, credentialNo *string, image []byte, signerIP, signerUA string) (sig *models.FlightSignature, ownerEmail, ownerName string, err error)
CompleteFromToken records the instructor's signature against a valid pending token. Returns the completed signature plus the flight owner's DB-sourced email/name for the confirmation mail.
func (*FlightSignatureService) CreateRequest ¶ added in v1.2.9
func (s *FlightSignatureService) CreateRequest(ctx context.Context, flightID, userID uuid.UUID, instructorEmail *string, expiresInHours *int) (sig *models.FlightSignature, rawToken string, err error)
CreateRequest starts a deferred (token-based) signature request. If instructorEmail is supplied the caller should send the request email immediately (see APIHandler.sendSignatureRequestEmail); if omitted, the request is created "pending, unsent" so the owner can send it whenever they have the instructor's address, or share the link/QR directly.
func (*FlightSignatureService) ExpirePendingRequests ¶ added in v1.2.9
func (s *FlightSignatureService) ExpirePendingRequests(ctx context.Context) (int64, error)
ExpirePendingRequests soft-expires any pending request whose token has passed its expiry, returning the number of rows affected. Called from the admin cleanup-tokens maintenance sweep.
func (*FlightSignatureService) Get ¶ added in v1.2.9
func (s *FlightSignatureService) Get(ctx context.Context, flightID, userID, signatureID uuid.UUID) (*models.FlightSignature, error)
Get returns a single signature the caller owns.
func (*FlightSignatureService) List ¶ added in v1.2.9
func (s *FlightSignatureService) List(ctx context.Context, flightID, userID uuid.UUID) ([]*models.FlightSignature, error)
List returns the full signature history for a flight, newest first.
func (*FlightSignatureService) MarkEmailSent ¶ added in v1.2.9
func (s *FlightSignatureService) MarkEmailSent(ctx context.Context, sig *models.FlightSignature) error
MarkEmailSent records that a request email was (re)sent. Call after a successful (or best-effort) Sender.Send from the handler layer.
func (*FlightSignatureService) Resend ¶ added in v1.2.9
func (s *FlightSignatureService) Resend(ctx context.Context, flightID, userID, signatureID uuid.UUID, instructorEmail *string) (sig *models.FlightSignature, rawToken string, err error)
Resend rotates the token (and, if a new address is supplied, updates the delivery email) for a still-pending request. This single action covers both "send to a different email" and "regenerate the shareable link/QR" — the caller decides whether to also send an email with the result.
func (*FlightSignatureService) ResolveToken ¶ added in v1.2.9
func (s *FlightSignatureService) ResolveToken(ctx context.Context, token string) (*models.FlightSignature, *models.Flight, error)
ResolveToken validates a public signing token and returns the pending signature plus its flight, for display on the public /sign/{token} page. Never returns information that would let a caller distinguish "token never existed" from "token already used/revoked/voided".
func (*FlightSignatureService) Revoke ¶ added in v1.2.9
func (s *FlightSignatureService) Revoke(ctx context.Context, flightID, userID, signatureID uuid.UUID) error
Revoke cancels a still-pending request; nobody has signed it yet.
func (*FlightSignatureService) SignLive ¶ added in v1.2.9
func (s *FlightSignatureService) SignLive(ctx context.Context, flightID, userID uuid.UUID, signerName string, credentialNo *string, image []byte, signerIP, signerUA string) (*models.FlightSignature, error)
SignLive records an in-person signature captured on the flight owner's own device. Completes synchronously; no token is involved.
func (*FlightSignatureService) Void ¶ added in v1.2.9
func (s *FlightSignatureService) Void(ctx context.Context, flightID, userID, signatureID uuid.UUID, reason string) error
Void invalidates an already-completed signature (a reason is required for the audit trail) and unlocks the flight for editing again. Editing and re-signing after a void is the "revalidation" workflow.
type IdempotencyClaim ¶ added in v1.3.2
type IdempotencyClaim struct {
Outcome IdempotencyOutcome
// ClaimedAt identifies this claim for Finish/Abandon. Set when the
// outcome is IdempotencyClaimed.
ClaimedAt time.Time
// Response is set when the outcome is IdempotencyReplay.
Response *IdempotentResponse
}
IdempotencyClaim is the result of Begin.
type IdempotencyOutcome ¶ added in v1.3.2
type IdempotencyOutcome int
IdempotencyOutcome is the verdict on a claim attempt.
const ( // IdempotencyClaimed means the key is ours: run the request, then call // Finish or Abandon. IdempotencyClaimed IdempotencyOutcome = iota // IdempotencyReplay means the request already ran to completion; return // the stored response instead of executing anything. IdempotencyReplay // IdempotencyInProgress means an earlier request with this key is still // running. Retrying after it settles yields the replay. IdempotencyInProgress // IdempotencyMismatch means the key was used before with a different // request. IdempotencyMismatch // IdempotencyNotReplayable means the original request completed but its // response was not stored, so it can be neither replayed nor safely // re-executed. IdempotencyNotReplayable )
type IdempotencyService ¶ added in v1.3.2
type IdempotencyService struct {
// contains filtered or unexported fields
}
IdempotencyService turns the raw replay records into the claim/finish lifecycle the HTTP layer needs, and owns their retention.
func NewIdempotencyService ¶ added in v1.3.2
func NewIdempotencyService(repo repository.IdempotencyRepository, ttl, lease time.Duration, maxResponseBytes int) *IdempotencyService
NewIdempotencyService creates the service. Non-positive values fall back to the defaults above.
func (*IdempotencyService) Abandon ¶ added in v1.3.2
func (s *IdempotencyService) Abandon(ctx context.Context, userID uuid.UUID, key string, claimedAt time.Time) error
Abandon drops the claim, leaving the key free for a genuine retry. Used on a server error or a panic.
func (*IdempotencyService) Begin ¶ added in v1.3.2
func (s *IdempotencyService) Begin(ctx context.Context, userID uuid.UUID, key string, requestHash []byte) (IdempotencyClaim, error)
Begin claims the key for this request, or reports why the request must not run. requestHash fingerprints the request; a key reused for a different payload is refused.
func (*IdempotencyService) Finish ¶ added in v1.3.2
func (s *IdempotencyService) Finish(ctx context.Context, userID uuid.UUID, key string, claimedAt time.Time, resp IdempotentResponse) error
Finish stores the response against a claim so retries replay it.
A response the caller could not capture (signalled with Status 0), or one larger than the cap, is recorded as completed with nothing to replay: the key stays consumed and a retry is told the response is gone.
func (*IdempotencyService) MaxResponseBytes ¶ added in v1.3.2
func (s *IdempotencyService) MaxResponseBytes() int
MaxResponseBytes is the largest response body the service will store.
func (*IdempotencyService) StartReaper ¶ added in v1.3.2
func (s *IdempotencyService) StartReaper(ctx context.Context, interval time.Duration)
StartReaper deletes expired records on a timer until ctx is cancelled. Hygiene only: Begin takes over any record past its expires_at.
type IdempotentResponse ¶ added in v1.3.2
IdempotentResponse is a captured response, replayed verbatim on retry.
type LicenseService ¶
type LicenseService struct {
// contains filtered or unexported fields
}
func NewLicenseService ¶
func NewLicenseService(licenseRepo repository.LicenseRepository) *LicenseService
func (*LicenseService) CreateLicense ¶
CreateLicense creates a new license for a user
func (*LicenseService) DeleteLicense ¶
DeleteLicense deletes a license and verifies user ownership
func (*LicenseService) GetLicense ¶
func (s *LicenseService) GetLicense(ctx context.Context, licenseID, userID uuid.UUID) (*models.License, error)
GetLicense retrieves a license by ID and verifies user ownership
func (*LicenseService) ListLicenses ¶
func (s *LicenseService) ListLicenses(ctx context.Context, userID uuid.UUID) ([]*models.License, error)
ListLicenses retrieves all licenses for a user
func (*LicenseService) ListLicensesUpdatedSince ¶ added in v1.3.2
func (s *LicenseService) ListLicensesUpdatedSince(ctx context.Context, userID uuid.UUID, updatedSince time.Time) ([]*models.License, error)
ListLicensesUpdatedSince retrieves the user's licenses that changed strictly after the given instant, for delta-syncing clients.
func (*LicenseService) UpdateLicense ¶
func (s *LicenseService) UpdateLicense(ctx context.Context, license *models.License, userID uuid.UUID) error
UpdateLicense updates a license and verifies user ownership
type LoginInput ¶
type NotificationService ¶
type NotificationService struct {
// contains filtered or unexported fields
}
func NewNotificationService ¶
func NewNotificationService( notifRepo repository.NotificationRepository, credentialRepo repository.CredentialRepository, flightRepo repository.FlightRepository, licenseRepo repository.LicenseRepository, userRepo repository.UserRepository, emailSender *email.Sender, currencyService *currency.Service, customService customCurrencyLister, ) *NotificationService
func (*NotificationService) GetNotificationHistory ¶
func (s *NotificationService) GetNotificationHistory(ctx context.Context, userID uuid.UUID, limit, offset int) ([]*models.NotificationLog, int, error)
GetNotificationHistory returns paginated notification history for a user
func (*NotificationService) GetPreferences ¶
func (s *NotificationService) GetPreferences(ctx context.Context, userID uuid.UUID) (*models.NotificationPreferences, error)
GetPreferences returns notification preferences for a user
func (*NotificationService) StartBackgroundChecker ¶
func (s *NotificationService) StartBackgroundChecker(ctx context.Context, interval time.Duration)
StartBackgroundChecker starts a goroutine that checks for notifications periodically
func (*NotificationService) TriggerCheck ¶
func (s *NotificationService) TriggerCheck(ctx context.Context)
TriggerCheck runs the notification check immediately for all users, bypassing the check-hour gating. Used by admin maintenance endpoint and E2E tests.
func (*NotificationService) UpdatePreferences ¶
func (s *NotificationService) UpdatePreferences(ctx context.Context, prefs *models.NotificationPreferences) error
UpdatePreferences updates notification preferences for a user
type OIDCAuthorization ¶ added in v1.3.2
type OIDCAuthorization struct {
AuthorizationURL string
BrowserToken string
// Expiry is when the pending login stops being usable; used as the
// cookie's Max-Age.
Expiry time.Time
}
OIDCAuthorization is what the authorize step hands back: the provider URL to send the browser to, and the value to plant in the browser as a cookie for the callback's same-browser check.
type OIDCConfig ¶ added in v1.3.2
type OIDCConfig struct {
// Issuer is the provider's issuer URL. Its presence enables OIDC mode.
Issuer string
// ClientID and ClientSecret identify NinerLog to the provider.
ClientID string
ClientSecret string
// RedirectURL is this API's own callback, exactly as registered with the
// provider (…/api/v1/auth/oidc/callback).
RedirectURL string
// PostLoginRedirect is the frontend URL the browser is sent to after a
// successful login. Fixed by configuration, never read from the request.
PostLoginRedirect string
// Scopes requested at the provider. "openid" is always included.
Scopes []string
// ProviderName is the label the sign-in button shows ("Sign in with …").
ProviderName string
// NameClaim is the claim used as the pilot's display name.
NameClaim string
// LinkByVerifiedEmail lets a first OIDC login adopt a pre-existing local
// account with the same address, but only when the ID token asserts
// email_verified. Off by default.
LinkByVerifiedEmail bool
// TrustEmailVerified marks provisioned users as email-verified even when
// the ID token carries no email_verified claim. Required for ADMIN_EMAIL
// to take effect with providers that omit the claim.
TrustEmailVerified bool
// LoginStateTTL and HandoffTTL bound the two single-use artefacts of a
// login round trip.
LoginStateTTL time.Duration
HandoffTTL time.Duration
}
OIDCConfig is the operator-supplied configuration for OIDC mode. It is built exclusively from environment variables; there is no per-user or database configuration for the provider.
func LoadOIDCConfig ¶ added in v1.3.2
func LoadOIDCConfig() (OIDCConfig, error)
LoadOIDCConfig reads OIDC configuration from the environment. It returns a disabled config (and no error) when OIDC_ISSUER is unset. When the issuer is set, every other mandatory value must be present and well-formed or startup stops.
func (OIDCConfig) CookiePath ¶ added in v1.3.2
func (c OIDCConfig) CookiePath() string
CookiePath scopes the login-state cookie to the OIDC endpoints. It is derived from the configured callback, including any reverse-proxy prefix.
func (OIDCConfig) CookieSecure ¶ added in v1.3.2
func (c OIDCConfig) CookieSecure() bool
CookieSecure reports whether the login-state cookie must carry the Secure attribute, derived from the configured callback URL's scheme.
func (OIDCConfig) Enabled ¶ added in v1.3.2
func (c OIDCConfig) Enabled() bool
Enabled reports whether OIDC mode is switched on.
type OIDCService ¶ added in v1.3.2
type OIDCService struct {
// contains filtered or unexported fields
}
OIDCService implements the authorization-code + PKCE login flow against a single configured provider.
It is constructed only when OIDC_ISSUER is set; a nil *OIDCService means the deployment runs in local-credential mode, and handlers check for that before touching any method here.
func NewOIDCService ¶ added in v1.3.2
func NewOIDCService( cfg OIDCConfig, userRepo repository.UserRepository, identityRepo repository.OIDCIdentityRepository, authService *AuthService, ) (*OIDCService, error)
NewOIDCService returns a service for the supplied configuration, or nil when OIDC is not enabled. It does not contact the provider.
func (*OIDCService) BeginLogin ¶ added in v1.3.2
func (s *OIDCService) BeginLogin(ctx context.Context) (*OIDCAuthorization, error)
BeginLogin creates a pending authorization request and returns the provider URL to redirect the browser to. Three independent single-use values are minted: `state`, `nonce`, and the PKCE verifier. Only hashes of the state and the browser token are persisted.
func (*OIDCService) CompleteCallback ¶ added in v1.3.2
func (s *OIDCService) CompleteCallback(ctx context.Context, code, state, browserToken string) (string, error)
CompleteCallback validates the provider's response, provisions or updates the local user, and returns only a single-use handoff code for the browser; the access and refresh tokens are minted later, by ExchangeHandoff.
func (*OIDCService) Config ¶ added in v1.3.2
func (s *OIDCService) Config() OIDCConfig
Config returns the effective configuration (no secrets are exposed by the callers that use it).
func (*OIDCService) ExchangeHandoff ¶ added in v1.3.2
func (s *OIDCService) ExchangeHandoff(ctx context.Context, handoff string) (*models.User, *TokenPair, error)
ExchangeHandoff redeems a handoff code for the user and a fresh token pair.
func (*OIDCService) PostLoginRedirect ¶ added in v1.3.2
func (s *OIDCService) PostLoginRedirect() string
PostLoginRedirect is the fixed frontend URL the callback redirects to.
func (*OIDCService) StartStateReaper ¶ added in v1.3.2
func (s *OIDCService) StartStateReaper(ctx context.Context, interval time.Duration)
StartStateReaper deletes expired login states and handoff codes on a timer. Hygiene only: consumption already refuses expired rows.
type PasswordResetRequest ¶ added in v1.3.2
type PasswordResetRequest struct {
// Token is the plaintext reset token to embed in the mail. Empty when no
// account matched; callers must stay silent in that case.
Token string
Email string
Name string
// Locale is the account's preferred locale, for template selection.
Locale string
// TwoFactorEnabled tells the mail to warn the user up front that they will
// also need their authenticator (or a recovery code) to finish the reset.
TwoFactorEnabled bool
}
PasswordResetRequest describes the recipient of a password-reset mail. All fields are loaded from the database, never from the HTTP request.
type PasswordResetResult ¶ added in v1.3.2
type PasswordResetResult struct {
UserID uuid.UUID
Email string
Name string
Locale string
// TwoFactorEnabled reports whether the account still has 2FA active; a
// reset never turns it off.
TwoFactorEnabled bool
}
PasswordResetResult describes a completed password reset.
type RegisterInput ¶
type TwoFactorService ¶
type TwoFactorService struct {
// contains filtered or unexported fields
}
func NewTwoFactorService ¶
func NewTwoFactorService(userRepo repository.UserRepository, jwtManager *jwt.Manager, aead *cryptoutil.AEAD) *TwoFactorService
NewTwoFactorService constructs the service. aead may be nil, in which case TOTP secrets are stored unencrypted (backward-compatible). Provide an AEAD (see cryptoutil) to encrypt secrets at rest.
func (*TwoFactorService) SetupTOTP ¶
SetupTOTP generates a new TOTP secret for a user (does not enable 2FA yet)
func (*TwoFactorService) ValidateTOTP ¶
func (s *TwoFactorService) ValidateTOTP(ctx context.Context, userID uuid.UUID, code string) (bool, error)
ValidateTOTP validates a TOTP code or recovery code for a user. It shares the per-account lockout with password login: a locked account is rejected with ErrAccountLocked, each failed code counts toward the lockout, and a successful validation resets the counter.
func (*TwoFactorService) VerifyAndEnable ¶
func (s *TwoFactorService) VerifyAndEnable(ctx context.Context, userID uuid.UUID, code string) ([]string, error)
VerifyAndEnable verifies a TOTP code and enables 2FA, returning recovery codes
type TwoFactorValidator ¶ added in v1.3.2
type TwoFactorValidator interface {
// ValidateTOTP reports whether code is a valid TOTP code or an unused
// recovery code for the user. Recovery codes are consumed on success, and
// failures count toward the account lockout.
ValidateTOTP(ctx context.Context, userID uuid.UUID, code string) (bool, error)
}
TwoFactorValidator is the part of TwoFactorService that the password-reset flow depends on.
type UnverifiedAccountConfig ¶ added in v1.3.2
type UnverifiedAccountConfig struct {
// ReminderAfter is how long after signup the follow-up email goes out.
ReminderAfter time.Duration
// Retention is how long after that reminder the account survives unverified.
Retention time.Duration
// SweepInterval is how often the worker looks for work.
SweepInterval time.Duration
// BatchSize bounds reminders per sweep.
BatchSize int
}
UnverifiedAccountConfig is the lifecycle timing. Zero values fall back to the defaults above.
func LoadUnverifiedAccountConfig ¶ added in v1.3.2
func LoadUnverifiedAccountConfig() UnverifiedAccountConfig
LoadUnverifiedAccountConfig reads the lifecycle timing from the environment. Every value is optional; an unparseable or non-positive setting falls back to the default.
type UnverifiedAccountService ¶ added in v1.3.2
type UnverifiedAccountService struct {
// contains filtered or unexported fields
}
UnverifiedAccountService reminds, then reaps, accounts that never verified their email address. cmd/api/main.go starts the worker only when the email sender is configured, and the service re-checks on every sweep.
func NewUnverifiedAccountService ¶ added in v1.3.2
func NewUnverifiedAccountService( users repository.UserRepository, tokens verificationTokenIssuer, sender reminderSender, baseURLFn func() string, cfg UnverifiedAccountConfig, ) *UnverifiedAccountService
func (*UnverifiedAccountService) Config ¶ added in v1.3.2
func (s *UnverifiedAccountService) Config() UnverifiedAccountConfig
Config reports the effective lifecycle timing.
func (*UnverifiedAccountService) Start ¶ added in v1.3.2
func (s *UnverifiedAccountService) Start(ctx context.Context)
Start runs the sweep loop until ctx is cancelled.
type UploadInput ¶ added in v1.3.2
UploadInput is one candidate image as it arrives from the handler. Data is the raw file; the content type is derived from it, never taken from the client's declared part header.
type WebAuthnService ¶ added in v1.2.0
type WebAuthnService struct {
// contains filtered or unexported fields
}
WebAuthnService implements passkey registration & login flows.
func NewWebAuthnService ¶ added in v1.2.0
func NewWebAuthnService( rpID, rpName string, rpOrigins []string, credRepo repository.WebAuthnCredentialRepository, sessionRepo repository.WebAuthnSessionRepository, userRepo repository.UserRepository, authService *AuthService, sessionTTL time.Duration, maxOpenCeremonies int, ) (*WebAuthnService, error)
NewWebAuthnService creates a new WebAuthnService. Returns nil and an error if the webauthn library cannot be initialized with the given config (e.g. invalid origins).
sessionTTL bounds how long ceremony state stays usable; non-positive values fall back to DefaultWebAuthnSessionTTL. maxOpenCeremonies caps how many ceremonies one user may hold open at once; non-positive values fall back to DefaultWebAuthnMaxOpenCeremonies.
func (*WebAuthnService) BeginLogin ¶ added in v1.2.0
func (s *WebAuthnService) BeginLogin(ctx context.Context, email string) (handle string, options *protocol.CredentialAssertion, err error)
BeginLogin starts a passkey login ceremony. If email is non-empty, the user's existing credentials are advertised; otherwise a discoverable-credential challenge is issued.
func (*WebAuthnService) BeginRegistration ¶ added in v1.2.0
func (s *WebAuthnService) BeginRegistration(ctx context.Context, userID uuid.UUID) (handle string, options *protocol.CredentialCreation, err error)
BeginRegistration starts a passkey registration ceremony for an authenticated user. The returned handle must be presented to FinishRegistration.
func (*WebAuthnService) DeleteCredential ¶ added in v1.2.0
func (s *WebAuthnService) DeleteCredential(ctx context.Context, userID, credentialID uuid.UUID) error
DeleteCredential revokes a passkey owned by the given user.
func (*WebAuthnService) FinishLogin ¶ added in v1.2.0
func (s *WebAuthnService) FinishLogin(ctx context.Context, handle string, responseJSON []byte) (*models.User, *TokenPair, error)
FinishLogin verifies an assertion and returns the authenticated user with a new TokenPair.
func (*WebAuthnService) FinishRegistration ¶ added in v1.2.0
func (s *WebAuthnService) FinishRegistration(ctx context.Context, userID uuid.UUID, handle string, label *string, responseJSON []byte) (*models.WebAuthnCredential, error)
FinishRegistration verifies an attestation and stores the new credential.
func (*WebAuthnService) ListCredentials ¶ added in v1.2.0
func (s *WebAuthnService) ListCredentials(ctx context.Context, userID uuid.UUID) ([]*models.WebAuthnCredential, error)
ListCredentials returns the registered passkeys for a user.
func (*WebAuthnService) StartSessionReaper ¶ added in v1.3.2
func (s *WebAuthnService) StartSessionReaper(ctx context.Context, interval time.Duration)
StartSessionReaper deletes expired ceremony rows on a timer until ctx is cancelled. Hygiene only: expiry is enforced by the `expires_at > NOW()` predicate in Consume.
Source Files
¶
- aircraft.go
- auth.go
- class_rating.go
- contact.go
- contact_vcard.go
- credential.go
- deletion.go
- document_file.go
- email_delivery.go
- flight.go
- flight_session.go
- flight_signature.go
- idempotency.go
- license.go
- notification.go
- notification_metrics.go
- oidc.go
- oidc_config.go
- password_policy.go
- twofactor.go
- unverified_account.go
- unverified_account_metrics.go
- webauthn.go
- webauthn_metrics.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package cloudbackup is the user-facing service for cloud backup destinations.
|
Package cloudbackup is the user-facing service for cloud backup destinations. |
|
netguard
Package netguard restricts the network destinations the cloud-backup subsystem is allowed to connect to (SSRF mitigation).
|
Package netguard restricts the network destinations the cloud-backup subsystem is allowed to connect to (SSRF mitigation). |
|
provider
Package provider defines the contract every cloud backup provider plugin must satisfy.
|
Package provider defines the contract every cloud backup provider plugin must satisfy. |
|
provider/s3
Package s3 implements the cloud backup provider contract against Amazon S3 and S3-compatible object stores (MinIO, Backblaze B2, Cloudflare R2, Wasabi, etc.) using the minio-go client.
|
Package s3 implements the cloud backup provider contract against Amazon S3 and S3-compatible object stores (MinIO, Backblaze B2, Cloudflare R2, Wasabi, etc.) using the minio-go client. |
|
provider/sftp
Package sftp implements the cloud backup provider contract against any SSH server with SFTP enabled (OpenSSH, Dropbear, atmoz/sftp, hosting providers offering SFTP-only accounts, etc.) using golang.org/x/crypto/ssh and github.com/pkg/sftp.
|
Package sftp implements the cloud backup provider contract against any SSH server with SFTP enabled (OpenSSH, Dropbear, atmoz/sftp, hosting providers offering SFTP-only accounts, etc.) using golang.org/x/crypto/ssh and github.com/pkg/sftp. |
|
provider/webdav
Package webdav implements the cloud backup provider contract against any RFC 4918 compliant WebDAV server (Nextcloud, ownCloud, mailbox.org, Box, Apache mod_dav, …) using the studio-b12/gowebdav client.
|
Package webdav implements the cloud backup provider contract against any RFC 4918 compliant WebDAV server (Nextcloud, ownCloud, mailbox.org, Box, Apache mod_dav, …) using the studio-b12/gowebdav client. |
|
Package flightrules is the single source of truth for "who/what counts as PIC, Dual, FI, Night, IFR, MP/SP …" across the codebase.
|
Package flightrules is the single source of truth for "who/what counts as PIC, Dual, FI, Night, IFR, MP/SP …" across the codebase. |