backup

package
v1.5.2 Latest Latest
Warning

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

Go to latest
Published: Jan 3, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package backup provides functionality for creating and restoring SafeShare backups.

Package backup provides functionality for creating and restoring SafeShare backups.

The backup package supports three backup modes:

  • config: Settings, webhooks, blocked IPs, admin credentials only
  • database: Full database without uploaded files
  • full: Database + all uploaded files

Backups are created as directory structures with a manifest.json file that contains metadata, checksums, and information about what's included.

Index

Constants

View Source
const (
	// ManifestFilename is the name of the manifest file in backup directories
	ManifestFilename = "manifest.json"

	// DatabaseFilename is the name of the database backup file
	DatabaseFilename = "safeshare.db"

	// UploadsDirname is the name of the uploads directory in full backups
	UploadsDirname = "uploads"
)
View Source
const (
	// BackupDirPerms is the permission mode for backup directories (owner only)
	BackupDirPerms = 0700
	// BackupFilePerms is the permission mode for backup files (owner only)
	BackupFilePerms = 0600
)
View Source
const ManifestVersion = "1.0"

ManifestVersion is the current backup manifest format version

View Source
const (
	// PartialUploadDir is the directory containing partial uploads (excluded from backup)
	PartialUploadDir = ".partial"
)

Variables

View Source
var ConfigTables = []string{
	"settings",
	"admin_credentials",
	"blocked_ips",
	"webhook_configs",
}

ConfigTables lists tables included in config-only backups

View Source
var ErrBackupAlreadyRunning = errors.New("another backup is already running")

ErrBackupAlreadyRunning indicates a backup is already in progress.

View Source
var ErrInvalidCronExpression = errors.New("invalid cron expression")

ErrInvalidCronExpression indicates an invalid cron expression.

View Source
var ExcludedTables = []string{
	"user_sessions",
	"admin_sessions",
	"partial_uploads",
}

ExcludedTables lists tables that should NOT be backed up

View Source
var FullDatabaseTables = []string{
	"files",
	"users",
	"settings",
	"admin_credentials",
	"blocked_ips",
	"webhook_configs",
	"api_tokens",
	"webhook_deliveries",
}

FullDatabaseTables lists all tables included in database/full backups

Functions

func BackupDatabase

func BackupDatabase(sourcePath, destPath string) error

BackupDatabase creates a hot backup of a SQLite database This uses VACUUM INTO which creates a consistent snapshot and handles WAL mode correctly

func CleanupUploadsDir

func CleanupUploadsDir(uploadsDir string, keepFiles map[string]bool) (int, error)

CleanupUploadsDir removes files from uploads directory that are not in the whitelist This is used during restore to remove files that were uploaded after the backup

func ComputeChecksum

func ComputeChecksum(filePath string) (string, error)

ComputeChecksum computes the SHA256 checksum of a file

func ComputeKeyFingerprint

func ComputeKeyFingerprint(encryptionKey string) string

ComputeKeyFingerprint computes the SHA256 fingerprint of an encryption key This allows verification that the correct key is used without storing the key itself

func CopyUploadsDir

func CopyUploadsDir(srcDir, destDir string, progressCallback func(current, total int, filename string)) (int, int64, error)

CopyUploadsDir copies all files from source uploads directory to destination Excludes the .partial directory which contains temporary chunked uploads

func CountUploadFiles

func CountUploadFiles(uploadsDir string) (int, error)

CountUploadFiles counts the number of files in uploads directory (excluding .partial)

func DeleteOrphanedFileRecords

func DeleteOrphanedFileRecords(dbPath string, storedFilenames []string) (int, error)

DeleteOrphanedFileRecords removes file records that don't have corresponding files

func FindOrphanedFiles

func FindOrphanedFiles(uploadsDir string, dbStoredFilenames map[string]bool) ([]string, error)

FindOrphanedFiles identifies files in uploads that don't have database records

func GetBackupDirName

func GetBackupDirName() string

GetBackupDirName generates a backup directory name based on timestamp

func GetDirectorySize

func GetDirectorySize(dirPath string) (int64, error)

GetDirectorySize calculates the total size of all files in a directory

func GetFileSize

