models

package
v0.0.0-...-101d28d Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (
	TransactionTypeCredit     = "credit"
	TransactionTypeDebit      = "debit"
	TransactionTypeAdjustment = "adjustment"
	TransactionTypeRefund     = "refund"
)

Transaction types

View Source
const (
	DefaultStorageLimit int64 = 1181116006 // 1.1GB in bytes
)
View Source
const MaxContactInfoSize = 8192

MaxContactInfoSize is the maximum size of the plaintext JSON blob (8 KB)

View Source
const MaxContactLabel = 100

MaxContactLabel is the maximum length for a custom contact label

View Source
const MaxContactValue = 500

MaxContactValue is the maximum length for a contact value

View Source
const MaxContacts = 20

MaxContacts is the maximum number of contact methods

View Source
const MaxDisplayNameLength = 100

MaxDisplayNameLength is the maximum length for the display name field

View Source
const MaxNotesLength = 2000

MaxNotesLength is the maximum length for the notes field

Variables

View Source
var (
	ErrRefreshTokenExpired  = errors.New("refresh token has expired")
	ErrUserNotFound         = errors.New("user not found for token")
	ErrRefreshTokenNotFound = errors.New("refresh token not found")
)

Pre-defined errors for token validation

View Source
var ValidContactTypes = map[string]bool{
	"email":    true,
	"sms":      true,
	"signal":   true,
	"whatsapp": true,
	"wechat":   true,
	"telegram": true,
	"matrix":   true,
	"other":    true,
}

ValidContactTypes lists the allowed contact method types

Functions

func BackfillFileStorageLocations

func BackfillFileStorageLocations(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, primaryProviderID string) (int64, error)

BackfillFileStorageLocations populates location records for files that don't have one yet. This is used on startup to ensure every existing file has at least one location record pointing to the current primary provider. Idempotent: skips files that already have locations.

func CalculateChunkCount

func CalculateChunkCount(sizeBytes int64, chunkSizeBytes int64) int64

CalculateChunkCount calculates the number of chunks needed for a file of given size

func CleanupExpiredTokens

func CleanupExpiredTokens(db *sql.DB) error

CleanupExpiredTokens removes expired tokens from the database

func CompleteAdminTask

func CompleteAdminTask(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, taskID string, details string) error

CompleteAdminTask marks a task as completed with final details.

func CountFilesByProvider

func CountFilesByProvider(db interface {
	QueryRow(string, ...interface{}) *sql.Row
}, providerID string) (int64, error)

CountFilesByProvider returns the count of active files on a given provider.

func CreateAdminTask

func CreateAdminTask(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, taskType, adminUsername string, progressTotal int) (string, error)

CreateAdminTask inserts a new admin task record and returns the generated task ID.

func CreateRefreshToken

func CreateRefreshToken(db *sql.DB, username string) (string, error)

CreateRefreshToken generates a new refresh token for a user

func DeleteContactInfo

func DeleteContactInfo(dbtx DBTX, username string) error

DeleteContactInfo removes contact info for a user

func DeleteFile

func DeleteFile(db *sql.DB, fileID string, ownerUsername string) error

DeleteFile removes a file record from the database by file_id

func FailAdminTask

func FailAdminTask(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, taskID string, errorMessage string) error

FailAdminTask marks a task as failed with an error message.

func FormatCreditsUSD

func FormatCreditsUSD(cents int64) string

FormatCreditsUSD formats credit cents as USD string (e.g., 1234 cents -> "$12.34")

func GenerateFileID

func GenerateFileID() string

GenerateFileID creates a new UUID v4 for file identification

func GenerateStorageID

func GenerateStorageID() string

GenerateStorageID creates a new UUID v4 for storage

func GetStorageProviderRole

func GetStorageProviderRole(db interface {
	QueryRow(string, ...interface{}) *sql.Row
}, providerID string) (string, error)

GetStorageProviderRole returns the role of a provider from the DB. Returns "" and sql.ErrNoRows if not found.

