sandbox

Jedan snippet u <head> preuzima svaki browser API na strani — mrežu, skladište, izvršavanje koda, senzitivne dozvole. Ništa ne prolazi dok politika ne kaže, a sve što je strana pokušala ostaje zapisano.

nalepi ovo kao prvi skript u <head>
<script>/* dist/t.js — 370 b */</script> <script src="/sbx/sbx.js" async></script>

Prvi red mora biti inline i prvi. Motor stiže asinhrono; dok ne stigne, snippet drži mrežu u redu i hvata greške.

zašto dva fajla

snippet, inline, ispod 400 b
Mora biti tu pre koda strane, inače je zakasnio. Zato je sitan: preuzme fetch i XHR, zakači se na greške i konzolu, i povuče motor.
motor, async, jedan snop
Head, vitals, profil, otprema i politika — pet fragmenata konkateniranih u jedan IIFE, deljeni closure. Kad sleti, usvoji red koji je snippet skupio i zapleni ostatak API-eva.
app.ready()
Politika stigne, otisak se izračuna, red se otpusti. Tek tad strana radi punom snagom — i tek tad je poznato šta joj je dozvoljeno.

šta se hvata

zaplenjeno
mreža
fetch · xhr · websocket · eventsource · sendBeacon
izvršavanje
eval · Function · document.write · Worker
skladište
localStorage · sessionStorage · cookie · indexedDB
dozvole
geolocation · mediaDevices · clipboard · notifications
posmatra se
console.* · onerror · unhandledrejection
politika
{ "mode": "enforce", "allowByDefault": true, "capabilities": { "eval": false }, "network": { "allow": ["self", "*.ltp.ge"], "deny": ["https://evil.example"] }, "collector": "/a/p" }

report režim ne lomi ništa — samo beleži šta bi bilo odbijeno. Tako politika ulazi na živu stranu bez rizika.

build

node build.js # otprema uključena node build.js --no-log # log-stub umesto log — ništa ne odlazi node build.js --src /sbx/sbx.js # odakle snippet povlači motor node build.js --config moj.json # druga politika

Build ušije politiku i adresu motora u snippet, spoji fragmente u jedan snop, minifikuje i izmeri. Cilj za snippet je ispod 400 b — build viče ako pređe.