func GetFileSize(filePath string) (int64, error)

GetFileSize returns the size of a file in bytes

func GetTableCounts

func GetTableCounts(db *sql.DB) (map[string]int, error)

GetTableCounts returns counts for all tables in the database

func GetUploadsTotalSize

func GetUploadsTotalSize(uploadsDir string) (int64, error)

GetUploadsTotalSize calculates total size of files in uploads directory (excluding .partial)

func RestoreDatabase

func RestoreDatabase(backupPath, destPath string) error

RestoreDatabase restores a database from a backup file The destination database file will be replaced

func RestoreUploadsDir

func RestoreUploadsDir(backupDir, destDir string, progressCallback func(current, total int, filename string)) (int, error)

RestoreUploadsDir restores files from backup to uploads directory

func ValidateCronExpression

func ValidateCronExpression(cronExpr string) error

ValidateCronExpression validates a cron expression. Supported format: minute hour day month weekday Examples: "0 2 * * *" (2 AM daily), "0 0 * * 0" (midnight Sunday)

func ValidateDatabase

func ValidateDatabase(dbPath string) error

ValidateDatabase checks if a SQLite database is valid and accessible

func ValidateManifest

func ValidateManifest(manifest *BackupManifest) error

ValidateManifest checks if a manifest is valid and complete

func VerifyChecksum

func VerifyChecksum(filePath, expectedChecksum string) error

VerifyChecksum verifies a file's checksum matches the expected value

func VerifyUploadsIntegrity

func VerifyUploadsIntegrity(uploadsDir string, expectedFiles []string) ([]string, error)

VerifyUploadsIntegrity checks that all expected files exist in uploads directory

func WriteManifest

func WriteManifest(manifest *BackupManifest, backupDir string) error

WriteManifest writes a manifest to a backup directory

Types

type BackupIncludes

type BackupIncludes struct {
	// Settings indicates if runtime settings are included
	Settings bool `json:"settings"`

	// Users indicates if user accounts are included
	Users bool `json:"users"`

	// FileMetadata indicates if file records (metadata) are included
	FileMetadata bool `json:"file_metadata"`

	// Files indicates if actual uploaded files are included
	Files bool `json:"files"`

	// Webhooks indicates if webhook configurations are included
	Webhooks bool `json:"webhooks"`

	// APITokens indicates if API tokens are included
	APITokens bool `json:"api_tokens"`

	// BlockedIPs indicates if IP blocklist is included
	BlockedIPs bool `json:"blocked_ips"`

	// AdminCredentials indicates if admin credentials are included
	AdminCredentials bool `json:"admin_credentials"`
}

BackupIncludes describes what data types are included in the backup

type BackupInfo

type BackupInfo struct {
	// Path is the path to the backup directory
	Path string `json:"path"`

	// Name is the directory name
	Name string `json:"name"`

	// CreatedAt is when the backup was created
	CreatedAt time.Time `json:"created_at"`

	// Mode is the backup mode
	Mode BackupMode `json:"mode"`

	// SafeShareVersion is the SafeShare version that created the backup
	SafeShareVersion string `json:"safeshare_version"`

	// TotalSizeBytes is the total backup size
	TotalSizeBytes int64 `json:"total_size_bytes"`

	// FileRecordsCount is the number of file records
	FileRecordsCount int `json:"file_records_count"`

	// FilesBackedUp is the number of files (for full backups)
	FilesBackedUp int `json:"files_backed_up"`
}

BackupInfo contains summary information about a backup (for listing)

func ListBackups

func ListBackups(backupsDir string) ([]BackupInfo, error)

ListBackups returns information about all backups in a directory

type BackupJob

type BackupJob struct {
	// ID is the unique job identifier
	ID string `json:"id"`

	// Type is either "backup" or "restore"
	Type string `json:"type"`

	// Mode is the backup mode
	Mode BackupMode `json:"mode"`

	// Status is the current job status
	Status JobStatus `json:"status"`

	// Progress is the percentage complete (0-100)
	Progress int `json:"progress"`

	// OutputPath is the path to the backup (for completed backups)
	OutputPath string `json:"output_path,omitempty"`

	// Error is the error message (for failed jobs)
	Error string `json:"error,omitempty"`

	// StartedAt is when the job started
	StartedAt time.Time `json:"started_at"`

	// CompletedAt is when the job completed (nil if still running)
	CompletedAt *time.Time `json:"completed_at,omitempty"`
}

