Skip to content

Commit 5f60b01

Browse files
authored
Disable node integration in worker (#8822)
* simplify out tough-cookie * remove fs from vite config * bridge fs os and decode * polyfill crypto and uuid * replace node:url * remove require interceptor * bridge jsonpath * disable node in worker * fix elevated extension * remove spectral optimzation * abstract and type db router * complete abstraction * add info about dev deps * revert encode url * fix and extend tests * use jsonpath-plus import esm * fix type check * hide the openapi spam * rename readFile * optimise import * fix md5 test * speed up grpc test * fix grpc test * use global timeout * fix lint * fix tests * fix types * complete os support * fix test * update nodeOS
1 parent 158e83c commit 5f60b01

File tree

18 files changed

+264
-373
lines changed

18 files changed

+264
-373
lines changed

.github/workflows/test-e2e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ concurrency:
1717

1818
jobs:
1919
Test:
20-
timeout-minutes: 15
20+
timeout-minutes: 40
2121
runs-on: ubuntu-22.04
2222
steps:
2323
- name: Checkout branch

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/insomnia-smoke-test/playwright.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,6 @@ const config: PlaywrightTestConfig = {
4343
timeout: process.env.CI ? 25 * 1000 : 10 * 1000,
4444
},
4545
workers: 1,
46+
globalTimeout: 20 * 60 * 1000,
4647
};
4748
export default config;

packages/insomnia-smoke-test/tests/smoke/grpc-interactions.test.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@ import { test } from '../../playwright/test';
66

