-- Ginxsom Blossom Server Database Schema -- SQLite database for blob metadata and server configuration -- Enable foreign key constraints PRAGMA foreign_keys = ON; -- Main blobs table for storing blob metadata CREATE TABLE IF NOT EXISTS blobs ( sha256 TEXT PRIMARY KEY NOT NULL, -- SHA-256 hash (64 hex chars) size INTEGER NOT NULL, -- File size in bytes type TEXT NOT NULL, -- MIME type uploaded_at INTEGER NOT NULL, -- Unix timestamp uploader_pubkey TEXT, -- Nostr public key (optional) filename TEXT, -- Original filename (optional) CHECK (length(sha256) = 64), -- Ensure valid SHA-256 hash length CHECK (size >= 0), -- Ensure non-negative size CHECK (uploaded_at > 0) -- Ensure valid timestamp ); -- Unified configuration table (replaces server_config and auth_config) CREATE TABLE IF NOT EXISTS config ( key TEXT PRIMARY KEY NOT NULL, -- Configuration key value TEXT NOT NULL, -- Configuration value description TEXT, -- Human-readable description created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), -- Creation timestamp updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')) -- Last update timestamp ); -- Indexes for performance optimization CREATE INDEX IF NOT EXISTS idx_blobs_uploaded_at ON blobs(uploaded_at); CREATE INDEX IF NOT EXISTS idx_blobs_uploader_pubkey ON blobs(uploader_pubkey); CREATE INDEX IF NOT EXISTS idx_blobs_type ON blobs(type); CREATE INDEX IF NOT EXISTS idx_config_updated_at ON config(updated_at); -- Insert default unified configuration INSERT OR IGNORE INTO config (key, value, description) VALUES ('max_file_size', '104857600', 'Maximum file size in bytes (100MB)'), ('auth_rules_enabled', 'false', 'Whether authentication rules are enabled for uploads'), ('server_name', 'ginxsom', 'Server name for responses'), ('admin_pubkey', '', 'Admin public key for API access'), ('admin_enabled', 'false', 'Whether admin API is enabled'), ('nip42_require_auth', 'false', 'Enable NIP-42 challenge/response authentication'), ('nip42_challenge_timeout', '600', 'NIP-42 challenge timeout in seconds'), ('nip42_time_tolerance', '300', 'NIP-42 timestamp tolerance in seconds'); -- Authentication rules table for whitelist/blacklist functionality CREATE TABLE IF NOT EXISTS auth_rules ( id INTEGER PRIMARY KEY AUTOINCREMENT, rule_type TEXT NOT NULL, -- 'pubkey_blacklist', 'pubkey_whitelist', -- 'hash_blacklist', 'mime_blacklist', 'mime_whitelist' rule_target TEXT NOT NULL, -- The pubkey, hash, or MIME type to match operation TEXT NOT NULL DEFAULT '*', -- 'upload', 'delete', 'list', or '*' for all enabled INTEGER NOT NULL DEFAULT 1, -- 1 = enabled, 0 = disabled priority INTEGER NOT NULL DEFAULT 100,-- Lower number = higher priority description TEXT, -- Human-readable description created_by TEXT, -- Admin pubkey who created the rule created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), -- Constraints CHECK (rule_type IN ('pubkey_blacklist', 'pubkey_whitelist', 'hash_blacklist', 'mime_blacklist', 'mime_whitelist')), CHECK (operation IN ('upload', 'delete', 'list', '*')), CHECK (enabled IN (0, 1)), CHECK (priority >= 0), -- Unique constraint: one rule per type/target/operation combination UNIQUE(rule_type, rule_target, operation) ); -- Indexes for performance optimization CREATE INDEX IF NOT EXISTS idx_auth_rules_type_target ON auth_rules(rule_type, rule_target); CREATE INDEX IF NOT EXISTS idx_auth_rules_operation ON auth_rules(operation); CREATE INDEX IF NOT EXISTS idx_auth_rules_enabled ON auth_rules(enabled); CREATE INDEX IF NOT EXISTS idx_auth_rules_priority ON auth_rules(priority); CREATE INDEX IF NOT EXISTS idx_auth_rules_type_operation ON auth_rules(rule_type, operation, enabled); -- View for storage statistics CREATE VIEW IF NOT EXISTS storage_stats AS SELECT COUNT(*) as total_blobs, SUM(size) as total_bytes, AVG(size) as avg_blob_size, MIN(uploaded_at) as first_upload, MAX(uploaded_at) as last_upload, COUNT(DISTINCT uploader_pubkey) as unique_uploaders FROM blobs;