[0.9.1] FORK_IA_UX: review pass — remove dead code + Karvan security hardening

Dead code (from the abandoned thumb-zone/Explore-sheet nav experiment):
- OasisMobile.css: removed ~90 lines of orphaned CSS (.oasis-bottombar-fork/.bb-fab-*,
  .hive-sheet*/.fork-sheet*/.hsq-*, .omt-spacer, .hive-sheet-seg/.hs-seg, dead
  .oasis-bottombar-fixed) — no element emits any of them.
- main_views.js: removed renderHiveSheet() (never called; sole emitter of that CSS).
- karvan_view.js: dropped dead export karvanShortId + unused karvanView param.
- Added a style for .karvan-msg-live (client emitted it with no rule).

Karvan security (from the review):
- GET /karvan/:id only adopts a mirror room on a real navigation (sec-fetch-dest
  document / Accept text/html), not on <img>/subresources → fixes a CSRF that could
  spam/evict the user's ephemeral rooms.
- Cap room.members at 50 (was unbounded; each poll echoed it back).
- Reject signal payloads >16KB (SDP/ICE are tiny) — anti memory-DoS.
- karvan.js: guard malformed {kind:desc} signals so one bad signal can't abort a poll batch.
Tests: 15/15 (added members-cap + oversized-payload). Verified: CSRF fix (nav=200,
subresource=302), pages unchanged after CSS removal, boot clean.
This commit is contained in:
s1to 2026-08-07 20:42:53 +02:00
parent af160dbd26
commit 2c2c8f241d
7 changed files with 34 additions and 131 deletions

View file

@ -151,6 +151,21 @@ async function test(name, fn) {
assert.ok(m.postMessage(id, { from: "a", text: "hola" }), "se puede postear en la adoptada");
});
await test("cap de miembros: no crece más allá de MAX_MEMBERS (50)", () => {
const m = makeModel();
const r = m.createRoom({});
for (let i = 0; i < 80; i++) m.postSignal(r.id, { from: "peer" + i, to: "", payload: { k: "hi" } });
const g = m.getSignals(r.id, { forId: "nadie", since: 0 });
assert.ok(g.members.length <= 50, "miembros capados a 50, got " + g.members.length);
});
await test("rechaza payload de señal gigante (>16KB), acepta pequeño", () => {
const m = makeModel();
const r = m.createRoom({});
assert.strictEqual(m.postSignal(r.id, { from: "a", to: "b", payload: { blob: "x".repeat(20000) } }), null);
assert.ok(m.postSignal(r.id, { from: "a", to: "b", payload: { sdp: "small" } }), "payload pequeño pasa");
});
console.log("\n" + passed + " passed, " + failed + " failed");
process.exit(failed ? 1 : 0);
})();