From a8e90cd1cb9399666a3b0757c08c386a12ce8834 Mon Sep 17 00:00:00 2001 From: shanexi Date: Thu, 6 Mar 2025 16:53:21 +0800 Subject: [PATCH 1/6] chore: safe exec --- web/packages/form-engine/package.json | 1 + .../form-engine/src/utils/exec.spec.ts | 45 ++++++ web/packages/form-engine/src/utils/exec.ts | 30 +++- web/packages/form-engine/wallaby.js | 5 + web/pnpm-lock.yaml | 128 +++++++----------- 5 files changed, 130 insertions(+), 79 deletions(-) create mode 100644 web/packages/form-engine/src/utils/exec.spec.ts create mode 100644 web/packages/form-engine/wallaby.js diff --git a/web/packages/form-engine/package.json b/web/packages/form-engine/package.json index 8ec87586..18070e02 100644 --- a/web/packages/form-engine/package.json +++ b/web/packages/form-engine/package.json @@ -30,6 +30,7 @@ "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-error-boundary": "^4.0.13", + "sval": "^0.6.1", "tailwind-merge": "^2.5.2", "zod": "^3.23.8", "zustand": "^4.5.5" diff --git a/web/packages/form-engine/src/utils/exec.spec.ts b/web/packages/form-engine/src/utils/exec.spec.ts new file mode 100644 index 00000000..9ab6f3fe --- /dev/null +++ b/web/packages/form-engine/src/utils/exec.spec.ts @@ -0,0 +1,45 @@ +import { exec, safeExec } from './exec'; +import Sval from 'sval'; + +describe('exec', () => { + it('should return the result of the code', () => { + const result = exec(`$this.value === "image"`, { + $this: { + value: 'text', + }, + }); + expect(result).toBe(false); + }); + + it('exec sval ver', () => { + const result = safeExec(`$this.value === "image"`, { + $this: { + value: 'image', + }, + }); + expect(result).toBe(true); + + const result2 = safeExec(`$this.value === "image"`, { + $this: { + value: 'text', + }, + }); + expect(result2).toBe(false); + }); + + it('sval', () => { + const interpreter = new Sval({ + ecmaVer: 'latest', + sourceType: 'script', + sandBox: true, + }); + const code = ` +globalThis.$this = { + value: "text" +} +exports.a = $this.value === "image" + `; + interpreter.run(code); + expect(interpreter.exports.a).toBe(false); + }); +}); diff --git a/web/packages/form-engine/src/utils/exec.ts b/web/packages/form-engine/src/utils/exec.ts index 4cd8f28e..f8581d56 100644 --- a/web/packages/form-engine/src/utils/exec.ts +++ b/web/packages/form-engine/src/utils/exec.ts @@ -1,4 +1,5 @@ import { TContext } from '../types'; +import Sval from 'sval'; function exec(code: string, scope: TContext) { try { @@ -6,7 +7,7 @@ function exec(code: string, scope: TContext) { var ${'____data'} = arguments[0]; with(${'____data'}) { return ${code} - } + } `; return new Function(str)(scope); @@ -15,4 +16,29 @@ function exec(code: string, scope: TContext) { } } -export { exec }; +function safeExec(expression: string, scope: TContext) { + const interpreter = new Sval({ + ecmaVer: 'latest', + sourceType: 'script', + sandBox: true, + }); + + let globalThisAssignments = ''; + + Object.keys(scope).forEach(key => { + const value = scope[key]; + globalThisAssignments += `globalThis[${JSON.stringify( + key, + )}] = ${JSON.stringify(value)};\n`; + }); + + const code = ` +${globalThisAssignments} +exports.a = ${expression};`; + + interpreter.run(code); + + return interpreter.exports.a; +} + +export { exec, safeExec }; diff --git a/web/packages/form-engine/wallaby.js b/web/packages/form-engine/wallaby.js new file mode 100644 index 00000000..685c3f40 --- /dev/null +++ b/web/packages/form-engine/wallaby.js @@ -0,0 +1,5 @@ +module.exports = function (wallaby) { + return { + autoDetect: ['jest'], + }; +}; diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index b378d916..132f9bd9 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -250,7 +250,7 @@ importers: version: 11.4.0 next-intl: specifier: ^2.20.0 - version: 2.22.1(next@14.2.12(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 2.22.1(next@14.2.12(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) next-themes: specifier: ^0.2.1 version: 0.2.1(next@14.2.12(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -461,7 +461,7 @@ importers: version: 12.2.0(less@4.2.0)(webpack@5.93.0(@swc/core@1.7.12(@swc/helpers@0.5.5))(esbuild@0.23.1)) next-intl: specifier: ^2.22.1 - version: 2.22.1(next@14.2.12(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 2.22.1(next@14.2.12(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) playwright: specifier: ^1.47.1 version: 1.47.1 @@ -946,13 +946,16 @@ importers: version: 5.1.0(react@18.3.1) react-dnd: specifier: ^16.0.1 - version: 16.0.1(@types/hoist-non-react-statics@3.3.5)(@types/node@22.4.1)(@types/react@18.3.3)(react@18.3.1) + version: 16.0.1(@types/hoist-non-react-statics@3.3.5)(@types/node@20.16.1)(@types/react@18.3.3)(react@18.3.1) react-dnd-html5-backend: specifier: ^16.0.1 version: 16.0.1 react-error-boundary: specifier: ^4.0.13 version: 4.0.13(react@18.3.1) + sval: + specifier: ^0.6.1 + version: 0.6.1 tailwind-merge: specifier: ^2.5.2 version: 2.5.2 @@ -989,16 +992,16 @@ importers: version: 10.4.20(postcss@8.4.41) jest: specifier: ^29.4.1 - version: 29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)) + version: 29.7.0(@types/node@20.16.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.12(@swc/helpers@0.5.5))(@types/node@20.16.1)(typescript@5.3.3)) postcss: specifier: ^8.4.41 version: 8.4.41 tailwindcss: specifier: ^3.4.10 - version: 3.4.10(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)) + version: 3.4.10(ts-node@10.9.2(@swc/core@1.7.12(@swc/helpers@0.5.5))(@types/node@20.16.1)(typescript@5.3.3)) ts-jest: specifier: ^29.0.5 - version: 29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)))(typescript@5.3.3) + version: 29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@20.16.1)(typescript@5.3.3)))(typescript@5.3.3) typescript: specifier: ~5.3.3 version: 5.3.3 @@ -1080,13 +1083,13 @@ importers: version: 0.1.3 jest: specifier: ^29.4.1 - version: 29.7.0(@types/node@20.5.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@20.5.1)(typescript@5.3.3)) + version: 29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)) node-emoji: specifier: ^2.1.3 version: 2.1.3 ts-jest: specifier: ^29.0.5 - version: 29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.5.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@20.5.1)(typescript@5.3.3)))(typescript@5.3.3) + version: 29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)))(typescript@5.3.3) typescript: specifier: ~5.3.3 version: 5.3.3 @@ -1312,7 +1315,7 @@ importers: version: 29.7.0(@types/node@20.16.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.12(@swc/helpers@0.5.5))(@types/node@20.16.1)(typescript@5.3.3)) next-intl: specifier: ^2.22.1 - version: 2.22.1(next@14.2.12(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 2.22.1(next@14.2.12(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) postcss: specifier: ^8.4.41 version: 8.4.41 @@ -3029,79 +3032,67 @@ packages: resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} @@ -3415,56 +3406,48 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@next/swc-linux-arm64-gnu@14.2.5': resolution: {integrity: sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@next/swc-linux-arm64-musl@14.2.12': resolution: {integrity: sha512-EfD9L7o9biaQxjwP1uWXnk3vYZi64NVcKUN83hpVkKocB7ogJfyH2r7o1pPnMtir6gHZiGCeHKagJ0yrNSLNHw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@next/swc-linux-arm64-musl@14.2.5': resolution: {integrity: sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@next/swc-linux-x64-gnu@14.2.12': resolution: {integrity: sha512-iQ+n2pxklJew9IpE47hE/VgjmljlHqtcD5UhZVeHICTPbLyrgPehaKf2wLRNjYH75udroBNCgrSSVSVpAbNoYw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@next/swc-linux-x64-gnu@14.2.5': resolution: {integrity: sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@next/swc-linux-x64-musl@14.2.12': resolution: {integrity: sha512-rFkUkNwcQ0ODn7cxvcVdpHlcOpYxMeyMfkJuzaT74xjAa5v4fxP4xDk5OoYmPi8QNLDs3UgZPMSBmpBuv9zKWA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@next/swc-linux-x64-musl@14.2.5': resolution: {integrity: sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@next/swc-win32-arm64-msvc@14.2.12': resolution: {integrity: sha512-PQFYUvwtHs/u0K85SG4sAdDXYIPXpETf9mcEjWc0R4JmjgMKSDwIU/qfZdavtP6MPNiMjuKGXHCtyhR/M5zo8g==} @@ -4760,28 +4743,24 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [glibc] '@swc/core-linux-arm64-musl@1.7.12': resolution: {integrity: sha512-WKtanqasnJ9cBD1tMsmOzZzxJ0Hg2sfJC7UNs2Z4meNPBK4xwOrhpSq8Q9GE4xgoLeSEhU3MmQnbfJKRq3mAZQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [musl] '@swc/core-linux-x64-gnu@1.7.12': resolution: {integrity: sha512-NQ0bb9eCIp2z2WdRyELzfWc1LDJJ99OYdxT+CIwW9ixPVgAerOv0Oc+BkdijLw5VeYMGlK6JEI4HdLvQE34f1g==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [glibc] '@swc/core-linux-x64-musl@1.7.12': resolution: {integrity: sha512-D8Tegag3/045wvGiq3NFNbKVDnkocNcl5hdKQtEvZ3b1u3nHGu+xqmPteUh4Ps+GB/gbpB3o/eYNO5JPm0R66Q==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [musl] '@swc/core-win32-arm64-msvc@1.7.12': resolution: {integrity: sha512-x8DWG4fCkwI6CmC8U1YMxVTab9Fe4DmCCX6dLrTqqpFPXlVwgdKA9PNBSXsUUtHjvqAB/9cGgmpmNHuNJRa1dA==} @@ -11484,6 +11463,9 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + sval@0.6.1: + resolution: {integrity: sha512-e4rndan/xKWMrzrqfZpBxt4IVEJofkaSQ+DFnCvcxGKEWumKHtKQDwcNQUUNt2grMAnksluv0tKnPyoE2SWxYw==} + swap-case@1.1.2: resolution: {integrity: sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==} @@ -14831,6 +14813,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3))': dependencies: @@ -17863,27 +17846,28 @@ snapshots: acorn-walk: 7.2.0 optional: true - acorn-import-attributes@1.9.5(acorn@8.12.1): + acorn-import-attributes@1.9.5(acorn@8.14.0): dependencies: - acorn: 8.12.1 + acorn: 8.14.0 acorn-jsx@5.3.2(acorn@7.4.1): dependencies: acorn: 7.4.1 - acorn-jsx@5.3.2(acorn@8.12.1): + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: - acorn: 8.12.1 + acorn: 8.14.0 acorn-walk@7.2.0: {} acorn-walk@8.3.3: dependencies: - acorn: 8.12.1 + acorn: 8.14.0 acorn@7.4.1: {} - acorn@8.12.1: {} + acorn@8.12.1: + optional: true acorn@8.14.0: {} @@ -18963,6 +18947,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true create-jest@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)): dependencies: @@ -19845,7 +19830,7 @@ snapshots: '@typescript-eslint/parser': 6.21.0(eslint@8.37.0)(typescript@5.3.3) eslint: 8.37.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.37.0) eslint-plugin-jsx-a11y: 6.9.0(eslint@8.37.0) eslint-plugin-react: 7.35.0(eslint@8.37.0) @@ -19881,12 +19866,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0): dependencies: debug: 4.3.6 enhanced-resolve: 5.17.1 eslint: 8.37.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0))(eslint@8.37.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0))(eslint@8.37.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.37.0) fast-glob: 3.3.2 get-tsconfig: 4.7.6 @@ -19915,14 +19900,14 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0))(eslint@8.37.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0))(eslint@8.37.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 6.21.0(eslint@8.37.0)(typescript@5.3.3) eslint: 8.37.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0) transitivePeerDependencies: - supports-color @@ -19953,7 +19938,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.37.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0))(eslint@8.37.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0))(eslint@8.37.0) hasown: 2.0.2 is-core-module: 2.15.0 is-glob: 4.0.3 @@ -20181,8 +20166,8 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.12.1 - acorn-jsx: 5.3.2(acorn@8.12.1) + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -21647,6 +21632,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true jest-cli@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)): dependencies: @@ -21728,6 +21714,7 @@ snapshots: transitivePeerDependencies: - babel-plugin-macros - supports-color + optional: true jest-config@29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)): dependencies: @@ -21790,6 +21777,7 @@ snapshots: transitivePeerDependencies: - babel-plugin-macros - supports-color + optional: true jest-config@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)): dependencies: @@ -22132,6 +22120,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true jest@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)): dependencies: @@ -23161,7 +23150,7 @@ snapshots: netmask@2.0.2: {} - next-intl@2.22.1(next@14.2.12(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): + next-intl@2.22.1(next@14.2.12(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): dependencies: '@formatjs/intl-localematcher': 0.2.32 negotiator: 0.6.3 @@ -25702,6 +25691,10 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + sval@0.6.1: + dependencies: + acorn: 8.14.0 + swap-case@1.1.2: dependencies: lower-case: 1.1.4 @@ -25831,7 +25824,7 @@ snapshots: terser@5.31.6: dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.12.1 + acorn: 8.14.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -25964,25 +25957,6 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.25.2) - ts-jest@29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.5.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@20.5.1)(typescript@5.3.3)))(typescript@5.3.3): - dependencies: - bs-logger: 0.2.6 - ejs: 3.1.10 - fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.5.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@20.5.1)(typescript@5.3.3)) - jest-util: 29.7.0 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.6.3 - typescript: 5.3.3 - yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.25.2 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.25.2) - ts-jest@29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)))(typescript@5.3.3): dependencies: bs-logger: 0.2.6 @@ -26010,7 +25984,7 @@ snapshots: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 20.16.1 - acorn: 8.12.1 + acorn: 8.14.0 acorn-walk: 8.3.3 arg: 4.1.3 create-require: 1.1.1 @@ -26030,7 +26004,7 @@ snapshots: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 16.18.105 - acorn: 8.12.1 + acorn: 8.14.0 acorn-walk: 8.3.3 arg: 4.1.3 create-require: 1.1.1 @@ -26050,7 +26024,7 @@ snapshots: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 20.5.1 - acorn: 8.12.1 + acorn: 8.14.0 acorn-walk: 8.3.3 arg: 4.1.3 create-require: 1.1.1 @@ -26070,7 +26044,7 @@ snapshots: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 22.4.1 - acorn: 8.12.1 + acorn: 8.14.0 acorn-walk: 8.3.3 arg: 4.1.3 create-require: 1.1.1 @@ -26325,7 +26299,7 @@ snapshots: unplugin@1.14.1(webpack-sources@3.2.3): dependencies: - acorn: 8.12.1 + acorn: 8.14.0 webpack-virtual-modules: 0.6.2 optionalDependencies: webpack-sources: 3.2.3 @@ -26621,8 +26595,8 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.12.1 - acorn-import-attributes: 1.9.5(acorn@8.12.1) + acorn: 8.14.0 + acorn-import-attributes: 1.9.5(acorn@8.14.0) browserslist: 4.23.3 chrome-trace-event: 1.0.4 enhanced-resolve: 5.17.1 @@ -26652,8 +26626,8 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@webassemblyjs/wasm-edit': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.12.1 - acorn-import-attributes: 1.9.5(acorn@8.12.1) + acorn: 8.14.0 + acorn-import-attributes: 1.9.5(acorn@8.14.0) browserslist: 4.23.3 chrome-trace-event: 1.0.4 enhanced-resolve: 5.17.1 From 454352ea131d214521840d402a00718699f82a29 Mon Sep 17 00:00:00 2001 From: shanexi Date: Thu, 6 Mar 2025 17:00:19 +0800 Subject: [PATCH 2/6] fix: sanitize dangerouslySetInnerHTML --- web/apps/web/package.json | 3 +- .../variable-value-block/components/index.tsx | 23 +++---- .../comfyui/widgets/comfyui-editor.tsx | 5 +- web/pnpm-lock.yaml | 60 ++++++++++++------- 4 files changed, 57 insertions(+), 34 deletions(-) diff --git a/web/apps/web/package.json b/web/apps/web/package.json index 5a7de574..b0343e98 100644 --- a/web/apps/web/package.json +++ b/web/apps/web/package.json @@ -90,7 +90,8 @@ "uuid": "^10.0.0", "zod": "^3.23.8", "zustand": "^4.5.4", - "zustand-computed-state": "^0.1.8" + "zustand-computed-state": "^0.1.8", + "isomorphic-dompurify": "^2.14.0" }, "devDependencies": { "@shellagent/eslint-config": "workspace:*", diff --git a/web/apps/web/src/components/app/node-form/widgets/highlight-input/variable-value-block/components/index.tsx b/web/apps/web/src/components/app/node-form/widgets/highlight-input/variable-value-block/components/index.tsx index 4e65c138..bb8c1b5d 100644 --- a/web/apps/web/src/components/app/node-form/widgets/highlight-input/variable-value-block/components/index.tsx +++ b/web/apps/web/src/components/app/node-form/widgets/highlight-input/variable-value-block/components/index.tsx @@ -3,6 +3,7 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { $getNodeByKey, COMMAND_PRIORITY_EDITOR } from 'lexical'; import { memo, useRef, useEffect } from 'react'; +import { sanitize } from 'isomorphic-dompurify'; import { cn } from '@/utils/cn'; @@ -125,21 +126,23 @@ const VariableValueBlockComponent = ({ }; const renderParts = () => { - return parts - .map(part => { - if (part.type === PartType.TEXT) { - return part.content; - } else if (part.type === PartType.VARIABLE) { - return ` { + if (part.type === PartType.TEXT) { + return part.content; + } else if (part.type === PartType.VARIABLE) { + return `${part.display}`; - } - return ''; - }) - .join(''); + } + return ''; + }) + .join(''), + ); }; return ( diff --git a/web/apps/web/src/components/app/plugins/comfyui/widgets/comfyui-editor.tsx b/web/apps/web/src/components/app/plugins/comfyui/widgets/comfyui-editor.tsx index 16a80eac..60f33e62 100644 --- a/web/apps/web/src/components/app/plugins/comfyui/widgets/comfyui-editor.tsx +++ b/web/apps/web/src/components/app/plugins/comfyui/widgets/comfyui-editor.tsx @@ -21,6 +21,7 @@ import { import { observer } from 'mobx-react-lite'; import React, { useEffect, useRef } from 'react'; import { Box, Flex } from 'react-system'; +import { sanitize } from 'isomorphic-dompurify'; import { DEFAULT_MODAL_STYLES, @@ -226,7 +227,9 @@ export const ComfyUIEditorModal = observer(() => { ]}>
') || '', + __html: sanitize( + model.messageDetail?.replaceAll('\n', '
') || '', + ), }} /> diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 132f9bd9..c2cb2b85 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -250,7 +250,7 @@ importers: version: 11.4.0 next-intl: specifier: ^2.20.0 - version: 2.22.1(next@14.2.12(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 2.22.1(next@14.2.12(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) next-themes: specifier: ^0.2.1 version: 0.2.1(next@14.2.12(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -461,7 +461,7 @@ importers: version: 12.2.0(less@4.2.0)(webpack@5.93.0(@swc/core@1.7.12(@swc/helpers@0.5.5))(esbuild@0.23.1)) next-intl: specifier: ^2.22.1 - version: 2.22.1(next@14.2.12(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 2.22.1(next@14.2.12(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) playwright: specifier: ^1.47.1 version: 1.47.1 @@ -591,6 +591,9 @@ importers: inversify-react: specifier: ^1.1.1 version: 1.1.1(inversify@6.0.2)(react@18.3.1) + isomorphic-dompurify: + specifier: ^2.14.0 + version: 2.14.0(bufferutil@4.0.8)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@5.0.10) json-source-map: specifier: ^0.6.1 version: 0.6.1 @@ -946,7 +949,7 @@ importers: version: 5.1.0(react@18.3.1) react-dnd: specifier: ^16.0.1 - version: 16.0.1(@types/hoist-non-react-statics@3.3.5)(@types/node@20.16.1)(@types/react@18.3.3)(react@18.3.1) + version: 16.0.1(@types/hoist-non-react-statics@3.3.5)(@types/node@22.4.1)(@types/react@18.3.3)(react@18.3.1) react-dnd-html5-backend: specifier: ^16.0.1 version: 16.0.1 @@ -992,16 +995,16 @@ importers: version: 10.4.20(postcss@8.4.41) jest: specifier: ^29.4.1 - version: 29.7.0(@types/node@20.16.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.12(@swc/helpers@0.5.5))(@types/node@20.16.1)(typescript@5.3.3)) + version: 29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)) postcss: specifier: ^8.4.41 version: 8.4.41 tailwindcss: specifier: ^3.4.10 - version: 3.4.10(ts-node@10.9.2(@swc/core@1.7.12(@swc/helpers@0.5.5))(@types/node@20.16.1)(typescript@5.3.3)) + version: 3.4.10(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)) ts-jest: specifier: ^29.0.5 - version: 29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@20.16.1)(typescript@5.3.3)))(typescript@5.3.3) + version: 29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)))(typescript@5.3.3) typescript: specifier: ~5.3.3 version: 5.3.3 @@ -1083,13 +1086,13 @@ importers: version: 0.1.3 jest: specifier: ^29.4.1 - version: 29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)) + version: 29.7.0(@types/node@20.5.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@20.5.1)(typescript@5.3.3)) node-emoji: specifier: ^2.1.3 version: 2.1.3 ts-jest: specifier: ^29.0.5 - version: 29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)))(typescript@5.3.3) + version: 29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.5.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@20.5.1)(typescript@5.3.3)))(typescript@5.3.3) typescript: specifier: ~5.3.3 version: 5.3.3 @@ -1315,7 +1318,7 @@ importers: version: 29.7.0(@types/node@20.16.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.12(@swc/helpers@0.5.5))(@types/node@20.16.1)(typescript@5.3.3)) next-intl: specifier: ^2.22.1 - version: 2.22.1(next@14.2.12(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 2.22.1(next@14.2.12(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) postcss: specifier: ^8.4.41 version: 8.4.41 @@ -14813,7 +14816,6 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3))': dependencies: @@ -18947,7 +18949,6 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true create-jest@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)): dependencies: @@ -19830,7 +19831,7 @@ snapshots: '@typescript-eslint/parser': 6.21.0(eslint@8.37.0)(typescript@5.3.3) eslint: 8.37.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.37.0) eslint-plugin-jsx-a11y: 6.9.0(eslint@8.37.0) eslint-plugin-react: 7.35.0(eslint@8.37.0) @@ -19866,12 +19867,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0): dependencies: debug: 4.3.6 enhanced-resolve: 5.17.1 eslint: 8.37.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0))(eslint@8.37.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0))(eslint@8.37.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.37.0) fast-glob: 3.3.2 get-tsconfig: 4.7.6 @@ -19900,14 +19901,14 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0))(eslint@8.37.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0))(eslint@8.37.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 6.21.0(eslint@8.37.0)(typescript@5.3.3) eslint: 8.37.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0) transitivePeerDependencies: - supports-color @@ -19938,7 +19939,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.37.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.37.0))(eslint@8.37.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.37.0)(typescript@5.3.3))(eslint@8.37.0))(eslint@8.37.0))(eslint@8.37.0) hasown: 2.0.2 is-core-module: 2.15.0 is-glob: 4.0.3 @@ -21632,7 +21633,6 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true jest-cli@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)): dependencies: @@ -21714,7 +21714,6 @@ snapshots: transitivePeerDependencies: - babel-plugin-macros - supports-color - optional: true jest-config@29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)): dependencies: @@ -21777,7 +21776,6 @@ snapshots: transitivePeerDependencies: - babel-plugin-macros - supports-color - optional: true jest-config@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)): dependencies: @@ -22120,7 +22118,6 @@ snapshots: - babel-plugin-macros - supports-color - ts-node - optional: true jest@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)): dependencies: @@ -23150,7 +23147,7 @@ snapshots: netmask@2.0.2: {} - next-intl@2.22.1(next@14.2.12(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): + next-intl@2.22.1(next@14.2.12(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): dependencies: '@formatjs/intl-localematcher': 0.2.32 negotiator: 0.6.3 @@ -25957,6 +25954,25 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.25.2) + ts-jest@29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.5.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@20.5.1)(typescript@5.3.3)))(typescript@5.3.3): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@20.5.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@20.5.1)(typescript@5.3.3)) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.3 + typescript: 5.3.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.25.2 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.25.2) + ts-jest@29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@22.4.1)(ts-node@10.9.2(@swc/core@1.7.12)(@types/node@22.4.1)(typescript@5.3.3)))(typescript@5.3.3): dependencies: bs-logger: 0.2.6 From 2dc8bbd013d1e3cdcc138f11befbd008f32f9a8d Mon Sep 17 00:00:00 2001 From: shanexi Date: Thu, 6 Mar 2025 17:04:16 +0800 Subject: [PATCH 3/6] fix: open redirect --- web/apps/web/src/services/base.ts | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/web/apps/web/src/services/base.ts b/web/apps/web/src/services/base.ts index 95947d9b..d12f8293 100755 --- a/web/apps/web/src/services/base.ts +++ b/web/apps/web/src/services/base.ts @@ -128,11 +128,27 @@ export const customFetch = async ( { toastId: 'login-error' }, ); setTimeout(() => { + const currentUrl = window.location.href; + const isValidRedirectUrl = (() => { + try { + const url = new URL(currentUrl); + return ( + url.hostname.endsWith('myshell.fun') || + url.hostname.endsWith('myshell.ai') || + url.hostname.endsWith('myshell.life') + ); + } catch (e) { + return false; + } + })(); + + const redirectUrl = isValidRedirectUrl + ? currentUrl + : 'https://myshell.ai'; + window.location.href = `${ process.env.NEXT_PUBLIC_LOGIN_URL - }?login=true&redirect=${decodeURIComponent( - window.location.href, - )}`; + }?login=true&redirect=${encodeURIComponent(redirectUrl)}`; }, 3000); } From dcc4cd0fb6fb7502952905ff99f192c9a8ef3606 Mon Sep 17 00:00:00 2001 From: shanexi Date: Thu, 6 Mar 2025 17:10:05 +0800 Subject: [PATCH 4/6] fix: file types whitelist of upload --- web/apps/web/src/services/common/index.ts | 51 +++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/web/apps/web/src/services/common/index.ts b/web/apps/web/src/services/common/index.ts index aab8ce8c..e982d451 100644 --- a/web/apps/web/src/services/common/index.ts +++ b/web/apps/web/src/services/common/index.ts @@ -6,10 +6,61 @@ export interface UploadResponse { url: string; } +const ALLOWED_FILE_TYPES = [ + // 图片类型 + 'image/jpeg', + 'image/png', + 'image/gif', + 'image/webp', + 'image/svg+xml', + 'image/bmp', + 'image/tiff', + // 音频类型 + 'audio/mpeg', + 'audio/ogg', + 'audio/wav', + 'audio/webm', + 'audio/aac', + 'audio/flac', + 'audio/mp4', + // 视频类型 + 'video/mp4', + 'video/webm', + 'video/ogg', + 'video/quicktime', + 'video/x-msvideo', + 'video/x-matroska', + // 文档类型 + 'application/pdf', + 'application/msword', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.ms-powerpoint', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + // 其他常见文件类型 + 'text/plain', + 'text/html', + 'text/csv', + 'application/json', + 'application/zip', + 'application/x-rar-compressed', +]; + export async function upload( file: File, name?: string, ): Promise { + if (!ALLOWED_FILE_TYPES.includes(file.type)) { + toast.error('Not supported file type', { + position: 'top-center', + autoClose: 2000, + hideProgressBar: true, + pauseOnHover: true, + closeButton: false, + }); + return { url: '' }; + } const formData = new FormData(); formData.append('file', file, name || file.name); const response = await APIFetch.post<{ file_path: string }>('/api/upload', { From 25dad60fd6b8a68a59aa98c7144201f082f5392b Mon Sep 17 00:00:00 2001 From: shanexi Date: Fri, 7 Mar 2025 15:29:07 +0800 Subject: [PATCH 5/6] fix: safeExec alias exec --- web/packages/form-engine/src/utils/exec.spec.ts | 6 +++--- web/packages/form-engine/src/utils/exec.ts | 17 +---------------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/web/packages/form-engine/src/utils/exec.spec.ts b/web/packages/form-engine/src/utils/exec.spec.ts index 9ab6f3fe..ca80445c 100644 --- a/web/packages/form-engine/src/utils/exec.spec.ts +++ b/web/packages/form-engine/src/utils/exec.spec.ts @@ -1,4 +1,4 @@ -import { exec, safeExec } from './exec'; +import { exec } from './exec'; import Sval from 'sval'; describe('exec', () => { @@ -12,14 +12,14 @@ describe('exec', () => { }); it('exec sval ver', () => { - const result = safeExec(`$this.value === "image"`, { + const result = exec(`$this.value === "image"`, { $this: { value: 'image', }, }); expect(result).toBe(true); - const result2 = safeExec(`$this.value === "image"`, { + const result2 = exec(`$this.value === "image"`, { $this: { value: 'text', }, diff --git a/web/packages/form-engine/src/utils/exec.ts b/web/packages/form-engine/src/utils/exec.ts index f8581d56..8d0b8b45 100644 --- a/web/packages/form-engine/src/utils/exec.ts +++ b/web/packages/form-engine/src/utils/exec.ts @@ -1,21 +1,6 @@ import { TContext } from '../types'; import Sval from 'sval'; -function exec(code: string, scope: TContext) { - try { - const str = ` - var ${'____data'} = arguments[0]; - with(${'____data'}) { - return ${code} - } - `; - - return new Function(str)(scope); - } catch (e) { - console.log(e); - } -} - function safeExec(expression: string, scope: TContext) { const interpreter = new Sval({ ecmaVer: 'latest', @@ -41,4 +26,4 @@ exports.a = ${expression};`; return interpreter.exports.a; } -export { exec, safeExec }; +export { safeExec as exec }; From f09833e77017ba306c718372079aae934835d3e7 Mon Sep 17 00:00:00 2001 From: shanexi Date: Fri, 7 Mar 2025 15:29:14 +0800 Subject: [PATCH 6/6] Revert "fix: file types whitelist of upload" This reverts commit d7f29656a42e6e68392b18eab7fe26843b91a2c8. --- web/apps/web/src/services/common/index.ts | 51 ----------------------- 1 file changed, 51 deletions(-) diff --git a/web/apps/web/src/services/common/index.ts b/web/apps/web/src/services/common/index.ts index e982d451..aab8ce8c 100644 --- a/web/apps/web/src/services/common/index.ts +++ b/web/apps/web/src/services/common/index.ts @@ -6,61 +6,10 @@ export interface UploadResponse { url: string; } -const ALLOWED_FILE_TYPES = [ - // 图片类型 - 'image/jpeg', - 'image/png', - 'image/gif', - 'image/webp', - 'image/svg+xml', - 'image/bmp', - 'image/tiff', - // 音频类型 - 'audio/mpeg', - 'audio/ogg', - 'audio/wav', - 'audio/webm', - 'audio/aac', - 'audio/flac', - 'audio/mp4', - // 视频类型 - 'video/mp4', - 'video/webm', - 'video/ogg', - 'video/quicktime', - 'video/x-msvideo', - 'video/x-matroska', - // 文档类型 - 'application/pdf', - 'application/msword', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'application/vnd.ms-excel', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'application/vnd.ms-powerpoint', - 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - // 其他常见文件类型 - 'text/plain', - 'text/html', - 'text/csv', - 'application/json', - 'application/zip', - 'application/x-rar-compressed', -]; - export async function upload( file: File, name?: string, ): Promise { - if (!ALLOWED_FILE_TYPES.includes(file.type)) { - toast.error('Not supported file type', { - position: 'top-center', - autoClose: 2000, - hideProgressBar: true, - pauseOnHover: true, - closeButton: false, - }); - return { url: '' }; - } const formData = new FormData(); formData.append('file', file, name || file.name); const response = await APIFetch.post<{ file_path: string }>('/api/upload', {