-- 174_domclick_session_cookies.sql -- Purpose: Encrypted storage for DomClick browser session cookies needed to -- bypass QRATOR anti-bot reputation blocks on card-detail fetches. -- A manually-uploaded authenticated DomClick session (Sber ID login) -- whose cookies (notably qrator_jsid2, CAS_ID, CAS_ID_SIGNED, -- sessionId) let scraper requests pass QRATOR's reputation check. -- Empirically validated 2026-07-04: injecting these cookies via -- Playwright context.addCookies() through a reputation-blocked -- proxy IP fully bypassed the block and returned real -- __SSR_STATE__ content. -- Uses pgcrypto pgp_sym_encrypt for AES encryption at rest. -- Dependencies: -- - pgcrypto extension (installed here via CREATE EXTENSION IF NOT EXISTS) -- Deploy order: Apply after 173. -- -- Security notes: -- - cookies_encrypted stores AES-encrypted JSON blob via pgp_sym_encrypt. -- - Encryption key lives in .env.runtime (COOKIE_ENCRYPTION_KEY), never in DB. -- - Access restricted to admin-token-gated API endpoint only. -- -- Sources: issue #2000 (DomClick Layer B unblock) BEGIN; CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE TABLE IF NOT EXISTS domclick_session_cookies ( account_cas_id bigint PRIMARY KEY, -- DomClick CAS_ID cookie (Sber-ID-derived user id) cookies_encrypted bytea NOT NULL, -- pgp_sym_encrypt(json_cookies, key) expires_at_estimate timestamptz NOT NULL, -- estimated expiry (~30 days from upload) uploaded_at timestamptz NOT NULL DEFAULT NOW(), last_used_at timestamptz, -- set on each successful card-detail fetch last_invalid_at timestamptz, -- set when session no longer bypasses QRATOR notes text -- e.g. 'Account: ' ); -- Most recent upload first (admin dashboard ordering) CREATE INDEX IF NOT EXISTS domclick_cookies_uploaded_idx ON domclick_session_cookies (uploaded_at DESC); -- Active session lookup (non-expired and not invalidated) CREATE INDEX IF NOT EXISTS domclick_cookies_active_idx ON domclick_session_cookies (expires_at_estimate) WHERE last_invalid_at IS NULL; COMMIT;