const CFG = { dnPack: 32 * 1024, upPack: 20 * 1024, dnMs: 1 }; export default { fetch: (req, env) => route(req, env) }; const txt = new TextEncoder(), dec = new TextDecoder(), nil = new Uint8Array(0), badHead = new Set(['HEAD', 'POST', 'GET ', 'OPTI']); const CRYPTO = globalThis.crypto, macKeys = new Map(), leases = new Map(); const reply = (body = null, status = 404) => new Response(body, { status }); function u8(v) { if (v instanceof Uint8Array && v.constructor === Uint8Array) return v; if (v instanceof ArrayBuffer) return new Uint8Array(v); if (ArrayBuffer.isView(v)) return new Uint8Array(v.buffer, v.byteOffset, v.byteLength); throw TypeError(); } const dup = v => u8(v).slice(); function cat(...args) { const parts = args.filter(v => v?.byteLength).map(u8); const out = new Uint8Array(parts.reduce((total, part) => total + part.byteLength, 0)); let o = 0; for (const part of parts) { out.set(part, o); o += part.byteLength; } return out; } const hex = v => Uint8Array.from({ length: v.length / 2 }, (_, i) => Number.parseInt(v.slice(i * 2, i * 2 + 2), 16)); function b64(v) { const b = v instanceof Uint8Array ? v : new Uint8Array(v); return btoa(String.fromCharCode(...b)).replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, ''); } const un64 = v => { const s = v.replaceAll('-', '+').replaceAll('_', '/'); return Uint8Array.from(atob(s + '='.repeat((4 - s.length % 4) % 4)), c => c.charCodeAt(0)); }; const rand = n => CRYPTO.getRandomValues(new Uint8Array(n)); const wake = st => { const { wake: ok } = st; st.wake = null; ok?.(); }; const isType = t => t === 1 || t === 2 || t === 3 || t === 4 || t === 17; function enc(type, sid, data = nil) { const body = u8(data); if (!isType(type)) throw RangeError(); if (!Number.isInteger(sid) || sid < 0 || sid > 0xffffff) { throw RangeError(); } if (body.byteLength > 1024 * 1024) throw RangeError(); const frame = new Uint8Array(8 + body.byteLength); frame[0] = type; frame[1] = sid >>> 16; frame[2] = sid >>> 8; frame[3] = sid; new DataView(frame.buffer).setUint32(4, body.byteLength, false); frame.set(body, 8); return frame; } function getFrame(b, o) { if (b.byteLength - o < 8) return null; const type = b[o]; if (!isType(type)) throw Error(); const view = new DataView(b.buffer, b.byteOffset + o, b.byteLength - o); const sid = (b[o + 1] << 16) | (b[o + 2] << 8) | b[o + 3]; const n = view.getUint32(4, false); if (n > 1024 * 1024) throw Error(); const total = 8 + n; if (b.byteLength - o < total) return null; return { frame: { type, sid, payload: b.subarray(o + 8, o + total) }, consumed: total, }; } function frames(v) { const src = u8(v), out = []; for (let o = 0; o < src.byteLength;) { const part = getFrame(src, o); if (!part) throw Error(); if (out.length >= 4096) throw Error(); out.push(part.frame); o += part.consumed; } return out; } function win(data) { const body = u8(data); if (body.byteLength !== 4) throw Error(); const n = new DataView(body.buffer, body.byteOffset, 4).getUint32(0, false); if (!n) throw Error(); return n; } function check(frame) { const { type, payload: data } = frame; if (type === 1 || type === 3) { if (data.byteLength) throw Error(); return 0; } if (type === 2) { if (!data.byteLength) throw Error(); return 0; } if (type === 4) return win(data); throw Error(); } const i16 = (b, o) => (b[o] | b[o + 1] << 8) << 16 >> 16; function headOf(head) { const tag = new DataView(head.buffer, head.byteOffset, head.byteLength).getUint32(56, true); const mode = tag === 0xefefefef ? 0xef : tag === 0xeeeeeeee ? 0xee : tag === 0xdddddddd ? 0xdd : 0; if (!mode) throw Error(); const dc = i16(head, 60); const target = Math.abs(dc) - 1; if (target < 0 || target >= 5) throw Error(); return { mode, target, media: dc < 0 }; } function mkHead(mode, target, media) { const head = new Uint8Array(64); do { CRYPTO.getRandomValues(head); } while ( head[0] === 0xef || badHead.has(dec.decode(head.subarray(0, 4))) || head.subarray(4, 8).every(v => v === 0) ); head.fill(mode, 56, 60); new DataView(head.buffer).setInt16(60, (target + 1) * (media ? -1 : 1), true); return head; } function getKey(v, keepTag = false) { const str = String(v || '').trim().toLowerCase(); if (!/^(?:[0-9a-f]{32}|(?:dd|ee|ef)[0-9a-f]{32})$/.test(str)) { throw Error(); } return hex(keepTag && str.length === 34 && str.startsWith('dd') ? str : str.slice(-32)); } function hostOf(v) { const host = String(v || '').trim().toLowerCase().replace(/\.$/, ''); const labels = host.split('.'); if (!host.includes('.') || host.length > 253 || host.includes(':') || labels.some(label => !/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(label))) { throw Error(); } return host; } const macKey = (raw, id) => { let key = macKeys.get(id); if (!key) macKeys.set(id, key = CRYPTO.subtle.importKey('raw', u8(raw), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'])); return key; }; const sign = async (key, v) => new Uint8Array(await CRYPTO.subtle.sign('HMAC', await key, u8(v))); async function mac(boot, kind, body) { const prefix = txt.encode(`${kind}\n`); const msg = new Uint8Array(prefix.byteLength + body.byteLength); msg.set(prefix); msg.set(body, prefix.byteLength); return (await sign( macKey(txt.encode(boot), `token:${boot}`), msg, )).slice(0, 16); } async function mkToken(boot, kind, expAt, nonce) { const body = new Uint8Array(4 + 12); const exp = Math.ceil(expAt / 1000); new DataView(body.buffer).setUint32(0, exp, false); body.set(nonce, 4); const token = new Uint8Array(32); token.set(body); token.set(await mac(boot, kind, body), body.byteLength); return b64(token); } const mkBoot = async boot => mkToken(boot, 'bootstrap', Date.now() + 2 * 60 * 1000, rand(12)); async function verify(v, boot, kind) { if (typeof v !== 'string' || !/^[A-Za-z0-9_-]{43}$/.test(v)) return false; let token; try { token = un64(v); } catch { return false; } if (token.byteLength !== 32 || b64(token) !== v) return false; const body = token.slice(0, 4 + 12); const sig = token.slice(body.byteLength); const exp = new DataView(body.buffer, body.byteOffset, body.byteLength).getUint32(0, false); if (exp <= Math.floor(Date.now() / 1000)) return false; const want = await mac(boot, kind, body); let diff = sig.byteLength ^ want.byteLength; for (let i = 0; i < want.length; i++) diff |= sig[i] ^ want[i]; return diff === 0; } const mkSess = async boot => mkToken(boot, 'session', Date.now() + 5 * 60 * 1000, rand(12)); const authBoot = async (v, boot) => v === boot || verify(v, boot, 'bootstrap'); const mkLease = token => ({ expires: new DataView(un64(token).buffer).getUint32(0) * 1000, active: new Set(), used: new Set(), deleted: false, }); const bearer = v => /^Bearer ([^\s]+)$/.exec(v || '')?.[1] ?? null; const binary = req => req.headers.get('Content-Type')?.trim().toLowerCase() === 'application/octet-stream'; function hello(body) { if (body.byteLength !== 9 || body[0] !== 0x10 || body[1] !== 0 || body[2] !== 0 || body[3] !== 0 || new DataView(body.buffer, body.byteOffset, body.byteLength).getUint32(4, false) !== 1 || body[8] !== 1) { throw Error(); } } const protos = req => (req.headers.get('Sec-WebSocket-Protocol') ?? '').split(',').map(v => v.trim()).filter(Boolean); const mkCfg = ({ SECRET, BOOT }) => { const secret = String(SECRET || '').trim(), boot = String(BOOT || '').trim(); if (!secret) throw Error(); if (!boot) throw Error(); return { secret, key: getKey(secret), boot }; }; async function mkCap(secret, host) { const key = macKey( getKey(secret, true), `bridge:${String(secret).trim().toLowerCase()}`, ); const sig = await sign( key, txt.encode(`tdesktop-web-proxy-bridge-v1\n${hostOf(host)}`), ); return b64(sig); } async function bridge(url, secret) { if (url.pathname !== '/' || url.search.length !== 51) return null; const cand = url.search.slice(8); if (url.search !== `?bridge=${cand}` || !/^[A-Za-z0-9_-]{43}$/.test(cand)) return null; const host = hostOf(url.hostname); const want = await mkCap(secret, host); if (cand.length !== want.length) return null; let diff = 0; for (let i = 0; i < want.length; i++) diff |= cand.charCodeAt(i) ^ want.charCodeAt(i); return diff === 0 ? host : null; } const sha = async v => new Uint8Array(await CRYPTO.subtle.digest('SHA-256', u8(v))); function step(ctr, n) { let carry = n; for (let i = ctr.length - 1; i >= 0 && carry; i--) { const next = ctr[i] + (carry & 0xff); ctr[i] = next & 0xff; carry = Math.floor(carry / 256) + Math.floor(next / 256); } if (carry) throw Error(); } const mkCtr = (key, ctr) => { let iv = dup(ctr), tail = nil; const ready = CRYPTO.subtle.importKey('raw', u8(key), { name: 'AES-CTR' }, false, ['encrypt']); const crypt = async (v) => { const b = u8(v); if (!b.byteLength) return new Uint8Array(0); const key = await ready; if (!tail.byteLength && !(b.byteLength % 16)) { const raw = new Uint8Array(await CRYPTO.subtle.encrypt( { name: 'AES-CTR', counter: iv.slice(), length: 128 }, key, b, )); step(iv, b.byteLength / 16); return raw; } if (b.byteLength <= tail.byteLength) { const out = new Uint8Array(b.byteLength); for (let i = 0; i < b.byteLength; i++) out[i] = b[i] ^ tail[i]; tail = tail.slice(b.byteLength); return out; } const skip = tail.byteLength ? 16 - tail.byteLength : 0; const ctr = iv.slice(); if (skip) { for (let i = ctr.length - 1; i >= 0; i--) if (ctr[i]--) break; } const end = skip + b.byteLength; const block = new Uint8Array(Math.ceil(end / 16) * 16); block.set(b, skip); const raw = new Uint8Array(await CRYPTO.subtle.encrypt( { name: 'AES-CTR', counter: ctr, length: 128 }, key, block, )); tail = raw.slice(end); step(iv, block.byteLength / 16 - (skip ? 1 : 0)); return raw.subarray(skip, end); }; return { crypt }; }; async function cipher(head, secret, reverse) { const mat = dup(u8(head).subarray(8, 56)); if (reverse) mat.reverse(); const key = secret.byteLength ? await sha(cat(mat.subarray(0, 32), secret)) : mat.subarray(0, 32); return mkCtr(key, mat.subarray(32, 48)); } async function wireHead(head) { const ctr = await cipher(head, nil, false); const raw = await ctr.crypt(head); raw.set(u8(head).subarray(0, 56)); return { wire: raw, cipher: ctr }; } const hosts = (dc, media) => [ `kws${dc}${media ? '-1' : ''}.web.telegram.org`, `kws${dc}${media ? '' : '-1'}.web.telegram.org`, ]; async function dial({ target, media, signal }) { for (const host of hosts(target + 1, media)) { if (signal?.aborted) throw Error(); const url = `wss://${host}/apiws`; let kws; try { kws = mkWire(new WebSocket(url, 'binary'), 7500, signal); await kws.ready; if (signal?.aborted) throw Error(); return kws; } catch (err) { kws?.close(); if (signal?.aborted) throw err; } } throw Error(); } const mkWire = (ws, ms, signal) => { const q = [], wait = []; let h = 0, qBytes = 0, closed = false, dead = false, up = false, fault = null; let pWake = null, pNeed, openTimer, readyOk, readyBad; const ready = new Promise((ok, bad) => { readyOk = ok; readyBad = bad; }); const onAbort = () => { end(Error()); close(); }; const onOpen = () => { if (closed) return; if (ws.protocol !== 'binary') { end(Error()); close(); return; } up = true; clearTimeout(openTimer); readyOk(api); }; const onData = (v) => { if (closed) return; const b = v instanceof Uint8Array ? v : new Uint8Array(v); if (!b.byteLength) return; const waiter = wait.shift(); if (waiter) waiter.resolve(b); else { q.push(b); qBytes += b.byteLength; if (pWake && (qBytes >= pNeed || b.byteLength >= CFG.dnPack)) pWake(); } }; const end = (err = null) => { if (closed) return; closed = true; fault = err; clearTimeout(openTimer); signal?.removeEventListener('abort', onAbort); if (!up) readyBad(err || Error()); pWake?.(); for (const waiter of wait.splice(0)) err ? waiter.reject(err) : waiter.resolve(null); }; const write = async (v) => { await ready; if (closed) throw fault || Error(); ws.send(u8(v)); }; const take = async () => { await ready; if (h < q.length) { const msg = q[h]; q[h++] = null; qBytes -= msg.byteLength; trim(); return msg; } if (fault) throw fault; if (closed) return null; return new Promise((ok, bad) => wait.push({ resolve: ok, reject: bad })); }; const pack = async () => { const first = await take(); if (dead) return null; if (!first || first.byteLength >= CFG.dnPack) return first; if (!closed && qBytes < CFG.dnPack - first.byteLength) { await new Promise(ok => { pNeed = CFG.dnPack - first.byteLength; const timer = setTimeout(() => pWake?.(), CFG.dnMs); pWake = () => { clearTimeout(timer); pWake = null; ok(); }; }); } if (dead) return null; let n = first.byteLength, end = h; while (end < q.length && n + q[end].byteLength <= CFG.dnPack) { n += q[end++].byteLength; } if (end === h) return first; const b = new Uint8Array(n); b.set(first); let o = first.byteLength; while (h < end) { const part = q[h]; q[h++] = null; b.set(part, o); o += part.byteLength; qBytes -= part.byteLength; } trim(); return b; }; const trim = () => { if (h === q.length) { q.length = 0; h = 0; } else if (h >= 256 && h * 2 >= q.length) { q.splice(0, h); h = 0; } }; const close = () => { if (dead) return; dead = true; if (!closed) end(); q.length = h = qBytes = 0; try { ws.close(1000); } catch {} }; const api = { ready, write, readPack: pack, close, get closed() { return closed; } }; ws.binaryType = 'arraybuffer'; ws.addEventListener('open', onOpen); ws.addEventListener('message', e => onData(e.data)); ws.addEventListener('error', () => end(Error())); ws.addEventListener('close', e => end( e?.code && e.code !== 1000 ? Error() : null, )); openTimer = setTimeout(() => { end(Error()); close(); }, ms); signal?.addEventListener('abort', onAbort, { once: true }); if (signal?.aborted) onAbort(); return api; }; const mkPkt = mode => { let tail = nil; const push = (v) => { const b = u8(v); if (b.byteLength) tail = tail.byteLength ? cat(tail, b) : b; const pkts = []; let o = 0; for (;;) { const avail = tail.byteLength - o; let hLen; let pLen; if (mode === 0xef) { if (avail < 1) break; let words = tail[o] & 0x7f; if (words === 0x7f) { if (avail < 4) break; words = tail[o + 1] | (tail[o + 2] << 8) | (tail[o + 3] << 16); hLen = 4; } else hLen = 1; pLen = words * 4; } else { if (avail < 4) break; pLen = new DataView( tail.buffer, tail.byteOffset + o, 4, ).getUint32(0, true) & 0x7fffffff; hLen = 4; } if (!pLen || pLen > 8 * 1024 * 1024) throw Error(); const total = hLen + pLen; if (avail < total) break; pkts.push(tail.subarray(o, o + total)); o += total; } if (o) tail = o === tail.byteLength ? nil : tail.slice(o); if (tail.byteLength > 8 * 1024 * 1024 + 4) throw Error(); return pkts; }; const clear = () => { tail = nil; }; return { push, clear }; }; const mkStream = ({ secret, emit, onClose }) => { let hdr = nil, cIn = null, cOut = null, kIn = null, kOut = null, peer = null, pkt = null; let init = false, closed = false, chain = Promise.resolve(); const ac = new AbortController(), uq = new Set(); const push = (v) => { if (closed) return Promise.reject(Error()); const job = { bytes: u8(v) }; uq.add(job); chain = chain.then(async () => { if (closed) throw Error(); if (!job.bytes) return job.result; const jobs = [job]; let n = job.bytes.byteLength; for (const next of uq) { if (next === job) continue; if (n >= CFG.upPack || n + next.bytes.byteLength > CFG.upPack) break; n += next.bytes.byteLength; jobs.push(next); } const b = jobs.length === 1 ? job.bytes : cat(...jobs.map(x => x.bytes)); for (const item of jobs) { uq.delete(item); item.bytes = null; } const out = await feed(b); for (const item of jobs) item.result = out; return out; }); return chain; }; const feed = async (b) => { if (closed) throw Error(); if (init && peer.closed) return false; if (!b.byteLength) return; if (!init) { const need = 64 - hdr.byteLength; if (b.byteLength < need) { hdr = cat(hdr, b); return; } hdr = cat(hdr, b.subarray(0, need)); await start(); const rest = b.subarray(need); if (rest.byteLength) return write(rest); return; } return write(b); }; const start = async () => { const raw = hdr; const cr = await cipher(raw, secret, false); const plain = await cr.crypt(raw); if (closed) return; const info = headOf(plain); const head = mkHead(info.mode, info.target, info.media); const [cw, out, kr] = await Promise.all([ cipher(raw, secret, true), wireHead(head), cipher(head, nil, true), ]); if (closed) return; const kws = await dial({ target: info.target, media: info.media, signal: ac.signal, }); if (closed) { kws.close(); return; } peer = kws; cIn = cr; cOut = cw; kOut = out.cipher; kIn = kr; pkt = mkPkt(info.mode); await kws.write(out.wire); if (closed) return; hdr = nil; init = true; pump().catch(() => close()); }; const write = async (raw) => { if (closed || peer.closed) return false; const plain = await cIn.crypt(raw); if (closed || peer.closed) return false; const pkts = pkt.push(plain); for (let start = 0; start < pkts.length;) { let end = start + 1, n = pkts[start].byteLength; while (end < pkts.length && n + pkts[end].byteLength <= CFG.upPack) { n += pkts[end++].byteLength; } const first = pkts[start]; const b = end === start + 1 ? first : new Uint8Array(first.buffer, first.byteOffset, n); if (closed || peer.closed) return false; const wire = await kOut.crypt(b); for (let o = 0; start < end; start++) { if (closed || peer.closed) return false; const n = pkts[start].byteLength; try { await peer.write(wire.subarray(o, o + n)); } catch (err) { if (closed || peer.closed) return false; throw err; } o += n; } } }; const pump = async () => { while (!closed) { const b = await peer.readPack(); if (closed) return; if (!b) return close(); const plain = await kIn.crypt(b); if (closed) return; const raw = await cOut.crypt(plain); if (closed) return; await emit(raw); } }; const close = () => { if (closed) return; closed = true; ac.abort(); try { peer?.close(); } catch {} for (const job of uq) job.bytes = null; uq.clear(); hdr = nil; pkt?.clear(); cIn = cOut = kIn = kOut = peer = null; try { onClose(); } catch {} }; return { push, close }; }; const mkSession = ({ secret, sid, onClose, lease }) => { let sock = null, closed = false, tx = Promise.resolve(), cur = null; const attach = (ws) => { if (sock || closed) throw Error(); sock = ws; ws.accept({ allowHalfOpen: true }); ws.binaryType = 'arraybuffer'; ws.addEventListener('message', e => { if (closed) return; try { onData(e.data); } catch { close(1008); } }); ws.addEventListener('close', () => close()); ws.addEventListener('error', () => close()); }; const onData = (v) => { if (closed) return; if (lease?.deleted) { return close(1000); } if (typeof v === 'string') throw Error(); const b = v instanceof Uint8Array ? v : new Uint8Array(v); if (!b.byteLength || b.byteLength > 2 * 1024 * 1024) { throw Error(); } for (const frame of frames(b)) { if (closed) return; const delta = check(frame); if (frame.sid !== sid) throw Error(); if (!cur && frame.type !== 1) throw Error(); if (frame.type !== 1 && cur?.closed) continue; if (frame.type === 1) open(); else if (frame.type === 2) write(frame.payload); else if (frame.type === 4) grant(delta); else if (frame.type === 3) end(false); else throw Error(); } }; const send = (type, data = nil) => { const out = enc(type, sid, data); const st = type === 2 || type === 4 ? cur : null; tx = tx.then(() => { if (closed) throw Error(); if ((type === 2 || type === 4) && (!st || st.closed)) return; sock.send(out); }); return tx; }; const open = () => { if (closed) return; if (cur) throw Error(); const st = { in: 4 * 1024 * 1024, out: 4 * 1024 * 1024, wake: null, closed: false, proxy: null, pItems: 0, }; st.proxy = mkStream({ secret, emit: b => emitDn(st, b), onClose: () => { if (!closed && !st.closed) end(true); }, }); cur = st; }; const write = (data) => { if (closed || cur?.closed) return; const st = cur; if (!st || st.closed) throw Error(); const n = data.byteLength; if (n > st.in) throw Error(); if (st.pItems >= 16384) { throw Error(); } st.in -= n; st.pItems++; st.proxy.push(data).then(accepted => { freeUp(st); if (closed || st.closed || accepted === false) return; st.in += n; const delta = new Uint8Array(4); new DataView(delta.buffer).setUint32(0, n); send(4, delta).catch(() => close()); }, () => { freeUp(st); if (!closed && !st.closed) st.proxy.close(); }).catch(() => close()); }; const freeUp = (st) => { if (st.closed) return; st.pItems--; }; const emitDn = async (st, b) => { for (let o = 0; o < b.byteLength; ) { while (!closed && !st.closed && st.out === 0) { await new Promise(ok => { st.wake = ok; }); } if (closed || st.closed) throw Error(); const n = Math.min(64 * 1024, b.byteLength - o, st.out); st.out -= n; await send(2, b.subarray(o, o + n)); o += n; } }; const grant = (n) => { if (closed || cur?.closed) return; const st = cur; if (!st || st.closed) throw Error(); st.out = Math.min(0xffffffff, st.out + n); wake(st); }; const stop = (st) => { st.closed = true; st.pItems = 0; wake(st); st.proxy.close(); }; const end = (notify) => { if (closed || cur?.closed) return; const st = cur; if (!st) throw Error(); stop(st); if (notify) send(3).then(() => close(), () => close()); else close(); }; const close = (code = 1000, reason = '') => { if (closed) return; closed = true; if (cur) stop(cur); cur = null; try { sock?.close(code, reason); } catch {} onClose?.(); onClose = null; }; return { attach, close }; }; function mkPage(host, boot) { const nonce = b64(rand(18)); const body = ``.replaceAll('__NONCE__', nonce).replace('__ORIGIN__', JSON.stringify(`https://${host}`)) .replace('__BOOTSTRAP__', JSON.stringify(String(boot))); const csp = [ "default-src 'none'", "base-uri 'none'", "child-src 'none'", `connect-src 'self' wss://${host}`, "font-src 'none'", "form-action 'none'", 'frame-ancestors http://127.0.0.1:*', "frame-src 'none'", "img-src 'none'", "manifest-src 'none'", "media-src 'none'", "object-src 'none'", `script-src 'nonce-${nonce}'`, "style-src 'none'", "worker-src 'none'", 'sandbox allow-same-origin allow-scripts', ].join('; '); return { body, csp }; } const route = async (req, env) => { const url = new URL(req.url), { pathname: path, origin } = url, { method, headers } = req; let cfg; try { cfg = mkCfg(env); } catch { return ['/', '/health', '/api/v1/session', '/api/v1/ws'].includes(path) ? reply(null, 500) : reply(); } if (path === '/' && (method === 'GET' || method === 'HEAD')) { let host = null; if (method === 'GET') { try { host = await bridge(url, cfg.secret); } catch {} } if (host) { const boot = await mkBoot(cfg.boot); const page = mkPage(host, boot); return new Response(page.body, { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8', 'Content-Security-Policy': page.csp, 'Cache-Control': 'no-store', 'Referrer-Policy': 'no-referrer', 'X-Content-Type-Options': 'nosniff', 'Permissions-Policy': [ 'accelerometer=()', 'autoplay=()', 'camera=()', 'clipboard-read=()', 'clipboard-write=()', 'display-capture=()', 'encrypted-media=()', 'fullscreen=()', 'geolocation=()', 'gyroscope=()', 'hid=()', 'idle-detection=()', 'magnetometer=()', 'microphone=()', 'midi=()', 'payment=()', 'picture-in-picture=()', 'publickey-credentials-create=()', 'publickey-credentials-get=()', 'screen-wake-lock=()', 'serial=()', 'usb=()', 'web-share=()', 'xr-spatial-tracking=()', ].join(', '), }, }); } return new Response(method === 'HEAD' ? null : 'Connection', { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' }, }); } if (path === '/health') { return new Response('{"ok":true}', { headers: { 'content-type': 'application/json; charset=utf-8' }, }); } if (path === '/api/v1/session') { const auth = bearer(headers.get('Authorization')); if (method === 'DELETE') { if (!auth || !(await verify(auth, cfg.boot, 'session'))) { return reply(); } let lease = leases.get(auth); if (!lease) leases.set(auth, lease = mkLease(auth)); lease.deleted = true; return reply(null, 204); } if (method !== 'POST' || !auth || !binary(req)) { return reply(); } if (!(await authBoot(auth, cfg.boot))) { return reply(); } try { const body = new Uint8Array(await req.arrayBuffer()); hello(body); const token = await mkSess(cfg.boot); return new Response(enc(0x11, 0), { status: 200, headers: { 'Content-Type': 'application/octet-stream', 'Cache-Control': 'no-store', 'X-Session-Token': token, 'X-Carrier-Mode': 'websocket-lanes', }, }); } catch { return reply(); } } if (path !== '/api/v1/ws' || method !== 'GET' || headers.get('Upgrade')?.toLowerCase() !== 'websocket' || (headers.has('Origin') && headers.get('Origin') !== origin)) { return reply(); } const offers = protos(req); const proto = offers.length === 1 ? offers[0] : null; const parts = proto?.split('.') ?? [], [kind, token = '', id] = parts, sid = Number(id); if (parts.length !== 3 || kind !== 'tproxy-lane-v1' || !/^[1-9][0-9]{0,7}$/.test(id) || sid > 0xffffff || !(await verify(token, cfg.boot, 'session'))) { return reply(); } const now = Date.now(); for (const [key, v] of leases) if (v.expires <= now && !v.active.size) leases.delete(key); let lease = leases.get(token); if (!lease) { if (leases.size >= 4096) return reply(null, 503); leases.set(token, lease = mkLease(token)); } if (lease.deleted || lease.used.has(sid) || lease.active.size >= 128 || lease.used.size >= 4096) { return reply(null, 409); } lease.used.add(sid); lease.active.add(sid); const sess = mkSession({ secret: cfg.key, sid, lease, onClose: () => lease.active.delete(sid), }); const { 0: client, 1: server } = new WebSocketPair(); try { sess.attach(server); } catch { sess.close(); return reply(null, 409); } return new Response(null, { status: 101, webSocket: client, headers: { 'Sec-WebSocket-Protocol': proto, 'Sec-WebSocket-Extensions': '', }, }); };