修复脚本导包
This commit is contained in:
@@ -8,6 +8,10 @@ import { db } from '@/lib/db';
|
|||||||
const SOURCE_SCRIPT_REGISTRY_KEY = 'source-script:registry';
|
const SOURCE_SCRIPT_REGISTRY_KEY = 'source-script:registry';
|
||||||
const DEFAULT_TIMEOUT_MS = 20000;
|
const DEFAULT_TIMEOUT_MS = 20000;
|
||||||
|
|
||||||
|
// 绕过 webpack 静态分析,获取真正的 Node.js require
|
||||||
|
// eslint-disable-next-line no-eval
|
||||||
|
const _nodeRequire = eval('require') as NodeRequire;
|
||||||
|
|
||||||
// ---- 内存缓存 ----
|
// ---- 内存缓存 ----
|
||||||
let _registryCache: { data: SourceScriptRegistry; ts: number } | null = null;
|
let _registryCache: { data: SourceScriptRegistry; ts: number } | null = null;
|
||||||
const REGISTRY_CACHE_TTL_MS = 5_000;
|
const REGISTRY_CACHE_TTL_MS = 5_000;
|
||||||
@@ -188,24 +192,6 @@ function assertScriptKey(key: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function assertSafeCode(code: string) {
|
|
||||||
const blockedPatterns = [
|
|
||||||
/\brequire\s*\(/,
|
|
||||||
/\bprocess\./,
|
|
||||||
/\bchild_process\b/,
|
|
||||||
/\bfs\b/,
|
|
||||||
/\bimport\s*\(/,
|
|
||||||
/\beval\s*\(/,
|
|
||||||
/\bnew\s+Function\b/,
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const pattern of blockedPatterns) {
|
|
||||||
if (pattern.test(code)) {
|
|
||||||
throw new Error(`脚本包含不允许的用法: ${pattern}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createLogCollector() {
|
function createLogCollector() {
|
||||||
const logs: string[] = [];
|
const logs: string[] = [];
|
||||||
|
|
||||||
@@ -313,17 +299,10 @@ function createUtils() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createScriptFactory(code: string) {
|
function createScriptFactory(code: string) {
|
||||||
assertSafeCode(code);
|
|
||||||
|
|
||||||
return new Function(
|
return new Function(
|
||||||
`"use strict";
|
'require',
|
||||||
const process = undefined;
|
`"use strict";\n${code}`
|
||||||
const require = undefined;
|
) as (req: NodeRequire) => any;
|
||||||
const module = undefined;
|
|
||||||
const exports = undefined;
|
|
||||||
const fetch = undefined;
|
|
||||||
${code}`
|
|
||||||
) as () => any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createScriptContext(script: SourceScriptRecord, configValues?: Record<string, string>) {
|
async function createScriptContext(script: SourceScriptRecord, configValues?: Record<string, string>) {
|
||||||
@@ -462,7 +441,7 @@ function getOrCompileScript(script: SourceScriptRecord) {
|
|||||||
if (cached) return cached;
|
if (cached) return cached;
|
||||||
|
|
||||||
const factory = createScriptFactory(script.code);
|
const factory = createScriptFactory(script.code);
|
||||||
const compiled = normalizeScript(factory());
|
const compiled = normalizeScript(factory(_nodeRequire));
|
||||||
|
|
||||||
if (_compiledCache.size >= MAX_COMPILED_CACHE_SIZE) {
|
if (_compiledCache.size >= MAX_COMPILED_CACHE_SIZE) {
|
||||||
const firstKey = _compiledCache.keys().next().value;
|
const firstKey = _compiledCache.keys().next().value;
|
||||||
@@ -550,7 +529,6 @@ export async function saveSourceScript(input: {
|
|||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
}) {
|
}) {
|
||||||
assertScriptKey(input.key);
|
assertScriptKey(input.key);
|
||||||
assertSafeCode(input.code);
|
|
||||||
|
|
||||||
const registry = await loadRegistry();
|
const registry = await loadRegistry();
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
@@ -602,7 +580,6 @@ export async function importSourceScripts(items: SourceScriptImportItem[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertScriptKey(item.key);
|
assertScriptKey(item.key);
|
||||||
assertSafeCode(item.code);
|
|
||||||
|
|
||||||
const existing = registry.items.find((record) => record.key === item.key);
|
const existing = registry.items.find((record) => record.key === item.key);
|
||||||
|
|
||||||
@@ -682,7 +659,7 @@ export async function testSourceScript(input: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const factory = createScriptFactory(input.code);
|
const factory = createScriptFactory(input.code);
|
||||||
const compiled = normalizeScript(factory());
|
const compiled = normalizeScript(factory(_nodeRequire));
|
||||||
const hook = compiled[input.hook];
|
const hook = compiled[input.hook];
|
||||||
if (typeof hook !== 'function') {
|
if (typeof hook !== 'function') {
|
||||||
throw new Error(`脚本未实现 ${input.hook} hook`);
|
throw new Error(`脚本未实现 ${input.hook} hook`);
|
||||||
|
|||||||
Reference in New Issue
Block a user