func HasContactInfo

func HasContactInfo(dbtx DBTX, username string) (bool, error)

HasContactInfo checks if a user has contact info set

func IncrementStorageProviderStats

func IncrementStorageProviderStats(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, providerID string, objectsDelta int64, sizeBytesDelta int64) error

IncrementStorageProviderStats adds to the cached object count and size for a provider.

func InsertFileStorageLocation

func InsertFileStorageLocation(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, fileID, providerID, storageID, status string) error

InsertFileStorageLocation creates a new location record for a file on a provider.

func MarkStaleTasksAsFailed

func MarkStaleTasksAsFailed(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}) (int64, error)

MarkStaleTasksAsFailed finds tasks stuck in "running" status (from a previous server crash) and marks them as failed. Called on server startup.

func ParseCreditsFromUSD

func ParseCreditsFromUSD(usdAmount string) (int64, error)

ParseCreditsFromUSD parses USD string to cents (e.g., "12.34" -> 1234 cents)

func RecalculateProviderStats

func RecalculateProviderStats(db interface {
	QueryRow(string, ...interface{}) *sql.Row
	Exec(string, ...interface{}) (sql.Result, error)
}, providerID string) error

RecalculateProviderStats recalculates total_objects and total_size_bytes for a provider from the file_storage_locations and file_metadata tables.

func RevokeAllUserTokens

func RevokeAllUserTokens(db *sql.DB, username string) error

RevokeAllUserTokens revokes all refresh tokens for a user

func RevokeRefreshToken

func RevokeRefreshToken(db *sql.DB, tokenString string) error

RevokeRefreshToken marks a token as revoked

func SaveContactInfo

func SaveContactInfo(dbtx DBTX, username string, info *ContactInfo) error

SaveContactInfo encrypts and stores contact info for a user

func StartAdminTask

func StartAdminTask(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, taskID string) error

StartAdminTask marks a task as running with a started_at timestamp.

func UpdateAdminTaskDetails

func UpdateAdminTaskDetails(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, taskID string, details string) error

UpdateAdminTaskDetails updates the details JSON field of a task (used for live progress).

func UpdateAdminTaskProgress

func UpdateAdminTaskProgress(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, taskID string, progressCurrent int) error

UpdateAdminTaskProgress updates the progress counters of a task.

func UpdateAdminTaskStatus

func UpdateAdminTaskStatus(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, taskID, status string) error

UpdateAdminTaskStatus updates the status of a task.

func UpdateFileStorageLocationStatus

func UpdateFileStorageLocationStatus(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, fileID, providerID, status string) error

UpdateFileStorageLocationStatus updates the status of a file location record.

func UpdateStorageProviderStats

func UpdateStorageProviderStats(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
}, providerID string, totalObjects int64, totalSizeBytes int64) error

UpdateStorageProviderStats updates the cached object count and size for a provider.

func UpsertStorageProvider

func UpsertStorageProvider(db interface {
	Exec(string, ...interface{}) (sql.Result, error)
	QueryRow(string, ...interface{}) *sql.Row
}, p *StorageProviderRecord) error

UpsertStorageProvider inserts or updates a storage provider record. On conflict (provider_id already exists), updates metadata fields but preserves the existing role assignment (DB is authoritative for roles after first startup).

func UserExists

func UserExists(dbtx DBTX, username string) (bool, error)

UserExists checks if a user exists by username

func ValidateRefreshToken

func ValidateRefreshToken(db *sql.DB, tokenString string) (string, error)

ValidateRefreshToken checks if a refresh token is valid and returns the username Uses sliding window expiry - extends token lifetime on successful use

Types

type AdminTask

