service

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: AGPL-3.0 Imports: 30 Imported by: 0

Documentation ¶

Index ¶

Constants ¶

This section is empty.

Variables ¶

View Source
var (
	ErrAircraftNotFound      = errors.New("aircraft not found")
	ErrUnauthorizedAircraft  = errors.New("unauthorized access to aircraft")
	ErrDuplicateRegistration = errors.New("aircraft registration already exists")
)
View Source
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")
	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")
)
View Source
var (
	ErrClassRatingNotFound     = errors.New("class rating not found")
	ErrInvalidClassType        = errors.New("invalid class type")
	ErrUnauthorizedClassRating = errors.New("unauthorized access to class rating")
)
View Source
var (
	ErrContactNotFound     = errors.New("contact not found")
	ErrUnauthorizedContact = errors.New("unauthorized access to contact")
)
View Source
var (
	ErrCredentialNotFound     = errors.New("credential not found")
	ErrUnauthorizedCredential = errors.New("unauthorized access to credential")
	ErrExpiryBeforeIssue      = errors.New("expiry date must be after issue date")
)
View Source
var (
	ErrFlightNotFound     = errors.New("flight not found")
	ErrInvalidFlight      = errors.New("invalid flight data")
	ErrUnauthorizedFlight = errors.New("unauthorized access to flight")
	// 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")
)
View Source
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 so a lookup miss and an
	// already-used token are indistinguishable to an anonymous caller.
	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. Deliberately not distinguished from each
	// other (or from "never existed") to avoid leaking state to an
	// unauthenticated caller.
	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")
)
View Source
var (
	ErrLicenseNotFound      = errors.New("license not found")
	ErrInvalidLicense       = errors.New("invalid license data")
	ErrLicenseAlreadyExists = errors.New("license already exists")
	ErrUnauthorizedAccess   = errors.New("unauthorized access to license")
)
View Source
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.",
		},
	)
)
View Source
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")
)
View Source
var (
	ErrWebAuthnNotConfigured     = errors.New("webauthn is not configured")
	ErrWebAuthnSessionNotFound   = errors.New("webauthn session not found or expired")
	ErrWebAuthnSessionExpired    = errors.New("webauthn session expired")
	ErrWebAuthnInvalidResponse   = errors.New("invalid webauthn response")
	ErrWebAuthnUnknownCredential = errors.New("unknown webauthn credential")
	ErrWebAuthnVerification      = errors.New("webauthn verification failed")
)
View Source
var ErrInvalidSessionEvent = errors.New("invalid flight session event")

Functions ¶

func GetCheckInterval ¶

func GetCheckInterval() time.Duration

GetCheckInterval reads NOTIFICATION_CHECK_INTERVAL env var, defaults to 1h

Types ¶

type AircraftService ¶

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

func NewAircraftService ¶

func NewAircraftService(aircraftRepo repository.AircraftRepository) *AircraftService

func (*AircraftService) CountAircraft ¶

func (s *AircraftService) CountAircraft(ctx context.Context, userID uuid.UUID) (int, error)

func (*AircraftService) CreateAircraft ¶

func (s *AircraftService) CreateAircraft(ctx context.Context, aircraft *models.Aircraft) error

func (*AircraftService) DeleteAircraft ¶

func (s *AircraftService) DeleteAircraft(ctx context.Context, id, userID uuid.UUID) error

func (*AircraftService) GetAircraft ¶

func (s *AircraftService) GetAircraft(ctx context.Context, id, userID uuid.UUID) (*models.Aircraft, error)

func (*AircraftService) ListAircraft ¶

func (s *AircraftService) ListAircraft(ctx context.Context, userID uuid.UUID) ([]*models.Aircraft, error)

func (*AircraftService) UpdateAircraft ¶

func (s *AircraftService) UpdateAircraft(ctx context.Context, aircraft *models.Aircraft, userID uuid.UUID) error

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,
) *AuthService

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) DeleteUser ¶

func (s *AuthService) DeleteUser(ctx context.Context, userID uuid.UUID, password string) error

DeleteUser permanently deletes a user account after verifying the password

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 ¶

func (s *AuthService) GetUserByID(ctx context.Context, userID uuid.UUID) (*models.User, error)

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

func (s *AuthService) MarkEmailVerified(ctx context.Context, userID uuid.UUID) error

MarkEmailVerified marks a user as verified and clears any outstanding verification tokens. Used for environments where email delivery is disabled.

func (*AuthService) RefreshToken ¶

func (s *AuthService) RefreshToken(ctx context.Context, refreshToken string) (*TokenPair, error)

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. The account is created with EmailVerified=false, an email-verification token is generated and stored, and the plaintext token is returned to the caller so the handler can deliver it via email. No JWT tokens are issued at this stage — the user must consume the verification token (see VerifyEmail) before they can log in.

func (*AuthService) RequestPasswordReset ¶

func (s *AuthService) RequestPasswordReset(ctx context.Context, email string) (token, userEmail string, err error)

RequestPasswordReset creates a password reset token.

