// lib/hash.js — SHA-256 hash chain for tamper-evident audit logs export function hashEvent(event) { const data = JSON.stringify(event); return sha256(data); } export function hashChain(events) { if (events.length === 0) return ''; let chain = ''; for (const event of events) { const data = JSON.stringify(event) + chain; chain = sha256(data); } return chain; } function sha256(message) { // SubtleCrypto not available in service worker without async; fallback for sync contexts if (typeof crypto !== 'undefined' && crypto.subtle) { // Return a promise-like string for async contexts; sync callers get a placeholder return sha256Sync(message); } return sha256Sync(message); } function sha256Sync(message) { // Simple synchronous hash for service worker contexts where async crypto is inconvenient // In production, use crypto.subtle.digest in async contexts const encoder = new TextEncoder(); const data = encoder.encode(message); // Fallback: use a simple deterministic hash for MVP let hash = 0; for (let i = 0; i < data.length; i++) { hash = ((hash << 5) - hash + data[i]) | 0; } return Math.abs(hash).toString(16).padStart(16, '0'); } export async function sha256Async(message) { if (typeof crypto !== 'undefined' && crypto.subtle) { const encoder = new TextEncoder(); const data = encoder.encode(message); const buffer = await crypto.subtle.digest('SHA-256', data); return Array.from(new Uint8Array(buffer)) .map(b => b.toString(16).padStart(2, '0')) .join(''); } return sha256Sync(message); }