200KB requires * reduction. Mirrors are disposable; swarm regrows through browser gossip plus * RAM-only reminders. Parity proves source bytes, not host behavior. No central * server, obfuscation, mirror-side entitlements, or server trust/moderation. * * 1 BOUNDARIES: MUST NOT use WebSocket, SSE, STUN, TURN, long-poll, sessions, * cookies, accounts, or server media decode. Single deployable file; runtime * files only as sec 4 permits. One upload pass and one fetch pass per active * panel/tick. Server routes by filename + size + mtime + tail only. * * 2 WIRE: [4 vLen BE][JPEG 3x3 80x60 sheet][4 aLen BE][G.711 u-law][UTF-8 tail]. * Host-only RTC after visible media MAY send vLen=0/aLen=0 maintenance blobs. * 9 frames x 256ms=2304ms, center crop .85, JPEG_Q=.50. Audio ON: 9 x 256ms * mono u-law at 12kHz (~30KB/s); OFF sends aLen=0. Non-8kHz audio MUST carry sr. * Exhaustive tail keys: head, sid, sr, msg, msg_ts, bridge_target, px_hit, rtc. * Adding keys is a protocol change. MUST NOT add seq. * * 3 IDENTITY: browser owns stable localStorage deviceId -> {deviceId}_{L|R}; * seekers append _S. KYC identity is separate by IP. * * 4 STORAGE: RAM: /dev/shm/nosignup/sprite/{peerId}.bin and * /dev/shm/nosignup/mirrors.txt. One RAM blob/user, two while bridging; newest * replaces old; flat dir; routing in filename. mirrors.txt is untrusted URL+ts * gossip only, cap 64, lazy/TTL, torn reads OK. Persistent KYC only: * /var/lib/nosignup/kyc/{crc32(IP)}/metadata.log + sample.jpg; one session row * per connected panel, 1-in-128 media sample rows, lazy-delete after 30d. * Sprite writes SHOULD be direct final replacement; clients drop torn/invalid/ * truncated/decode-failed blobs as no-fresh-frame. Seek uses fresh _S only. * * 5 UPLOAD: active panel prep blob -> fire POST without await -> next pass at * UPLOAD_MS - prep; cadence=max(prep,UPLOAD_MS), not prep+post. Exactly one POST; * _postInflight skips prep+POST while prior POST is out. ACK cutoff below * UPLOAD_MS. Idle uploads nothing. Instrument prep_ms/post_ms/queue/code. JPEG * encode SHOULD use Worker; fallback explicit synchronous toDataURL, never * main-thread toBlob callback. Mic SHOULD use AudioWorklet; ScriptProcessor is * fallback. api=encworker/api=micworklet are startup-only same-file scripts. * MUST NOT vary chunks, frame rate, upload cadence, or JPEG_Q to chase bytes. * * 6 FETCH/LIVENESS: fetch target peerId on 1024ms grid, one GET in flight/panel. * Manual stop/reset is authoritative; stale async callbacks MUST NOT revive old * epochs. Fresh decoded head > high-water is alive. Same/older head, 404/204, * fetch error, invalid blob, decode failure -> same no-fresh-frame path. Match * may echo _S sid/head; client rejects sid mismatch or far-out first head. After * match briefly publish own _S; exact remote BASE fetch MAY serve fresh remote _S. * Disconnect budgets are wall-clock: orphan 6s, established 6s. Silence=black/silence. * * 7 PLAYBACK: cursor advances 1 frame/256ms by wall clock. Blobs lay absolute * rails: firstAbs=head-8; wantAbs=anchor.abs+floor((now-anchor.time)/256). Draw * newest blob covering wantAbs; audio same abs, play once. Arrival order irrelevant. * Re-anchor only on first blob/underrun/runaway/sender swap; skip forward to * newestAbs-PLAY_RUNWAY. Exhaustion blanks. No hold, loop, catch-up speed, or back replay. * * 8 SENDER/BRIDGE: head > high-water alive; head <= high-water within * SWAP_GAP_FRAMES drop; larger drop means sender swap -> re-anchor. Bridge only * after both panels decode fresh heads. Bridge is HTTP-mode only; WebRTC/HD * disables Bridge UI/state. Bridge sets bridge_target={peerId}; /sprite * reads only that key, emits X-Bridge-Target, streams target if fresh. * Clients accept SID changes only under that header. * * 9 ADD-ONS: PIXEL px_hit best-effort; click/draw mapping MUST use displayed * bitmap rect; receiver dedupes id and blacks mapped outgoing pixel for 1d/session; * px_hit MUST carry w,h. HELP NETWORK ?src=1 MUST expose normalized parity CORS; * browser MUST hash source before mirror use. PHP MAY remember untrusted mirror * URLs only in RAM mirrors.txt; MUST NOT fetch/probe/score/relay mirrors. DONATION * vanity is browser self-rename only; PHP MUST NOT check ledgers, trust proofs, * store names, edit KYC, reserve IDs, refund, recover, or be name authority. * AUDIO RAIL is local visualization only. SPECIFIC-ID is browser-owned; explicit * ID or substring resolves via fresh base/_S sprite filenames; no directory/inbox/caller * queue/mailbox. Cross-mirror lookup MAY probe same-parity staged mirrors by CORS * sprite reads; remote mirror URL stays browser-local; PHP MUST NOT relay. TRUSTED * mirrors are browser-held; PHP stores URL hints only, never trust/rank/vote. * * 9A AUDIO/ADULT: audio media only: sr=12000 when ON, aLen=0 when OFF, no match * split. Adult section publishes {deviceId}_H_{L|R}; normal publishes {deviceId}_{L|R}; * random/partial/explicit same-mirror matches MUST NOT cross namespace. `_H` * reserved; PHP enforces by filename/fromPeerId. HTML Mode default. WebRTC Mode * explicit opt-in: host-only, iceServers=[], signaling via rtc tail, PHP blind, * peer IP may be exposed, strict NAT falls back to HTTP. UI MUST warn about IP, * hostile-state/DDOS risk, explicit/extreme content, no moderation/warranty/ * recovery/recourse. HD tooltip states current mode; toggle retunes own cam. * Once RTC visible, HTTP SHOULD become no-media head/sid/rtc/chat/px maintenance. * * 10 DIAGNOSTICS: trace/overlay opt-in and MUST NOT alter protocol. Judge production * with trace/debug OFF. Key metric: jitter-buffer lead vs PLAY_RUNWAY. * * 11 LANDMINES: no background-send uploads; no await-held prep guard; no rAF * capture/playback; no unbounded/awaited upload cadence or skip grids; no seq; * no held/looped underrun frame; no unmeasured timing cuts; no per-event DOM trace; * no temp files/locks/validation for sprite races; no masking gaps by raising * runway; no ACK wait past next slot; no jitter re-anchor; no main-thread toBlob; * no ScriptProcessor-only mic. * DO NOT DELETE/REMOVE THIS BLOCK - NOSIGNUP.CHAT PROTOCOL CONTRACT. */ // ===== FILE MAP (sections in physical order) ===== // ================================================= // ===== BLOCK 1: PHP CONFIG + STORAGE DIRS ===== error_reporting(0); ini_set('display_errors', 0); ini_set('log_errors', 1); $SPRITE_DIR = '/dev/shm/nosignup/sprite'; $MIRROR_FILE = '/dev/shm/nosignup/mirrors.txt'; $KYC_BASE = '/var/lib/nosignup/kyc'; $SEEK_MATCH_FRESH_MS = 3000; $SPRITE_FRESH_SEC = 5; $MIRROR_FRESH_SEC = 86400 * 30; $MIRROR_CAP = 64; if (!is_dir($SPRITE_DIR)) @mkdir($SPRITE_DIR, 0755, true); if (!is_dir($KYC_BASE)) @mkdir($KYC_BASE, 0755, true); $STORAGE_PROBLEMS = array(); if (!is_dir($SPRITE_DIR) || !is_writable($SPRITE_DIR)) { $STORAGE_PROBLEMS[] = array('crit', 'Chat storage is not writable', $SPRITE_DIR, 'Frames cannot be stored, so chat will not work until this is fixed.'); } elseif (!is_dir($KYC_BASE) || !is_writable($KYC_BASE)) { $STORAGE_PROBLEMS[] = array('warn', 'Verification (KYC) storage is not writable', $KYC_BASE, 'Chat works now; identity sampling is disabled until this folder exists and is writable.'); } function lazy_expire($path) { if (file_exists($path) && (time() - filemtime($path)) > 86400 * 30) { @unlink($path); } } function source_hash() { $s = (string)@file_get_contents(__FILE__); if (substr($s, 0, 3) === "\xEF\xBB\xBF") $s = substr($s, 3); $s = str_replace(["\r\n", "\r"], "\n", $s); $s = preg_replace('/[ \t]+\n/', "\n", $s); return hash('sha256', rtrim($s, "\n") . "\n"); } function mirror_ok($u) { $u = trim((string)$u); if ($u === '') return null; if (!preg_match('#^https?://#i', $u)) $u = 'https://' . $u; if (strlen($u) > 220) return null; $p = @parse_url($u); if (!$p || empty($p['host'])) return null; $scheme = strtolower($p['scheme'] ?? 'https'); if ($scheme !== 'http' && $scheme !== 'https') return null; $host = strtolower($p['host']); if (preg_match('/^(localhost|127\.|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|0\.|169\.254\.|::1)/i', $host)) return null; if (strpos($host, '.') === false && !filter_var($host, FILTER_VALIDATE_IP)) return null; $port = isset($p['port']) ? ':' . (int)$p['port'] : ''; $path = $p['path'] ?? '/index.php'; if ($path === '' || $path === '/') $path = '/index.php'; elseif (!preg_match('/\.php$/i', $path)) $path = rtrim($path, '/') . '/index.php'; return $scheme . '://' . $host . $port . $path; } function mirrors_read() { global $MIRROR_FILE, $MIRROR_FRESH_SEC; if (!is_file($MIRROR_FILE)) return []; $now = time(); $out = []; foreach (@file($MIRROR_FILE, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [] as $line) { $p = explode("\t", $line, 2); $u = mirror_ok($p[0] ?? ''); $t = (int)($p[1] ?? 0); if ($u !== null && $t > 0 && ($now - $t) < $MIRROR_FRESH_SEC) $out[$u] = $t; } return $out; } function mirrors_add($txt) { global $MIRROR_FILE, $MIRROR_CAP; $cur = mirrors_read(); $now = time(); $changed = false; foreach (preg_split('/[\s,]+/', (string)$txt) as $u) { $u = mirror_ok($u); if ($u === null) continue; unset($cur[$u]); $cur[$u] = $now; $changed = true; } if (!$changed) return; if (count($cur) > $MIRROR_CAP) $cur = array_slice($cur, -$MIRROR_CAP, null, true); $s = ''; foreach ($cur as $u => $t) $s .= $u . "\t" . $t . "\n"; @file_put_contents($MIRROR_FILE, $s); } function mirrors_sample($n) { $u = array_keys(mirrors_read()); if (!$u) return []; shuffle($u); return array_slice($u, 0, $n); } function sprite_info($pid) { global $SPRITE_DIR; $pid = preg_replace('/[^a-zA-Z0-9_\-]/', '', $pid); if (strlen($pid) < 8) return null; $file = "$SPRITE_DIR/$pid.bin"; if (!is_file($file)) return null; $mt = @filemtime($file); $sz = @filesize($file); if ($mt === false || $sz === false) return null; return [$file, $mt, $sz]; } function pid_hd_video($pid) { return preg_match('/_H_(L|R)(?:_S)?$/', $pid) === 1; } function pid_has_panel($pid) { return preg_match('/_(?:H_)?(L|R)(?:_S)?$/', $pid) === 1; } function sprite_partial_info($prefix, $exclude = '') { global $SPRITE_DIR, $SPRITE_FRESH_SEC; $prefix = preg_replace('/[^a-zA-Z0-9_\-]/', '', $prefix); $exclude = preg_replace('/[^a-zA-Z0-9_\-]/', '', $exclude); $excludeBase = preg_replace('/_S$/', '', $exclude); if (strlen($prefix) < 3) return null; $hasMode = pid_has_panel($exclude); $wantHd = pid_hd_video($exclude); if (preg_match('/^(.+)_(L|R)$/', $prefix, $m)) { $needle = $m[1]; $wantCh = $m[2]; } else { $needle = $prefix; $wantCh = null; } $now = time(); $best = null; $bestMt = -1; foreach (glob("$SPRITE_DIR/*.bin") ?: [] as $f) { $pid = basename($f, '.bin'); $basePid = preg_replace('/_S$/', '', $pid); if ($excludeBase !== '' && $basePid === $excludeBase) continue; if (!preg_match('/^(.+)_(L|R)(?:_S)?$/', $pid, $pm)) continue; if ($hasMode && pid_hd_video($pid) !== $wantHd) continue; if ($wantCh !== null && $pm[2] !== $wantCh) continue; $hay = $wantCh === null ? $pid : $pm[1]; if (stripos($hay, $needle) === false) continue; $mt = @filemtime($f); if ($mt === false || ($now - $mt) > $SPRITE_FRESH_SEC) continue; $sz = @filesize($f); if ($sz === false || $sz <= 0) continue; if ($mt > $bestMt || ($mt === $bestMt && strcmp($pid, $best[0] ?? '') < 0)) { $best = [$basePid, $f, $mt, $sz]; $bestMt = $mt; } } return $best; } function sprite_tail_get($file, $size, $key) { $fh = @fopen($file, 'rb'); if (!$fh) return null; $st = @fstat($fh); if ($st && isset($st['size'])) $size = $st['size']; $h = fread($fh, 4); if (strlen($h) < 4) { fclose($fh); return null; } $vLen = unpack('N', $h)[1]; if (4 + $vLen + 4 > $size) { fclose($fh); return null; } fseek($fh, 4 + $vLen); $ah = fread($fh, 4); if (strlen($ah) < 4) { fclose($fh); return null; } $aLen = unpack('N', $ah)[1]; $tailStart = 8 + $vLen + $aLen; if ($tailStart > $size) { fclose($fh); return null; } fseek($fh, $tailStart); $tail = stream_get_contents($fh); fclose($fh); foreach (explode("\n", $tail) as $line) { $eq = strpos($line, '='); if ($eq !== false && substr($line, 0, $eq) === $key) { return preg_replace('/[^a-zA-Z0-9_\-]/', '', substr($line, $eq + 1)); } } return null; } function stream_sprite_file($file) { $sz = @filesize($file); if ($sz === false || $sz <= 0) return false; header('Content-Type: application/octet-stream'); header('Content-Length: ' . $sz); @readfile($file); return true; } function log_kyc($peerId, $blob) { global $KYC_BASE; $pid = preg_replace('/[^a-zA-Z0-9_\-]/', '', $peerId); if (preg_match('/^(.+)_S$/', $pid, $m)) $pid = $m[1]; if ($pid === '') return; $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; $ipDir = $KYC_BASE . '/' . sprintf('%08x', crc32($ip)); if (!is_dir($ipDir) && !@mkdir($ipDir, 0755, true)) return; $logFile = "$ipDir/metadata.log"; $sampleFile = "$ipDir/sample.jpg"; lazy_expire($logFile); lazy_expire($sampleFile); @file_put_contents($logFile, time() . ",$pid,$ip\n", FILE_APPEND); if (strlen($blob) >= 4) { $vLen = unpack('N', substr($blob, 0, 4))[1]; if ($vLen > 0 && 4 + $vLen <= strlen($blob)) { @file_put_contents($sampleFile, substr($blob, 4, $vLen)); } } } function log_kyc_session($peerId, $remoteId) { global $KYC_BASE; $pid = preg_replace('/[^a-zA-Z0-9_\-]/', '', $peerId); if (preg_match('/^(.+)_S$/', $pid, $m)) $pid = $m[1]; $rid = preg_replace('/[^a-zA-Z0-9_\-]/', '', $remoteId); if ($pid === '' || $rid === '') return; $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; $ipDir = $KYC_BASE . '/' . sprintf('%08x', crc32($ip)); if (!is_dir($ipDir) && !@mkdir($ipDir, 0755, true)) return; $logFile = "$ipDir/metadata.log"; lazy_expire($logFile); @file_put_contents($logFile, time() . ",$pid,$rid,$ip\n", FILE_APPEND); } function write_sprite($pid, $blob) { global $SPRITE_DIR; $pid = preg_replace('/[^a-zA-Z0-9_\-]/', '', $pid); if (strlen($pid) < 8 || $blob === false || strlen($blob) === 0) return false; $dst = "$SPRITE_DIR/$pid.bin"; $n = @file_put_contents($dst, $blob); if ($n === false) return false; if (!preg_match('/_S$/', $pid)) @unlink("$SPRITE_DIR/{$pid}_S.bin"); return true; } $a = $_GET['api'] ?? ''; if ($a !== '') { header('Cache-Control: no-store, no-cache, must-revalidate'); // ===== ENCODER WORKER SCRIPT ===== if ($a === 'encworker' && $_SERVER['REQUEST_METHOD'] === 'GET') { $worker = <<<'JS' let _ocv=null,_octx=null; self.onmessage=async (e)=>{ const d=e.data; try{ const t0=performance.now(); if(!_ocv||_ocv.width!==d.w||_ocv.height!==d.h){ _ocv=new OffscreenCanvas(d.w,d.h); _octx=_ocv.getContext('2d'); } _octx.putImageData(new ImageData(new Uint8ClampedArray(d.buf),d.w,d.h),0,0); const t1=performance.now(); const b=await _ocv.convertToBlob({type:'image/jpeg',quality:d.q}); const ab=await b.arrayBuffer(); const t2=performance.now(); self.postMessage({id:d.id,ab:ab,wdraw:Math.round(t1-t0),wenc:Math.round(t2-t1)},[ab]); }catch(err){ self.postMessage({id:d.id,err:String(err)}); } }; JS; header('Content-Type: application/javascript; charset=UTF-8'); header('Content-Length: ' . strlen($worker)); echo $worker; exit; } if ($a === 'micworklet' && $_SERVER['REQUEST_METHOD'] === 'GET') { $worker = <<<'JS' class N extends AudioWorkletProcessor{constructor(o){super();let p=o&&o.processorOptions||{};this.r=p.targetRate||8000;this.c=p.chunkBytes||2048;this.q=sampleRate/this.r;this.n=0;this.a=[]}e(v){let s=Math.max(-32768,Math.min(32767,v*32768))|0,g=s<0?128:0;if(g)s=-s;s=Math.min(s+132,32767);let e=7,m=16384;while(e>0&&!(s&m)){e--;m>>=1}return~(g|e<<4|(s>>e+3&15))&255}p(b){this.a.push(b);while(this.a.length>=this.c){let o=new Uint8Array(this.a.splice(0,this.c));this.port.postMessage({buf:o.buffer},[o.buffer])}}process(i,o){let z=o[0]&&o[0][0];if(z)z.fill(0);let x=i[0]&&i[0][0];if(!x)return true;let r=this.q>0?this.q:sampleRate/this.r,p=this.n;while(p 1, 'mirrors' => mirrors_sample(8)], JSON_UNESCAPED_SLASHES); header('Content-Length: ' . strlen($j)); echo $j; exit; } // ===== UPLOAD ===== if ($a === 'upload' && $_SERVER['REQUEST_METHOD'] === 'POST') { $codeStart = microtime(true); $reqStart = $_SERVER['REQUEST_TIME_FLOAT'] ?? $codeStart; // pre-PHP time: body upload + FPM queue $writes = 0; header('Content-Type: application/json'); $body = @file_get_contents('php://input'); if ($body !== false && strlen($body) > 0) { $mode = $_GET['mode'] ?? 'same'; $doKyc = (mt_rand(1, 128) === 1); $kycPid = null; $kycBlob = null; if ($mode === 'split') { $lenL = max(0, (int)($_GET['lenL'] ?? 0)); $lenR = max(0, (int)($_GET['lenR'] ?? 0)); if ($lenL > 0 && isset($_GET['peerIdL'])) { $part = substr($body, 0, $lenL); if (write_sprite($_GET['peerIdL'], $part)) { $writes++; if ($doKyc && $kycPid === null) { $kycPid = $_GET['peerIdL']; $kycBlob = $part; } if (isset($_GET['sessL'])) log_kyc_session($_GET['peerIdL'], $_GET['sessL']); } } if ($lenR > 0 && isset($_GET['peerIdR'])) { $part = substr($body, $lenL, $lenR); if (write_sprite($_GET['peerIdR'], $part)) { $writes++; if ($doKyc && $kycPid === null) { $kycPid = $_GET['peerIdR']; $kycBlob = $part; } if (isset($_GET['sessR'])) log_kyc_session($_GET['peerIdR'], $_GET['sessR']); } } } else { foreach (['L', 'R'] as $ch) { $key = 'peerId' . $ch; if (isset($_GET[$key]) && write_sprite($_GET[$key], $body)) { $writes++; if ($doKyc && $kycPid === null) { $kycPid = $_GET[$key]; $kycBlob = $body; } if (isset($_GET['sess' . $ch])) log_kyc_session($_GET[$key], $_GET['sess' . $ch]); } } } if ($doKyc && $kycPid !== null && $kycBlob !== null) log_kyc($kycPid, $kycBlob); } header('X-Upload-Queue-Ms: ' . round(($codeStart - $reqStart) * 1000)); header('X-Upload-Code-Ms: ' . round((microtime(true) - $codeStart) * 1000)); header('X-Upload-Writes: ' . $writes); header('X-Sprite-Store: shm'); header('Content-Length: 8'); // exact length of {"ok":1} - client finishes the response immediately, doesn't wait on connection framing echo '{"ok":1}'; exit; } // ===== SPRITE FETCH ===== if ($a === 'sprite' && $_SERVER['REQUEST_METHOD'] === 'GET') { header('Access-Control-Allow-Origin: *'); header('Access-Control-Expose-Headers: X-Match-Peer, X-Match-Sid, X-Match-Head, X-Resolved-Peer, X-Bridge-Target'); $pid = preg_replace('/[^a-zA-Z0-9_\-]/', '', $_GET['peerId'] ?? ''); if (strlen($pid) < 3) { http_response_code(400); exit; } $fromPid = preg_replace('/[^a-zA-Z0-9_\-]/', '', $_GET['fromPeerId'] ?? ''); if ($fromPid !== '' && pid_has_panel($fromPid) && pid_has_panel($pid) && pid_hd_video($fromPid) !== pid_hd_video($pid)) { http_response_code(404); exit; } $now = time(); if (preg_match('/^(.+)_(L|R)_S$/', $pid, $m)) { $base = $m[1]; $ch = $m[2]; $candidates = []; $nowMs = microtime(true) * 1000; $wantHd = pid_hd_video($pid); foreach (glob("$SPRITE_DIR/*_{$ch}_S.bin") ?: [] as $f) { $other = basename($f, '.bin'); if ($other === $pid) continue; if (pid_hd_video($other) !== $wantHd) continue; $mt = @filemtime($f); if ($mt === false) continue; if (($nowMs - ($mt * 1000)) > $SEEK_MATCH_FRESH_MS) continue; if (strpos($other, $base) === 0) continue; $candidates[] = $other; } if ($candidates) { $found = $candidates[array_rand($candidates)]; $remoteBase = preg_replace('/_S$/', '', $found); $sz = @filesize("$SPRITE_DIR/$found.bin"); $sid = ($sz !== false) ? sprite_tail_get("$SPRITE_DIR/$found.bin", $sz, 'sid') : null; $head = ($sz !== false) ? sprite_tail_get("$SPRITE_DIR/$found.bin", $sz, 'head') : null; header('X-Match-Peer: ' . $remoteBase); if ($sid !== null && $sid !== '') header('X-Match-Sid: ' . $sid); if ($head !== null && $head !== '') header('X-Match-Head: ' . preg_replace('/[^0-9]/', '', $head)); header('Content-Type: application/octet-stream'); header('Content-Length: 0'); http_response_code(200); exit; } http_response_code(204); exit; } $resolvedPid = null; $info = sprite_info($pid); if ($info !== null && ($now - $info[1]) > $SPRITE_FRESH_SEC) $info = null; if ($info === null && preg_match('/^.+_(L|R)$/', $pid)) { $aliasInfo = sprite_info($pid . '_S'); if ($aliasInfo !== null && ($now - $aliasInfo[1]) <= $SPRITE_FRESH_SEC) $info = $aliasInfo; } if ($info === null) { $partial = sprite_partial_info($pid, $fromPid); if ($partial !== null) { $resolvedPid = $partial[0]; $info = [$partial[1], $partial[2], $partial[3]]; } } if ($info === null || ($now - $info[1]) > $SPRITE_FRESH_SEC) { http_response_code(404); exit; } if ($resolvedPid !== null) header('X-Resolved-Peer: ' . $resolvedPid); $serve = $info[0]; $bt = sprite_tail_get($info[0], $info[2], 'bridge_target'); if ($bt !== null && $bt !== '' && $bt !== $pid) { $btInfo = sprite_info($bt); if ($btInfo !== null && ($now - $btInfo[1]) <= $SPRITE_FRESH_SEC) { $serve = $btInfo[0]; header('X-Bridge-Target: ' . $bt); } } if (!stream_sprite_file($serve)) http_response_code(404); exit; } http_response_code(404); exit; } if (isset($_GET['src'])) { header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="nosignup.php"'); header('Access-Control-Allow-Origin: *'); header('Access-Control-Expose-Headers: X-NSC-Parity-SHA256'); header('X-NSC-Parity-SHA256: ' . source_hash()); header('Content-Length: ' . filesize(__FILE__)); readfile(__FILE__); exit; } ?> NOSIGNUP.CHAT - Anonymous Spritesheet Chat
! . As root: mkdir -p '' && chmod 777 '' (tidier: chown it to your web user - www-data / nginx / apache - then chmod 755).
IDLE
Peer 1 appears here
IDLE
Peer 2 appears here