On success it returns both the reset token and the recipient email address loaded from the database. The handler uses the database-sourced email (rather than the HTTP request) when sending the reset mail, which keeps untrusted input out of the SMTP message (CWE-640).

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 — callers should not distinguish "unknown email" from "already verified" to avoid enumeration.

func (*AuthService) ResetPassword ¶

func (s *AuthService) ResetPassword(ctx context.Context, token, newPassword string) error

ResetPassword resets a user's password using a reset token

func (*AuthService) UpdateUser ¶

func (s *AuthService) UpdateUser(ctx context.Context, user *models.User) error

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 so the frontend can log the user in.

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 (*ClassRatingService) CreateClassRating ¶

func (s *ClassRatingService) CreateClassRating(ctx context.Context, cr *models.ClassRating, userID uuid.UUID) error

func (*ClassRatingService) DeleteClassRating ¶

func (s *ClassRatingService) DeleteClassRating(ctx context.Context, ratingID, userID uuid.UUID) 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 (s *ContactService) CreateContact(ctx context.Context, contact *models.Contact) error

func (*ContactService) DeleteContact ¶

func (s *ContactService) DeleteContact(ctx context.Context, id, userID uuid.UUID) error

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 (s *ContactService) GetContact(ctx context.Context, id, userID uuid.UUID) (*models.Contact, error)

func (*ContactService) ListContacts ¶

func (s *ContactService) ListContacts(ctx context.Context, userID uuid.UUID) ([]*models.Contact, error)

func (*ContactService) SearchContacts ¶

func (s *ContactService) SearchContacts(ctx context.Context, userID uuid.UUID, query string, limit int) ([]*models.Contact, error)

func (*ContactService) UpdateContact ¶

func (s *ContactService) UpdateContact(ctx context.Context, contact *models.Contact, userID uuid.UUID) error

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 (s *CredentialService) DeleteCredential(ctx context.Context, id, userID uuid.UUID) error

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) UpdateCredential ¶

func (s *CredentialService) UpdateCredential(ctx context.Context, credential *models.Credential, userID uuid.UUID) error

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 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 ¶

func (s *FlightService) CreateFlight(ctx context.Context, flight *models.Flight) error

CreateFlight creates a new flight log entry

func (*FlightService) DeleteAllFlights ¶

func (s *FlightService) DeleteAllFlights(ctx context.Context, userID uuid.UUID) (int64, error)

DeleteAllFlights deletes all flights for a user

func (*FlightService) DeleteBaseline ¶ added in v1.2.3

func (s *FlightService) DeleteBaseline(ctx context.Context, userID uuid.UUID) error

DeleteBaseline removes the user's initial-hours snapshot.

func (*FlightService) DeleteFlight ¶

func (s *FlightService) DeleteFlight(ctx context.Context, flightID, userID uuid.UUID) error

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

func (s *FlightSessionService) Discard(ctx context.Context, userID uuid.UUID) error

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

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, which makes offline retries and double-taps safe. 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 (*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 so the caller can send a confirmation without ever trusting client-supplied contact details (CWE-640).

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

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 LicenseService ¶

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

func NewLicenseService ¶

func NewLicenseService(licenseRepo repository.LicenseRepository) *LicenseService

func (*LicenseService) CreateLicense ¶

func (s *LicenseService) CreateLicense(ctx context.Context, license *models.License) error

CreateLicense creates a new license for a user

func (*LicenseService) DeleteLicense ¶

func (s *LicenseService) DeleteLicense(ctx context.Context, licenseID, userID uuid.UUID) error

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) 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 LoginInput struct {
	Email    string
	Password string
}

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,
) *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 RegisterInput ¶

type RegisterInput struct {
	Email           string
	Password        string
	Name            string
	PreferredLocale string
}

type TokenPair ¶

type TokenPair struct {
	AccessToken  string
	RefreshToken string
}

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) Disable ¶

func (s *TwoFactorService) Disable(ctx context.Context, userID uuid.UUID, password string) error

Disable disables 2FA for a user after password verification

func (*TwoFactorService) IsEnabled ¶

func (s *TwoFactorService) IsEnabled(ctx context.Context, userID uuid.UUID) (bool, error)

IsEnabled checks if 2FA is enabled for a user

func (*TwoFactorService) SetupTOTP ¶

func (s *TwoFactorService) SetupTOTP(ctx context.Context, userID uuid.UUID) (string, string, error)

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.

The 2FA step is brute-force protected with the same per-account lockout used by password login: a locked account is rejected with ErrAccountLocked, each failed code counts toward the lockout, and a successful validation resets the counter. This prevents an attacker who has the password from grinding TOTP codes via repeated /auth/2fa/login calls.

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 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,
) (*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).

func (*WebAuthnService) BeginLogin ¶ added in v1.2.0

func (s *WebAuthnService) BeginLogin(ctx context.Context, email string) (sessionID 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) (sessionID string, options *protocol.CredentialCreation, err error)

BeginRegistration starts a passkey registration ceremony for an authenticated user.

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, sessionID 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, sessionID 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.

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, mitigating server-side request forgery (SSRF).
Package netguard restricts the network destinations the cloud-backup subsystem is allowed to connect to, mitigating server-side request forgery (SSRF).
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.

Jump to

Keyboard shortcuts

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