Files
NetMesh/electron/plugins/nativePermissionDecision.test.cjs

134 lines
4.5 KiB
JavaScript
Raw Permalink Normal View History

"use strict";
const assert = require("node:assert/strict");
const test = require("node:test");
const {
MAX_VISIBLE_FIELD_LENGTH,
MAX_VISIBLE_RESOURCES,
createNativePermissionDecisionProvider,
describePermissionRequest,
escapePermissionText,
} = require("./nativePermissionDecision.cjs");
function permissionRequest(overrides = {}) {
return {
requestId: "request-1",
pluginId: "com.example.permissions",
pluginName: "Permissions",
publisher: "example",
permission: "filesystem.read",
resources: ["/allowed"],
resourceKinds: ["directory"],
reason: "Read project files",
...overrides,
};
}
test("native permission decisions expose every host-owned grant scope", async () => {
for (const { sessionId, response, expected } of [
{ response: 0, expected: { requestId: "request-1", decision: "deny" } },
{ response: 1, expected: { requestId: "request-1", decision: "allow", scope: "once" } },
{ sessionId: "session-1", response: 2, expected: {
requestId: "request-1", decision: "allow", scope: "session",
} },
{ response: 2, expected: {
requestId: "request-1", decision: "allow", scope: "application",
} },
{ response: 3, expected: {
requestId: "request-1", decision: "allow", scope: "always",
} },
]) {
let captured;
const signal = new AbortController().signal;
const provider = createNativePermissionDecisionProvider({
dialog: {
async showMessageBox(_window, options) {
captured = options;
return { response };
},
},
window: {},
});
assert.deepEqual(await provider(permissionRequest({ sessionId }), { signal }), expected);
assert.equal(captured.signal, signal);
assert.equal(captured.cancelId, 0);
assert.match(captured.detail, /directory and descendants/u);
}
});
test("native permission decisions fail closed on cancellation and abort", async () => {
const provider = createNativePermissionDecisionProvider({
dialog: { showMessageBox: async () => ({ response: 999 }) },
});
assert.deepEqual(await provider(permissionRequest()), {
requestId: "request-1",
decision: "deny",
});
const controller = new AbortController();
controller.abort(new Error("runtime stopped"));
await assert.rejects(provider(permissionRequest(), { signal: controller.signal }), /runtime stopped/);
});
test("terminal interceptor permission prompts omit the unsupported one-use choice", async () => {
let captured;
const provider = createNativePermissionDecisionProvider({
dialog: {
async showMessageBox(options) {
captured = options;
return { response: 1 };
},
},
});
assert.deepEqual(await provider(permissionRequest({
sessionId: "session-1",
operationId: `terminal.interceptor.input:com.example.${"x".repeat(170)}`,
allowedScopes: ["session", "application", "always"],
})), {
requestId: "request-1",
decision: "allow",
scope: "session",
});
assert.deepEqual(captured.buttons, [
"Deny",
"Allow for Session",
"Allow for Application",
"Always Allow",
]);
});
test("native permission request details are bounded and preserve resource kinds", () => {
const resources = Array.from({ length: MAX_VISIBLE_RESOURCES + 5 }, (_, index) => `/path/${index}`);
const detail = describePermissionRequest(permissionRequest({
resources,
resourceKinds: resources.map(() => "exact"),
}));
assert.match(detail, /and 5 more/u);
assert.doesNotMatch(detail, /\/path\/24/u);
});
test("native permission dialogs visibly escape control and bidi characters", async () => {
let captured;
const provider = createNativePermissionDecisionProvider({
dialog: {
async showMessageBox(options) {
captured = options;
return { response: 0 };
},
},
});
await provider(permissionRequest({
pluginName: "Plugin\nPermission: vault.credentials",
publisher: "publisher\u202e",
reason: "Read this\r\nAlways Allow",
resources: ["/safe\nPermission: runtime.advanced"],
resourceKinds: ["exact"],
}));
assert.match(captured.message, /Plugin\\nPermission: vault\.credentials/u);
assert.match(captured.detail, /publisher\\u202e/u);
assert.match(captured.detail, /Read this\\r\\nAlways Allow/u);
assert.match(captured.detail, /\/safe\\nPermission: runtime\.advanced/u);
assert.equal(captured.detail.split("\n").filter((line) => line.startsWith("Permission:")).length, 1);
assert.equal(escapePermissionText("x".repeat(MAX_VISIBLE_FIELD_LENGTH + 20)).length, MAX_VISIBLE_FIELD_LENGTH);
});