feat: add custom script monitor provider

This commit is contained in:
moonrailgun 2024-01-01 04:26:57 +08:00
parent e0e338f819
commit 8dfa679127
9 changed files with 339 additions and 10 deletions

View File

@ -52,6 +52,7 @@
"filesize": "^10.0.12", "filesize": "^10.0.12",
"fs-extra": "^11.1.1", "fs-extra": "^11.1.1",
"is-localhost-ip": "^2.0.0", "is-localhost-ip": "^2.0.0",
"isolated-vm": "^4.6.0",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",

View File

@ -91,6 +91,9 @@ dependencies:
is-localhost-ip: is-localhost-ip:
specifier: ^2.0.0 specifier: ^2.0.0
version: 2.0.0 version: 2.0.0
isolated-vm:
specifier: ^4.6.0
version: 4.6.0
jsonwebtoken: jsonwebtoken:
specifier: ^9.0.2 specifier: ^9.0.2
version: 9.0.2 version: 9.0.2
@ -3184,7 +3187,6 @@ packages:
buffer: 5.7.1 buffer: 5.7.1
inherits: 2.0.4 inherits: 2.0.4
readable-stream: 3.6.2 readable-stream: 3.6.2
dev: true
/bl@5.1.0: /bl@5.1.0:
resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==}
@ -3430,6 +3432,10 @@ packages:
fsevents: 2.3.3 fsevents: 2.3.3
dev: true dev: true
/chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
dev: false
/chownr@2.0.0: /chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -4181,7 +4187,6 @@ packages:
engines: {node: '>=10'} engines: {node: '>=10'}
dependencies: dependencies:
mimic-response: 3.1.0 mimic-response: 3.1.0
dev: true
/deep-equal@1.1.1: /deep-equal@1.1.1:
resolution: {integrity: sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==} resolution: {integrity: sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==}
@ -4197,7 +4202,6 @@ packages:
/deep-extend@0.6.0: /deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'} engines: {node: '>=4.0.0'}
dev: true
/default-browser-id@3.0.0: /default-browser-id@3.0.0:
resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==}
@ -4302,6 +4306,11 @@ packages:
resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==} resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==}
dev: false dev: false
/detect-libc@2.0.2:
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
engines: {node: '>=8'}
dev: false
/devtools-protocol@0.0.1179426: /devtools-protocol@0.0.1179426:
resolution: {integrity: sha512-KKC7IGwdOr7u9kTGgjUvGTov/z1s2H7oHi3zKCdR9eSDyCPia5CBi4aRhtp7d8uR7l0GS5UTDw3TjKGu5CqINg==} resolution: {integrity: sha512-KKC7IGwdOr7u9kTGgjUvGTov/z1s2H7oHi3zKCdR9eSDyCPia5CBi4aRhtp7d8uR7l0GS5UTDw3TjKGu5CqINg==}
dev: false dev: false
@ -4683,6 +4692,11 @@ packages:
strip-final-newline: 3.0.0 strip-final-newline: 3.0.0
dev: true dev: true
/expand-template@2.0.3:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
dev: false
/express-async-errors@3.1.1(express@4.18.2): /express-async-errors@3.1.1(express@4.18.2):
resolution: {integrity: sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==} resolution: {integrity: sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==}
peerDependencies: peerDependencies:
@ -4990,7 +5004,6 @@ packages:
/fs-constants@1.0.0: /fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
dev: true
/fs-extra@11.1.1: /fs-extra@11.1.1:
resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==}
@ -5135,6 +5148,10 @@ packages:
git-up: 7.0.0 git-up: 7.0.0
dev: true dev: true
/github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
dev: false
/gl-matrix@3.4.3: /gl-matrix@3.4.3:
resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==} resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==}
dev: false dev: false
@ -5516,7 +5533,6 @@ packages:
/ini@1.3.8: /ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
dev: true
/ini@2.0.0: /ini@2.0.0:
resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
@ -5859,6 +5875,14 @@ packages:
/isexe@2.0.0: /isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
/isolated-vm@4.6.0:
resolution: {integrity: sha512-MEnfC/54q5PED3VJ9UJYJPOlU6mYFHS3ivR9E8yeNNBEFRFUNBnY0xO4Rj3D/SOtFKPNmsQp9NWUYSKZqAoZiA==}
engines: {node: '>=16.0.0'}
requiresBuild: true
dependencies:
prebuild-install: 7.1.1
dev: false
/issue-parser@6.0.0: /issue-parser@6.0.0:
resolution: {integrity: sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==} resolution: {integrity: sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==}
engines: {node: '>=10.13'} engines: {node: '>=10.13'}
@ -6389,7 +6413,6 @@ packages:
/mimic-response@3.1.0: /mimic-response@3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
dev: true
/mimic-response@4.0.0: /mimic-response@4.0.0:
resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==}
@ -6557,6 +6580,10 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true hasBin: true
/napi-build-utils@1.0.2:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
dev: false
/negotiator@0.6.3: /negotiator@0.6.3:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@ -6582,6 +6609,13 @@ packages:
type-fest: 2.19.0 type-fest: 2.19.0
dev: true dev: true
/node-abi@3.52.0:
resolution: {integrity: sha512-JJ98b02z16ILv7859irtXn4oUaFWADtvkzy2c0IAatNVX2Mc9Yoh8z6hZInn3QwvMEYhHuQloYi+TTQy67SIdQ==}
engines: {node: '>=10'}
dependencies:
semver: 7.5.4
dev: false
/node-domexception@1.0.0: /node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'} engines: {node: '>=10.5.0'}
@ -7260,6 +7294,25 @@ packages:
resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==} resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==}
dev: false dev: false
/prebuild-install@7.1.1:
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
engines: {node: '>=10'}
hasBin: true
dependencies:
detect-libc: 2.0.2
expand-template: 2.0.3
github-from-package: 0.0.0
minimist: 1.2.8
mkdirp-classic: 0.5.3
napi-build-utils: 1.0.2
node-abi: 3.52.0
pump: 3.0.0
rc: 1.2.8
simple-get: 4.0.1
tar-fs: 2.1.1
tunnel-agent: 0.6.0
dev: false
/prettier@2.8.8: /prettier@2.8.8:
resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
@ -8108,7 +8161,6 @@ packages:
ini: 1.3.8 ini: 1.3.8
minimist: 1.2.8 minimist: 1.2.8
strip-json-comments: 2.0.1 strip-json-comments: 2.0.1
dev: true
/react-color@2.17.1(react@18.2.0): /react-color@2.17.1(react@18.2.0):
resolution: {integrity: sha512-S+I6TkUKJaqfALLkAIfiCZ/MANQyy7dKkf7g9ZU5GTUy2rf8c2Rx62otyvADAviWR+6HRkzdf2vL1Qvz9goCLQ==} resolution: {integrity: sha512-S+I6TkUKJaqfALLkAIfiCZ/MANQyy7dKkf7g9ZU5GTUy2rf8c2Rx62otyvADAviWR+6HRkzdf2vL1Qvz9goCLQ==}
@ -8791,6 +8843,18 @@ packages:
engines: {node: '>=14'} engines: {node: '>=14'}
dev: true dev: true
/simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
dev: false
/simple-get@4.0.1:
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
dependencies:
decompress-response: 6.0.0
once: 1.4.0
simple-concat: 1.0.1
dev: false
/simple-swizzle@0.2.2: /simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
dependencies: dependencies:
@ -9132,7 +9196,6 @@ packages:
/strip-json-comments@2.0.1: /strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dev: true
/stylis@4.3.0: /stylis@4.3.0:
resolution: {integrity: sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==} resolution: {integrity: sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==}
@ -9253,6 +9316,15 @@ packages:
through: 2.3.8 through: 2.3.8
dev: false dev: false
/tar-fs@2.1.1:
resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
dependencies:
chownr: 1.1.4
mkdirp-classic: 0.5.3
pump: 3.0.0
tar-stream: 2.2.0
dev: false
/tar-fs@3.0.4: /tar-fs@3.0.4:
resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==} resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==}
dependencies: dependencies:
@ -9270,7 +9342,6 @@ packages:
fs-constants: 1.0.0 fs-constants: 1.0.0
inherits: 2.0.4 inherits: 2.0.4
readable-stream: 3.6.2 readable-stream: 3.6.2
dev: true
/tar-stream@3.1.6: /tar-stream@3.1.6:
resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==} resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
@ -9525,6 +9596,12 @@ packages:
/tslib@2.6.2: /tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
/tunnel-agent@0.6.0:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
dependencies:
safe-buffer: 5.2.1
dev: false
/type-fest@0.16.0: /type-fest@0.16.0:
resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==}
engines: {node: '>=10'} engines: {node: '>=10'}