BackupJob represents an async backup or restore job

type BackupManifest

type BackupManifest struct {
	// Version of the manifest format
	Version string `json:"version"`

	// CreatedAt is when the backup was created
	CreatedAt time.Time `json:"created_at"`

	// SafeShareVersion is the version of SafeShare that created this backup
	SafeShareVersion string `json:"safeshare_version"`

	// Mode indicates what type of backup this is
	Mode BackupMode `json:"mode"`

	// Includes describes what data is included in this backup
	Includes BackupIncludes `json:"includes"`

	// Stats contains counts and sizes of backed up data
	Stats BackupStats `json:"stats"`

	// Checksums contains SHA256 checksums of backup files
	Checksums map[string]string `json:"checksums"`

	// Encryption contains information about encryption state
	Encryption EncryptionInfo `json:"encryption"`

	// Warnings contains any warnings generated during backup
	Warnings []string `json:"warnings,omitempty"`

	// SourceDBPath is the original database path (informational only)
	SourceDBPath string `json:"source_db_path,omitempty"`

	// SourceUploadsDir is the original uploads directory (informational only)
	SourceUploadsDir string `json:"source_uploads_dir,omitempty"`
}

BackupManifest contains metadata about a backup

func NewManifest

func NewManifest(mode BackupMode, safeShareVersion string) *BackupManifest

NewManifest creates a new backup manifest with default values

func ReadManifest

func ReadManifest(backupDir string) (*BackupManifest, error)

ReadManifest reads and parses a manifest from a backup directory

type BackupMode

type BackupMode string

BackupMode defines the type of backup to create

const (
	// ModeConfig backs up only configuration: settings, webhooks, blocked IPs, admin credentials
	ModeConfig BackupMode = "config"

	// ModeDatabase backs up the full database without uploaded files
	ModeDatabase BackupMode = "database"

	// ModeFull backs up the database and all uploaded files
	ModeFull BackupMode = "full"
)

func (BackupMode) IsValid

func (m BackupMode) IsValid() bool

IsValid returns true if the backup mode is valid

func (BackupMode) String

func (m BackupMode) String() string

String returns the string representation of BackupMode

type BackupResult

type BackupResult struct {
	// Success indicates if the backup completed successfully
	Success bool `json:"success"`

	// BackupPath is the path to the created backup directory
	BackupPath string `json:"backup_path,omitempty"`

	// Manifest is the backup manifest (included on success)
	Manifest *BackupManifest `json:"manifest,omitempty"`

	// Error is the error message if backup failed
	Error string `json:"error,omitempty"`

	// Duration is how long the backup took
	Duration time.Duration `json:"duration"`

	// DurationString is a human-readable duration
	DurationString string `json:"duration_string"`
}

BackupResult contains the result of a backup operation

func Create

func Create(opts CreateOptions) (*BackupResult, error)

Create creates a backup according to the specified options

type BackupStats

type BackupStats struct {
	// UsersCount is the number of user accounts
	UsersCount int `json:"users_count"`

	// FileRecordsCount is the number of file metadata records
	FileRecordsCount int `json:"file_records_count"`

	// FilesBackedUp is the number of actual files backed up (0 if mode != full)
	FilesBackedUp int `json:"files_backed_up"`

	// WebhooksCount is the number of webhook configurations
	WebhooksCount int `json:"webhooks_count"`

	// APITokensCount is the number of API tokens
	APITokensCount int `json:"api_tokens_count"`

	// BlockedIPsCount is the number of blocked IP entries
	BlockedIPsCount int `json:"blocked_ips_count"`

	// TotalSizeBytes is the total size of the backup in bytes
	TotalSizeBytes int64 `json:"total_size_bytes"`

	// DatabaseSizeBytes is the size of the database backup
	DatabaseSizeBytes int64 `json:"database_size_bytes"`

	// FilesSizeBytes is the total size of backed up files (0 if mode != full)
	FilesSizeBytes int64 `json:"files_size_bytes"`
}