77
test.describe('gRPC interactions', () => {
88
test.slow(process.platform === 'darwin' || process.platform === 'win32', 'Slow app start on these platforms');
9-
let statusTag: Locator;
10-
let responseBody: Locator;
11-
let streamMessage: Locator;
129

13-
test.beforeEach(async ({ app, page }) => {
10+
test('can send all types of requests', async ({ page, app }) => {
1411
const text = await loadFixture('grpc.yaml');
1512
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
1613

@@ -20,14 +17,12 @@ test.describe('gRPC interactions', () => {
2017
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
2118
await page.getByLabel('PreRelease gRPC').click();
2219

23-
statusTag = page.locator('[data-testid="response-status-tag"]:visible');
24-
responseBody = page.locator('[data-testid="response-pane"] >> [data-testid="CodeEditor"]:visible', {
20+
const statusTag = page.locator('[data-testid="response-status-tag"]:visible');
21+
const responseBody = page.locator('[data-testid="response-pane"] >> [data-testid="CodeEditor"]:visible', {
2522
has: page.locator('.CodeMirror-activeline'),
2623
});
27-
streamMessage = page.locator('[data-testid="request-pane"] button:has-text("Stream")');
28-
});
24+
const streamMessage = page.locator('[data-testid="request-pane"] button:has-text("Stream")');
2925

30-
test('can send unidirectional requests', async ({ page }) => {
3126
await page.getByLabel('Request Collection').getByTestId('Unary').click();
3227
await page.locator('[data-testid="request-pane"] >> text=Unary').click();
3328
await page.click('text=Send');
@@ -36,9 +31,7 @@ test.describe('gRPC interactions', () => {
3631
await page.click('text=Response 1');
3732
await expect.soft(statusTag).toContainText('0 OK');
3833
await expect.soft(responseBody).toContainText('Berkshire Valley Management Area Trail');
39-
});
4034

41-
test('can send bidirectional requests', async ({ page }) => {
4235
await page.getByLabel('Request Collection').getByTestId('Bidirectional Stream').press('Enter');
4336
await page.locator('text=Bi-directional Streaming').click();
4437
await page.click('text=Start');
@@ -55,9 +48,7 @@ test.describe('gRPC interactions', () => {
5548
// Finish the stream
5649
await page.locator('text=Commit').click();
5750
await expect.soft(statusTag).toContainText('0 OK');
58-
});
5951

60-
test('can send client stream requests', async ({ page }) => {
6152
await page.getByLabel('Request Collection').getByTestId('Client Stream').press('Enter');
6253
await page.click('text=Client Streaming');
6354
await page.click('text=Start');
@@ -73,9 +64,7 @@ test.describe('gRPC interactions', () => {
7364
await page.locator('text=Response 1').click();
7465
await expect.soft(statusTag).toContainText('0 OK');
7566
await expect.soft(responseBody).toContainText('point_count": 3');
76-
});
7767

78-
test('can send server stream requests', async ({ page }) => {
7968
await page.getByLabel('Request Collection').getByTestId('Server Stream').press('Enter');
8069
await page.click('text=Server Streaming');
8170
await page.click('text=Start');

packages/insomnia-smoke-test/tests/smoke/grpc.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ test('can send gRPC requests with reflection', async ({ app, page }) => {
2020
await page.getByLabel('PreRelease gRPC').click();
2121

2222
await page.getByLabel('Request Collection').getByTestId('UnaryWithOutProtoFile').press('Enter');
23-
await expect.soft(page.getByRole('button', { name: 'Select Method' })).toBeDisabled();
2423
await page.getByTestId('button-server-reflection').click();
2524

2625
await page.getByRole('button', { name: 'Select Method' }).click();

packages/insomnia-smoke-test/tests/smoke/template-tags-interactions.test.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ const templateTagTestCases: Record<string, TemplateTagTestCase[]> = {
1919
expectedResult: 'File Tag Test',
2020
},
2121
],
22-
hash: [{ tagPrefix: "{% hash 'md5', 'hex', 'insomnia-test' %}", expectedResult: 'b9c076eabf32fa4cdd7573a6df12d33c' }],
22+
hash: [
23+
{
24+
tagPrefix: "{% hash 'md5', 'hex', 'insomnia-test' %}",
25+
expectedResult: 'b79b28083768d54575eacc7389e9128624685310',
26+
},
27+
],
2328
jsonPath: [{ tagPrefix: '{% jsonpath', expectedResult: 'bar' }],
2429
os: [{ tagPrefix: "{% os 'arch', '' %}", expectedResult: os.arch() }],
2530
timeStamp: [
@@ -84,11 +89,11 @@ test('Critical Path For Template Tags Interactions', async ({ page, app }) => {
8489
// wait for render complete
8590
await expect.soft(previewResult).not.toHaveText('rendering...');
8691
const previewText = await previewResult.textContent();
92+
const isFunction = typeof expectedResult === 'function';
8793
expect
8894
.soft(
89-
typeof expectedResult === 'function'
90-
? expectedResult(previewText || '')
91-
: previewText?.includes(expectedResult),
95+
isFunction ? expectedResult(previewText || '') : previewText?.includes(expectedResult),
96+
` Template tag "${tagPrefix}" should render as "${expectedResult}" but returned ${previewText}.`,
9297
)
9398
.toBeTruthy();
9499
// close modal

packages/insomnia/package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@
3535
"type-check:watch": "npm run type-check -- --watch",
3636
"convert-svg": "npm_config_yes=true npx @svgr/[email protected] --no-index --config-file svgr.config.js --out-dir src/ui/components/assets/svgr src/ui/components/assets/"
3737
},
38+
"//": [
39+
"dependencies will be external to the vite bundle and electron main (commonjs)",
40+
"devDependencies will be included in the vite bundle (esm)",
41+
"See: packages/insomnia/vite.config.ts",
42+
"and: packages/insomnia/esbuild.main.ts"
43+
],
3844
"dependencies": {
3945
"@apideck/better-ajv-errors": "^0.3.6",
4046
"@apidevtools/swagger-parser": "10.1.1",
@@ -75,7 +81,6 @@
7581
"jsdom": "^25.0.1",
7682
"jshint": "^2.13.6",
7783
"jsonlint-mod-fixed": "1.7.7",
78-
"jsonpath-plus": "^10.3.0",
7984
"marked": "^5.1.2",
8085
"mime-types": "^2.1.35",
8186
"mocha": "^10.8.2",
@@ -161,6 +166,7 @@
161166
"httplease-asap": "^0.6.0",
162167
"isomorphic-git": "1.25.7",
163168
"json-order": "^1.1.3",
169+
"jsonpath-plus": "^10.3.0",
164170
"less": "^4.3.0",
165171
"monaco-editor": "^0.52.2",
166172
"nunjucks": "^3.2.4",

packages/insomnia/src/common/__tests__/import.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,14 @@ describe('importRaw()', () => {
150150
it('should import an openapi collection to an existing workspace with scope design', async () => {
151151
const fixturePath = path.join(__dirname, '..', '__fixtures__', 'openapi', 'endpoint-security-input.yaml');
152152
const content = fs.readFileSync(fixturePath, 'utf8').toString();
153-
153+
const disableLogs = console.log;
154+
console.log = () => {};
154155
const scanResult = await importUtil.scanResources([
155156
{
156157
contentStr: content,
157158
},
158159
]);
159-
160+
console.log = disableLogs;
160161
expect(scanResult[0].type?.id).toBe('openapi3');
161162
expect(scanResult[0].errors.length).toBe(0);
162163
});

packages/insomnia/src/common/__tests__/render.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ describe('render tests', () => {
5353
const rootEnvironment = envBuilder
5454
.data({
5555
consume: '{{ replaced }}',
56-
hashed: "{% hash 'md5', 'hex', value %}",
57-
replaced: "{{ hashed | replace('f67565de946a899a534fd908e7eef872', 'cat') }}",
56+
hashed: "{% hash 'sha1', 'hex', value %}",
57+
replaced: "{{ hashed | replace('1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f', 'cat') }}",
5858
value: 'ThisIsATopSecretValue',
5959
})
6060
.dataPropertyOrder({
@@ -65,9 +65,9 @@ describe('render tests', () => {
6565
const context = await renderUtils.buildRenderContext({ ancestors: [], rootEnvironment });
6666
expect(context).toEqual({
6767
value: 'ThisIsATopSecretValue',
68-
hashed: 'f67565de946a899a534fd908e7eef872',
69-
replaced: 'f67565de946a899a534fd908e7eef872',
70-
consume: 'f67565de946a899a534fd908e7eef872',
68+
hashed: '1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f',
69+
replaced: '1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f',
70+
consume: '1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f',
7171
});
7272
// In runtime, this context is used to render, which re-evaluates the expression for replaced in the rootEnvironment by using the built context
7373
// Regression test from issue 1917 - https://github.com/Kong/insomnia/issues/1917
@@ -450,8 +450,8 @@ describe('render tests', () => {
450450
const rootEnvironment = envBuilder
451451
.data({
452452
consume: '{{ replaced }}',
453-
hashed: "{% hash 'md5', 'hex', value %}",
454-
replaced: "{{ hashed | replace('f67565de946a899a534fd908e7eef872', 'cat') }}",
453+
hashed: "{% hash 'sha1', 'hex', value %}",
454+
replaced: "{{ hashed | replace('1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f', 'cat') }}",
455455
value: 'ThisIsATopSecretValue',
456456
})
457457
.dataPropertyOrder({
@@ -461,7 +461,7 @@ describe('render tests', () => {
461461
const context = await renderUtils.buildRenderContext({ ancestors: [], rootEnvironment });
462462
expect(context).toEqual({
463463
value: 'ThisIsATopSecretValue',
464-
hashed: 'f67565de946a899a534fd908e7eef872',
464+
hashed: '1d8445ef1467a6b7a36dc794ce37cf2e9d945a9f',
465465
replaced: 'cat',
466466
consume: 'cat',
467467
});
Lines changed: 75 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,91 @@
1+
import fs from 'node:fs';
2+
import os from 'node:os';
3+
4+
import iconv from 'iconv-lite';
5+
16
import { database as db } from '../common/database';
27
import * as models from '../models';
38
import type { Request as DBRequest } from '../models/request';
49
import type { RequestGroup } from '../models/request-group';
10+
import type { Response } from '../models/response';
511
import type { Workspace } from '../models/workspace';
612
import { fetchRequestData, sendCurlAndWriteTimeline, tryToInterpolateRequest } from '../network/network';
7-
813
export const resolveDbByKey = async (request: Request) => {
914
const url = new URL(request.url);
10-
let result;
1115
const body = await request.json();
12-
if (url.host === 'request.getById'.toLowerCase()) {
13-
result = await models.request.getById(body.id);
14-
}
15-
if (url.host === 'request.getAncestors'.toLowerCase()) {
16-
result = await db.withAncestors<DBRequest | RequestGroup | Workspace>(body.request, body.types);
17-
}
18-
if (url.host === 'workspace.getById'.toLowerCase()) {
19-
result = await models.workspace.getById(body.id);
20-
}
21-
if (url.host === 'oAuth2Token.getByRequestId'.toLowerCase()) {
22-
result = await models.oAuth2Token.getByParentId(body.parentId);
23-
}
24-
if (url.host === 'cookieJar.getOrCreateForParentId'.toLowerCase()) {
25-
result = await models.cookieJar.getOrCreateForParentId(body.parentId);
26-
}
27-
if (url.host === 'response.getLatestForRequestId'.toLowerCase()) {
28-
result = await models.response.getLatestForRequest(body.requestId, body.environmentId);
29-
}
30-
if (url.host === 'response.getBodyBuffer'.toLowerCase()) {
31-
result = await models.response.getBodyBuffer(body.response, body.readFailureValue);
32-
}
33-
if (url.host === 'pluginData.hasItem'.toLowerCase()) {
16+
// url get normalized to lowercase, so we need to normalize the keys to lower case as well
17+
const withLowercasedKeys = Object.fromEntries(
18+
Object.entries(pluginToMainAPI).map(([key, value]) => [key.toLowerCase(), value]),
19+
);
20+
const result = await withLowercasedKeys[url.host.toLowerCase()](body);
21+
return new Response(JSON.stringify(result));
22+
};
23+
24+
// These are exposed to the templating worker and can be used by plugins from context.util
25+
const pluginToMainAPI = {
26+
'readFile': async (body: { path: string; encoding: 'utf8' }) => {
27+
return await fs.promises.readFile(body.path, { encoding: body.encoding || 'utf8' });
28+
},
29+
'nodeOS': async () => {
30+
return {
31+
arch: os.arch(),
32+
platform: os.platform(),
33+
release: os.release(),
34+
cpus: os.cpus(),
35+
hostname: os.hostname(),
36+
freemem: os.freemem(),
37+
userInfo: os.userInfo(),
38+
};
39+
},
40+
'decode': async (body: { buffer: Buffer; encoding: 'utf8' }) => {
41+
return iconv.decode(body.buffer, body.encoding || 'utf8');
42+
},
43+
'request.getById': async (body: { id: string }) => {
44+
return await models.request.getById(body.id);
45+
},
46+
'request.getAncestors': async (body: { request: DBRequest | RequestGroup | Workspace; types: string[] }) => {
47+
return await db.withAncestors<DBRequest | RequestGroup | Workspace>(body.request, body.types);
48+
},
49+
'workspace.getById': async (body: { id: string }) => {
50+
return await models.workspace.getById(body.id);
51+
},
52+
'oAuth2Token.getByRequestId': async (body: { parentId: string }) => {
53+
return await models.oAuth2Token.getByParentId(body.parentId);
54+
},
55+
'cookieJar.getOrCreateForParentId': async (body: { parentId: string }) => {
56+
return await models.cookieJar.getOrCreateForParentId(body.parentId);
57+
},
58+
'response.getLatestForRequestId': async (body: { requestId: string; environmentId: string }) => {
59+
return await models.response.getLatestForRequest(body.requestId, body.environmentId);
60+
},
61+
'response.getBodyBuffer': async (body: { response: Response; readFailureValue: string }) => {
62+
return await models.response.getBodyBuffer(body.response, body.readFailureValue);
63+
},
64+
'pluginData.hasItem': async (body: { pluginName: string; key: string }) => {
3465
const doc = await models.pluginData.getByKey(body.pluginName, body.key);
35-
result = doc !== null;
36-
}
37-
if (url.host === 'pluginData.setItem'.toLowerCase()) {
38-
result = models.pluginData.upsertByKey(body.pluginName, body.key, String(body.value));
39-
}
40-
if (url.host === 'pluginData.getItem'.toLowerCase()) {
66+
return doc !== null;
67+
},
68+
'pluginData.setItem': async (body: { pluginName: string; key: string; value: string }) => {
69+
return models.pluginData.upsertByKey(body.pluginName, body.key, String(body.value));
70+
},
71+
'pluginData.getItem': async (body: { pluginName: string; key: string }) => {
4172
const doc = await models.pluginData.getByKey(body.pluginName, body.key);
42-
result = doc ? doc.value : null;
43-
}
44-
if (url.host === 'pluginData.removeItem'.toLowerCase()) {
45-
result = models.pluginData.removeByKey(body.pluginName, body.key);
46-
}
47-
if (url.host === 'pluginData.clear'.toLowerCase()) {
48-
result = models.pluginData.removeAll(body.pluginName);
49-
}
50-
if (url.host === 'pluginData.all'.toLowerCase()) {
73+
return doc ? doc.value : null;
74+
},
75+
'pluginData.removeItem': async (body: { pluginName: string; key: string }) => {
76+
return models.pluginData.removeByKey(body.pluginName, body.key);
77+
},
78+
'pluginData.clear': async (body: { pluginName: string }) => {
79+
return models.pluginData.removeAll(body.pluginName);
80+
},
81+
'pluginData.all': async (body: { pluginName: string }) => {
5182
const docs = (await models.pluginData.all(body.pluginName)) || [];
52-
result = docs.map(d => ({
83+
return docs.map(d => ({
5384
value: d.value,
5485
key: d.key,
5586
}));
56-
}
57-
if (url.host === 'network.sendRequest'.toLowerCase()) {
87+
},
88+
'network.sendRequest': async (body: { request: DBRequest; extraInfo?: { requestChain: string[] } }) => {
5889
const { request, environment, settings, clientCertificates, caCert, timelinePath, responseId } =
5990
await fetchRequestData(body.request._id);
6091

@@ -72,8 +103,6 @@ export const resolveDbByKey = async (request: Request) => {
72103
timelinePath,
73104
responseId,
74105
);
75-
result = await models.response.create({ ...response, bodyCompression: null }, settings.maxHistoryResponses);
76-
}
77-
78-
return new Response(JSON.stringify(result));
106+
return await models.response.create({ ...response, bodyCompression: null }, settings.maxHistoryResponses);
107+
},
79108
};

0 commit comments

Comments
 (0)