aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-client/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-client/src')
-rw-r--r--packages/meshbay-client/src/main.js23
-rw-r--r--packages/meshbay-client/src/transcripts.js16
2 files changed, 18 insertions, 21 deletions
diff --git a/packages/meshbay-client/src/main.js b/packages/meshbay-client/src/main.js
index cbaabc4..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,38 +2178,28 @@ 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];
+ return ['POST', `${group(a)}/roots`, body];
},
updateRoot: (a) => ['PATCH', root(a), anObject(a.updates)],
ejectRoot: (a) => ['PUT', `${root(a)}/eject`],
diff --git a/packages/meshbay-client/src/transcripts.js b/packages/meshbay-client/src/transcripts.js
index 0b6d0c0..8b0f6ef 100644
--- a/packages/meshbay-client/src/transcripts.js
+++ b/packages/meshbay-client/src/transcripts.js
@@ -30,6 +30,20 @@ function lenPrefixed(prefix, parts) {
return Buffer.concat(chunks);
}
+// The signed operations this application asks a node to perform
+// (meshbay_common/adminop.py). A list, not a pattern: what widens a node's
+// sharing — `root_add`, `root_update`, `group_attach`, gone from MNP 6.0 — is
+// never signed here, so a node older than that cannot be driven into it by a
+// script in the page either.
+const ADMIN_OPS = new Set([
+ 'file_delete', 'dir_delete', 'invite_create', 'invite_link_create',
+ 'invite_cancel', 'member_revoke', 'apps_enabled', 'set_scan_settings',
+ 'tmdb_config', 'tmdb_enabled', 'tmdb_override', 'tmdb_rematch',
+ 'musicbrainz_enabled', 'root_remove', 'root_eject', 'root_plug',
+ 'app_directories', 'chat_directory', 'chat_link_preview', 'search_listed',
+ 'chat_epoch',
+]);
+
// ── Field checks ──────────────────────────────────────────────────────────
//
// Shapes, not trust: what is checked here is that a field is what its name
@@ -143,7 +157,7 @@ function transcriptFor(kind, f, ctx) {
}
case 'admin': {
const op = String(fields.op ?? '');
- if (!/^[a-z_]{1,32}$/.test(op)) refuse('not an operation');
+ if (!ADMIN_OPS.has(op)) refuse('not an operation');
return lenPrefixed(PREFIX.admin, [
enc(op), enc(sameNode()), enc(groupId(fields.groupId)),
enc(text(fields.subject, 'the subject', 16384)),