BackupStats contains statistics about the backup

func GetDatabaseStats

func GetDatabaseStats(dbPath string) (*BackupStats, error)

GetDatabaseStats retrieves statistics from the database for backup manifest

type ChecksumMismatch

type ChecksumMismatch struct {
	// File is the filename
	File string `json:"file"`

	// Expected is the expected checksum from manifest
	Expected string `json:"expected"`

	// Actual is the actual computed checksum
	Actual string `json:"actual"`
}

ChecksumMismatch represents a file with a checksum mismatch

type CreateOptions

type CreateOptions struct {
	// Mode is the type of backup to create
	Mode BackupMode

	// DBPath is the path to the SQLite database
	DBPath string

	// UploadsDir is the path to the uploads directory (required for full mode)
	UploadsDir string

	// OutputDir is the directory where the backup will be created
	OutputDir string

	// EncryptionKey is the 64-character hex encryption key (for fingerprint)
	EncryptionKey string

	// SafeShareVersion is the application version string
	SafeShareVersion string

	// ProgressCallback is called with progress updates during backup
	// Parameters: current step, total steps, description
	ProgressCallback func(current, total int, description string)
}

CreateOptions contains options for creating a backup

type EncryptionInfo

type EncryptionInfo struct {
	// Enabled indicates if encryption was enabled when backup was created
	Enabled bool `json:"enabled"`

	// KeyFingerprint is the SHA256 hash of the encryption key (for verification)
	// This allows verification that the correct key is used during restore
	// without storing the actual key in the backup
	KeyFingerprint string `json:"key_fingerprint,omitempty"`
}

EncryptionInfo contains information about the encryption state

type FileRecord

type FileRecord struct {
	ClaimCode        string
	OriginalFilename string
	StoredFilename   string
	FileSize         int64
}

FileRecord represents a file entry from the database (minimal fields for backup)

func FindMissingFiles

func FindMissingFiles(uploadsDir string, dbRecords []FileRecord) ([]FileRecord, error)

FindMissingFiles identifies database records that don't have corresponding files

func GetFileRecords

func GetFileRecords(dbPath string) ([]FileRecord, error)

GetFileRecords retrieves all file records from the database

type JobStatus

type JobStatus string

JobStatus represents the status of an async backup/restore job

const (
	// JobStatusPending indicates the job is queued but not started
	JobStatusPending JobStatus = "pending"

	// JobStatusRunning indicates the job is currently executing
	JobStatusRunning JobStatus = "running"

	// JobStatusCompleted indicates the job completed successfully
	JobStatusCompleted JobStatus = "completed"

	// JobStatusFailed indicates the job failed
	JobStatusFailed JobStatus = "failed"
)

type OrphanHandling

type OrphanHandling string

OrphanHandling defines how to handle orphaned file records during restore

const (
	// OrphanKeep keeps orphaned file records (metadata preserved, files not recoverable)
	OrphanKeep OrphanHandling = "keep"

	// OrphanRemove removes orphaned file records from the database
	OrphanRemove OrphanHandling = "remove"

	// OrphanPrompt prompts the user for each orphaned record (interactive mode only)
	OrphanPrompt OrphanHandling = "prompt"
)

func (OrphanHandling) IsValid

func (o OrphanHandling) IsValid() bool

IsValid returns true if the orphan handling mode is valid

func (OrphanHandling) String

func (o OrphanHandling) String() string

String returns the string representation of OrphanHandling

type RestoreOptions

type RestoreOptions struct {
	// InputDir is the path to the backup directory
	InputDir string

	// DBPath is the path where the database should be restored
	DBPath string

	// UploadsDir is the path where files should be restored (for full backups)
	UploadsDir string

	// HandleOrphans defines how to handle orphaned file records
	HandleOrphans OrphanHandling

	// DryRun previews the restore without making changes
	DryRun bool

	// Force overwrites existing data without confirmation
	Force bool

	// EncryptionKey is used to verify against the key fingerprint
	EncryptionKey string

	// OrphanCallback is called for each orphan when HandleOrphans is OrphanPrompt
	// Returns true to keep the record, false to remove it
	OrphanCallback func(claimCode, filename string, fileSize int64) bool

	// ProgressCallback is called with progress updates during restore
	// Parameters: current step, total steps, description
	ProgressCallback func(current, total int, description string)
}

