Documentation
¶
Index ¶
- Constants
- Variables
- func BackfillFileStorageLocations(db interface{ ... }, primaryProviderID string) (int64, error)
- func CalculateChunkCount(sizeBytes int64, chunkSizeBytes int64) int64
- func CleanupExpiredTokens(db *sql.DB) error
- func CompleteAdminTask(db interface{ ... }, taskID string, details string) error
- func CountFilesByProvider(db interface{ ... }, providerID string) (int64, error)
- func CreateAdminTask(db interface{ ... }, taskType, adminUsername string, progressTotal int) (string, error)
- func CreateRefreshToken(db *sql.DB, username string) (string, error)
- func DeleteContactInfo(dbtx DBTX, username string) error
- func DeleteFile(db *sql.DB, fileID string, ownerUsername string) error
- func FailAdminTask(db interface{ ... }, taskID string, errorMessage string) error
- func FormatCreditsUSD(cents int64) string
- func GenerateFileID() string
- func GenerateStorageID() string
- func GetStorageProviderRole(db interface{ ... }, providerID string) (string, error)
- func HasContactInfo(dbtx DBTX, username string) (bool, error)
- func IncrementStorageProviderStats(db interface{ ... }, providerID string, objectsDelta int64, ...) error
- func InsertFileStorageLocation(db interface{ ... }, fileID, providerID, storageID, status string) error
- func MarkStaleTasksAsFailed(db interface{ ... }) (int64, error)
- func ParseCreditsFromUSD(usdAmount string) (int64, error)
- func RecalculateProviderStats(db interface{ ... }, providerID string) error
- func RevokeAllUserTokens(db *sql.DB, username string) error
- func RevokeRefreshToken(db *sql.DB, tokenString string) error
- func SaveContactInfo(dbtx DBTX, username string, info *ContactInfo) error
- func StartAdminTask(db interface{ ... }, taskID string) error
- func UpdateAdminTaskDetails(db interface{ ... }, taskID string, details string) error
- func UpdateAdminTaskProgress(db interface{ ... }, taskID string, progressCurrent int) error
- func UpdateAdminTaskStatus(db interface{ ... }, taskID, status string) error
- func UpdateFileStorageLocationStatus(db interface{ ... }, fileID, providerID, status string) error
- func UpdateStorageProviderStats(db interface{ ... }, providerID string, totalObjects int64, ...) error
- func UpsertStorageProvider(db interface{ ... }, p *StorageProviderRecord) error
- func UserExists(dbtx DBTX, username string) (bool, error)
- func ValidateRefreshToken(db *sql.DB, tokenString string) (string, error)
- type AdminTask
- type ContactInfo
- type ContactMethod
- type CreditTransaction
- func AddCredits(db *sql.DB, username string, amountCents int64, transactionType, reason string, ...) (*CreditTransaction, error)
- func DebitCredits(db *sql.DB, username string, amountCents int64, transactionType, reason string, ...) (*CreditTransaction, error)
- func GetUserTransactions(db *sql.DB, username string, limit int, offset int) ([]*CreditTransaction, error)
- func SetCredits(db *sql.DB, username string, newBalanceCents int64, reason string, ...) (*CreditTransaction, error)
- type CreditsSummaryResponse
- type DBTX
- type File
- type FileMetadataForClient
- type FileMetadataListItem
- type FileStorageLocation
- type RefreshToken
- type StorageProviderRecord
- type User
- func (u *User) ApproveUser(dbtx DBTX, adminUsername string) error
- func (u *User) CheckStorageAvailable(size int64) bool
- func (u *User) Delete(db *sql.DB) error
- func (u *User) GetStorageUsagePercent() float64
- func (u *User) HasAdminPrivileges() bool
- func (u *User) HasOPAQUEAccount(db *sql.DB) (bool, error)
- func (u *User) UpdateStorageUsage(tx *sql.Tx, deltaBytes int64) error
- type UserCredit
Constants ¶
const ( TransactionTypeCredit = "credit" TransactionTypeDebit = "debit" TransactionTypeAdjustment = "adjustment" TransactionTypeRefund = "refund" )
Transaction types
const (
DefaultStorageLimit int64 = 1181116006 // 1.1GB in bytes
)
const MaxContactInfoSize = 8192
MaxContactInfoSize is the maximum size of the plaintext JSON blob (8 KB)
const MaxContactLabel = 100
MaxContactLabel is the maximum length for a custom contact label
const MaxContactValue = 500
MaxContactValue is the maximum length for a contact value
const MaxContacts = 20
MaxContacts is the maximum number of contact methods
const MaxDisplayNameLength = 100
MaxDisplayNameLength is the maximum length for the display name field
const MaxNotesLength = 2000
MaxNotesLength is the maximum length for the notes field
Variables ¶
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
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 ¶
CalculateChunkCount calculates the number of chunks needed for a file of given size
func CleanupExpiredTokens ¶
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 ¶
CreateRefreshToken generates a new refresh token for a user
func DeleteContactInfo ¶
DeleteContactInfo removes contact info for a user
func DeleteFile ¶
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 ¶
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 ¶
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 ¶
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 ¶
RevokeAllUserTokens revokes all refresh tokens for a user
func RevokeRefreshToken ¶
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 ¶
UserExists checks if a user exists by username
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.
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 ¶
GetFileByFileID retrieves a file record by file_id
func GetFileByStorageID ¶
GetFileByStorageID retrieves a file record by storage_id
func GetFilesByOwner ¶
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.
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 ¶
CreateUser creates a new user in the database for OPAQUE authentication
func GetPendingUsers ¶
GetPendingUsers retrieves users pending approval (admin only)
func GetUserByUsername ¶
GetUserByUsername retrieves a user by username
func (*User) ApproveUser ¶
ApproveUser approves a user (admin only)
func (*User) CheckStorageAvailable ¶
CheckStorageAvailable checks if a file of the given size can be stored
func (*User) GetStorageUsagePercent ¶
GetStorageUsagePercent returns the user's storage usage as a percentage
func (*User) HasAdminPrivileges ¶
HasAdminPrivileges checks if a user has admin privileges
func (*User) HasOPAQUEAccount ¶
HasOPAQUEAccount checks if the user has an OPAQUE account registered Uses the RFC-compliant opaque_user_data table
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