Free, Resilient, Communications

  • Two channels: random or pasted PeerID.
  • Bridge: connect two peers through you.
  • HTTP-only: firewall-friendly, resilient chat.
  • No accounts: no cookies, no tracking, one PHP file.
Strangers may show anything. Ephemeral service; no warranty, moderation, recovery, or recourse.
*

Options


!

HD WARNING. HTML uses mirrors and hides your IP from your peer. WebRTC is direct: faster, higher quality, UNMODERATED, and exposes your IP. That is usually harmless unless someone wants to DDOS you. NO RECOURSE: strangers may show explicit nudity/genitals, gore, snuff, or anything else; no complaints, moderation, recovery, warranty, or appeal.

$

one .php file. drop it on any PHP host.
no build step. no dependencies. it just runs.

download nosignup.php
BITCOIN - electrumbc1qqnu6n0jztxl4f6krv7klradghle09uhyu7uymz
MONERO - feather8Ab24DppUvcdtHfm7K8gTqdBTmPCBiak1GwxgPm1C3osYVQL2QdC1C8GMwggKF77RKKzDgP2R8E3VH8ifetsKms5AqkVyVg
LITECOIN - electrum-ltcltc1qlpdy8qzejcmjdn6vwarpyz8djdlk780w4qkwyp

+

Drop this file into any PHP host, then paste its IP in this input box below.

download full index.php