2025-03-15 14:12:58 +08:00

388 lines
11 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

utools.getAppVersion() < "2.6.1" && alert("请升级 uTools 至最新版本");
// -----------------------------------------------------------------
const fs = require("fs");
const os = require("os");
const child_process = require("child_process");
const iconv = require("iconv-lite");
const electron = require("electron");
const path = require("path");
const axios = require("axios");
const http = require("http");
const https = require("https");
const url = require("url");
const crypto = require("crypto");
const DOMPurify = require("dompurify");
require("ses");
const md5 = (input) => {
return crypto.createHash("md5").update(input, "utf8").digest("hex");
};
window.lodashM = require("./lib/lodashMini");
window.pinyinMatch = require("pinyin-match");
window.DOMPurify = DOMPurify;
const createTerminalCommand = require("./lib/createTerminalCommand");
const shortCodes = require("./lib/shortCodes");
const { pluginInfo, getUtoolsPlugins } = require("./lib/getUtoolsPlugins");
const {
resolveFileToBase64,
getFileInfo,
getCurrentFolderPathFix,
saveFile,
getSelectFile,
convertFilePathToUtoolsPayload,
} = require("./lib/utils");
window.pluginInfo = pluginInfo;
window.getUtoolsPlugins = getUtoolsPlugins;
window.resolveFileToBase64 = resolveFileToBase64;
window.getFileInfo = getFileInfo;
window.getCurrentFolderPathFix = getCurrentFolderPathFix;
window.saveFile = saveFile;
window.getSelectFile = getSelectFile;
window.convertFilePathToUtoolsPayload = convertFilePathToUtoolsPayload;
window.getuToolsLite = require("./lib/utoolsLite");
window.quickcommand = require("./lib/quickcommand");
window.quickcomposer = require("./lib/quickcomposer");
window.showUb = require("./lib/showDocs");
window.getQuickcommandTempFile =
require("./lib/getQuickcommandFile").getQuickcommandTempFile;
window.getSharedQcById = async (id) => {
const url = "https://qc.qaz.ink/home/quick/script/getScript";
const timeStamp = parseInt(new Date().getTime() / 1000);
const { data } = await axios.get(url, {
params: {
id,
},
headers: {
"verify-encrypt": md5("quickcommand666" + timeStamp),
"verify-time": timeStamp,
},
});
return JSON.stringify(data.data);
};
// 检测进程是否存在
let isProcessExits = (pid) => {
try {
return process.kill(pid, 0);
} catch (e) {
return false;
}
};
window.isAppVersion4 = () => utools.getAppVersion() >= "4.0.0";
// 多开检测
window.multiProcessDetection = () => {
let pids = JSON.parse(localStorage.getItem("processes")) || [];
if (pids.length) pids = pids.filter((x) => isProcessExits(x));
pids.push(process.pid);
localStorage.setItem("processes", JSON.stringify(pids));
if (pids.length > 1) return true;
return false;
};
/**
* 忘了为什么之前注释下面的语句了 -_-!,保留浏览器的 axios
* axios.defaults.adapter = require('axios/lib/adapters/http')
* 另外创建一个 node 的 axios
*/
const nodeAxios = axios.create({
httpAgent: new http.Agent(),
httpsAgent: new https.Agent({
rejectUnauthorized: false,
}),
});
nodeAxios.defaults.adapter = "http";
if (!window.utools.isWindows())
process.env.PATH = `/usr/local/bin:/usr/local/sbin:${process.env.PATH}`;
if (window.utools.isMacOS())
process.env.PATH = `/opt/homebrew/bin:/opt/homebrew/sbin:${process.env.PATH}`;
window.htmlEncode = (value) => {
let dom = quickcommand.htmlParse().querySelector("body");
dom.innerText = value;
return dom.innerHTML;
};
window.removeHtmlTags = (value) => {
return quickcommand.htmlParse(value).querySelector("body").innerText;
};
window.hexEncode = (text) => Buffer.from(text, "utf8").toString("hex");
window.hexDecode = (text) => Buffer.from(text, "hex").toString("utf8");
window.base64Decode = (text) => Buffer.from(text, "base64").toString("utf8");
window.processPlatform = process.platform;
window.joinPath = path.join;
window.clipboardReadText = () => electron.clipboard.readText();
let getSandboxFuns = () => {
var sandbox = {
fetch: fetch.bind(window),
utools: window.getuToolsLite(),
electron,
axios: nodeAxios,
Audio,
AbortController,
AbortSignal,
Buffer,
require,
// 兼容老版本
fs,
path,
os,
child_process,
quickcomposer,
// timeout
setTimeout: quickcommand.setTimeout,
clearTimeout: quickcommand.clearTimeout,
};
Object.keys(shortCodes).forEach((f) => {
sandbox[f] = shortCodes[f];
});
return sandbox;
};
// 简化报错信息
let liteErr = (e) => {
if (!e) return;
if (typeof e === "string") return e;
return e.error
? e.error.stack.replace(/([ ] +at.+)|(.+\.js:\d+)/g, "").trim()
: e.message;
};
// vm 模块将无法在渲染进程中使用,改用 ses 来执行代码
window.evalCodeInSandbox = (code, addVars = {}) => {
let sandboxWithAD = Object.assign(addVars, getSandboxFuns());
sandboxWithAD.quickcommand = window.lodashM.cloneDeep(quickcommand);
try {
return new Compartment(sandboxWithAD).evaluate(code);
} catch (error) {
throw liteErr(error);
}
};
let isWatchingError = false;
window.runCodeInSandbox = (code, callback, addVars = {}) => {
let sandbox = getSandboxFuns();
sandbox.console = {
log: (...stdout) => {
console.log("Result:", stdout);
callback(stdout, null);
},
error: (...stderr) => {
callback(null, stderr);
},
clear: () => {
callback({ __clearQuickcommandRunResult: true }, null);
},
};
let sandboxWithAD = Object.assign(addVars, sandbox);
sandboxWithAD.quickcommand = window.lodashM.cloneDeep(quickcommand);
if (addVars.enterData) {
sandboxWithAD.quickcommand.enterData = addVars.enterData;
sandboxWithAD.quickcommand.payload = addVars.enterData.payload;
}
try {
new Compartment(sandboxWithAD).evaluate(code);
} catch (e) {
console.log("Error: ", e);
callback(null, liteErr(e));
}
// 自动捕捉错误
let cbUnhandledError = (e) => {
removeAllListener();
console.log("UnhandledError: ", e);
callback(null, liteErr(e));
};
let cbUnhandledRejection = (e) => {
removeAllListener();
console.log("UnhandledRejection: ", e);
callback(null, liteErr(e.reason));
};
let removeAllListener = () => {
window.removeEventListener("error", cbUnhandledError);
window.removeEventListener("unhandledrejection", cbUnhandledRejection);
isWatchingError = false;
};
if (!isWatchingError) {
window.addEventListener("error", cbUnhandledError);
window.addEventListener("unhandledrejection", cbUnhandledRejection);
isWatchingError = true;
}
};
// 构建命令行字符串的工具函数
const buildCommandLine = (bin, argv, script, scptarg) => {
if (bin.slice(-7) === "csc.exe") {
const outFile = script.slice(0, -2) + "exe";
return `${bin} ${argv} /out:"${outFile}" "${script}" && "${outFile}" ${scptarg}`;
}
if (bin === "gcc") {
const suffix = utools.isWindows() ? ".exe" : "";
const outFile = script.slice(0, -2) + suffix;
return `${bin} ${argv} "${script.slice(
0,
-2
)}" "${script}" && "${outFile}" ${scptarg}`;
}
if (utools.isWindows() && bin === "bash") {
const wslPath = script.replace(/\\/g, "/").replace(/C:/i, "/mnt/c");
return `wsl -e ${bin} ${argv} "${wslPath}" ${scptarg}`;
}
return `${bin} ${argv} "${script}" ${scptarg}`;
};
// 处理进程输出的工具函数
const handleProcessOutput = (child, charset, callback, realTime) => {
const chunks = [];
const errChunks = [];
child.stdout.on("data", (chunk) => {
const decodedChunk = charset.outputCode
? iconv.decode(chunk, charset.outputCode)
: chunk;
realTime
? callback(decodedChunk.toString(), null)
: chunks.push(decodedChunk);
});
child.stderr.on("data", (errChunk) => {
const decodedChunk = charset.outputCode
? iconv.decode(errChunk, charset.outputCode)
: errChunk;
realTime
? callback(null, decodedChunk.toString())
: errChunks.push(decodedChunk);
});
if (!realTime) {
child.on("close", () => {
callback(chunks.join(""), errChunks.join(""));
});
}
};
window.runCodeFile = (
cmd,
option,
terminalOptions,
callback,
realTime = true
) => {
const { bin, argv, ext, charset, scptarg, envPath, alias } = option;
const script = getQuickcommandTempFile(ext, "quickcommandTempScript");
// 处理编码和换行
const processedCmd = charset.scriptCode
? iconv.encode(cmd.replace(/\n/g, "\r\n"), charset.scriptCode)
: cmd;
fs.writeFileSync(script, processedCmd);
// 构建命令行
let cmdline = buildCommandLine(bin, argv, script, scptarg);
// 处理环境变量
const processEnv = window.lodashM.cloneDeep(process.env);
if (envPath) processEnv.PATH = envPath;
if (alias) cmdline = `${alias}\n${cmdline}`;
if (!!terminalOptions) {
cmdline = createTerminalCommand(cmdline, terminalOptions);
}
// 创建子进程
const child = child_process.spawn(cmdline, {
encoding: "buffer",
shell: true,
env: processEnv,
});
console.log("Running: " + cmdline);
handleProcessOutput(child, charset, callback, realTime);
return child;
};
const dbStorage = utools.dbStorage;
let httpServer;
window.quickcommandHttpServer = () => {
let run = (port = 33442) => {
let httpResponse = (res, code, result) => {
// 只收受一次 console.log接收后就关闭连接
if (res.finished) return;
res.writeHead(code, {
"Content-Type": "text/html",
});
if (result) res.write(result);
res.end();
};
let runUserCode = (res, userVars) => {
let cmd = dbStorage.getItem("cfg_serverCode");
// 不需要返回输出的提前关闭连接
if (!cmd.includes("console.log")) httpResponse(res, 200);
window.runCodeInSandbox(
cmd,
(stdout, stderr) => {
// 错误返回 500
if (stderr) return httpResponse(res, 500, stderr.join(" "));
return httpResponse(res, 200, stdout.join(" "));
},
userVars
);
};
httpServer = http.createServer();
httpServer.on("request", (req, res) => {
if (req.method === "GET") {
let parsedParams = window.lodashM.cloneDeep(
url.parse(req.url, true).query
);
runUserCode(res, parsedParams);
} else if (req.method === "POST") {
let data = [];
req.on("data", (chunk) => {
data.push(chunk);
});
req.on("end", () => {
let parsedParams;
let params = data.join("").toString();
// 先尝试作为 json 解析
try {
parsedParams = JSON.parse(params);
} catch (error) {
parsedParams = window.lodashM.cloneDeep(
url.parse("?" + params, true).query
);
}
runUserCode(res, parsedParams);
});
} else {
httpResponse(res, 405);
}
});
httpServer.listen(port, "localhost");
httpServer.on("error", (err) => {
utools.showNotification("快捷命令服务:", err);
});
};
let stop = () => {
if (!httpServer) return;
httpServer.close();
};
return {
run,
stop,
};
};