type AdminTask struct {
	TaskID          string         `json:"task_id"`
	TaskType        string         `json:"task_type"` // "copy-all", "copy-user-files", "copy-file"
	Status          string         `json:"status"`    // "pending", "running", "completed", "failed", "canceled"
	AdminUsername   string         `json:"admin_username"`
	ProgressCurrent int            `json:"progress_current"`
	ProgressTotal   int            `json:"progress_total"`
	StartedAt       sql.NullString `json:"started_at"`
	CompletedAt     sql.NullString `json:"completed_at"`
	ErrorMessage    sql.NullString `json:"error_message"`
	Details         sql.NullString `json:"details"` // JSON text for task-specific metadata
	CreatedAt       sql.NullString `json:"created_at"`
	UpdatedAt       sql.NullString `json:"updated_at"`
}

AdminTask represents a row in the admin_tasks table. Tracks background task progress for long-running admin operations.

func GetAdminTask

func GetAdminTask(db interface {
	QueryRow(string, ...interface{}) *sql.Row
}, taskID string) (*AdminTask, error)

GetAdminTask retrieves an admin task by its ID.

type ContactInfo

type ContactInfo struct {
	DisplayName string          `json:"display_name"`
	Contacts    []ContactMethod `json:"contacts"`
	Notes       string          `json:"notes"`
}

ContactInfo represents the plaintext contact information structure

func GetContactInfo

func GetContactInfo(dbtx DBTX, username string) (*ContactInfo, error)

GetContactInfo retrieves and decrypts contact info for a user

func (*ContactInfo) Validate

func (ci *ContactInfo) Validate() error

Validate checks that the contact info structure is well-formed

type ContactMethod

type ContactMethod struct {
	Type  string `json:"type"`
	Value string `json:"value"`
	Label string `json:"label,omitempty"` // Only used when Type is "other"
}

ContactMethod represents a single contact method (email, signal, etc.)

type CreditTransaction

type CreditTransaction struct {
	ID                   int64     `json:"id"`
	TransactionID        *string   `json:"transaction_id,omitempty"`
	Username             string    `json:"username"`
	AmountUSDCents       int64     `json:"amount_usd_cents"`
	BalanceAfterUSDCents int64     `json:"balance_after_usd_cents"`
	TransactionType      string    `json:"transaction_type"`
	Reason               *string   `json:"reason,omitempty"`
	AdminUsername        *string   `json:"admin_username,omitempty"`
	Metadata             *string   `json:"metadata,omitempty"`
	CreatedAt            time.Time `json:"created_at"`
}

CreditTransaction represents a credit transaction record

func AddCredits

func AddCredits(db *sql.DB, username string, amountCents int64, transactionType, reason string, transactionID *string, adminUsername *string) (*CreditTransaction, error)

AddCredits adds credits to a user's balance (creates transaction record)

func DebitCredits

func DebitCredits(db *sql.DB, username string, amountCents int64, transactionType, reason string, transactionID *string, adminUsername *string) (*CreditTransaction, error)

DebitCredits removes credits from a user's balance (creates transaction record)

func GetUserTransactions

func GetUserTransactions(db *sql.DB, username string, limit int, offset int) ([]*CreditTransaction, error)

GetUserTransactions retrieves credit transactions for a user

func SetCredits

func SetCredits(db *sql.DB, username string, newBalanceCents int64, reason string, adminUsername string) (*CreditTransaction, error)

SetCredits sets a user's credit balance to a specific amount (admin only)

type CreditsSummaryResponse

type CreditsSummaryResponse struct {
	Username           string               `json:"username"`
	Balance            *UserCredit          `json:"balance"`
	RecentTransactions []*CreditTransaction `json:"recent_transactions"`
	FormattedBalance   string               `json:"formatted_balance"`
}

CreditsSummaryResponse represents a summary of user's credit status

func GetUserCreditsSummary

func GetUserCreditsSummary(db *sql.DB, username string) (*CreditsSummaryResponse, error)

GetUserCreditsSummary gets a complete summary of user's credit status

type DBTX

type DBTX interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
	Query(query string, args ...interface{}) (*sql.Rows, error)
	QueryRow(query string, args ...interface{}) *sql.Row
}

DBTX is an interface for database operations that can be handled by either a *sql.DB or a *sql.Tx

