koishi-plugin-freekill-u 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +540 -55
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
};
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
|
|
19
|
-
// src/index.ts
|
|
19
|
+
// packages/freekill-u/src/index.ts
|
|
20
20
|
var src_exports = {};
|
|
21
21
|
__export(src_exports, {
|
|
22
22
|
Config: () => Config,
|
|
@@ -29,40 +29,76 @@ var import_koishi = require("koishi");
|
|
|
29
29
|
var { Client } = require("ssh2");
|
|
30
30
|
var name = "freekill-u";
|
|
31
31
|
var Config = import_koishi.Schema.object({
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
servers: import_koishi.Schema.array(import_koishi.Schema.object({
|
|
33
|
+
name: import_koishi.Schema.string().description('\u670D\u52A1\u5668\u540D\u79F0\uFF08\u7528\u4F5C\u547D\u4EE4\u524D\u7F00\uFF0C\u5982"\u5B98\u670D"\u5219\u547D\u4EE4\u4E3A \u5B98\u670D.u / \u5B98\u670D.stat \u7B49\uFF09').required(),
|
|
34
|
+
host: import_koishi.Schema.string().description("SSH \u670D\u52A1\u5668 IP").default(""),
|
|
35
|
+
port: import_koishi.Schema.number().description("SSH \u7AEF\u53E3").default(22).min(1).max(65535),
|
|
36
|
+
username: import_koishi.Schema.string().description("SSH \u7528\u6237\u540D").default(""),
|
|
37
|
+
password: import_koishi.Schema.string().role("secret").description("SSH \u5BC6\u7801").default(""),
|
|
38
|
+
screenSession: import_koishi.Schema.string().description("screen \u4F1A\u8BDD\u6807\u8BC6\uFF08\u591A\u4E2A screen \u65F6\u586B\u5199\uFF0C\u7559\u7A7A\u5219\u7528 screen -r \u9ED8\u8BA4\u9009\u62E9\uFF09").default(""),
|
|
39
|
+
updateCommand: import_koishi.Schema.string().description("\u66F4\u65B0\u547D\u4EE4\uFF08\u5728\u65B0\u6708\u6740\u547D\u4EE4\u884C\u8F93\u5165\u7684\u6307\u4EE4\uFF09").default("u"),
|
|
40
|
+
operators: import_koishi.Schema.string().description("\u64CD\u4F5C\u5458 QQ \u53F7\u767D\u540D\u5355\uFF08\u591A\u4E2A\u7528\u9017\u53F7/\u7A7A\u683C\u5206\u9694\uFF0C\u7559\u7A7A\u5219\u4E0D\u9650\u5236\uFF09\u3002\u4E0D\u5728\u767D\u540D\u5355\u5185\u7684\u7528\u6237\u6267\u884C\u547D\u4EE4\u65F6\u9759\u9ED8\u5FFD\u7565").default(""),
|
|
41
|
+
attachDelay: import_koishi.Schema.number().description("screen -r \u540E\u7B49\u5F85 attach \u7684\u6BEB\u79D2\u6570").default(3e3).min(500).max(3e4),
|
|
42
|
+
updateWait: import_koishi.Schema.number().description("\u53D1\u9001\u66F4\u65B0\u547D\u4EE4\u540E\u7B49\u5F85\u8F93\u51FA\u7684\u6BEB\u79D2\u6570").default(3e4).min(5e3).max(3e5),
|
|
43
|
+
quitWait: import_koishi.Schema.number().description("\u53D1\u9001 quit \u540E\u7B49\u5F85\u670D\u52A1\u5668\u5173\u95ED\u7684\u6BEB\u79D2\u6570").default(5e3).min(2e3).max(6e4),
|
|
44
|
+
restartWait: import_koishi.Schema.number().description("\u53D1\u9001\u542F\u52A8\u547D\u4EE4\u540E\u7B49\u5F85\u670D\u52A1\u5668\u542F\u52A8\u7684\u6BEB\u79D2\u6570").default(6e4).min(1e4).max(3e5),
|
|
45
|
+
commandWait: import_koishi.Schema.number().description("\u666E\u901A\u67E5\u8BE2\u547D\u4EE4\u7B49\u5F85\u8F93\u51FA\u7684\u6BEB\u79D2\u6570").default(3e3).min(1e3).max(3e4)
|
|
46
|
+
})).description("\u670D\u52A1\u5668\u5217\u8868\uFF0C\u6BCF\u4E2A\u670D\u52A1\u5668\u5BF9\u5E94\u4E00\u7EC4 SSH \u8FDE\u63A5\u4FE1\u606F\u548C\u547D\u4EE4\u524D\u7F00").default([]),
|
|
47
|
+
authority: import_koishi.Schema.number().description("\u4F7F\u7528\u547D\u4EE4\u6240\u9700\u7684\u6700\u4F4E\u6743\u9650\u7B49\u7EA7").default(4).min(1).max(5),
|
|
41
48
|
debugMode: import_koishi.Schema.boolean().description("\u8C03\u8BD5\u6A21\u5F0F\uFF1A\u663E\u793A\u5B8C\u6574 SSH \u8F93\u51FA\uFF08\u542B\u654F\u611F\u5185\u5BB9\uFF0C\u4EC5\u8C03\u8BD5\u65F6\u5F00\u542F\uFF09").default(false)
|
|
42
49
|
});
|
|
43
50
|
var usage = `
|
|
44
|
-
# \u65B0\u6708\u6740\u8FDC\u7A0B\
|
|
51
|
+
# \u65B0\u6708\u6740\u8FDC\u7A0B\u7BA1\u7406\u63D2\u4EF6
|
|
45
52
|
|
|
46
|
-
\u901A\u8FC7 SSH \u8FDE\u63A5\u670D\u52A1\u5668\uFF0C\u81EA\u52A8\u8FDB\u5165 screen \u4F1A\u8BDD\u6267\u884C\
|
|
53
|
+
\u901A\u8FC7 SSH \u8FDE\u63A5\u670D\u52A1\u5668\uFF0C\u81EA\u52A8\u8FDB\u5165 screen \u4F1A\u8BDD\u6267\u884C\u7BA1\u7406\u547D\u4EE4\u3002
|
|
47
54
|
\u5371\u9669\u64CD\u4F5C\uFF0C\u8BF7\u52A1\u5FC5\u8BBE\u7F6E\u8DB3\u591F\u7684\u6743\u9650\u7B49\u7EA7\u3002
|
|
48
55
|
|
|
49
|
-
## \
|
|
56
|
+
## \u914D\u7F6E\u65B9\u6CD5
|
|
50
57
|
|
|
51
|
-
\u5728\
|
|
58
|
+
\u5728\u63D2\u4EF6\u914D\u7F6E\u4E2D\u6DFB\u52A0\u670D\u52A1\u5668\u5217\u8868\uFF0C\u6BCF\u4E2A\u670D\u52A1\u5668\u914D\u7F6E\uFF1A
|
|
59
|
+
- **\u540D\u79F0**\uFF1A\u7528\u4F5C\u547D\u4EE4\u524D\u7F00\uFF0C\u5982\u586B\u5199"\u5B98\u670D"\uFF0C\u5219\u547D\u4EE4\u4E3A **\u5B98\u670D.u**\u3001**\u5B98\u670D.stat** \u7B49
|
|
60
|
+
- **SSH \u4FE1\u606F**\uFF1A\u4E3B\u673A\u3001\u7AEF\u53E3\u3001\u7528\u6237\u540D\u3001\u5BC6\u7801
|
|
61
|
+
- **screen \u4F1A\u8BDD**\uFF1A\u6709\u591A\u4E2A screen \u65F6\u586B\u5199\u4F1A\u8BDD\u6807\u8BC6
|
|
62
|
+
- **\u64CD\u4F5C\u5458\u767D\u540D\u5355**\uFF1A\u586B\u5199 QQ \u53F7\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u4E0D\u5728\u767D\u540D\u5355\u5185\u7684\u7528\u6237\u6267\u884C\u547D\u4EE4\u65F6 bot \u9759\u9ED8\u4E0D\u54CD\u5E94
|
|
52
63
|
|
|
53
|
-
## \
|
|
64
|
+
## \u547D\u4EE4\u5217\u8868
|
|
54
65
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
66
|
+
\u6240\u6709\u547D\u4EE4\u683C\u5F0F\uFF1A\`\u670D\u52A1\u5668\u540D.\u5B50\u547D\u4EE4\`
|
|
67
|
+
|
|
68
|
+
| \u547D\u4EE4 | \u522B\u540D | \u8BF4\u660E |
|
|
69
|
+
|------|------|------|
|
|
70
|
+
| \`\u670D\u52A1\u5668.u\` | \u2014 | \u8FDC\u7A0B\u66F4\u65B0\u670D\u52A1\u5668 |
|
|
71
|
+
| \`\u670D\u52A1\u5668.r\` | \u2014 | \u8FDC\u7A0B\u91CD\u542F\u670D\u52A1\u5668 |
|
|
72
|
+
| \`\u670D\u52A1\u5668.stat\` | \u2014 | \u67E5\u770B\u8FD0\u884C\u72B6\u6001 |
|
|
73
|
+
| \`\u670D\u52A1\u5668.reloadconf\` | \`.r\` (\u91CD\u8F7D) | \u91CD\u8F7D\u914D\u7F6E\u6587\u4EF6 |
|
|
74
|
+
| \`\u670D\u52A1\u5668.lsplayer\` | \u2014 | \u67E5\u770B\u5728\u7EBF\u73A9\u5BB6 |
|
|
75
|
+
| \`\u670D\u52A1\u5668.lsroom [id]\` | \u2014 | \u67E5\u770B\u623F\u95F4\u5217\u8868 |
|
|
76
|
+
| \`\u670D\u52A1\u5668.msg <\u5185\u5BB9>\` | \`.m\` | \u53D1\u5168\u4F53\u516C\u544A |
|
|
77
|
+
| \`\u670D\u52A1\u5668.msgroom <\u623F\u95F4> <\u5185\u5BB9>\` | \`.mr\` | \u5411\u623F\u95F4\u53D1\u6D88\u606F |
|
|
78
|
+
| \`\u670D\u52A1\u5668.kick <\u73A9\u5BB6>\` | \u2014 | \u8E22\u51FA\u73A9\u5BB6 |
|
|
79
|
+
| \`\u670D\u52A1\u5668.killroom <\u623F\u95F4>\` | \u2014 | \u5E9F\u5F03\u623F\u95F4 |
|
|
80
|
+
| \`\u670D\u52A1\u5668.checklobby\` | \u2014 | \u6E05\u5927\u5385\u50F5\u5C38 |
|
|
81
|
+
| \`\u670D\u52A1\u5668.ban <\u76EE\u6807>\` | \u2014 | \u5C01\u7981\u8D26\u53F7 |
|
|
82
|
+
| \`\u670D\u52A1\u5668.unban <\u76EE\u6807>\` | \u2014 | \u89E3\u5C01\u8D26\u53F7 |
|
|
83
|
+
| \`\u670D\u52A1\u5668.banip <IP>\` | \u2014 | \u5C01\u7981 IP |
|
|
84
|
+
| \`\u670D\u52A1\u5668.unbanip <IP>\` | \u2014 | \u89E3\u5C01 IP |
|
|
85
|
+
| \`\u670D\u52A1\u5668.banuuid <UUID>\` | \u2014 | \u5C01\u7981 UUID |
|
|
86
|
+
| \`\u670D\u52A1\u5668.unbanuuid <UUID>\` | \u2014 | \u89E3\u5C01 UUID |
|
|
87
|
+
| \`\u670D\u52A1\u5668.tempban <\u76EE\u6807> <\u65F6\u957F>\` | \u2014 | \u4E34\u65F6\u5C01\u7981 |
|
|
88
|
+
| \`\u670D\u52A1\u5668.tempmute <\u76EE\u6807> <\u65F6\u957F>\` | \u2014 | \u4E34\u65F6\u7981\u8A00 |
|
|
89
|
+
| \`\u670D\u52A1\u5668.unmute <\u76EE\u6807>\` | \u2014 | \u89E3\u9664\u7981\u8A00 |
|
|
90
|
+
| \`\u670D\u52A1\u5668.whitelist <\u64CD\u4F5C>\` | \u2014 | \u7BA1\u7406\u767D\u540D\u5355 |
|
|
91
|
+
| \`\u670D\u52A1\u5668.resetpassword <\u8D26\u53F7>\` | \`.rp\` | \u91CD\u7F6E\u5BC6\u7801 |
|
|
92
|
+
| \`\u670D\u52A1\u5668.pkgs\` | \u2014 | \u67E5\u770B\u6269\u5C55\u5305 |
|
|
93
|
+
| \`\u670D\u52A1\u5668.syncpkgs\` | \u2014 | \u540C\u6B65\u6269\u5C55\u5305 |
|
|
94
|
+
| \`\u670D\u52A1\u5668.install <URL>\` | \u2014 | \u5B89\u88C5\u6269\u5C55\u5305 |
|
|
95
|
+
| \`\u670D\u52A1\u5668.remove <\u540D\u79F0>\` | \u2014 | \u79FB\u9664\u6269\u5C55\u5305 |
|
|
96
|
+
| \`\u670D\u52A1\u5668.enable <\u540D\u79F0>\` | \u2014 | \u542F\u7528\u6269\u5C55\u5305 |
|
|
97
|
+
| \`\u670D\u52A1\u5668.disable <\u540D\u79F0>\` | \u2014 | \u7981\u7528\u6269\u5C55\u5305 |
|
|
62
98
|
|
|
63
99
|
## \u6CE8\u610F\u4E8B\u9879
|
|
64
100
|
|
|
65
|
-
- screen \u4F1A\u8BDD\u5FC5\u987B\u662F **detached** \u72B6\u6001
|
|
101
|
+
- screen \u4F1A\u8BDD\u5FC5\u987B\u662F **detached** \u72B6\u6001
|
|
66
102
|
- \u672C\u63D2\u4EF6\u6D89\u53CA\u670D\u52A1\u5668\u5B89\u5168\uFF0C\u8BF7\u52A1\u5FC5\u8BBE\u7F6E\u8DB3\u591F\u7684\u6743\u9650\u7B49\u7EA7
|
|
67
103
|
|
|
68
104
|
## \u53CD\u9988\u6E20\u9053
|
|
@@ -70,47 +106,289 @@ QQ \u7FA4\uFF1A1078815356
|
|
|
70
106
|
`;
|
|
71
107
|
function apply(ctx, config) {
|
|
72
108
|
const logger = ctx.logger("freekill-u");
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
109
|
+
for (const server of config.servers) {
|
|
110
|
+
registerServerCommands(ctx, config, server, logger);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function registerServerCommands(ctx, config, server, logger) {
|
|
114
|
+
const prefix = server.name;
|
|
115
|
+
function checkAuth(session) {
|
|
116
|
+
if (!server.host || !server.username) return `\u26A0\uFE0F [${prefix}] \u8BF7\u5148\u5728\u63D2\u4EF6\u914D\u7F6E\u4E2D\u586B\u5199 SSH \u8FDE\u63A5\u4FE1\u606F\u3002`;
|
|
117
|
+
if (server.operators && server.operators.trim()) {
|
|
118
|
+
const allowedIds = server.operators.split(/[,,\s]+/).map((s) => s.trim()).filter(Boolean);
|
|
119
|
+
if (allowedIds.length > 0) {
|
|
120
|
+
const userId = session.userId || "";
|
|
121
|
+
if (!allowedIds.includes(userId)) return void 0;
|
|
122
|
+
}
|
|
76
123
|
}
|
|
77
124
|
const userAuthority = session.user?.authority ?? 0;
|
|
78
|
-
if (userAuthority < config.authority) {
|
|
79
|
-
|
|
80
|
-
|
|
125
|
+
if (userAuthority < config.authority) return `\u26A0\uFE0F \u6743\u9650\u4E0D\u8DB3\uFF0C\u9700\u8981\u7B49\u7EA7 ${config.authority} \u4EE5\u4E0A\u3002`;
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
async function execShellCmd(session, shellCmd, label) {
|
|
81
129
|
const startTime = Date.now();
|
|
82
|
-
await session.send("\u{1F50C} \u6B63\u5728\u8FDE\u63A5\u670D\u52A1\u5668\u2026");
|
|
83
130
|
try {
|
|
84
|
-
const result = await
|
|
131
|
+
const result = await executeShellCommand(shellCmd, server);
|
|
85
132
|
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
86
|
-
const
|
|
87
|
-
if (
|
|
88
|
-
|
|
133
|
+
const output = cleanShellOutput(result.output);
|
|
134
|
+
if (output.length > 1500) {
|
|
135
|
+
return `\u{1F4CB} [${prefix}] ${label}
|
|
136
|
+
\u23F1 ${elapsed}s
|
|
137
|
+
|
|
138
|
+
${output.slice(-1500)}
|
|
139
|
+
\u2026\uFF08\u8F93\u51FA\u5DF2\u622A\u65AD\uFF09`;
|
|
89
140
|
}
|
|
141
|
+
return `\u{1F4CB} [${prefix}] ${label}
|
|
142
|
+
\u23F1 ${elapsed}s
|
|
143
|
+
|
|
144
|
+
${output || "(\u65E0\u8F93\u51FA)"}`;
|
|
145
|
+
} catch (e) {
|
|
146
|
+
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
147
|
+
logger.warn("Shell\u547D\u4EE4\u5931\u8D25", { server: prefix, cmd: shellCmd, error: e?.message || String(e) });
|
|
148
|
+
return `\u274C [${prefix}] ${label} \u5931\u8D25\uFF08${elapsed}s\uFF09\uFF1A${e?.message || String(e)}`;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
ctx.command(`${prefix}`, `${prefix} \u670D\u52A1\u5668\u7BA1\u7406`);
|
|
152
|
+
ctx.command(`${prefix}.u`, `\u66F4\u65B0 ${prefix} \u670D\u52A1\u5668`).userFields(["authority"]).action(async ({ session }) => {
|
|
153
|
+
const err = checkAuth(session);
|
|
154
|
+
if (err === void 0) return;
|
|
155
|
+
if (err) return err;
|
|
156
|
+
const startTime = Date.now();
|
|
157
|
+
await session.send(`\u{1F50C} [${prefix}] \u6B63\u5728\u8FDE\u63A5\u670D\u52A1\u5668\u2026`);
|
|
158
|
+
try {
|
|
159
|
+
const result = await executeUpdate(server);
|
|
160
|
+
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
161
|
+
const lines = [`\u2705 [${prefix}] \u66F4\u65B0\u5B8C\u6210\uFF01`, `\u23F1 \u8017\u65F6 ${elapsed} \u79D2`];
|
|
162
|
+
if (result.hasError) lines.push("\u26A0\uFE0F \u68C0\u6D4B\u5230\u53EF\u80FD\u7684\u9519\u8BEF\uFF0C\u5EFA\u8BAE\u68C0\u67E5\u670D\u52A1\u5668\u65E5\u5FD7\u3002");
|
|
90
163
|
if (config.debugMode && result.output) {
|
|
91
164
|
let output = filterSensitive(result.output);
|
|
92
|
-
if (output.length > 2e3)
|
|
93
|
-
output = output.slice(-2e3) + "\n\u2026\uFF08\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u4EC5\u663E\u793A\u672B\u5C3E 2000 \u5B57\u7B26\uFF09";
|
|
94
|
-
}
|
|
165
|
+
if (output.length > 2e3) output = output.slice(-2e3) + "\n\u2026\uFF08\u8F93\u51FA\u5DF2\u622A\u65AD\uFF09";
|
|
95
166
|
lines.push(`
|
|
96
167
|
\u{1F4CB} \u66F4\u65B0\u8F93\u51FA\uFF1A
|
|
97
168
|
${output}`);
|
|
98
169
|
}
|
|
99
|
-
if (result.hasError) {
|
|
100
|
-
|
|
170
|
+
if (result.hasError) logger.warn("\u66F4\u65B0\u53EF\u80FD\u5931\u8D25", { server: prefix, elapsed, lines: result.lineCount });
|
|
171
|
+
await session.send(lines.join("\n"));
|
|
172
|
+
} catch (e) {
|
|
173
|
+
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
174
|
+
logger.warn("\u66F4\u65B0\u5931\u8D25", { server: prefix, error: e?.message || String(e), elapsed });
|
|
175
|
+
await session.send(`\u274C [${prefix}] \u66F4\u65B0\u5931\u8D25\uFF08${elapsed}s\uFF09\uFF1A${e?.message || String(e)}`);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
ctx.command(`${prefix}.r`, `\u91CD\u542F ${prefix} \u670D\u52A1\u5668`).userFields(["authority"]).action(async ({ session }) => {
|
|
179
|
+
const err = checkAuth(session);
|
|
180
|
+
if (err === void 0) return;
|
|
181
|
+
if (err) return err;
|
|
182
|
+
const startTime = Date.now();
|
|
183
|
+
await session.send(`\u{1F50C} [${prefix}] \u6B63\u5728\u8FDE\u63A5\u670D\u52A1\u5668\u2026`);
|
|
184
|
+
try {
|
|
185
|
+
const result = await executeRestart(server);
|
|
186
|
+
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
187
|
+
const lines = [`\u2705 [${prefix}] \u91CD\u542F\u5B8C\u6210\uFF01`, `\u23F1 \u8017\u65F6 ${elapsed} \u79D2`];
|
|
188
|
+
if (result.hasError) lines.push("\u26A0\uFE0F \u68C0\u6D4B\u5230\u53EF\u80FD\u7684\u9519\u8BEF\uFF0C\u5EFA\u8BAE\u68C0\u67E5\u670D\u52A1\u5668\u65E5\u5FD7\u3002");
|
|
189
|
+
if (config.debugMode && result.output) {
|
|
190
|
+
let output = filterSensitive(result.output);
|
|
191
|
+
if (output.length > 2e3) output = output.slice(-2e3) + "\n\u2026\uFF08\u8F93\u51FA\u5DF2\u622A\u65AD\uFF09";
|
|
192
|
+
lines.push(`
|
|
193
|
+
\u{1F4CB} \u91CD\u542F\u8F93\u51FA\uFF1A
|
|
194
|
+
${output}`);
|
|
101
195
|
}
|
|
196
|
+
if (result.hasError) logger.warn("\u91CD\u542F\u53EF\u80FD\u5931\u8D25", { server: prefix, elapsed, lines: result.lineCount });
|
|
102
197
|
await session.send(lines.join("\n"));
|
|
103
198
|
} catch (e) {
|
|
104
199
|
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
105
|
-
logger.warn("\
|
|
106
|
-
await session.send(`\u274C \
|
|
200
|
+
logger.warn("\u91CD\u542F\u5931\u8D25", { server: prefix, error: e?.message || String(e), elapsed });
|
|
201
|
+
await session.send(`\u274C [${prefix}] \u91CD\u542F\u5931\u8D25\uFF08${elapsed}s\uFF09\uFF1A${e?.message || String(e)}`);
|
|
107
202
|
}
|
|
108
203
|
});
|
|
204
|
+
ctx.command(`${prefix}.stat`, "\u67E5\u770B\u670D\u52A1\u5668\u8FD0\u884C\u72B6\u6001\uFF08GC \u7B49\uFF09").userFields(["authority"]).action(async ({ session }) => {
|
|
205
|
+
const err = checkAuth(session);
|
|
206
|
+
if (err === void 0) return;
|
|
207
|
+
if (err) return err;
|
|
208
|
+
await session.send(`\u{1F50C} [${prefix}] \u67E5\u8BE2\u4E2D\u2026`);
|
|
209
|
+
return execShellCmd(session, "stat", "stat");
|
|
210
|
+
});
|
|
211
|
+
ctx.command(`${prefix}.reloadconf`, "\u91CD\u8F7D\u670D\u52A1\u5668\u914D\u7F6E\u6587\u4EF6").userFields(["authority"]).action(async ({ session }) => {
|
|
212
|
+
const err = checkAuth(session);
|
|
213
|
+
if (err === void 0) return;
|
|
214
|
+
if (err) return err;
|
|
215
|
+
await session.send(`\u{1F50C} [${prefix}] \u67E5\u8BE2\u4E2D\u2026`);
|
|
216
|
+
return execShellCmd(session, "reloadconf", "reloadconf");
|
|
217
|
+
});
|
|
218
|
+
ctx.command(`${prefix}.lsplayer`, "\u67E5\u770B\u6240\u6709\u5728\u7EBF\u73A9\u5BB6").userFields(["authority"]).action(async ({ session }) => {
|
|
219
|
+
const err = checkAuth(session);
|
|
220
|
+
if (err === void 0) return;
|
|
221
|
+
if (err) return err;
|
|
222
|
+
await session.send(`\u{1F50C} [${prefix}] \u67E5\u8BE2\u4E2D\u2026`);
|
|
223
|
+
return execShellCmd(session, "lsplayer", "lsplayer");
|
|
224
|
+
});
|
|
225
|
+
ctx.command(`${prefix}.lsroom [id]`, "\u67E5\u770B\u8FD0\u884C\u4E2D\u7684\u623F\u95F4\uFF08\u53EF\u6307\u5B9A\u623F\u95F4ID\u67E5\u770B\u8BE6\u60C5\uFF09").userFields(["authority"]).action(async ({ session }, id) => {
|
|
226
|
+
const err = checkAuth(session);
|
|
227
|
+
if (err === void 0) return;
|
|
228
|
+
if (err) return err;
|
|
229
|
+
await session.send(`\u{1F50C} [${prefix}] \u67E5\u8BE2\u4E2D\u2026`);
|
|
230
|
+
const cmd = id ? `lsroom ${id}` : "lsroom";
|
|
231
|
+
return execShellCmd(session, cmd, cmd);
|
|
232
|
+
});
|
|
233
|
+
ctx.command(`${prefix}.msg <message:text>`, "\u5411\u5168\u4F53\u73A9\u5BB6\u53D1\u9001\u516C\u544A").alias(`${prefix}.m`).userFields(["authority"]).action(async ({ session }, message) => {
|
|
234
|
+
const err = checkAuth(session);
|
|
235
|
+
if (err === void 0) return;
|
|
236
|
+
if (err) return err;
|
|
237
|
+
await session.send(`\u{1F50C} [${prefix}] \u53D1\u9001\u4E2D\u2026`);
|
|
238
|
+
return execShellCmd(session, `msg ${message}`, "msg");
|
|
239
|
+
});
|
|
240
|
+
ctx.command(`${prefix}.msgroom <roomId> <message:text>`, "\u5411\u6307\u5B9A\u623F\u95F4\u53D1\u9001\u6D88\u606F").alias(`${prefix}.mr`).userFields(["authority"]).action(async ({ session }, roomId, message) => {
|
|
241
|
+
const err = checkAuth(session);
|
|
242
|
+
if (err === void 0) return;
|
|
243
|
+
if (err) return err;
|
|
244
|
+
await session.send(`\u{1F50C} [${prefix}] \u53D1\u9001\u4E2D\u2026`);
|
|
245
|
+
return execShellCmd(session, `msgroom ${roomId} ${message}`, "msgroom");
|
|
246
|
+
});
|
|
247
|
+
ctx.command(`${prefix}.kick <name:text>`, "\u8E22\u51FA\u6307\u5B9A\u73A9\u5BB6").userFields(["authority"]).action(async ({ session }, name2) => {
|
|
248
|
+
const err = checkAuth(session);
|
|
249
|
+
if (err === void 0) return;
|
|
250
|
+
if (err) return err;
|
|
251
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
252
|
+
return execShellCmd(session, `kick ${name2}`, "kick");
|
|
253
|
+
});
|
|
254
|
+
ctx.command(`${prefix}.killroom <roomId>`, "\u8E22\u51FA\u623F\u95F4\u6240\u6709\u4EBA\u5E76\u5E9F\u5F03\u623F\u95F4").userFields(["authority"]).action(async ({ session }, roomId) => {
|
|
255
|
+
const err = checkAuth(session);
|
|
256
|
+
if (err === void 0) return;
|
|
257
|
+
if (err) return err;
|
|
258
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
259
|
+
return execShellCmd(session, `killroom ${roomId}`, "killroom");
|
|
260
|
+
});
|
|
261
|
+
ctx.command(`${prefix}.checklobby`, "\u6E05\u9664\u5927\u5385\u4E2D\u7684\u50F5\u5C38\u73A9\u5BB6").userFields(["authority"]).action(async ({ session }) => {
|
|
262
|
+
const err = checkAuth(session);
|
|
263
|
+
if (err === void 0) return;
|
|
264
|
+
if (err) return err;
|
|
265
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
266
|
+
return execShellCmd(session, "checklobby", "checklobby");
|
|
267
|
+
});
|
|
268
|
+
ctx.command(`${prefix}.ban <name:text>`, "\u5C01\u7981\u6307\u5B9A\u8D26\u53F7 / IP / UUID\uFF08\u53EF\u591A\u4E2A\uFF0C\u7A7A\u683C\u5206\u9694\uFF09").userFields(["authority"]).action(async ({ session }, name2) => {
|
|
269
|
+
const err = checkAuth(session);
|
|
270
|
+
if (err === void 0) return;
|
|
271
|
+
if (err) return err;
|
|
272
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
273
|
+
return execShellCmd(session, `ban ${name2}`, "ban");
|
|
274
|
+
});
|
|
275
|
+
ctx.command(`${prefix}.unban <name:text>`, "\u89E3\u5C01\u6307\u5B9A\u8D26\u53F7\uFF08\u53EF\u591A\u4E2A\uFF09").userFields(["authority"]).action(async ({ session }, name2) => {
|
|
276
|
+
const err = checkAuth(session);
|
|
277
|
+
if (err === void 0) return;
|
|
278
|
+
if (err) return err;
|
|
279
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
280
|
+
return execShellCmd(session, `unban ${name2}`, "unban");
|
|
281
|
+
});
|
|
282
|
+
ctx.command(`${prefix}.banip <name:text>`, "\u5C01\u7981 IP \u5730\u5740").userFields(["authority"]).action(async ({ session }, name2) => {
|
|
283
|
+
const err = checkAuth(session);
|
|
284
|
+
if (err === void 0) return;
|
|
285
|
+
if (err) return err;
|
|
286
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
287
|
+
return execShellCmd(session, `banip ${name2}`, "banip");
|
|
288
|
+
});
|
|
289
|
+
ctx.command(`${prefix}.unbanip <name:text>`, "\u89E3\u5C01 IP \u5730\u5740").userFields(["authority"]).action(async ({ session }, name2) => {
|
|
290
|
+
const err = checkAuth(session);
|
|
291
|
+
if (err === void 0) return;
|
|
292
|
+
if (err) return err;
|
|
293
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
294
|
+
return execShellCmd(session, `unbanip ${name2}`, "unbanip");
|
|
295
|
+
});
|
|
296
|
+
ctx.command(`${prefix}.banuuid <name:text>`, "\u5C01\u7981 UUID").userFields(["authority"]).action(async ({ session }, name2) => {
|
|
297
|
+
const err = checkAuth(session);
|
|
298
|
+
if (err === void 0) return;
|
|
299
|
+
if (err) return err;
|
|
300
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
301
|
+
return execShellCmd(session, `banuuid ${name2}`, "banuuid");
|
|
302
|
+
});
|
|
303
|
+
ctx.command(`${prefix}.unbanuuid <name:text>`, "\u89E3\u5C01 UUID").userFields(["authority"]).action(async ({ session }, name2) => {
|
|
304
|
+
const err = checkAuth(session);
|
|
305
|
+
if (err === void 0) return;
|
|
306
|
+
if (err) return err;
|
|
307
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
308
|
+
return execShellCmd(session, `unbanuuid ${name2}`, "unbanuuid");
|
|
309
|
+
});
|
|
310
|
+
ctx.command(`${prefix}.tempban <name:text> <duration:text>`, "\u4E34\u65F6\u5C01\u7981\uFF08\u65F6\u957F\u5982 30m/2h/7d/1mo\uFF09").userFields(["authority"]).action(async ({ session }, name2, duration) => {
|
|
311
|
+
const err = checkAuth(session);
|
|
312
|
+
if (err === void 0) return;
|
|
313
|
+
if (err) return err;
|
|
314
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
315
|
+
return execShellCmd(session, `tempban ${name2} ${duration}`, "tempban");
|
|
316
|
+
});
|
|
317
|
+
ctx.command(`${prefix}.tempmute <name:text> <duration:text>`, "\u4E34\u65F6\u7981\u8A00\uFF08\u65F6\u957F\u5982 30m/2h/7d/1mo\uFF09").userFields(["authority"]).action(async ({ session }, name2, duration) => {
|
|
318
|
+
const err = checkAuth(session);
|
|
319
|
+
if (err === void 0) return;
|
|
320
|
+
if (err) return err;
|
|
321
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
322
|
+
return execShellCmd(session, `tempmute ${name2} ${duration}`, "tempmute");
|
|
323
|
+
});
|
|
324
|
+
ctx.command(`${prefix}.unmute <name:text>`, "\u89E3\u9664\u7981\u8A00\uFF08\u53EF\u591A\u4E2A\uFF09").userFields(["authority"]).action(async ({ session }, name2) => {
|
|
325
|
+
const err = checkAuth(session);
|
|
326
|
+
if (err === void 0) return;
|
|
327
|
+
if (err) return err;
|
|
328
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
329
|
+
return execShellCmd(session, `unmute ${name2}`, "unmute");
|
|
330
|
+
});
|
|
331
|
+
ctx.command(`${prefix}.whitelist <rest:text>`, "\u7BA1\u7406\u767D\u540D\u5355\uFF08add/remove \u540D\u5355\uFF09").userFields(["authority"]).action(async ({ session }, rest) => {
|
|
332
|
+
const err = checkAuth(session);
|
|
333
|
+
if (err === void 0) return;
|
|
334
|
+
if (err) return err;
|
|
335
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
336
|
+
return execShellCmd(session, `whitelist ${rest}`, "whitelist");
|
|
337
|
+
});
|
|
338
|
+
ctx.command(`${prefix}.resetpassword <name:text>`, "\u91CD\u7F6E\u8D26\u53F7\u5BC6\u7801\u4E3A 1234").alias(`${prefix}.rp`).userFields(["authority"]).action(async ({ session }, name2) => {
|
|
339
|
+
const err = checkAuth(session);
|
|
340
|
+
if (err === void 0) return;
|
|
341
|
+
if (err) return err;
|
|
342
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
343
|
+
return execShellCmd(session, `resetpassword ${name2}`, "resetpassword");
|
|
344
|
+
});
|
|
345
|
+
ctx.command(`${prefix}.install <url:text>`, "\u4ECE URL \u5B89\u88C5\u6269\u5C55\u5305").userFields(["authority"]).action(async ({ session }, url) => {
|
|
346
|
+
const err = checkAuth(session);
|
|
347
|
+
if (err === void 0) return;
|
|
348
|
+
if (err) return err;
|
|
349
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
350
|
+
return execShellCmd(session, `install ${url}`, "install");
|
|
351
|
+
});
|
|
352
|
+
ctx.command(`${prefix}.remove <name:text>`, "\u79FB\u9664\u6269\u5C55\u5305").userFields(["authority"]).action(async ({ session }, name2) => {
|
|
353
|
+
const err = checkAuth(session);
|
|
354
|
+
if (err === void 0) return;
|
|
355
|
+
if (err) return err;
|
|
356
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
357
|
+
return execShellCmd(session, `remove ${name2}`, "remove");
|
|
358
|
+
});
|
|
359
|
+
ctx.command(`${prefix}.pkgs`, "\u67E5\u770B\u6240\u6709\u5DF2\u5B89\u88C5\u6269\u5C55\u5305").userFields(["authority"]).action(async ({ session }) => {
|
|
360
|
+
const err = checkAuth(session);
|
|
361
|
+
if (err === void 0) return;
|
|
362
|
+
if (err) return err;
|
|
363
|
+
await session.send(`\u{1F50C} [${prefix}] \u67E5\u8BE2\u4E2D\u2026`);
|
|
364
|
+
return execShellCmd(session, "pkgs", "pkgs");
|
|
365
|
+
});
|
|
366
|
+
ctx.command(`${prefix}.syncpkgs`, "\u4ECE\u6587\u4EF6\u7CFB\u7EDF\u540C\u6B65\u6269\u5C55\u5305\u5230\u6570\u636E\u5E93").userFields(["authority"]).action(async ({ session }) => {
|
|
367
|
+
const err = checkAuth(session);
|
|
368
|
+
if (err === void 0) return;
|
|
369
|
+
if (err) return err;
|
|
370
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
371
|
+
return execShellCmd(session, "syncpkgs", "syncpkgs");
|
|
372
|
+
});
|
|
373
|
+
ctx.command(`${prefix}.enable <name:text>`, "\u542F\u7528\u6307\u5B9A\u6269\u5C55\u5305").userFields(["authority"]).action(async ({ session }, name2) => {
|
|
374
|
+
const err = checkAuth(session);
|
|
375
|
+
if (err === void 0) return;
|
|
376
|
+
if (err) return err;
|
|
377
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
378
|
+
return execShellCmd(session, `enable ${name2}`, "enable");
|
|
379
|
+
});
|
|
380
|
+
ctx.command(`${prefix}.disable <name:text>`, "\u7981\u7528\u6307\u5B9A\u6269\u5C55\u5305").userFields(["authority"]).action(async ({ session }, name2) => {
|
|
381
|
+
const err = checkAuth(session);
|
|
382
|
+
if (err === void 0) return;
|
|
383
|
+
if (err) return err;
|
|
384
|
+
await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
|
|
385
|
+
return execShellCmd(session, `disable ${name2}`, "disable");
|
|
386
|
+
});
|
|
109
387
|
}
|
|
110
|
-
function executeUpdate(
|
|
388
|
+
function executeUpdate(server) {
|
|
111
389
|
return new Promise((resolve, reject) => {
|
|
112
390
|
const conn = new Client();
|
|
113
|
-
const totalTimeout =
|
|
391
|
+
const totalTimeout = server.attachDelay + server.updateWait + 3e4;
|
|
114
392
|
const timer = setTimeout(() => {
|
|
115
393
|
try {
|
|
116
394
|
conn.end();
|
|
@@ -159,11 +437,11 @@ function executeUpdate(config) {
|
|
|
159
437
|
(async () => {
|
|
160
438
|
try {
|
|
161
439
|
output += await collectOutput(1e3);
|
|
162
|
-
const screenCmd =
|
|
440
|
+
const screenCmd = server.screenSession ? `screen -r ${server.screenSession}
|
|
163
441
|
` : `screen -r
|
|
164
442
|
`;
|
|
165
|
-
output += await sendAndWait(screenCmd,
|
|
166
|
-
const updateOutput = await sendAndWait(
|
|
443
|
+
output += await sendAndWait(screenCmd, server.attachDelay);
|
|
444
|
+
const updateOutput = await sendAndWait(server.updateCommand + "\n", server.updateWait);
|
|
167
445
|
output += updateOutput;
|
|
168
446
|
checkError(updateOutput);
|
|
169
447
|
stream.write("d");
|
|
@@ -181,11 +459,215 @@ function executeUpdate(config) {
|
|
|
181
459
|
}
|
|
182
460
|
const cleanOutput = stripAnsi(output);
|
|
183
461
|
const lines = cleanOutput.split("\n").filter((l) => l.trim()).length;
|
|
184
|
-
resolve({
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
462
|
+
resolve({ output: cleanOutput, lineCount: lines, hasError });
|
|
463
|
+
} catch (e) {
|
|
464
|
+
clearTimeout(timer);
|
|
465
|
+
try {
|
|
466
|
+
stream.close();
|
|
467
|
+
} catch {
|
|
468
|
+
}
|
|
469
|
+
try {
|
|
470
|
+
conn.end();
|
|
471
|
+
} catch {
|
|
472
|
+
}
|
|
473
|
+
reject(e);
|
|
474
|
+
}
|
|
475
|
+
})();
|
|
476
|
+
});
|
|
477
|
+
});
|
|
478
|
+
conn.on("error", (err) => {
|
|
479
|
+
clearTimeout(timer);
|
|
480
|
+
reject(new Error(`SSH \u8FDE\u63A5\u9519\u8BEF: ${err.message}`));
|
|
481
|
+
});
|
|
482
|
+
conn.connect({
|
|
483
|
+
host: server.host,
|
|
484
|
+
port: server.port,
|
|
485
|
+
username: server.username,
|
|
486
|
+
password: server.password,
|
|
487
|
+
readyTimeout: 15e3
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
function executeRestart(server) {
|
|
492
|
+
return new Promise((resolve, reject) => {
|
|
493
|
+
const conn = new Client();
|
|
494
|
+
const totalTimeout = server.attachDelay + server.quitWait + server.restartWait + 3e4;
|
|
495
|
+
const timer = setTimeout(() => {
|
|
496
|
+
try {
|
|
497
|
+
conn.end();
|
|
498
|
+
} catch {
|
|
499
|
+
}
|
|
500
|
+
reject(new Error("SSH \u64CD\u4F5C\u8D85\u65F6"));
|
|
501
|
+
}, totalTimeout);
|
|
502
|
+
conn.on("ready", () => {
|
|
503
|
+
conn.shell({ term: "xterm-256color", cols: 200, rows: 50 }, (err, stream) => {
|
|
504
|
+
if (err) {
|
|
505
|
+
clearTimeout(timer);
|
|
506
|
+
try {
|
|
507
|
+
conn.end();
|
|
508
|
+
} catch {
|
|
509
|
+
}
|
|
510
|
+
reject(new Error(`\u6253\u5F00 shell \u5931\u8D25: ${err.message}`));
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
let output = "";
|
|
514
|
+
let hasError = false;
|
|
515
|
+
const collectOutput = (duration) => {
|
|
516
|
+
return new Promise((resolveCollected) => {
|
|
517
|
+
let buf = "";
|
|
518
|
+
const onData = (data) => {
|
|
519
|
+
buf += data.toString("utf8");
|
|
520
|
+
};
|
|
521
|
+
stream.on("data", onData);
|
|
522
|
+
setTimeout(() => {
|
|
523
|
+
stream.removeListener("data", onData);
|
|
524
|
+
resolveCollected(buf);
|
|
525
|
+
}, duration);
|
|
526
|
+
});
|
|
527
|
+
};
|
|
528
|
+
const sendAndWait = async (cmd, waitMs) => {
|
|
529
|
+
stream.write(cmd);
|
|
530
|
+
return collectOutput(waitMs);
|
|
531
|
+
};
|
|
532
|
+
const checkError = (text) => {
|
|
533
|
+
const lower = text.toLowerCase();
|
|
534
|
+
if (/error|fail|fatal|exception|拒绝|失败|错误/.test(lower)) {
|
|
535
|
+
if (!/0 errors?|no error/i.test(lower)) {
|
|
536
|
+
hasError = true;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
(async () => {
|
|
541
|
+
try {
|
|
542
|
+
output += await collectOutput(1e3);
|
|
543
|
+
const screenCmd = server.screenSession ? `screen -r ${server.screenSession}
|
|
544
|
+
` : `screen -r
|
|
545
|
+
`;
|
|
546
|
+
output += await sendAndWait(screenCmd, server.attachDelay);
|
|
547
|
+
const quitOutput = await sendAndWait("quit\n", server.quitWait);
|
|
548
|
+
output += quitOutput;
|
|
549
|
+
checkError(quitOutput);
|
|
550
|
+
const restartOutput = await sendAndWait("\x1B[A\n", server.restartWait);
|
|
551
|
+
output += restartOutput;
|
|
552
|
+
checkError(restartOutput);
|
|
553
|
+
stream.write("d");
|
|
554
|
+
output += await collectOutput(1e3);
|
|
555
|
+
stream.write("exit\n");
|
|
556
|
+
output += await collectOutput(500);
|
|
557
|
+
clearTimeout(timer);
|
|
558
|
+
try {
|
|
559
|
+
stream.close();
|
|
560
|
+
} catch {
|
|
561
|
+
}
|
|
562
|
+
try {
|
|
563
|
+
conn.end();
|
|
564
|
+
} catch {
|
|
565
|
+
}
|
|
566
|
+
const cleanOutput = stripAnsi(output);
|
|
567
|
+
const lines = cleanOutput.split("\n").filter((l) => l.trim()).length;
|
|
568
|
+
resolve({ output: cleanOutput, lineCount: lines, hasError });
|
|
569
|
+
} catch (e) {
|
|
570
|
+
clearTimeout(timer);
|
|
571
|
+
try {
|
|
572
|
+
stream.close();
|
|
573
|
+
} catch {
|
|
574
|
+
}
|
|
575
|
+
try {
|
|
576
|
+
conn.end();
|
|
577
|
+
} catch {
|
|
578
|
+
}
|
|
579
|
+
reject(e);
|
|
580
|
+
}
|
|
581
|
+
})();
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
conn.on("error", (err) => {
|
|
585
|
+
clearTimeout(timer);
|
|
586
|
+
reject(new Error(`SSH \u8FDE\u63A5\u9519\u8BEF: ${err.message}`));
|
|
587
|
+
});
|
|
588
|
+
conn.connect({
|
|
589
|
+
host: server.host,
|
|
590
|
+
port: server.port,
|
|
591
|
+
username: server.username,
|
|
592
|
+
password: server.password,
|
|
593
|
+
readyTimeout: 15e3
|
|
594
|
+
});
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
function executeShellCommand(shellCmd, server) {
|
|
598
|
+
return new Promise((resolve, reject) => {
|
|
599
|
+
const conn = new Client();
|
|
600
|
+
const totalTimeout = server.attachDelay + server.commandWait + 2e4;
|
|
601
|
+
const timer = setTimeout(() => {
|
|
602
|
+
try {
|
|
603
|
+
conn.end();
|
|
604
|
+
} catch {
|
|
605
|
+
}
|
|
606
|
+
reject(new Error("SSH \u64CD\u4F5C\u8D85\u65F6"));
|
|
607
|
+
}, totalTimeout);
|
|
608
|
+
conn.on("ready", () => {
|
|
609
|
+
conn.shell({ term: "xterm-256color", cols: 200, rows: 50 }, (err, stream) => {
|
|
610
|
+
if (err) {
|
|
611
|
+
clearTimeout(timer);
|
|
612
|
+
try {
|
|
613
|
+
conn.end();
|
|
614
|
+
} catch {
|
|
615
|
+
}
|
|
616
|
+
reject(new Error(`\u6253\u5F00 shell \u5931\u8D25: ${err.message}`));
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
let output = "";
|
|
620
|
+
let hasError = false;
|
|
621
|
+
const collectOutput = (duration) => {
|
|
622
|
+
return new Promise((resolveCollected) => {
|
|
623
|
+
let buf = "";
|
|
624
|
+
const onData = (data) => {
|
|
625
|
+
buf += data.toString("utf8");
|
|
626
|
+
};
|
|
627
|
+
stream.on("data", onData);
|
|
628
|
+
setTimeout(() => {
|
|
629
|
+
stream.removeListener("data", onData);
|
|
630
|
+
resolveCollected(buf);
|
|
631
|
+
}, duration);
|
|
632
|
+
});
|
|
633
|
+
};
|
|
634
|
+
const checkError = (text) => {
|
|
635
|
+
const lower = text.toLowerCase();
|
|
636
|
+
if (/error|fail|fatal|exception|拒绝|失败|错误/.test(lower)) {
|
|
637
|
+
if (!/0 errors?|no error/i.test(lower)) {
|
|
638
|
+
hasError = true;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
(async () => {
|
|
643
|
+
try {
|
|
644
|
+
output += await collectOutput(500);
|
|
645
|
+
const screenCmd = server.screenSession ? `screen -r ${server.screenSession}
|
|
646
|
+
` : `screen -r
|
|
647
|
+
`;
|
|
648
|
+
output += await collectOutput(server.attachDelay);
|
|
649
|
+
stream.write(screenCmd);
|
|
650
|
+
output += await collectOutput(server.attachDelay);
|
|
651
|
+
stream.write(shellCmd + "\n");
|
|
652
|
+
const cmdOutput = await collectOutput(server.commandWait);
|
|
653
|
+
output += cmdOutput;
|
|
654
|
+
checkError(cmdOutput);
|
|
655
|
+
stream.write("d");
|
|
656
|
+
output += await collectOutput(500);
|
|
657
|
+
stream.write("exit\n");
|
|
658
|
+
output += await collectOutput(300);
|
|
659
|
+
clearTimeout(timer);
|
|
660
|
+
try {
|
|
661
|
+
stream.close();
|
|
662
|
+
} catch {
|
|
663
|
+
}
|
|
664
|
+
try {
|
|
665
|
+
conn.end();
|
|
666
|
+
} catch {
|
|
667
|
+
}
|
|
668
|
+
const cleanOutput = stripAnsi(output);
|
|
669
|
+
const lines = cleanOutput.split("\n").filter((l) => l.trim()).length;
|
|
670
|
+
resolve({ output: cleanOutput, lineCount: lines, hasError });
|
|
189
671
|
} catch (e) {
|
|
190
672
|
clearTimeout(timer);
|
|
191
673
|
try {
|
|
@@ -206,14 +688,17 @@ function executeUpdate(config) {
|
|
|
206
688
|
reject(new Error(`SSH \u8FDE\u63A5\u9519\u8BEF: ${err.message}`));
|
|
207
689
|
});
|
|
208
690
|
conn.connect({
|
|
209
|
-
host:
|
|
210
|
-
port:
|
|
211
|
-
username:
|
|
212
|
-
password:
|
|
691
|
+
host: server.host,
|
|
692
|
+
port: server.port,
|
|
693
|
+
username: server.username,
|
|
694
|
+
password: server.password,
|
|
213
695
|
readyTimeout: 15e3
|
|
214
696
|
});
|
|
215
697
|
});
|
|
216
698
|
}
|
|
699
|
+
function cleanShellOutput(text) {
|
|
700
|
+
return text.replace(/\[detached[^\n]*\n?/gi, "").replace(/\[screen[^\n]*\n?/gi, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
701
|
+
}
|
|
217
702
|
function filterSensitive(text) {
|
|
218
703
|
return text.replace(/\/home\/[^/\s]+/g, "/home/***").replace(/\/root\//g, "/root/***/").replace(/(token|secret|password|passwd|key|apikey)\s*[=:]\s*\S+/gi, "$1=***").replace(/\b(\d{1,3})\.(\d{1,3})\.\d{1,3}\.\d{1,3}\b/g, "$1.$2.*.*");
|
|
219
704
|
}
|