From e4f61771131be635b9e81a19203a00707b4b19df Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Fri, 2 Oct 2026 10:20:09 +0200 Subject: feat(mnp): sharing a folder is decided on the node's machine only (MNP 6.0) root_add, root_update and group_attach leave MNP: adding a directory and switching writable/removable go through the loopback API (native dialog in the desktop app) or the CLI. The operator's Settings tab still lists the roots from any browser, read-only. The desktop app refuses to sign those ops; a loopback flag change now reaches open pages (publish_roots). Co-Authored-By: Claude Opus 5.5 --- .../src/meshbay_hub/static/group-settings.js | 129 +++++++++------------ 1 file changed, 56 insertions(+), 73 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 bde218b..eddef8e 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js @@ -22,21 +22,23 @@ export const INVITE_EMAIL_PREF = 'invite_email'; * One component, two modes, because the Create Group wizard and the Settings * page were drifting apart while showing the same thing: * - * mode="live" — a hosted group. Every change is a signed operator op sent - * over MNP, or the loopback API when the node is on this - * machine and there is no live connection. + * mode="live" — a hosted group. What widens the node's sharing — adding + * a directory, its `writable` and `removable` switches — goes + * through the loopback API only, so only on the node's own + * machine. Removing, ejecting and plugging are signed ops + * over MNP, or the loopback API when there is no connection. * mode="local" — the wizard, before the group exists. Changes are held in * an array the caller owns; nothing is persisted until the * group is attached. * - * **Both paths matter and neither is optional.** The operator of a node is not - * necessarily sitting at it: they may be signing in from any browser, and the - * only thing that reaches their node from there is MNP. An earlier version of - * this read its roots exclusively from the loopback API, which resolves to - * "not available" in a browser — so the section rendered for nobody on the - * web, while the controls it replaced had worked there. `mnpRoots` is the - * source whenever a connection exists; the loopback list is the fallback for - * a local node that is not currently connected (a group still scanning, say). + * **The list is shown wherever the operator is.** They may be signing in from + * any browser, and the only thing that reaches their node from there is MNP. + * An earlier version of this read its roots exclusively from the loopback API, + * which resolves to "not available" in a browser — so the section rendered for + * nobody on the web. `mnpRoots` is the source whenever a connection exists; the + * loopback list is the fallback for a local node that is not currently + * connected (a group still scanning, say). From a browser the table is read + * only where it would widen anything (MNP 6.0). * * Props: * roots — the node's current roots: { name, path, writable, @@ -75,8 +77,6 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn,

${msg.text}

