// Package types provides custom types for better type safety across the vaultik codebase. // Using distinct types for IDs, hashes, paths, and credentials prevents accidental // mixing of semantically different values that happen to share the same underlying type. package types import ( "database/sql/driver" "fmt" "github.com/google/uuid" ) // FileID is a UUID identifying a file record in the database. type FileID uuid.UUID // NewFileID generates a new random FileID. func NewFileID() FileID { return FileID(uuid.New()) } // ParseFileID parses a string into a FileID. func ParseFileID(s string) (FileID, error) { id, err := uuid.Parse(s) if err != nil { return FileID{}, err } return FileID(id), nil } // IsZero returns true if the FileID is the zero value. func (id FileID) IsZero() bool { return uuid.UUID(id) == uuid.Nil } // Value implements driver.Valuer for database serialization. func (id FileID) Value() (driver.Value, error) { return uuid.UUID(id).String(), nil } // Scan implements sql.Scanner for database deserialization. func (id *FileID) Scan(src interface{}) error { if src == nil { *id = FileID{} return nil } var s string switch v := src.(type) { case string: s = v case []byte: s = string(v) default: return fmt.Errorf("cannot scan %T into FileID", src) } parsed, err := uuid.Parse(s) if err != nil { return fmt.Errorf("invalid FileID: %w", err) } *id = FileID(parsed) return nil } // BlobID is a UUID identifying a blob record in the database. // This is distinct from BlobHash which is the content-addressed hash of the blob. type BlobID uuid.UUID // NewBlobID generates a new random BlobID. func NewBlobID() BlobID { return BlobID(uuid.New()) } // ParseBlobID parses a string into a BlobID. func ParseBlobID(s string) (BlobID, error) { id, err := uuid.Parse(s) if err != nil { return BlobID{}, err } return BlobID(id), nil } // IsZero returns true if the BlobID is the zero value. func (id BlobID) IsZero() bool { return uuid.UUID(id) == uuid.Nil } // Value implements driver.Valuer for database serialization. func (id BlobID) Value() (driver.Value, error) { return uuid.UUID(id).String(), nil } // Scan implements sql.Scanner for database deserialization. func (id *BlobID) Scan(src interface{}) error { if src == nil { *id = BlobID{} return nil } var s string switch v := src.(type) { case string: s = v case []byte: s = string(v) default: return fmt.Errorf("cannot scan %T into BlobID", src) } parsed, err := uuid.Parse(s) if err != nil { return fmt.Errorf("invalid BlobID: %w", err) } *id = BlobID(parsed) return nil } // SnapshotID identifies a snapshot, typically in format "hostname_name_timestamp". type SnapshotID string // ChunkHash is the SHA256 hash of a chunk's content. // Used for content-addressing and deduplication of file chunks. type ChunkHash string // BlobHash is the SHA256 hash of a blob's compressed and encrypted content. // This is used as the filename in S3 storage for content-addressed retrieval. type BlobHash string // FilePath represents an absolute path to a file or directory. type FilePath string // SourcePath represents the root directory from which files are backed up. // Used during restore to strip the source prefix from paths. type SourcePath string // AgeRecipient is an age public key used for encryption. // Format: age1... (Bech32-encoded X25519 public key) type AgeRecipient string // AgeSecretKey is an age private key used for decryption. // Format: AGE-SECRET-KEY-... (Bech32-encoded X25519 private key) // This type should never be logged or serialized in plaintext. type AgeSecretKey string // S3Endpoint is the URL of an S3-compatible storage endpoint. type S3Endpoint string // BucketName is the name of an S3 bucket. type BucketName string // S3Prefix is the path prefix within an S3 bucket. type S3Prefix string // AWSRegion is an AWS region identifier (e.g., "us-east-1"). type AWSRegion string // AWSAccessKeyID is an AWS access key ID for authentication. type AWSAccessKeyID string // AWSSecretAccessKey is an AWS secret access key for authentication. // This type should never be logged or serialized in plaintext. type AWSSecretAccessKey string // Hostname identifies a host machine. type Hostname string // Version is a semantic version string. type Version string // GitRevision is a git commit SHA. type GitRevision string // GlobPattern is a glob pattern for file matching (e.g., "*.log", "node_modules"). type GlobPattern string // String methods for Stringer interface func (id FileID) String() string { return uuid.UUID(id).String() } func (id BlobID) String() string { return uuid.UUID(id).String() } func (id SnapshotID) String() string { return string(id) } func (h ChunkHash) String() string { return string(h) } func (h BlobHash) String() string { return string(h) } func (p FilePath) String() string { return string(p) } func (p SourcePath) String() string { return string(p) } func (r AgeRecipient) String() string { return string(r) } func (e S3Endpoint) String() string { return string(e) } func (b BucketName) String() string { return string(b) } func (p S3Prefix) String() string { return string(p) } func (r AWSRegion) String() string { return string(r) } func (k AWSAccessKeyID) String() string { return string(k) } func (h Hostname) String() string { return string(h) } func (v Version) String() string { return string(v) } func (r GitRevision) String() string { return string(r) } func (p GlobPattern) String() string { return string(p) } // Redacted String methods for sensitive types - prevents accidental logging func (k AgeSecretKey) String() string { return "[REDACTED]" } func (k AWSSecretAccessKey) String() string { return "[REDACTED]" } // Raw returns the actual value for sensitive types when explicitly needed func (k AgeSecretKey) Raw() string { return string(k) } func (k AWSSecretAccessKey) Raw() string { return string(k) }