type File

type File struct {
	ID                     int64          `json:"id"`
	FileID                 string         `json:"file_id"`    // UUID v4 for file identification
	StorageID              string         `json:"storage_id"` // UUID v4 for storage backend
	OwnerUsername          string         `json:"owner_username"`
	PasswordHint           string         `json:"password_hint,omitempty"`
	PasswordType           string         `json:"password_type"`
	FilenameNonce          string         // Now stored as base64 strings directly
	EncryptedFilename      string         // Now stored as base64 strings directly
	Sha256sumNonce         string         // base64 nonce for EncryptedSha256sum (plaintext-file hash)
	EncryptedSha256sum     string         // base64 ciphertext of SHA-256 of plaintext file; client-encrypted, AAD-bound
	EncryptedFileSha256sum sql.NullString `json:"-"` // PLAINTEXT server-computed hash of encrypted stream; name is historical, not ciphertext
	EncryptedFEK           string         // Now stored as base64 strings directly

	SizeBytes      int64         `json:"size_bytes"`       // Original file size
	PaddedSize     sql.NullInt64 `json:"padded_size"`      // Size with padding for privacy/security
	ChunkCount     int64         `json:"chunk_count"`      // Number of 16MB chunks for chunked downloads
	ChunkSizeBytes int64         `json:"chunk_size_bytes"` // Size of each chunk (16MB default)
	UploadDate     time.Time     `json:"upload_date"`
}

SHA-256 fields on File / file_metadata:

Sha256sumNonce + EncryptedSha256sum
  SHA-256 of the user's original PLAINTEXT file. Computed client-side,
  encrypted client-side under the account key, and stored as ciphertext
  (nonce + ct||tag, base64). The server never sees this value in
  plaintext. AAD-bound to (file_id, "sha256sum", owner_username) per
  docs/wip/folders-multi-upload-v2.md §3 so cross-row / cross-field
  tampering fails at client decrypt time.

EncryptedFileSha256sum
  Despite the "Encrypted" prefix in the column/field name, this value
  is NOT ciphertext. It is a plaintext SHA-256 computed on the server
  as a running hash over the already-client-side-encrypted data stream
  (pre-padding) as chunks arrive during upload. The server holds it
  in plaintext by construction. Used by the client as an
  anti-equivocation record: at upload completion the server reports
  this value; the client can later re-download, re-hash the
  ciphertext it receives, and confirm the server is still reporting
  the same value. NOT in AAD scope because it is not encrypted. The
  name is kept for historical reasons; see the plan doc for details.

(See also stored_blob_sha256sum on file_metadata — SHA-256 of all
 bytes written to S3 including crypto-random padding, used for
 server-side at-rest integrity checks during download. Plaintext,
 server-computed, not surfaced on this struct.)

func CreateFile

func CreateFile(db *sql.DB, fileID, storageID, ownerUsername, passwordHint, passwordType string,
	filenameNonce, encryptedFilename, sha256sumNonce, encryptedSha256sum string, sizeBytes int64) (*File, error)

CreateFile creates a new file record in the database with encrypted metadata (base64 strings)

func GetFileByFileID

func GetFileByFileID(db *sql.DB, fileID string) (*File, error)

GetFileByFileID retrieves a file record by file_id

func GetFileByStorageID

func GetFileByStorageID(db *sql.DB, storageID string) (*File, error)

GetFileByStorageID retrieves a file record by storage_id

func GetFilesByOwner

func GetFilesByOwner(db *sql.DB, ownerUsername string) ([]*File, error)

GetFilesByOwner retrieves all files owned by a specific user

func (*File) ToClientMetadata

func (f *File) ToClientMetadata() *FileMetadataForClient

ToClientMetadata converts a File to FileMetadataForClient for sending to the client. All data is now stored as base64 strings directly, so we return them as-is.

func (*File) UpdatePasswordHint

func (f *File) UpdatePasswordHint(db *sql.DB, newHint string) error

UpdatePasswordHint updates the password hint for a file

