// worker/src/index.js import { CloudFireAuth } from 'cloudfire-auth'; // Stream proxy – preserves referrer & CORS for YouTube audio async function handleStream(request, env) { const url = new URL(request.url); const streamKey = url.pathname.split('/stream/')[1]; if (!streamKey) return new Response('Missing stream key', { status: 400 }); try { // Decode base64URL key -> { directUrl, referer } const decoded = JSON.parse(atob(streamKey.replace(/-/g, '+').replace(/_/g, '/'))); const { directUrl, referer } = decoded; const upstream = await fetch(directUrl, { headers: { 'Referer': referer, 'User-Agent': request.headers.get('User-Agent') || 'Mozilla/5.0', }, // Range requests for seeking ...(request.headers.get('Range') && { headers: { 'Range': request.headers.get('Range') } }), }); const headers = new Headers(upstream.headers); headers.set('Access-Control-Allow-Origin', '*'); headers.set('Access-Control-Allow-Headers', 'Range'); headers.set('Access-Control-Expose-Headers', 'Content-Length, Content-Range'); return new Response(upstream.body, { status: upstream.status, headers, }); } catch (e) { return new Response('Stream error: ' + e.message, { status: 500 }); } } // Firebase custom token – used by /auth/login with a generated key async function handleAuth(request, env) { const { key, deviceId } = await request.json(); if (!key || !deviceId) return new Response('Missing key or deviceId', { status: 400 }); const auth = new CloudFireAuth(JSON.parse(env.FIREBASE_SERVICE_ACCOUNT_KEY), env.KV_NAMESPACE); // Check key in Firestore via REST (or use your own KV store) const keyDoc = await fetch( `https://firestore.googleapis.com/v1/projects/${env.FIREBASE_PROJECT_ID}/databases/(default)/documents/keys/${key}?key=${env.FIREBASE_API_KEY}` ).then(r => r.json()); if (!keyDoc.fields) return new Response('Invalid key', { status: 401 }); const boundDevice = keyDoc.fields.boundDeviceId?.stringValue; if (boundDevice && boundDevice !== deviceId) { return new Response('Key locked to another device', { status: 403 }); } // Bind device if first use if (!boundDevice) { await fetch( `https://firestore.googleapis.com/v1/projects/${env.FIREBASE_PROJECT_ID}/databases/(default)/documents/keys/${key}?updateMask.fieldPaths=boundDeviceId&key=${env.FIREBASE_API_KEY}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ fields: { boundDeviceId: { stringValue: deviceId } }, }), } ); } // Create Firebase custom token const uid = `key_${key}`; const customToken = await auth.createCustomToken(uid, { premium: keyDoc.fields.type?.stringValue === 'premium', dev: key === env.MASTER_KEY, }); return new Response(JSON.stringify({ token: customToken }), { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, }); } export default { async fetch(request, env) { const url = new URL(request.url); // CORS preflight if (request.method === 'OPTIONS') { return new Response(null, { headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Range', }, }); } if (url.pathname.startsWith('/stream/')) return handleStream(request, env); if (url.pathname === '/auth/login') return handleAuth(request, env); return new Response('Not found', { status: 404 }); }, };