-- Migration: Add fingerprint persistence fields for account-bound fingerprints -- Date: 2025-01-13 -- Add new columns to browser_fingerprints table for persistent fingerprint support ALTER TABLE browser_fingerprints ADD COLUMN static_components TEXT; -- JSON: Unchangeable hardware/platform values ALTER TABLE browser_fingerprints ADD COLUMN rotation_seed TEXT; -- Seed for deterministic noise generation ALTER TABLE browser_fingerprints ADD COLUMN rotation_policy TEXT DEFAULT 'normal'; -- strict/normal/relaxed ALTER TABLE browser_fingerprints ADD COLUMN last_major_rotation TIMESTAMP; ALTER TABLE browser_fingerprints ADD COLUMN trust_score REAL DEFAULT 0.0; -- How established this fingerprint is ALTER TABLE browser_fingerprints ADD COLUMN evolution_history TEXT; -- JSON: Track gradual changes ALTER TABLE browser_fingerprints ADD COLUMN account_bound BOOLEAN DEFAULT 0; -- Is this bound to specific account(s) -- Create table for fingerprint-account associations (many-to-many) CREATE TABLE IF NOT EXISTS fingerprint_accounts ( id INTEGER PRIMARY KEY AUTOINCREMENT, fingerprint_id TEXT NOT NULL, account_id TEXT NOT NULL, assigned_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, primary_fingerprint BOOLEAN DEFAULT 0, last_used TIMESTAMP, success_count INTEGER DEFAULT 0, failure_count INTEGER DEFAULT 0, FOREIGN KEY (fingerprint_id) REFERENCES browser_fingerprints(id), FOREIGN KEY (account_id) REFERENCES accounts(id), UNIQUE(fingerprint_id, account_id) ); -- Create table for fingerprint rotation history CREATE TABLE IF NOT EXISTS fingerprint_rotation_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, fingerprint_id TEXT NOT NULL, rotation_type TEXT NOT NULL, -- 'minor', 'gradual', 'major' rotated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, previous_values TEXT NOT NULL, -- JSON: What changed new_values TEXT NOT NULL, -- JSON: New values trigger_reason TEXT, -- Why rotation happened FOREIGN KEY (fingerprint_id) REFERENCES browser_fingerprints(id) ); -- Create indexes for performance CREATE INDEX IF NOT EXISTS idx_fingerprints_account_bound ON browser_fingerprints(account_bound); CREATE INDEX IF NOT EXISTS idx_fingerprints_trust_score ON browser_fingerprints(trust_score); CREATE INDEX IF NOT EXISTS idx_fingerprints_rotation_policy ON browser_fingerprints(rotation_policy); CREATE INDEX IF NOT EXISTS idx_fingerprint_accounts_account ON fingerprint_accounts(account_id); CREATE INDEX IF NOT EXISTS idx_fingerprint_accounts_fingerprint ON fingerprint_accounts(fingerprint_id); CREATE INDEX IF NOT EXISTS idx_rotation_history_fingerprint ON fingerprint_rotation_history(fingerprint_id); CREATE INDEX IF NOT EXISTS idx_rotation_history_timestamp ON fingerprint_rotation_history(rotated_at); -- Create view for account fingerprint status CREATE VIEW IF NOT EXISTS v_account_fingerprints AS SELECT a.id as account_id, a.username, bf.id as fingerprint_id, bf.trust_score, bf.rotation_policy, bf.last_major_rotation, fa.primary_fingerprint, fa.last_used, fa.success_count, fa.failure_count, ROUND(CAST(fa.success_count AS REAL) / NULLIF(fa.success_count + fa.failure_count, 0), 2) as success_rate FROM accounts a LEFT JOIN fingerprint_accounts fa ON a.id = fa.account_id LEFT JOIN browser_fingerprints bf ON fa.fingerprint_id = bf.id WHERE fa.primary_fingerprint = 1 OR fa.fingerprint_id IS NOT NULL;