mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-17 16:37:43 +00:00
* docs(plugins): add microsoft 365 calendar provider plan * fix(jira): gate Electron requests behind one-shot capability Claim privileged Jira IPC before plugin startup and return responses through invoke instead of a broadcast event. Keep arbitrary HTTP(S) Jira hosts supported while rejecting redirects and bounding request resources. * fix(jira): enforce Electron request capability Bind privileged Jira IPC to a main-issued renderer-document token and strip raw Electron events from renderer callbacks. Scope image authentication by origin, base path, and resource type while preserving safe redirects and legacy configurations. * fix(electron): handle payload-only IPC lifecycle Clear Jira image authentication before replacement and when a new renderer document claims the capability. Parse before-close IDs from payload-only events so pending sync and finish-day hooks can complete. * fix(electron): address Jira IPC capability review findings - electron.effects: read ANY_FILE_DOWNLOADED payload at [0] after the payload-only IPC refactor (was [1], now undefined -> TypeError on every download); guard against a malformed payload - jira-capability: rotate the token on re-register so a renderer reload that reuses the WebFrameMain object is not permanently locked out of Jira; invalidates any stale token - document that the one-shot consumption order, not the bypassable main-frame check, is the real capability boundary - jira-electron-bridge: skip the no-op clearImgHeaders IPC round-trip when image auth was never set up (non-Jira detail-panel open/close) - jira-api: route a synchronous _toElectronRequestInit throw through _handleResponse instead of leaking a dangling request-log entry * test(electron): cover ANY_FILE_DOWNLOADED payload parsing Extract parseDownloadedFilePayload from ElectronEffects and add a regression spec pinning the payload-only shape ([file], not [event, file]) that caused a TypeError on every download. Hardened against non-array input surfaced by the new test. * fix(electron): restore Node ambient globals for frontend build
94 lines
2.6 KiB
JavaScript
94 lines
2.6 KiB
JavaScript
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const path = require('node:path');
|
|
|
|
require('ts-node/register/transpile-only');
|
|
|
|
const { IPC } = require(
|
|
path.resolve(__dirname, 'shared-with-frontend/ipc-events.const.ts'),
|
|
);
|
|
const {
|
|
createJiraPreloadApiConsumer,
|
|
toPayloadOnlyIpcListener,
|
|
} = require(path.resolve(__dirname, 'shared-with-frontend/preload-api.ts'));
|
|
|
|
test('renderer listeners receive payloads without the Electron event object', () => {
|
|
const received = [];
|
|
const listener = toPayloadOnlyIpcListener((...args) => received.push(args));
|
|
const rawEvent = {
|
|
sender: {
|
|
invoke: () => {
|
|
throw new Error('must not be exposed');
|
|
},
|
|
},
|
|
};
|
|
|
|
listener(rawEvent, { safe: true }, 'payload');
|
|
|
|
assert.deepEqual(received, [[{ safe: true }, 'payload']]);
|
|
assert.notEqual(received[0][0], rawEvent);
|
|
});
|
|
|
|
test('Jira preload capability registers eagerly and can only be consumed once', async () => {
|
|
const invocations = [];
|
|
const invoke = async (channel, ...args) => {
|
|
invocations.push([channel, ...args]);
|
|
if (channel === IPC.JIRA_REGISTER_CAPABILITY) {
|
|
return 'main-issued-token';
|
|
}
|
|
return { requestId: 'request-1', response: { ok: true } };
|
|
};
|
|
|
|
const consume = createJiraPreloadApiConsumer(invoke);
|
|
assert.deepEqual(invocations, [[IPC.JIRA_REGISTER_CAPABILITY]]);
|
|
|
|
const api = consume();
|
|
assert.ok(api);
|
|
assert.equal(consume(), null);
|
|
assert.equal(consume(), null);
|
|
|
|
const request = {
|
|
requestId: 'request-1',
|
|
url: 'https://jira.example.com/rest/api/latest/myself',
|
|
requestInit: { method: 'GET', headers: {} },
|
|
allowSelfSignedCertificate: false,
|
|
};
|
|
await api.makeRequest(request);
|
|
await api.clearImgHeaders();
|
|
|
|
assert.deepEqual(invocations[1], [
|
|
IPC.JIRA_MAKE_REQUEST_EVENT,
|
|
{
|
|
capabilityToken: 'main-issued-token',
|
|
payload: request,
|
|
},
|
|
]);
|
|
assert.deepEqual(invocations[2], [
|
|
IPC.JIRA_CLEAR_IMG_HEADERS,
|
|
{
|
|
capabilityToken: 'main-issued-token',
|
|
payload: null,
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('Jira preload API refuses calls when main does not issue a capability', async () => {
|
|
const invocations = [];
|
|
const invoke = async (channel, ...args) => {
|
|
invocations.push([channel, ...args]);
|
|
return null;
|
|
};
|
|
const api = createJiraPreloadApiConsumer(invoke)();
|
|
|
|
await assert.rejects(
|
|
() =>
|
|
api.makeRequest({
|
|
requestId: 'request-1',
|
|
url: 'https://jira.example.com',
|
|
requestInit: { method: 'GET', headers: {} },
|
|
allowSelfSignedCertificate: false,
|
|
}),
|
|
/unavailable/i,
|
|
);
|
|
assert.deepEqual(invocations, [[IPC.JIRA_REGISTER_CAPABILITY]]);
|
|
});
|