mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 04:47:29 -08:00
fix(core): Updated expressions allowlist and denylist. (#3424)
* feat: Updated expressions allowlist and denylist. * test: Added unit tests for expression allow and deny list. * feat: Updated riot-tmpl to be installed from n8n fork. * fix: Added check for non-standard browser built-in. * chore: Removed package-lock.json from branch. * chore: Removed package-lock.json from branch. * chore: Added jest-environment-jsdom@27
This commit is contained in:
parent
ad09d9aab9
commit
d18a29d588
|
@ -21,7 +21,8 @@
|
|||
"lint": "cd ../.. && node_modules/eslint/bin/eslint.js packages/workflow",
|
||||
"lintfix": "cd ../.. && node_modules/eslint/bin/eslint.js packages/workflow --fix",
|
||||
"watch": "tsc --watch",
|
||||
"test": "jest"
|
||||
"test": "jest",
|
||||
"test:dev": "jest --watch"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
@ -32,8 +33,8 @@
|
|||
"@types/jmespath": "^0.15.0",
|
||||
"@types/lodash.get": "^4.4.6",
|
||||
"@types/lodash.merge": "^4.6.6",
|
||||
"@types/luxon": "^2.0.9",
|
||||
"@types/lodash.set": "^4.3.6",
|
||||
"@types/luxon": "^2.0.9",
|
||||
"@types/node": "14.17.27",
|
||||
"@types/xml2js": "^0.4.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.0",
|
||||
|
@ -44,6 +45,7 @@
|
|||
"eslint-plugin-import": "^2.23.4",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"jest": "^27.4.7",
|
||||
"jest-environment-jsdom": "^27.5.1",
|
||||
"prettier": "^2.3.2",
|
||||
"ts-jest": "^27.1.3",
|
||||
"tslint": "^6.1.2",
|
||||
|
@ -56,7 +58,7 @@
|
|||
"lodash.merge": "^4.6.2",
|
||||
"lodash.set": "^4.3.2",
|
||||
"luxon": "^2.3.0",
|
||||
"riot-tmpl": "^3.0.8",
|
||||
"riot-tmpl": "github:n8n-io/tmpl",
|
||||
"xml2js": "^0.4.23"
|
||||
},
|
||||
"jest": {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable id-denylist */
|
||||
// @ts-ignore
|
||||
import * as tmpl from 'riot-tmpl';
|
||||
import { DateTime, Duration, Interval } from 'luxon';
|
||||
|
@ -125,12 +126,17 @@ export class Expression {
|
|||
versions: process.versions,
|
||||
};
|
||||
|
||||
/**
|
||||
* Denylist
|
||||
*/
|
||||
|
||||
// @ts-ignore
|
||||
data.document = {};
|
||||
data.global = {};
|
||||
data.window = {};
|
||||
data.Window = {};
|
||||
data.this = {};
|
||||
data.globalThis = {};
|
||||
data.self = {};
|
||||
|
||||
// Alerts
|
||||
|
@ -140,6 +146,7 @@ export class Expression {
|
|||
|
||||
// Prevent Remote Code Execution
|
||||
data.eval = {};
|
||||
data.uneval = {};
|
||||
data.setTimeout = {};
|
||||
data.setInterval = {};
|
||||
data.Function = {};
|
||||
|
@ -148,13 +155,103 @@ export class Expression {
|
|||
data.fetch = {};
|
||||
data.XMLHttpRequest = {};
|
||||
|
||||
// Prevent control abstraction
|
||||
data.Promise = {};
|
||||
data.Generator = {};
|
||||
data.GeneratorFunction = {};
|
||||
data.AsyncFunction = {};
|
||||
data.AsyncGenerator = {};
|
||||
data.AsyncGeneratorFunction = {};
|
||||
|
||||
// Prevent WASM
|
||||
data.WebAssembly = {};
|
||||
|
||||
// Prevent Reflection
|
||||
data.Reflect = {};
|
||||
data.Proxy = {};
|
||||
|
||||
// @ts-ignore
|
||||
data.constructor = {};
|
||||
|
||||
// Deprecated
|
||||
data.escape = {};
|
||||
data.unescape = {};
|
||||
|
||||
/**
|
||||
* Allowlist
|
||||
*/
|
||||
|
||||
// Dates
|
||||
data.Date = Date;
|
||||
data.DateTime = DateTime;
|
||||
data.Interval = Interval;
|
||||
data.Duration = Duration;
|
||||
|
||||
// @ts-ignore
|
||||
data.constructor = {};
|
||||
// Objects
|
||||
data.Object = Object;
|
||||
|
||||
// Arrays
|
||||
data.Array = Array;
|
||||
data.Int8Array = Int8Array;
|
||||
data.Uint8Array = Uint8Array;
|
||||
data.Uint8ClampedArray = Uint8ClampedArray;
|
||||
data.Int16Array = Int16Array;
|
||||
data.Uint16Array = Uint16Array;
|
||||
data.Int32Array = Int32Array;
|
||||
data.Uint32Array = Uint32Array;
|
||||
data.Float32Array = Float32Array;
|
||||
data.Float64Array = Float64Array;
|
||||
data.BigInt64Array = typeof BigInt64Array !== 'undefined' ? BigInt64Array : {};
|
||||
data.BigUint64Array = typeof BigUint64Array !== 'undefined' ? BigUint64Array : {};
|
||||
|
||||
// Collections
|
||||
data.Map = typeof Map !== 'undefined' ? Map : {};
|
||||
data.WeakMap = typeof WeakMap !== 'undefined' ? WeakMap : {};
|
||||
data.Set = typeof Set !== 'undefined' ? Set : {};
|
||||
data.WeakSet = typeof WeakSet !== 'undefined' ? WeakSet : {};
|
||||
|
||||
// Errors
|
||||
data.Error = Error;
|
||||
data.TypeError = TypeError;
|
||||
data.SyntaxError = SyntaxError;
|
||||
data.EvalError = EvalError;
|
||||
data.RangeError = RangeError;
|
||||
data.ReferenceError = ReferenceError;
|
||||
data.URIError = URIError;
|
||||
|
||||
// Internationalization
|
||||
data.Intl = typeof Intl !== 'undefined' ? Intl : {};
|
||||
|
||||
// Text
|
||||
data.String = String;
|
||||
data.RegExp = RegExp;
|
||||
|
||||
// Math
|
||||
data.Math = Math;
|
||||
data.Number = Number;
|
||||
data.BigInt = typeof BigInt !== 'undefined' ? BigInt : {};
|
||||
data.Infinity = Infinity;
|
||||
data.NaN = NaN;
|
||||
data.isFinite = Number.isFinite;
|
||||
data.isNaN = Number.isNaN;
|
||||
data.parseFloat = parseFloat;
|
||||
data.parseInt = parseInt;
|
||||
|
||||
// Structured data
|
||||
data.JSON = JSON;
|
||||
data.ArrayBuffer = typeof ArrayBuffer !== 'undefined' ? ArrayBuffer : {};
|
||||
data.SharedArrayBuffer = typeof SharedArrayBuffer !== 'undefined' ? SharedArrayBuffer : {};
|
||||
data.Atomics = typeof Atomics !== 'undefined' ? Atomics : {};
|
||||
data.DataView = typeof DataView !== 'undefined' ? DataView : {};
|
||||
|
||||
data.encodeURI = encodeURI;
|
||||
data.encodeURIComponent = encodeURIComponent;
|
||||
data.decodeURI = decodeURI;
|
||||
data.decodeURIComponent = decodeURIComponent;
|
||||
|
||||
// Other
|
||||
data.Boolean = Boolean;
|
||||
data.Symbol = Symbol;
|
||||
|
||||
// Execute the expression
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
|
145
packages/workflow/test/Expression.test.ts
Normal file
145
packages/workflow/test/Expression.test.ts
Normal file
|
@ -0,0 +1,145 @@
|
|||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import {
|
||||
Expression,
|
||||
Workflow,
|
||||
} from "../src";
|
||||
import * as Helpers from "./Helpers";
|
||||
import {
|
||||
DateTime,
|
||||
Duration,
|
||||
Interval
|
||||
} from "luxon";
|
||||
|
||||
describe('Expression', () => {
|
||||
describe('getParameterValue()', () => {
|
||||
const nodeTypes = Helpers.NodeTypes();
|
||||
const workflow = new Workflow({ nodes: [
|
||||
{
|
||||
name: 'node',
|
||||
typeVersion: 1,
|
||||
type: 'test.set',
|
||||
position: [0, 0],
|
||||
parameters: {}
|
||||
}
|
||||
], connections: {}, active: false, nodeTypes });
|
||||
const expression = new Expression(workflow);
|
||||
|
||||
const evaluate = (value: string) => expression.getParameterValue(
|
||||
value,
|
||||
null,
|
||||
0,
|
||||
0,
|
||||
'node',
|
||||
[],
|
||||
'manual',
|
||||
'',
|
||||
{},
|
||||
);
|
||||
|
||||
it('should not be able to use global built-ins from denylist', () => {
|
||||
expect(evaluate('={{document}}')).toEqual({});
|
||||
expect(evaluate('={{window}}')).toEqual({});
|
||||
|
||||
expect(evaluate('={{Window}}')).toEqual({});
|
||||
expect(evaluate('={{globalThis}}')).toEqual({});
|
||||
expect(evaluate('={{self}}')).toEqual({});
|
||||
|
||||
expect(evaluate('={{alert}}')).toEqual({});
|
||||
expect(evaluate('={{prompt}}')).toEqual({});
|
||||
expect(evaluate('={{confirm}}')).toEqual({});
|
||||
|
||||
expect(evaluate('={{eval}}')).toEqual({});
|
||||
expect(evaluate('={{uneval}}')).toEqual({});
|
||||
expect(evaluate('={{setTimeout}}')).toEqual({});
|
||||
expect(evaluate('={{setInterval}}')).toEqual({});
|
||||
expect(evaluate('={{Function}}')).toEqual({});
|
||||
|
||||
expect(evaluate('={{fetch}}')).toEqual({});
|
||||
expect(evaluate('={{XMLHttpRequest}}')).toEqual({});
|
||||
|
||||
expect(evaluate('={{Promise}}')).toEqual({});
|
||||
expect(evaluate('={{Generator}}')).toEqual({});
|
||||
expect(evaluate('={{GeneratorFunction}}')).toEqual({});
|
||||
expect(evaluate('={{AsyncFunction}}')).toEqual({});
|
||||
expect(evaluate('={{AsyncGenerator}}')).toEqual({});
|
||||
expect(evaluate('={{AsyncGeneratorFunction}}')).toEqual({});
|
||||
|
||||
expect(evaluate('={{WebAssembly}}')).toEqual({});
|
||||
|
||||
expect(evaluate('={{Reflect}}')).toEqual({});
|
||||
expect(evaluate('={{Proxy}}')).toEqual({});
|
||||
|
||||
expect(evaluate('={{constructor}}')).toEqual({});
|
||||
|
||||
expect(evaluate('={{escape}}')).toEqual({});
|
||||
expect(evaluate('={{unescape}}')).toEqual({});
|
||||
});
|
||||
|
||||
it('should be able to use global built-ins from allowlist', () => {
|
||||
expect(evaluate('={{new Date()}}')).toBeInstanceOf(Date);
|
||||
expect(evaluate('={{DateTime.now().toLocaleString()}}')).toEqual(DateTime.now().toLocaleString());
|
||||
expect(evaluate('={{Interval.after(new Date(), 100)}}')).toEqual(Interval.after(new Date(), 100));
|
||||
expect(evaluate('={{Duration.fromMillis(100)}}')).toEqual(Duration.fromMillis(100));
|
||||
|
||||
expect(evaluate('={{new Object()}}')).toEqual(new Object());
|
||||
|
||||
expect(evaluate('={{new Array()}}')).toEqual(new Array());
|
||||
expect(evaluate('={{new Int8Array()}}')).toEqual(new Int8Array());
|
||||
expect(evaluate('={{new Uint8Array()}}')).toEqual(new Uint8Array());
|
||||
expect(evaluate('={{new Uint8ClampedArray()}}')).toEqual(new Uint8ClampedArray());
|
||||
expect(evaluate('={{new Int16Array()}}')).toEqual(new Int16Array());
|
||||
expect(evaluate('={{new Uint16Array()}}')).toEqual(new Uint16Array());
|
||||
expect(evaluate('={{new Int32Array()}}')).toEqual(new Int32Array());
|
||||
expect(evaluate('={{new Uint32Array()}}')).toEqual(new Uint32Array());
|
||||
expect(evaluate('={{new Float32Array()}}')).toEqual(new Float32Array());
|
||||
expect(evaluate('={{new Float64Array()}}')).toEqual(new Float64Array());
|
||||
expect(evaluate('={{new BigInt64Array()}}')).toEqual(new BigInt64Array());
|
||||
expect(evaluate('={{new BigUint64Array()}}')).toEqual(new BigUint64Array());
|
||||
|
||||
expect(evaluate('={{new Map()}}')).toEqual(new Map());
|
||||
expect(evaluate('={{new WeakMap()}}')).toEqual(new WeakMap());
|
||||
expect(evaluate('={{new Set()}}')).toEqual(new Set());
|
||||
expect(evaluate('={{new WeakSet()}}')).toEqual(new WeakSet());
|
||||
|
||||
expect(evaluate('={{new Error()}}')).toEqual(new Error());
|
||||
expect(evaluate('={{new TypeError()}}')).toEqual(new TypeError());
|
||||
expect(evaluate('={{new SyntaxError()}}')).toEqual(new SyntaxError());
|
||||
expect(evaluate('={{new EvalError()}}')).toEqual(new EvalError());
|
||||
expect(evaluate('={{new RangeError()}}')).toEqual(new RangeError());
|
||||
expect(evaluate('={{new ReferenceError()}}')).toEqual(new ReferenceError());
|
||||
expect(evaluate('={{new URIError()}}')).toEqual(new URIError());
|
||||
|
||||
expect(evaluate('={{Intl}}')).toEqual(Intl);
|
||||
|
||||
expect(evaluate('={{new String()}}')).toEqual(new String());
|
||||
expect(evaluate('={{new RegExp(\'\')}}')).toEqual(new RegExp(''));
|
||||
|
||||
expect(evaluate('={{Math}}')).toEqual(Math);
|
||||
expect(evaluate('={{new Number()}}')).toEqual(new Number());
|
||||
expect(evaluate('={{BigInt(\'1\')}}')).toEqual(BigInt('1'));
|
||||
expect(evaluate('={{Infinity}}')).toEqual(Infinity);
|
||||
expect(evaluate('={{NaN}}')).toEqual(NaN);
|
||||
expect(evaluate('={{isFinite(1)}}')).toEqual(isFinite(1));
|
||||
expect(evaluate('={{isNaN(1)}}')).toEqual(isNaN(1));
|
||||
expect(evaluate('={{parseFloat(\'1\')}}')).toEqual(parseFloat('1'));
|
||||
expect(evaluate('={{parseInt(\'1\', 10)}}')).toEqual(parseInt('1', 10));
|
||||
|
||||
expect(evaluate('={{JSON.stringify({})}}')).toEqual(JSON.stringify({}));
|
||||
expect(evaluate('={{new ArrayBuffer(10)}}')).toEqual(new ArrayBuffer(10));
|
||||
expect(evaluate('={{new SharedArrayBuffer(10)}}')).toEqual(new SharedArrayBuffer(10));
|
||||
expect(evaluate('={{Atomics}}')).toEqual(Atomics);
|
||||
expect(evaluate('={{new DataView(new ArrayBuffer(1))}}')).toEqual(new DataView(new ArrayBuffer(1)));
|
||||
|
||||
expect(evaluate('={{encodeURI(\'https://google.com\')}}')).toEqual(encodeURI('https://google.com'));
|
||||
expect(evaluate('={{encodeURIComponent(\'https://google.com\')}}')).toEqual(encodeURIComponent('https://google.com'));
|
||||
expect(evaluate('={{decodeURI(\'https://google.com\')}}')).toEqual(decodeURI('https://google.com'));
|
||||
expect(evaluate('={{decodeURIComponent(\'https://google.com\')}}')).toEqual(decodeURIComponent('https://google.com'));
|
||||
|
||||
expect(evaluate('={{Boolean(1)}}')).toEqual(Boolean(1));
|
||||
expect(evaluate('={{Symbol(1).toString()}}')).toEqual(Symbol(1).toString());
|
||||
});
|
||||
});
|
||||
})
|
Loading…
Reference in a new issue