RestoreOptions contains options for restoring from a backup

type RestoreResult

type RestoreResult struct {
	// Success indicates if the restore completed successfully
	Success bool `json:"success"`

	// DryRun indicates if this was a dry run
	DryRun bool `json:"dry_run"`

	// Error is the error message if restore failed
	Error string `json:"error,omitempty"`

	// Warnings contains any warnings generated during restore
	Warnings []string `json:"warnings,omitempty"`

	// TablesRestored lists the database tables that were restored
	TablesRestored []string `json:"tables_restored,omitempty"`

	// FilesRestored is the count of files restored (for full backups)
	FilesRestored int `json:"files_restored"`

	// OrphansFound is the count of orphaned file records found
	OrphansFound int `json:"orphans_found"`

	// OrphansRemoved is the count of orphaned records that were removed
	OrphansRemoved int `json:"orphans_removed"`

	// OrphansKept is the count of orphaned records that were kept
	OrphansKept int `json:"orphans_kept"`

	// Duration is how long the restore took
	Duration time.Duration `json:"duration"`

	// DurationString is a human-readable duration
	DurationString string `json:"duration_string"`
}

RestoreResult contains the result of a restore operation

func Restore

func Restore(opts RestoreOptions) (*RestoreResult, error)

Restore restores from a backup according to the specified options

type Scheduler

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

Scheduler manages automatic backup execution based on configured schedules.

func NewScheduler

func NewScheduler(cfg *config.Config, repos *repository.Repositories) *Scheduler

NewScheduler creates a new backup scheduler.

func (*Scheduler) IsRunning

func (s *Scheduler) IsRunning() bool

IsRunning returns whether the scheduler is currently running.

func (*Scheduler) Start

func (s *Scheduler) Start(ctx context.Context) error

Start begins the scheduler's background goroutine. It periodically checks for due backup schedules and executes them. This method is non-blocking and returns immediately.

func (*Scheduler) Stop

func (s *Scheduler) Stop()

Stop gracefully stops the scheduler. It waits for any currently running backup to complete before returning.

func (*Scheduler) TriggerBackup

func (s *Scheduler) TriggerBackup(ctx context.Context, mode string, triggerType repository.BackupTriggerType) (*repository.BackupRun, error)

TriggerBackup triggers a manual backup with the specified mode. Returns the backup run record. Uses mutex to prevent race condition between check and execution.

type VerifyResult

type VerifyResult struct {
	// Valid indicates if the backup is valid and complete
	Valid bool `json:"valid"`

	// ManifestValid indicates if the manifest is readable and valid
	ManifestValid bool `json:"manifest_valid"`

	// DatabaseValid indicates if the database file is present and valid
	DatabaseValid bool `json:"database_valid"`

	// ChecksumsValid indicates if all checksums match
	ChecksumsValid bool `json:"checksums_valid"`

	// FilesValid indicates if all expected files are present (for full backups)
	FilesValid bool `json:"files_valid"`

	// Errors contains any validation errors found
	Errors []string `json:"errors,omitempty"`

	// Warnings contains any validation warnings
	Warnings []string `json:"warnings,omitempty"`

	// Manifest is the parsed manifest (if readable)
	Manifest *BackupManifest `json:"manifest,omitempty"`

	// MissingFiles lists files referenced in manifest but not found
	MissingFiles []string `json:"missing_files,omitempty"`

	// ChecksumMismatches lists files with checksum mismatches
	ChecksumMismatches []ChecksumMismatch `json:"checksum_mismatches,omitempty"`
}

VerifyResult contains the result of a backup verification

func QuickVerify

func QuickVerify(backupDir string) *VerifyResult

QuickVerify performs a fast verification without checksum validation

func Verify

func Verify(backupDir string) *VerifyResult

Verify checks the integrity of a backup

func VerifyWithProgress

func VerifyWithProgress(backupDir string, progressCallback func(current, total int, description string)) *VerifyResult

VerifyWithProgress performs verification with progress callbacks

Jump to

Keyboard shortcuts

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