`; - const [pathDraft, setPathDraft] = useState(''); - const [addingByPath, setAddingByPath] = useState(false); // A toggle has to move under the finger, and the answer only comes back // when the node has signed, written node.toml and pushed the new table. @@ -115,12 +115,21 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, // left out otherwise, rather than printing a row of blanks. const hasPaths = displayRoots.some((r) => r.path); - // Which door a change goes through. MNP first: it is the only one that - // exists for an operator on the web, and it is signed, which the loopback - // API is not (it is authorized by being on localhost with the run token). + // Which door a change goes through. + // + // Widening what the node shares — a new directory, `writable`, `removable` — + // only through the loopback API, which exists only on the node's own machine + // and where the desktop application asks in a native dialog before anything + // is shared or opened to writes. Over MNP these were signed ops, and a + // signature proves that the operator's key signed, not that the operator + // meant it: in a browser that key is driven by code the hub serves. + // + // Narrowing — remove, eject, plug — MNP first, then loopback. const overMnp = !isLocal && transport && transport.connected; const overLoopback = !isLocal && !overMnp && nodeAvail; + const onNodeMachine = !isLocal && nodeAvail; const canEdit = isLocal || overMnp || overLoopback; + const canWiden = isLocal || onNodeMachine; // Deliberately no index refresh after a root change. // @@ -158,9 +167,8 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, ...prev, [rootName]: { ...(prev[rootName] || {}), ...updates }, })); const ok = await run(async () => { - if (overMnp) await transport.updateRoot(groupId, rootName, updates, signFn); - else if (overLoopback) await platform.node.op('updateRoot', { groupId, rootName, updates }); - else throw new Error(t('node.root_no_route')); + if (onNodeMachine) await platform.node.op('updateRoot', { groupId, rootName, updates }); + else throw new Error(t('settings_node.roots_local_only_hint')); }); // Only a failure clears the patch here; a success waits for the node's // own table, so the switch never travels backwards on its way forwards. @@ -169,8 +177,7 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, const next = { ...prev }; delete next[rootName]; return next; }); } - }, [isLocal, localRoots, onLocalRootsChange, overMnp, overLoopback, - transport, groupId, signFn, run]); + }, [isLocal, localRoots, onLocalRootsChange, onNodeMachine, groupId, run]); const doEjectRoot = useCallback((rootName) => run(async () => { if (overMnp) await transport.ejectRoot(groupId, rootName, signFn); @@ -203,10 +210,9 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, }, [isLocal, localRoots, onLocalRootsChange, overMnp, overLoopback, transport, groupId, signFn, run]); - // Adding a root needs a directory that exists on the *node's* filesystem. - // With the node on this machine that is a native folder picker; from any - // other browser the operator has to type the path, because nothing in a web - // page can browse a remote disk. Both end at the same signed op. + // Adding a root: a native folder picker on the node's own machine, and + // nothing anywhere else — a path typed into a page is a path a script in the + // page could have typed. const addRootAtPath = useCallback(async (path, name) => { if (isLocal) { if ((localRoots || []).some(r => r.path === path)) return true; @@ -222,16 +228,12 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, } setIndexProgress(null); return run(async () => { - if (overMnp) { - await transport.addRoot(groupId, path, { name }, signFn); - } else if (overLoopback) { - 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')); + if (!onNodeMachine) throw new Error(t('settings_node.roots_local_only_hint')); + await platform.node.op('addRoot', { groupId, path, name }); + await platform.node.op('reload'); + await platform.watchIndexProgress(groupId, setIndexProgress); }); - }, [isLocal, localRoots, onLocalRootsChange, overMnp, overLoopback, - transport, groupId, signFn, run]); + }, [isLocal, localRoots, onLocalRootsChange, onNodeMachine, groupId, run]); const doPickRoot = useCallback(async () => { const chosen = await platform.rootPicker.choose(); @@ -240,48 +242,23 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, if (ok && !isLocal) say(t('node.root_added')); }, [addRootAtPath, isLocal]); - const doAddByPath = useCallback(async () => { - const path = pathDraft.trim(); - if (!path) return; - // The name is the node's business — it derives the basename and refuses a - // duplicate. Sending one guessed from a string typed here would be a - // second opinion about something already decided in one place. - const ok = await addRootAtPath(path, ''); - if (ok) { setPathDraft(''); setAddingByPath(false); if (!isLocal) say(t('node.root_added')); } - }, [pathDraft, addRootAtPath, isLocal]); - - const addControls = !canEdit ? '' : html` - ${platform.rootPicker.available ? html` - - ` : addingByPath ? html` -
- setPathDraft(e.target.value)} - onKeyDown=${(e) => { if (e.key === 'Enter') doAddByPath(); }} /> - - -
-

${t('node.root_path_hint')}

- ` : html` - - `} + const addControls = !canWiden || !platform.rootPicker.available ? '' : html` + `; + // Said once, under the table, rather than as a tooltip on each switch: the + // switches are not broken, they are somewhere else. + const localOnlyHint = canEdit && !canWiden && html` +

+ ${t('settings_node.roots_local_only_hint')}

`; if (!displayRoots.length) { return html`

${t('settings_node.shared_directories_hint')}

