experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(tile-ipc): tile:log:write + tile:app:quit/restart strict shims (Phase 3.5f)

Add 3 fire-and-forget strict shims using ipcMain.on (matching legacy
pattern):
- tile:log:write — token-only gate; mirrors renderer-log
- tile:app:quit — trustedBuiltin enforced; mirrors app-quit
- tile:app:restart — trustedBuiltin enforced; mirrors app-restart

Add corresponding wrapper methods in tile-preload.cts via
ipcRenderer.send. Additive only — legacy ipcMain.on('renderer-log',
'app-quit', 'app-restart') handlers untouched (Wave 2b 3.6f flips them).

+105 -1
+69 -1
backend/electron/tile-ipc.ts
··· 17 17 * Every handler validates the capability token before executing. 18 18 */ 19 19 20 - import { ipcMain, BrowserWindow, net, dialog, webContents, nativeTheme, screen } from 'electron'; 20 + import { ipcMain, BrowserWindow, net, dialog, webContents, nativeTheme, screen, app } from 'electron'; 21 21 import fs from 'node:fs'; 22 22 import path from 'node:path'; 23 23 ··· 6463 6463 } catch (err) { 6464 6464 return { success: false, error: err instanceof Error ? err.message : String(err) }; 6465 6465 } 6466 + }); 6467 + 6468 + // ── tile:log:write ──────────────────────────────────────────────── 6469 + // 6470 + // Strict shim for the legacy `renderer-log` fire-and-forget channel. 6471 + // Any tile with a valid token may log — no capability check beyond a 6472 + // valid token (all tiles can log). Prints forwarded renderer output to 6473 + // the main-process terminal, matching the legacy shortSource format. 6474 + ipcMain.on('tile:log:write', (_event, args: { 6475 + token: string; 6476 + args?: unknown[]; 6477 + source?: string; 6478 + }) => { 6479 + if (!args?.token) return; 6480 + const grant = getGrantForToken(args.token); 6481 + if (!grant) { 6482 + handleViolation(null, 'log', 'tile:log:write', 'invalid token', args.token); 6483 + return; 6484 + } 6485 + const shortSource = (args.source ?? grant.tileId) 6486 + .replace('peek://app/', '') 6487 + .replace('peek://ext/', 'ext/'); 6488 + console.log(`[${shortSource}]`, ...(args.args ?? [])); 6489 + }); 6490 + 6491 + // ── tile:app:quit ───────────────────────────────────────────────── 6492 + // 6493 + // Strict shim for the legacy `app-quit` channel. Requires trustedBuiltin 6494 + // (only core tiles — cmd, hud, page — may quit the application). 6495 + ipcMain.on('tile:app:quit', (_event, args: { 6496 + token: string; 6497 + source?: string; 6498 + }) => { 6499 + if (!args?.token) return; 6500 + const grant = getGrantForToken(args.token); 6501 + if (!grant) { 6502 + handleViolation(null, 'app', 'tile:app:quit', 'invalid token', args.token); 6503 + return; 6504 + } 6505 + if (!grant.trustedBuiltin) { 6506 + handleViolation(grant, 'app', 'tile:app:quit', 'trustedBuiltin required', args.token); 6507 + return; 6508 + } 6509 + DEBUG && console.log('[tile-ipc] app:quit requested from:', args.source ?? grant.tileId); 6510 + app.quit(); 6511 + }); 6512 + 6513 + // ── tile:app:restart ────────────────────────────────────────────── 6514 + // 6515 + // Strict shim for the legacy `app-restart` channel. Requires trustedBuiltin. 6516 + // Calls app.relaunch() then app.quit() matching the legacy ipc.ts pattern. 6517 + ipcMain.on('tile:app:restart', (_event, args: { 6518 + token: string; 6519 + source?: string; 6520 + }) => { 6521 + if (!args?.token) return; 6522 + const grant = getGrantForToken(args.token); 6523 + if (!grant) { 6524 + handleViolation(null, 'app', 'tile:app:restart', 'invalid token', args.token); 6525 + return; 6526 + } 6527 + if (!grant.trustedBuiltin) { 6528 + handleViolation(grant, 'app', 'tile:app:restart', 'trustedBuiltin required', args.token); 6529 + return; 6530 + } 6531 + DEBUG && console.log('[tile-ipc] app:restart requested from:', args.source ?? grant.tileId); 6532 + app.relaunch(); 6533 + app.quit(); 6466 6534 }); 6467 6535 6468 6536 DEBUG && console.log('[tile-ipc] All tile IPC handlers registered');
+36
backend/electron/tile-preload.cts
··· 2079 2079 ipcRenderer.send('app-restart', { source: sourceAddress }); 2080 2080 }; 2081 2081 2082 + // ── tile:app:quit / tile:app:restart strict shims (Phase 3.5f) ────── 2083 + // 2084 + // New strict-channel counterparts to api.quit / api.restart above. 2085 + // Route through tile:app:* channels which enforce trustedBuiltin gating 2086 + // on the main-process side (tile-ipc.ts). The token is passed so the 2087 + // handler can validate the grant without relying on the sender's origin. 2088 + // 2089 + // Wave 3.6f will flip api.quit / api.restart to call these methods and 2090 + // delete the legacy app-quit / app-restart ipcMain.on handlers from ipc.ts. 2091 + api.tileQuit = () => { 2092 + if (!trustedBuiltin) { 2093 + console.warn('[tile-preload] api.tileQuit requires trustedBuiltin — ignored'); 2094 + return; 2095 + } 2096 + ipcRenderer.send('tile:app:quit', { token: tileToken, source: sourceAddress }); 2097 + }; 2098 + 2099 + api.tileRestart = () => { 2100 + if (!trustedBuiltin) { 2101 + console.warn('[tile-preload] api.tileRestart requires trustedBuiltin — ignored'); 2102 + return; 2103 + } 2104 + ipcRenderer.send('tile:app:restart', { token: tileToken, source: sourceAddress }); 2105 + }; 2106 + 2107 + // ── tile:log:write strict shim (Phase 3.5f) ────────────────────────── 2108 + // 2109 + // New strict-channel counterpart to api.log above (which still sends to 2110 + // the legacy `renderer-log` channel). Routes through tile:log:write with 2111 + // token validation on the main-process side. Any tile with a valid token 2112 + // may log — no additional capability check. Wave 3.6f will flip api.log 2113 + // to use this channel and delete the legacy renderer-log handler. 2114 + api.tileLog = (...args: unknown[]) => { 2115 + ipcRenderer.send('tile:log:write', { token: tileToken, source: sourceAddress, args }); 2116 + }; 2117 + 2082 2118 // ── Theme (trustedBuiltin extensions) ──────────────────────────────── 2083 2119 // 2084 2120 // Core renderers (app/index.js in particular) call setWindowColorScheme