service

package
v1.2.5 Latest Latest
Warning

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

Go to latest
Published: May 27, 2026 License: AGPL-3.0 Imports: 26 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")
)
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"},
	)
)
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")
)

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) 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 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
}

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) *TwoFactorService

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

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