+ ${localOnlyHint} ${addControls} ${message}
@@ -326,14 +303,15 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, doing the job. */''} ${canEdit && html` - <${ToggleSwitch} checked=${!!r.writable} disabled=${busy || !!r.ejected} + <${ToggleSwitch} checked=${!!r.writable} + disabled=${busy || !!r.ejected || !canWiden} label=${t('node.root_rw')} onChange=${(v) => doUpdateRoot(r.name, { writable: v })} /> `} ${canEdit && !isLocal && html` - <${ToggleSwitch} checked=${!!r.removable} disabled=${busy} + <${ToggleSwitch} checked=${!!r.removable} disabled=${busy || !canWiden} label=${t('node.removable')} onChange=${(v) => doUpdateRoot(r.name, { removable: v })} /> @@ -360,6 +338,7 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, `; })} + ${localOnlyHint} ${addControls} ${message} ${indexProgress && indexProgress.scanning && html` @@ -426,6 +405,9 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, // Node loopback state (Electron-only) const [nodeDetected, setNodeDetected] = useState(false); + // A node on this machine is not necessarily the one hosting this group, and + // the table's loopback door is only a door to *that* node. + const [nodeHostsGroup, setNodeHostsGroup] = useState(false); const [nodeRoots, setNodeRoots] = useState([]); const [nodeGroupName, setNodeGroupName] = useState(''); const [nodeBusy, setNodeBusy] = useState(false); @@ -464,6 +446,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, const data = await platform.node.op('groups'); const groups = data.groups || []; const ng = groups.find(g => g.id === groupId); + setNodeHostsGroup(Boolean(ng)); if (ng) { setNodeRoots(ng.roots || []); setNodeGroupName(ng.name || ''); @@ -1182,7 +1165,7 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef, groupId=${groupId} transport=${transportRef.current} signFn=${adminSignFn} - nodeDetected=${nodeDetected} + nodeDetected=${nodeDetected && nodeHostsGroup} onRootsChange=${loadNodeInfo} onRefreshIndex=${onRefreshIndex} /> -- cgit v1.2.3 From c928547ca6e402bfe5e06bb59d55ac91e6822cd0 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Fri, 2 Oct 2026 10:32:18 +0200 Subject: fix(client): no confirmation dialog for adding a folder or its flags Removes confirmFolder (addRoot, attachGroup) and the writable confirmation added in e4f6177, with their two catalogue keys. Co-Authored-By: Claude Opus 5.5 --- docs/MESHBAY_DESIGN.md | 3 +- docs/MESHBAY_NODE_PROTOCOL.md | 3 +- packages/meshbay-client/src/main.js | 34 +++------------------- .../meshbay-common/src/meshbay_common/__init__.py | 2 +- .../meshbay-common/src/meshbay_common/adminop.py | 2 +- .../src/meshbay_hub/static/group-settings.js | 5 ++-- .../src/meshbay_hub/static/locales/de.js | 2 -- .../src/meshbay_hub/static/locales/en.js | 2 -- .../src/meshbay_hub/static/locales/es.js | 2 -- .../src/meshbay_hub/static/locales/fr.js | 2 -- .../src/meshbay_hub/static/locales/it.js | 2 -- .../src/meshbay_hub/static/locales/ja.js | 2 -- .../src/meshbay_hub/static/locales/nl.js | 2 -- .../src/meshbay_hub/static/locales/pl.js | 2 -- .../src/meshbay_hub/static/locales/pt-BR.js | 2 -- .../src/meshbay_hub/static/locales/zh-CN.js | 2 -- packages/meshbay-hub/tests/test_desktop_shell.py | 12 +++----- .../tests/test_sharing_is_local_only.py | 2 +- 18 files changed, 15 insertions(+), 68 deletions(-) (limited to 'packages/meshbay-hub/src/meshbay_hub/static/group-settings.js') diff --git a/docs/MESHBAY_DESIGN.md b/docs/MESHBAY_DESIGN.md index e145ed4..49bd99b 100644 --- a/docs/MESHBAY_DESIGN.md +++ b/docs/MESHBAY_DESIGN.md @@ -1544,8 +1544,7 @@ Several roots may be writable and none need be — a fully read-only group is va **What widens the sharing is decided on the node's own machine.** Adding a root, hosting a group over a directory, and switching `writable` or `removable` go through -the loopback API (in the desktop application, behind a native dialog for anything -that shares a folder or opens one to writes) or the CLI — never over MNP, since 6.0. +the loopback API (the desktop application) or the CLI — never over MNP, since 6.0. A signed op proves that the operator's key signed, not that they meant it: in a browser that key is driven by code the hub serves (T3), and in the desktop application by a renderer that parses content from nodes. Either could otherwise diff --git a/docs/MESHBAY_NODE_PROTOCOL.md b/docs/MESHBAY_NODE_PROTOCOL.md index d03b7eb..cdcc2c0 100644 --- a/docs/MESHBAY_NODE_PROTOCOL.md +++ b/docs/MESHBAY_NODE_PROTOCOL.md @@ -1183,8 +1183,7 @@ drop box", which is the ordinary arrangement. **Nothing in this table widens what the node shares**, and that is the design too. Adding a directory to a group, hosting a new group over a directory, and switching a root's `writable` or `removable` flag are done on the node's own machine — the -desktop application over the loopback API, which asks in a native dialog before it -shares a folder or opens one to writes, or the CLI — and never over MNP. Until 6.0 +desktop application over the loopback API, or the CLI — and never over MNP. Until 6.0 they were the signed ops `root_add`, `group_attach` and `root_update`. A signature proves that the operator's key signed, not that the operator meant it: in a browser that key is driven by code the hub serves (T3), and in the desktop application by a diff --git a/packages/meshbay-client/src/main.js b/packages/meshbay-client/src/main.js index 0020084..0ad7e71 100644 --- a/packages/meshbay-client/src/main.js +++ b/packages/meshbay-client/src/main.js @@ -1144,19 +1144,12 @@ function registerBridge() { return true; }); - // A folder chosen here is one the person pointed at in a dialog this process - // drew, which is the consent that sharing it needs: the node is given it - // without asking again. A folder the page names that was not chosen here is - // confirmed natively before the node hears of it (`node:op`). - const pickedFolders = new Set(); - handle('root:choose', async () => { const result = await dialog.showOpenDialog(mainWindow, { properties: ['openDirectory', 'createDirectory'], }); if (result.canceled || !result.filePaths.length) return null; const chosen = result.filePaths[0]; - pickedFolders.add(path.resolve(chosen)); return { path: chosen, name: path.basename(chosen) }; }); @@ -2185,49 +2178,30 @@ function registerBridge() { const group = (a) => `/api/groups/${anId(a.groupId, 'the group')}`; const root = (a) => `${group(a)}/roots/${encodeURIComponent(aText(a.rootName, 'the folder name'))}`; - // Sharing a folder the person did not choose in this process's dialog. - async function confirmFolder(folder) { - if (!pickedFolders.has(path.resolve(folder))) { - await confirmOrRefuse('native.folder_confirm', { path: folder }); - } - } - const NODE_OPS = { status: () => ['GET', '/api/status'], groups: () => ['GET', '/api/groups'], indexStatus: () => ['GET', '/api/index-status'], groupIndexStatus: (a) => ['GET', `${group(a)}/index-status`], reload: () => ['POST', '/api/reload'], - attachGroup: async (a) => { + attachGroup: (a) => { const body = { name: aText(a.name, 'the group name'), shared_dir: aText(a.path, 'the folder', 4096), writable: a.writable !== false, // The person's choice on the creation form; the node never // takes it from the hub. join_policy: a.joinPolicy === 'open' ? 'open' : 'invite' }; - await confirmFolder(body.shared_dir); return ['POST', '/api/groups/attach', body]; }, detachGroup: (a) => ['POST', '/api/groups/detach', { name: aText(a.name, 'the group name') }], - addRoot: async (a) => { + addRoot: (a) => { const body = { path: aText(a.path, 'the folder', 4096) }; if (a.name) body.name = aText(a.name, 'the folder name'); if (a.writable !== undefined) body.writable = Boolean(a.writable); if (a.removable !== undefined) body.removable = Boolean(a.removable); - const target = `${group(a)}/roots`; - await confirmFolder(body.path); - return ['POST', target, body]; - }, - // Opening a folder to writes from every member is asked like sharing it; - // closing it, or the removable flag, only narrows. - updateRoot: async (a) => { - const updates = anObject(a.updates); - if (updates.writable === true) { - await confirmOrRefuse('native.root_writable_confirm', - { name: aText(a.rootName, 'the folder name') }); - } - return ['PATCH', root(a), updates]; + return ['POST', `${group(a)}/roots`, body]; }, + updateRoot: (a) => ['PATCH', root(a), anObject(a.updates)], ejectRoot: (a) => ['PUT', `${root(a)}/eject`], plugRoot: (a) => ['PUT', `${root(a)}/plug`], removeRoot: (a) => ['DELETE', root(a)], diff --git a/packages/meshbay-common/src/meshbay_common/__init__.py b/packages/meshbay-common/src/meshbay_common/__init__.py index c5c04a5..cb84e2c 100644 --- a/packages/meshbay-common/src/meshbay_common/__init__.py +++ b/packages/meshbay-common/src/meshbay_common/__init__.py @@ -264,7 +264,7 @@ __version__ = "0.17.0" # 6.0 (2026-10-02) is a MAJOR — three signed operations are removed: `root_add`, # `root_update` and `group_attach`. What of the operator's disk is shared, and # whether members may write there, is decided on the node's own machine (the -# desktop application over loopback, behind a native dialog, or the CLI), never +# desktop application over loopback, or the CLI), never # over the wire. A 5.x client that sends one gets no answer, as for any unknown # type; everything else it does still works, so the floor stays at 4.0. MNP_VERSION = "6.0" diff --git a/packages/meshbay-common/src/meshbay_common/adminop.py b/packages/meshbay-common/src/meshbay_common/adminop.py index 11100b5..b8915a9 100644 --- a/packages/meshbay-common/src/meshbay_common/adminop.py +++ b/packages/meshbay-common/src/meshbay_common/adminop.py @@ -129,7 +129,7 @@ OP_GROUP_DETACH = "group_detach" # signature proves only that the operator's key signed — in a browser, through # code the hub serves; on the desktop, through a renderer that parses content # from nodes. Sharing a folder, hosting a group and opening a folder to writes -# are done on the node's own machine (loopback, behind a native dialog) or with +# are done on the node's own machine (loopback) or with # the CLI, and a message that does not exist cannot be mis-authorized. # OP_GEK_BUNDLE_STORE is gone. Members no longer hand the node key material at # all: the node holds the GEK and wraps it itself, for a key the recipient proved 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 eddef8e..29aa7eb 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/group-settings.js @@ -118,9 +118,8 @@ function SharedDirectoriesTable({ roots, groupId, transport, signFn, // Which door a change goes through. // // Widening what the node shares — a new directory, `writable`, `removable` — - // only through the loopback API, which exists only on the node's own machine - // and where the desktop application asks in a native dialog before anything - // is shared or opened to writes. Over MNP these were signed ops, and a + // only through the loopback API, which exists only on the node's own + // machine. Over MNP these were signed ops, and a // signature proves that the operator's key signed, not that the operator // meant it: in a browser that key is driven by code the hub serves. // diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js index 003a770..c78bb52 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js @@ -1250,8 +1250,6 @@ export default { 'settings.browser_access_off_in_browser': 'Der Browserzugang ist für dieses Konto ausgeschaltet. Er wird in der MeshBay-Desktopanwendung eingeschaltet, die diesen Browser auch für sich selbst freigeben kann.', 'group.browser_access_off': 'Der Browserzugang ist für dieses Konto ausgeschaltet. Schalten Sie ihn in der MeshBay-Desktopanwendung (Profil) ein oder geben Sie diesen Browser dort frei.', // Worded by the desktop main process for its own dialogs (main.js). - 'native.folder_confirm': 'Den Ordner {path} mit den Mitgliedern einer auf diesem Computer gehosteten Gruppe teilen? Er wurde nicht in der Ordnerauswahl gewählt.', - 'native.root_writable_confirm': 'Den Mitgliedern einer auf diesem Computer gehosteten Gruppe erlauben, in {name} zu schreiben?', 'native.node_account_confirm': 'Der Node auf diesem Computer ist für {current} eingerichtet. Stattdessen für {next} einrichten? Er stellt dann die Gruppen, die er für {current} hostet, nicht mehr bereit.', 'native.browser_access_confirm': 'Die Anmeldung über einen Browser erlauben? Die Anwendung legt Ihre Identität auf jedem genutzten Node ab, so versiegelt, dass nur Ihre Passphrase zusammen mit Ihrem Hub-Konto sie öffnen kann.', 'native.declined': 'Abgebrochen — nichts wurde geändert.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js index 1d22e56..f5879b3 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js @@ -1231,8 +1231,6 @@ export default { 'settings.browser_access_off_in_browser': 'Browser access is off for this account. It is turned on in the MeshBay desktop application, which can also approve this browser for itself.', 'group.browser_access_off': 'Browser access is off for this account. Turn it on in the MeshBay desktop application (Profile), or approve this browser from it.', // Worded by the desktop main process for its own dialogs (main.js). - 'native.folder_confirm': 'Share the folder {path} with the members of a group hosted on this computer? It was not chosen in the folder picker.', - 'native.root_writable_confirm': 'Let the members of a group hosted on this computer write into {name}?', 'native.node_account_confirm': 'The node on this computer is set up for {current}. Set it up for {next} instead? It will stop serving the groups it hosts for {current}.', 'native.browser_access_confirm': 'Allow signing in from a browser? The application will leave your identity on every node you use, sealed so that only your passphrase together with your hub account can open it.', 'native.declined': 'Cancelled — nothing was changed.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js index b6d4b10..a35aa96 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js @@ -1244,8 +1244,6 @@ export default { 'settings.browser_access_off_in_browser': 'El acceso desde el navegador está desactivado para esta cuenta. Se activa en la aplicación de escritorio de MeshBay, que también puede aprobar este navegador por sí mismo.', 'group.browser_access_off': 'El acceso desde el navegador está desactivado para esta cuenta. Actívelo en la aplicación de escritorio de MeshBay (Perfil) o apruebe este navegador desde ella.', // Worded by the desktop main process for its own dialogs (main.js). - 'native.folder_confirm': '¿Compartir la carpeta {path} con los miembros de un grupo alojado en este ordenador? No se eligió en el selector de carpetas.', - 'native.root_writable_confirm': '¿Permitir que los miembros de un grupo alojado en este ordenador escriban en {name}?', 'native.node_account_confirm': 'El node de este ordenador está configurado para {current}. ¿Configurarlo para {next} en su lugar? Dejará de servir los grupos que aloja para {current}.', 'native.browser_access_confirm': '¿Permitir el acceso desde un navegador? La aplicación dejará su identidad en cada node que use, sellada de modo que solo su frase de contraseña, junto con su cuenta del hub, pueda abrirla.', 'native.declined': 'Cancelado: no se ha cambiado nada.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js index 2c7a148..2e823cd 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js @@ -1259,8 +1259,6 @@ export default { 'settings.browser_access_off_in_browser': 'L\'accès depuis un navigateur est désactivé pour ce compte. Il s\'active dans l\'application de bureau MeshBay, qui peut aussi approuver ce navigateur pour lui-même.', 'group.browser_access_off': 'L\'accès depuis un navigateur est désactivé pour ce compte. Activez-le dans l\'application de bureau MeshBay (Profil), ou approuvez ce navigateur depuis celle-ci.', // Worded by the desktop main process for its own dialogs (main.js). - 'native.folder_confirm': 'Partager le dossier {path} avec les membres d\'un groupe hébergé sur cet ordinateur ? Il n\'a pas été choisi dans le sélecteur de dossier.', - 'native.root_writable_confirm': 'Autoriser les membres d\'un groupe hébergé sur cet ordinateur à écrire dans {name} ?', 'native.node_account_confirm': 'Le node de cet ordinateur est configuré pour {current}. Le configurer pour {next} à la place ? Il cessera de servir les groupes qu\'il héberge pour {current}.', 'native.browser_access_confirm': 'Autoriser la connexion depuis un navigateur ? L\'application déposera votre identité sur chaque node que vous utilisez, scellée de sorte que seule votre phrase secrète, avec votre compte sur le hub, puisse l\'ouvrir.', 'native.declined': 'Annulé — rien n\'a été modifié.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js index 75fb4ca..84879e8 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js @@ -1258,8 +1258,6 @@ export default { 'settings.browser_access_off_in_browser': 'L\'accesso dal browser è disattivato per questo account. Si attiva nell\'applicazione desktop di MeshBay, che può anche approvare questo browser per sé.', 'group.browser_access_off': 'L\'accesso dal browser è disattivato per questo account. Attivalo nell\'applicazione desktop di MeshBay (Profilo) o approva questo browser da lì.', // Worded by the desktop main process for its own dialogs (main.js). - 'native.folder_confirm': 'Condividere la cartella {path} con i membri di un gruppo ospitato su questo computer? Non è stata scelta nel selettore di cartelle.', - 'native.root_writable_confirm': 'Consentire ai membri di un gruppo ospitato su questo computer di scrivere in {name}?', 'native.node_account_confirm': 'Il node di questo computer è configurato per {current}. Configurarlo invece per {next}? Smetterà di servire i gruppi che ospita per {current}.', 'native.browser_access_confirm': 'Consentire l\'accesso da un browser? L\'applicazione lascerà la tua identità su ogni node che usi, sigillata in modo che solo la tua passphrase, insieme al tuo account sull\'hub, possa aprirla.', 'native.declined': 'Annullato: non è stato modificato nulla.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js index 6350811..9167efe 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js @@ -1242,8 +1242,6 @@ export default { 'settings.browser_access_off_in_browser': 'このアカウントではブラウザーからのアクセスがオフです。MeshBay デスクトップアプリでオンにできます。アプリからこのブラウザーだけを承認することもできます。', 'group.browser_access_off': 'このアカウントではブラウザーからのアクセスがオフです。MeshBay デスクトップアプリ(プロフィール)でオンにするか、アプリからこのブラウザーを承認してください。', // Worded by the desktop main process for its own dialogs (main.js). - 'native.folder_confirm': 'このコンピューターでホストしているグループのメンバーとフォルダー {path} を共有しますか?このフォルダーはフォルダー選択画面で選ばれたものではありません。', - 'native.root_writable_confirm': 'このコンピューターでホストしているグループのメンバーに {name} への書き込みを許可しますか?', 'native.node_account_confirm': 'このコンピューターの node は {current} 用に設定されています。代わりに {next} 用に設定しますか?{current} のためにホストしているグループは提供されなくなります。', 'native.browser_access_confirm': 'ブラウザーからのサインインを許可しますか?アプリは、利用中のすべての node にあなたの ID を残します。これは、パスフレーズと hub のアカウントの両方がそろった場合にのみ開けるよう封印されます。', 'native.declined': 'キャンセルしました。何も変更されていません。', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js index 3adb51e..4845c03 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js @@ -1260,8 +1260,6 @@ export default { 'settings.browser_access_off_in_browser': 'Browsertoegang staat uit voor dit account. Die wordt aangezet in de MeshBay-desktoptoepassing, die deze browser ook voor zichzelf kan goedkeuren.', 'group.browser_access_off': 'Browsertoegang staat uit voor dit account. Zet die aan in de MeshBay-desktoptoepassing (Profiel), of keur deze browser daar goed.', // Worded by the desktop main process for its own dialogs (main.js). - 'native.folder_confirm': 'De map {path} delen met de leden van een groep die op deze computer wordt gehost? Hij is niet gekozen in de mapkiezer.', - 'native.root_writable_confirm': 'De leden van een groep die op deze computer wordt gehost laten schrijven in {name}?', 'native.node_account_confirm': 'De node op deze computer is ingesteld voor {current}. In plaats daarvan instellen voor {next}? Hij stopt dan met het aanbieden van de groepen die hij voor {current} host.', 'native.browser_access_confirm': 'Aanmelden vanuit een browser toestaan? De toepassing laat je identiteit achter op elke node die je gebruikt, zo verzegeld dat alleen je wachtzin samen met je hub-account haar kan openen.', 'native.declined': 'Geannuleerd — er is niets gewijzigd.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js index be1ae4f..e3f21d3 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js @@ -1286,8 +1286,6 @@ export default { 'settings.browser_access_off_in_browser': 'Dostęp z przeglądarki jest wyłączony dla tego konta. Włącza się go w aplikacji desktopowej MeshBay, która może też zatwierdzić tę przeglądarkę dla niej samej.', 'group.browser_access_off': 'Dostęp z przeglądarki jest wyłączony dla tego konta. Włącz go w aplikacji desktopowej MeshBay (Profil) albo zatwierdź tę przeglądarkę w tej aplikacji.', // Worded by the desktop main process for its own dialogs (main.js). - 'native.folder_confirm': 'Udostępnić folder {path} członkom grupy hostowanej na tym komputerze? Nie został wybrany w oknie wyboru folderu.', - 'native.root_writable_confirm': 'Pozwolić członkom grupy hostowanej na tym komputerze zapisywać w {name}?', 'native.node_account_confirm': 'Node na tym komputerze jest skonfigurowany dla {current}. Skonfigurować go zamiast tego dla {next}? Przestanie obsługiwać grupy, które hostuje dla {current}.', 'native.browser_access_confirm': 'Zezwolić na logowanie z przeglądarki? Aplikacja pozostawi Twoją tożsamość na każdym używanym node, zapieczętowaną tak, by otworzyć ją mogło tylko Twoje hasło wraz z kontem na hubie.', 'native.declined': 'Anulowano — nic nie zostało zmienione.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js index 9cbfb93..00510c6 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js @@ -1245,8 +1245,6 @@ export default { 'settings.browser_access_off_in_browser': 'O acesso pelo navegador está desativado para esta conta. Ele é ativado no aplicativo de desktop do MeshBay, que também pode aprovar este navegador para si.', 'group.browser_access_off': 'O acesso pelo navegador está desativado para esta conta. Ative-o no aplicativo de desktop do MeshBay (Perfil) ou aprove este navegador por ele.', // Worded by the desktop main process for its own dialogs (main.js). - 'native.folder_confirm': 'Compartilhar a pasta {path} com os membros de um grupo hospedado neste computador? Ela não foi escolhida no seletor de pastas.', - 'native.root_writable_confirm': 'Permitir que os membros de um grupo hospedado neste computador gravem em {name}?', 'native.node_account_confirm': 'O node deste computador está configurado para {current}. Configurá-lo para {next} em vez disso? Ele deixará de servir os grupos que hospeda para {current}.', 'native.browser_access_confirm': 'Permitir o acesso por um navegador? O aplicativo deixará sua identidade em cada node que você usa, selada de forma que apenas sua frase secreta, junto com sua conta no hub, possa abri-la.', 'native.declined': 'Cancelado — nada foi alterado.', diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js index 6409444..51a6572 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js @@ -1231,8 +1231,6 @@ export default { 'settings.browser_access_off_in_browser': '此账户已关闭浏览器访问。可在 MeshBay 桌面应用中开启,该应用也可以单独批准此浏览器。', 'group.browser_access_off': '此账户已关闭浏览器访问。请在 MeshBay 桌面应用(个人资料)中开启,或从该应用批准此浏览器。', // Worded by the desktop main process for its own dialogs (main.js). - 'native.folder_confirm': '与这台电脑上托管的群组成员共享文件夹 {path}?该文件夹不是在文件夹选择器中选择的。', - 'native.root_writable_confirm': '允许这台电脑上托管的群组成员写入 {name}?', 'native.node_account_confirm': '这台电脑上的 node 已为 {current} 设置。改为为 {next} 设置吗?它将不再为 {current} 提供其托管的群组。', 'native.browser_access_confirm': '允许从浏览器登录吗?应用会在您使用的每个 node 上留下您的身份,并加以封存,只有您的密码短语配合您的 hub 账户才能打开。', 'native.declined': '已取消,未做任何更改。', diff --git a/packages/meshbay-hub/tests/test_desktop_shell.py b/packages/meshbay-hub/tests/test_desktop_shell.py index 311e613..c2ea4ca 100644 --- a/packages/meshbay-hub/tests/test_desktop_shell.py +++ b/packages/meshbay-hub/tests/test_desktop_shell.py @@ -425,14 +425,10 @@ def test_the_page_names_node_operations_not_routes(): assert defined <= used, f"defined but never called: {defined - used}" -@pytest.mark.parametrize("op", ["attachGroup", "addRoot", "updateRoot", "clearDenylist"]) -def test_what_widens_the_node_is_confirmed_natively(op): - """Sharing a folder, hosting a group, opening a folder to every member's - writes, re-admitting a revoked subject: asked - by a dialog the main process draws, which a script in the page cannot - answer. A folder chosen in the native picker is its own confirmation.""" - body = _node_ops()[op] - assert "confirmOrRefuse(" in body or "confirmFolder(" in body +def test_readmitting_a_revoked_subject_is_confirmed_natively(): + """Asked by a dialog the main process draws, which a script in the page + cannot answer.""" + assert "confirmOrRefuse(" in _node_ops()["clearDenylist"] def test_the_native_dialogs_are_worded_in_every_language(): diff --git a/packages/meshbay-node/tests/test_sharing_is_local_only.py b/packages/meshbay-node/tests/test_sharing_is_local_only.py index cd550e4..ac8bebb 100644 --- a/packages/meshbay-node/tests/test_sharing_is_local_only.py +++ b/packages/meshbay-node/tests/test_sharing_is_local_only.py @@ -7,7 +7,7 @@ meant it: in a browser the key is driven by code the hub serves, and in the desktop application by a renderer that parses content from nodes. `root_add`, `root_update` and `group_attach` let either of them share any folder on the machine, or open one to writes, from anywhere. They are gone; the loopback API -(behind a native dialog in the desktop application) and the CLI remain. +(the desktop application) and the CLI remain. And the consequence that has to hold for the operator's list to stay true: a flag changed through the loopback API reaches every connected page, which the -- cgit v1.2.3