type FileMetadataForClient

type FileMetadataForClient struct {
	FileID             string    `json:"file_id"`
	StorageID          string    `json:"storage_id"`
	PasswordHint       string    `json:"password_hint,omitempty"`
	PasswordType       string    `json:"password_type"`
	FilenameNonce      string    `json:"filename_nonce"`
	EncryptedFilename  string    `json:"encrypted_filename"`
	Sha256sumNonce     string    `json:"sha256sum_nonce"`
	EncryptedSha256sum string    `json:"encrypted_sha256sum"`
	EncryptedFEK       string    `json:"encrypted_fek"`
	SizeBytes          int64     `json:"size_bytes"`
	UploadDate         time.Time `json:"upload_date"`
}

FileMetadataForClient represents the encrypted metadata that gets sent to the client. All binary data is Base64-encoded as strings for robust JSON transport.

type FileMetadataListItem

type FileMetadataListItem struct {
	FileID             string    `json:"file_id"`
	PasswordType       string    `json:"password_type"`
	FilenameNonce      string    `json:"filename_nonce"`
	EncryptedFilename  string    `json:"encrypted_filename"`
	Sha256sumNonce     string    `json:"sha256sum_nonce"`
	EncryptedSha256sum string    `json:"encrypted_sha256sum"`
	SizeBytes          int64     `json:"size_bytes"`
	UploadDate         time.Time `json:"upload_date"`
}

FileMetadataListItem is a lightweight owner-only metadata shape for listing and local client-side decryption workflows.

func GetFileMetadataBatchByOwner

func GetFileMetadataBatchByOwner(db *sql.DB, ownerUsername string, fileIDs []string) ([]*FileMetadataListItem, error)

GetFileMetadataBatchByOwner retrieves lightweight metadata for an explicit batch of file IDs owned by a specific user.

func GetRecentFileMetadataByOwner

func GetRecentFileMetadataByOwner(db *sql.DB, ownerUsername string, limit, offset int) ([]*FileMetadataListItem, error)

GetRecentFileMetadataByOwner retrieves a paginated recent metadata view for files owned by a specific user, ordered by upload date descending.

type FileStorageLocation

type FileStorageLocation struct {
	ID         int64          `json:"id"`
	FileID     string         `json:"file_id"`
	ProviderID string         `json:"provider_id"`
	StorageID  string         `json:"storage_id"`
	Status     string         `json:"status"` // "active", "pending", "failed", "deleted", "delete_failed"
	CreatedAt  sql.NullString `json:"created_at"`
	VerifiedAt sql.NullString `json:"verified_at"`
}

FileStorageLocation represents a row in the file_storage_locations table. Tracks which providers hold a copy of each file's encrypted blob.

func GetActiveFileStorageLocations

func GetActiveFileStorageLocations(db interface {
	Query(string, ...interface{}) (*sql.Rows, error)
}, fileID string) ([]FileStorageLocation, error)

GetActiveFileStorageLocations returns only active location records for a file.

func GetFileStorageLocations

func GetFileStorageLocations(db interface {
	Query(string, ...interface{}) (*sql.Rows, error)
}, fileID string) ([]FileStorageLocation, error)

GetFileStorageLocations returns all location records for a given file.

type RefreshToken

type RefreshToken struct {
	ID        string
	Username  string
	TokenHash string
	ExpiresAt time.Time
	CreatedAt time.Time
	Revoked   bool
	LastUsed  *time.Time
}

RefreshToken represents a refresh token in the database

type StorageProviderRecord

type StorageProviderRecord struct {
	ProviderID     string         `json:"provider_id"`
	ProviderType   string         `json:"provider_type"`
	BucketName     string         `json:"bucket_name"`
	Endpoint       string         `json:"endpoint"`
	Region         string         `json:"region"`
	Role           string         `json:"role"`
	EnvVarPrefix   string         `json:"env_var_prefix"`
	IsActive       bool           `json:"is_active"`
	TotalObjects   int64          `json:"total_objects"`
	TotalSizeBytes int64          `json:"total_size_bytes"`
	CostPerTBCents sql.NullInt64  `json:"cost_per_tb_cents"`
	LastVerifiedAt sql.NullString `json:"last_verified_at"`
	CreatedAt      time.Time      `json:"created_at"`
	UpdatedAt      time.Time      `json:"updated_at"`
}

