mirror of
https://github.com/whyour/qinglong.git
synced 2026-10-17 07:20:51 +08:00
* fix: harden scoped API inputs and isolate login throttling * fix: close script path gaps and harden security boundaries * fix: preserve subscription aliases and avoid extension eval * fix: allow cancelling invalid historical subscriptions * fix: make script parent validation explicit for CodeQL * fix: limit command execution and clarify trusted path branches * fix: separate diff tool script access from config APIs * fix: clean up obsolete subscription SSH credentials
127 lines
3.5 KiB
JavaScript
127 lines
3.5 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const test = require('node:test');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const vm = require('node:vm');
|
|
const ts = require('typescript');
|
|
|
|
const source = fs.readFileSync(
|
|
path.join(__dirname, '../../src/pages/diff/index.tsx'),
|
|
'utf8',
|
|
);
|
|
const ast = ts.createSourceFile(
|
|
'diff.tsx',
|
|
source,
|
|
ts.ScriptTarget.Latest,
|
|
true,
|
|
ts.ScriptKind.TSX,
|
|
);
|
|
const callbacks = new Map();
|
|
function visit(node) {
|
|
if (
|
|
ts.isVariableDeclaration(node) &&
|
|
['getConfig', 'updateConfig', 'getSample'].includes(node.name.getText(ast))
|
|
) {
|
|
callbacks.set(node.name.getText(ast), node.initializer.getText(ast));
|
|
}
|
|
ts.forEachChild(node, visit);
|
|
}
|
|
visit(ast);
|
|
|
|
function fixture(current, editorContent) {
|
|
const calls = [];
|
|
const values = {};
|
|
const context = {
|
|
current,
|
|
origin: 'sample/notify.js',
|
|
currentValue: '',
|
|
editorRef: {
|
|
current:
|
|
editorContent === undefined
|
|
? null
|
|
: {
|
|
getModel: () => ({ modified: { getValue: () => editorContent } }),
|
|
},
|
|
},
|
|
config: { apiPrefix: '/panel/api/' },
|
|
request: {
|
|
get: async (url) => {
|
|
calls.push({ method: 'GET', url });
|
|
return { code: 200, data: 'file content' };
|
|
},
|
|
post: async (url, body) => {
|
|
calls.push({ method: 'POST', url, body });
|
|
return { code: 200 };
|
|
},
|
|
},
|
|
setCurrentValue: (value) => {
|
|
values.current = value;
|
|
},
|
|
setOriginValue: (value) => {
|
|
values.origin = value;
|
|
},
|
|
message: {
|
|
success: (value) => {
|
|
values.message = value;
|
|
},
|
|
},
|
|
intl: { get: (value) => value },
|
|
};
|
|
vm.createContext(context);
|
|
for (const [name, initializer] of callbacks) {
|
|
vm.runInContext(
|
|
ts.transpile(`var ${name} = ${initializer}`, {
|
|
target: ts.ScriptTarget.ES2020,
|
|
}),
|
|
context,
|
|
);
|
|
}
|
|
return { context, calls, values };
|
|
}
|
|
|
|
for (const [target, filename] of [
|
|
['config.sh', null],
|
|
['data/scripts/sendNotify.js', 'sendNotify.js'],
|
|
['data/scripts/notify.py', 'notify.py'],
|
|
['data/scripts/子目录/a b.js', '子目录/a b.js'],
|
|
]) {
|
|
test(`diff tool reads and saves ${target} through its resource API`, async () => {
|
|
const { context, calls, values } = fixture(target, 'updated\r\n');
|
|
context.getConfig();
|
|
context.updateConfig();
|
|
await new Promise((resolve) => setImmediate(resolve));
|
|
assert.equal(
|
|
calls[0].url,
|
|
filename
|
|
? `/panel/api/scripts/detail?file=${encodeURIComponent(filename)}`
|
|
: '/panel/api/configs/detail?path=config.sh',
|
|
);
|
|
assert.equal(
|
|
calls[1].url,
|
|
filename ? '/panel/api/scripts' : '/panel/api/configs/save',
|
|
);
|
|
assert.equal(
|
|
calls[1].body[filename ? 'filename' : 'name'],
|
|
filename || target,
|
|
);
|
|
assert.equal(calls[1].body.content, 'updated\n');
|
|
assert.equal(values.current, 'file content');
|
|
assert.equal(values.message, '保存成功');
|
|
});
|
|
}
|
|
|
|
test('mobile diff tool can save an empty notification script and load its sample', async () => {
|
|
const { context, calls, values } = fixture('data/scripts/sendNotify.js');
|
|
context.updateConfig();
|
|
context.getSample();
|
|
await new Promise((resolve) => setImmediate(resolve));
|
|
assert.equal(calls[0].url, '/panel/api/scripts');
|
|
assert.equal(calls[0].body.filename, 'sendNotify.js');
|
|
assert.equal(calls[0].body.content, '');
|
|
assert.equal(
|
|
calls[1].url,
|
|
'/panel/api/configs/detail?path=sample%2Fnotify.js',
|
|
);
|
|
assert.equal(values.origin, 'file content');
|
|
});
|