View File

@ -0,0 +1,24 @@
import { Form, Input } from 'antd';
import React from 'react';
import { MonitorProvider } from './types';
export const MonitorCustom: React.FC = React.memo(() => {
return (
<>
<Form.Item
label="Script JS Code"
name={['payload', 'code']}
rules={[{ required: true }]}
>
<Input.TextArea placeholder="return 1" rows={10} />
</Form.Item>
</>
);
});
MonitorCustom.displayName = 'MonitorCustom';
export const customProvider: MonitorProvider = {
label: 'Custom',
name: 'custom',
form: MonitorCustom,
};

View File

@ -4,11 +4,13 @@ import { pingProvider } from './ping';
import { httpProvider } from './http'; import { httpProvider } from './http';
import { MonitorProvider } from './types'; import { MonitorProvider } from './types';
import { openaiProvider } from './openai'; import { openaiProvider } from './openai';
import { customProvider } from './custom';
export const monitorProviders: MonitorProvider[] = [ export const monitorProviders: MonitorProvider[] = [
pingProvider, // ping pingProvider, // ping
httpProvider, // http httpProvider, // http
openaiProvider, // http openaiProvider, // http
customProvider, // custom node script
]; ];
export function getMonitorProvider(type: string) { export function getMonitorProvider(type: string) {

View File

@ -0,0 +1,46 @@
import { MonitorProvider } from './type';
import ivm from 'isolated-vm';
import { buildSandbox, environmentScript } from '../../../utils/sandbox';
import { env } from '../../../utils/env';
export const custom: MonitorProvider<{
code: string;
}> = {
run: async (monitor) => {
if (typeof monitor.payload !== 'object') {
throw new Error('monitor.payload should be object');
}
const { code } = monitor.payload;
const res = await runCodeInVM(code);
if (typeof res !== 'number') {
return -1;
}
return res;
},
};
async function runCodeInVM(_code: string) {
const isolate = new ivm.Isolate({ memoryLimit: env.sandboxMemoryLimit });
const code = `${environmentScript}\n\n;(async () => {${_code}})()`;
const [context, script] = await Promise.all([
isolate.createContext(),
isolate.compileScript(code),
]);
buildSandbox(context);
const res = await script.run(context, {
promise: true,
});
context.release();
script.release();
return res;
}

View File

@ -2,9 +2,11 @@ import { http } from './http';
import { ping } from './ping'; import { ping } from './ping';
import { openai } from './openai'; import { openai } from './openai';
import type { MonitorProvider } from './type'; import type { MonitorProvider } from './type';
import { custom } from './custom';
export const monitorProviders: Record<string, MonitorProvider<any>> = { export const monitorProviders: Record<string, MonitorProvider<any>> = {
ping, ping,
http, http,
openai, openai,
custom,
}; };

View File

@ -3,6 +3,9 @@ export const env = {
allowOpenapi: checkEnvTrusty(process.env.ALLOW_OPENAPI), allowOpenapi: checkEnvTrusty(process.env.ALLOW_OPENAPI),
websiteId: process.env.WEBSITE_ID, websiteId: process.env.WEBSITE_ID,
serverUrl: process.env.SERVER_URL, // example: https://tianji.example.com serverUrl: process.env.SERVER_URL, // example: https://tianji.example.com
sandboxMemoryLimit: process.env.SANDBOX_MEMORY_LIMIT
? Number(process.env.SANDBOX_MEMORY_LIMIT)
: 16, // MB
}; };
export function checkEnvTrusty(env: string | undefined): boolean { export function checkEnvTrusty(env: string | undefined): boolean {

174
src/server/utils/sandbox.ts Normal file
View File

@ -0,0 +1,174 @@
import axios, { AxiosRequestConfig } from 'axios';
import EventEmitter from 'events';
import ivm, { Context } from 'isolated-vm';
function isTransferable(data: any): data is ivm.Transferable {
const dataType = typeof data;
if (data === ivm) {
return true;
}
if (
['null', 'undefined', 'string', 'number', 'boolean', 'function'].includes(
dataType
)
) {
return true;
}
if (dataType !== 'object') {
return false;
}
return (
data instanceof ivm.Isolate ||
data instanceof ivm.Context ||
data instanceof ivm.Script ||
data instanceof ivm.ExternalCopy ||
data instanceof ivm.Callback ||
data instanceof ivm.Reference
);
}
function proxyObject(
obj: Record<string, any>,
forbiddenKeys: string[] = []
): Record<string, any> {
return copyObject({
isProxy: true,
get: (key: string) => {
if (forbiddenKeys.includes(key)) {
return undefined;
}
const value = obj[key];
if (typeof value === 'function') {
return new ivm.Reference(async (...args: any[]) => {
const result = (obj[key] as any)(...args);
if (result && result instanceof Promise) {
return new Promise(async (resolve, reject) => {
try {
const awaitedResult = await result;
resolve(makeTransferable(awaitedResult));
} catch (e) {
reject(e);
}
});
}
return makeTransferable(result);
});
}
return makeTransferable(value);
},
});
}
// Semi-transferable data can be copied with an ivm.ExternalCopy without needing any manipulation.
function isSemiTransferable(data: any) {
return data instanceof ArrayBuffer;
}
export function copyObject(
obj: Record<string, any> | any[]
): Record<string, any> | any[] {
if (Array.isArray(obj)) {
return obj.map((data) => copyData(data));
}
if (obj instanceof Response) {
return proxyObject(obj, ['clone']);
}
if (isSemiTransferable(obj)) {
return obj;
}
if (typeof obj[Symbol.iterator as any] === 'function') {
return copyObject(Array.from(obj as any));
}
if (obj instanceof EventEmitter) {
return {};
}
const keys = Object.keys(obj);
return {
...Object.fromEntries(
keys.map((key) => {
const data = obj[key];
if (typeof data === 'function') {
return [key, new ivm.Callback((...args: any[]) => obj[key](...args))];
}
return [key, copyData(data)];
})
),
};
}
function copyData<T extends ivm.Transferable | Record<string, any> | any[]>(
data: T
) {
return isTransferable(data) ? data : copyObject(data);
}
function makeTransferable(data: any) {
return isTransferable(data)
? data
: new ivm.ExternalCopy(copyObject(data)).copyInto();
}
export function buildSandbox(context: Context) {
const jail = context.global;
jail.setSync('global', jail.derefInto());
jail.setSync('ivm', ivm);
jail.setSync('console', makeTransferable(console));
jail.setSync(
'_request',
new ivm.Reference(async (config: AxiosRequestConfig) => {
const result = await axios.request(config);
return makeTransferable({
data: result.data,
status: result.status,
});
})
);
}
export const environmentScript = `
const reproxy = (reference) => {
return new Proxy(reference, {
get(target, p, receiver) {
if (target !== reference || p === 'then') {
return Reflect.get(target, p, receiver);
}
const data = reference.get(p);
if (typeof data === 'object' && data instanceof ivm.Reference && data.typeof === 'function') {
return (...args) => data.apply(undefined, args, { arguments: { copy: true }, result: { promise: true } });
}
return data;
}
});
};
const request = async (...args) => {
const result = await _request.apply(undefined, args, { arguments: { copy: true }, result: { promise: true } });
if (result && typeof result === 'object' && result.isProxy) {
return reproxy(result);
}
return result;
};
`;

View File

@ -53,7 +53,7 @@ export function initSocketio(httpServer: HTTPServer) {
} }
socket.onAny((eventName, eventData, callback) => { socket.onAny((eventName, eventData, callback) => {
console.log('[Socket] receive:', { eventName, eventData }); // console.log('[Socket] receive:', { eventName, eventData });
socketEventBus.emit(eventName, eventData, socket, callback); socketEventBus.emit(eventName, eventData, socket, callback);
}); });
}); });