StorageProviderRecord represents a row in the storage_providers table.

func GetStorageProviderByID

func GetStorageProviderByID(db interface {
	QueryRow(string, ...interface{}) *sql.Row
}, providerID string) (*StorageProviderRecord, error)

GetStorageProviderByID retrieves a storage provider by its ID.

type User

type User struct {
	ID                int64          `json:"id"`
	Username          string         `json:"username"`
	CreatedAt         time.Time      `json:"created_at"`
	TotalStorageBytes int64          `json:"total_storage_bytes"`
	StorageLimitBytes int64          `json:"storage_limit_bytes"`
	IsApproved        bool           `json:"is_approved"`
	ApprovedBy        sql.NullString `json:"approved_by,omitempty"`
	ApprovedAt        sql.NullTime   `json:"approved_at,omitempty"`
	IsAdmin           bool           `json:"is_admin"`
}

func CreateUser

func CreateUser(dbtx DBTX, username string) (*User, error)

CreateUser creates a new user in the database for OPAQUE authentication

func GetPendingUsers

func GetPendingUsers(dbtx DBTX) ([]*User, error)

GetPendingUsers retrieves users pending approval (admin only)

func GetUserByUsername

func GetUserByUsername(dbtx DBTX, username string) (*User, error)

GetUserByUsername retrieves a user by username

func (*User) ApproveUser

func (u *User) ApproveUser(dbtx DBTX, adminUsername string) error

ApproveUser approves a user (admin only)

func (*User) CheckStorageAvailable

func (u *User) CheckStorageAvailable(size int64) bool

CheckStorageAvailable checks if a file of the given size can be stored

func (*User) Delete

func (u *User) Delete(db *sql.DB) error

Delete removes the user and all associated data

func (*User) GetStorageUsagePercent

func (u *User) GetStorageUsagePercent() float64

GetStorageUsagePercent returns the user's storage usage as a percentage

func (*User) HasAdminPrivileges

func (u *User) HasAdminPrivileges() bool

HasAdminPrivileges checks if a user has admin privileges

func (*User) HasOPAQUEAccount

func (u *User) HasOPAQUEAccount(db *sql.DB) (bool, error)

HasOPAQUEAccount checks if the user has an OPAQUE account registered Uses the RFC-compliant opaque_user_data table

func (*User) UpdateStorageUsage

func (u *User) UpdateStorageUsage(tx *sql.Tx, deltaBytes int64) error

UpdateStorageUsage updates the user's total storage (should be called in a transaction)

type UserCredit

type UserCredit struct {
	ID              int64     `json:"id"`
	Username        string    `json:"username"`
	BalanceUSDCents int64     `json:"balance_usd_cents"`
	CreatedAt       time.Time `json:"created_at"`
	UpdatedAt       time.Time `json:"updated_at"`
}

UserCredit represents a user's credit balance

func CreateUserCredits

func CreateUserCredits(db *sql.DB, username string) (*UserCredit, error)

CreateUserCredits creates a new user credit record with 0 balance

func GetAllUserCredits

func GetAllUserCredits(db *sql.DB) ([]*UserCredit, error)

GetAllUserCredits retrieves all user credit balances (admin only)

func GetOrCreateUserCredits

func GetOrCreateUserCredits(db *sql.DB, username string) (*UserCredit, error)

GetOrCreateUserCredits gets existing credits or creates a new record with 0 balance

func GetUserCredits

func GetUserCredits(db *sql.DB, username string) (*UserCredit, error)

GetUserCredits retrieves a user's credit balance

Jump to

Keyboard shortcuts

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