From 2c6921aa2c35ffd41b6c453e6700574ef631ba2c Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 30 Sep 2026 12:57:58 +0200 Subject: fix(client): the page names node operations, and the app confirms what widens the node node:call is replaced by named operations with checked arguments; hosting a group, sharing an unpicked folder, key rotation, denylist clearing and a change of node account are confirmed by a native dialog. Every channel checks its sender, secrets:get/set/clear are gone, node:start writes the app's own hub. Co-Authored-By: Claude Opus 5.5 --- .../src/meshbay_hub/static/group-settings.js | 28 +++++++++------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'packages/meshbay-hub/src/meshbay_hub/static/group-settings.js') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js index 048f831..f16bdf8 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js @@ -122,9 +122,6 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, const overLoopback = !isLocal && !overMnp && nodeAvail; const canEdit = isLocal || overMnp || overLoopback; - const rootUrl = (name, suffix = '') => - '/api/groups/' + groupId + '/roots/' + encodeURIComponent(name) + suffix; - // Deliberately no index refresh after a root change. // // Adding a root makes the node reload, which rescans — minutes on a real @@ -162,7 +159,7 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, })); const ok = await run(async () => { if (overMnp) await transport.updateRoot(groupId, rootName, updates, signFn); - else if (overLoopback) await platform.node.call('PATCH', rootUrl(rootName), updates); + else if (overLoopback) await platform.node.op('updateRoot', { groupId, rootName, updates }); else throw new Error(t('node.root_no_route')); }); // Only a failure clears the patch here; a success waits for the node's @@ -177,13 +174,13 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, const doEjectRoot = useCallback((rootName) => run(async () => { if (overMnp) await transport.ejectRoot(groupId, rootName, signFn); - else if (overLoopback) await platform.node.call('PUT', rootUrl(rootName, '/eject')); + else if (overLoopback) await platform.node.op('ejectRoot', { groupId, rootName }); else throw new Error(t('node.root_no_route')); }), [overMnp, overLoopback, transport, groupId, signFn, run]); const doPlugRoot = useCallback((rootName) => run(async () => { if (overMnp) await transport.plugRoot(groupId, rootName, signFn); - else if (overLoopback) await platform.node.call('PUT', rootUrl(rootName, '/plug')); + else if (overLoopback) await platform.node.op('plugRoot', { groupId, rootName }); else throw new Error(t('node.root_no_route')); }), [overMnp, overLoopback, transport, groupId, signFn, run]); @@ -198,8 +195,8 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, const ok = await run(async () => { if (overMnp) await transport.removeRoot(groupId, rootName, signFn); else if (overLoopback) { - await platform.node.call('DELETE', rootUrl(rootName)); - await platform.node.call('POST', '/api/reload'); + await platform.node.op('removeRoot', { groupId, rootName }); + await platform.node.op('reload'); } else throw new Error(t('node.root_no_route')); }); if (ok) say(t('node.root_removed')); @@ -228,9 +225,8 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, if (overMnp) { await transport.addRoot(groupId, path, { name }, signFn); } else if (overLoopback) { - await platform.node.call('POST', '/api/groups/' + groupId + '/roots', - { path, name }); - await platform.node.call('POST', '/api/reload'); + await platform.node.op('addRoot', { groupId, path, name }); + await platform.node.op('reload'); await platform.watchIndexProgress(groupId, setIndexProgress); } else throw new Error(t('node.root_no_route')); }); @@ -468,7 +464,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, const detect = await platform.node.detect(); if (!detect.detected) { setNodeDetected(false); return; } setNodeDetected(true); - const data = await platform.node.call('GET', '/api/groups'); + const data = await platform.node.op('groups'); const groups = data.groups || []; const ng = groups.find(g => g.id === groupId); if (ng) { @@ -496,7 +492,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, const waitForRootCount = useCallback(async (expectedCount) => { for (let i = 0; i < 10; i++) { try { - const data = await platform.node.call('GET', '/api/groups'); + const data = await platform.node.op('groups'); const ng = (data.groups || []).find(g => g.id === groupId); const roots = (ng && ng.roots) || []; if (roots.length === expectedCount) { @@ -780,8 +776,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, try { if (platform.node.available) { try { - await platform.node.call('POST', - `/api/members/${member.user_id}/revoke?group_id=${groupId}`); + await platform.node.op('revokeMember', { userId: member.user_id, groupId }); } catch { /* best effort — node may not host this group */ } } else if (transport && transport.connected && operatorPaired) { const sk = transport.sessionKeys && transport.sessionKeys.skEdB64; @@ -1311,8 +1306,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, // Node detach first (reversible), then hub delete (irreversible) if (nodeDetected && nodeGroupName) { try { - await platform.node.call('POST', '/api/groups/detach', - { name: nodeGroupName }); + await platform.node.op('detachGroup', { name: nodeGroupName }); } catch (detachErr) { if (!await ask(t('settings_node.detach_failed_continue'))) return; } -- cgit v1.2.3