koishi-plugin-maibot 1.7.68 → 1.7.70
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/binding-verify.d.ts +15 -16
- package/lib/binding-verify.d.ts.map +1 -1
- package/lib/binding-verify.js +27 -74
- package/lib/binding-verify.js.map +1 -1
- package/lib/index.d.ts +0 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +93 -34
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/binding-verify.d.ts
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
import type { UserBinding } from './database';
|
|
2
2
|
export declare function normalizePreviewUserId(userId: string | number): string;
|
|
3
|
-
/**
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export declare function playerNameSimilarityRatio(a: string, b: string): number;
|
|
3
|
+
/** 老版本密钥存库的 maiUid 常见以 Base64 前缀 MDk(即 ASCII「097…」)开头 */
|
|
4
|
+
export declare function isLegacyMdkMaiUid(boundUid: string): boolean;
|
|
5
|
+
export type VerifyPreviewBindingResult = {
|
|
6
|
+
ok: true;
|
|
7
|
+
} | {
|
|
8
|
+
ok: false;
|
|
9
|
+
message: string;
|
|
10
|
+
} | {
|
|
11
|
+
ok: true;
|
|
12
|
+
migratedToUid: string;
|
|
13
|
+
notice: string;
|
|
14
|
+
};
|
|
16
15
|
/**
|
|
17
|
-
* 校验 preview
|
|
18
|
-
*
|
|
16
|
+
* 校验 preview 与绑定是否为同一街机账号:比较绑定记录的 maiUid 与二维码 preview 的 UserID。
|
|
17
|
+
* 绑定为老格式(maiUid 以 MDk 开头)且与二维码 UID 不一致时,视为同账号升级格式,返回 ok + 迁移信息(由调用方写库并提示)。
|
|
19
18
|
*/
|
|
20
19
|
export declare function verifyPreviewMatchesBinding(binding: UserBinding, preview: {
|
|
21
20
|
UserID: string | number;
|
|
22
21
|
UserName?: string;
|
|
23
|
-
}
|
|
22
|
+
}): VerifyPreviewBindingResult;
|
|
24
23
|
/** lastStateAt:maibot_user_rebind_state.lastBindChangeAt;bindTime:当前绑定记录的 bindTime(无绑定则 0) */
|
|
25
24
|
export declare function msUntilBindChangeAllowed(lastStateAtMs: number, bindTimeMs: number, minIntervalDays: number): number;
|
|
26
25
|
export declare function formatBindChangeWaitHuman(ms: number): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding-verify.d.ts","sourceRoot":"","sources":["../src/binding-verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAEtE;AAED,
|
|
1
|
+
{"version":3,"file":"binding-verify.d.ts","sourceRoot":"","sources":["../src/binding-verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAEtE;AAED,yDAAyD;AACzD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,MAAM,MAAM,0BAA0B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC9B;IACE,EAAE,EAAE,IAAI,CAAA;IACR,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAEL;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACtD,0BAA0B,CA4B5B;AAED,8FAA8F;AAC9F,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,GACtB,MAAM,CAMR;AAED,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAS5D"}
|
package/lib/binding-verify.js
CHANGED
|
@@ -1,94 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.normalizePreviewUserId = normalizePreviewUserId;
|
|
4
|
-
exports.
|
|
5
|
-
exports.normalizePlayerNameForMatch = normalizePlayerNameForMatch;
|
|
6
|
-
exports.playerNameSimilarityRatio = playerNameSimilarityRatio;
|
|
4
|
+
exports.isLegacyMdkMaiUid = isLegacyMdkMaiUid;
|
|
7
5
|
exports.verifyPreviewMatchesBinding = verifyPreviewMatchesBinding;
|
|
8
6
|
exports.msUntilBindChangeAllowed = msUntilBindChangeAllowed;
|
|
9
7
|
exports.formatBindChangeWaitHuman = formatBindChangeWaitHuman;
|
|
10
8
|
function normalizePreviewUserId(userId) {
|
|
11
9
|
return String(userId);
|
|
12
10
|
}
|
|
13
|
-
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
if (typeof p !== 'number' || Number.isNaN(p))
|
|
17
|
-
p = DEFAULT_MIN_SIMILARITY;
|
|
18
|
-
p = Math.min(100, Math.max(0, p));
|
|
19
|
-
return { minSimilarityPercent: p };
|
|
20
|
-
}
|
|
21
|
-
/** 玩家名规范化:去首尾空白 + Unicode NFKC(全角英数、兼容字符等与半角统一) */
|
|
22
|
-
function normalizePlayerNameForMatch(name) {
|
|
23
|
-
return name.normalize('NFKC').trim();
|
|
24
|
-
}
|
|
25
|
-
function levenshtein(a, b) {
|
|
26
|
-
const m = a.length;
|
|
27
|
-
const n = b.length;
|
|
28
|
-
if (m === 0)
|
|
29
|
-
return n;
|
|
30
|
-
if (n === 0)
|
|
31
|
-
return m;
|
|
32
|
-
const dp = new Uint32Array(n + 1);
|
|
33
|
-
for (let j = 0; j <= n; j++)
|
|
34
|
-
dp[j] = j;
|
|
35
|
-
for (let i = 1; i <= m; i++) {
|
|
36
|
-
let prev = dp[0];
|
|
37
|
-
dp[0] = i;
|
|
38
|
-
for (let j = 1; j <= n; j++) {
|
|
39
|
-
const tmp = dp[j];
|
|
40
|
-
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
41
|
-
dp[j] = Math.min(dp[j] + 1, dp[j - 1] + 1, prev + cost);
|
|
42
|
-
prev = tmp;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return dp[n];
|
|
46
|
-
}
|
|
47
|
-
/** 0–1,分母为 max(len);用于短玩家名 */
|
|
48
|
-
function playerNameSimilarityRatio(a, b) {
|
|
49
|
-
if (a === b)
|
|
50
|
-
return 1;
|
|
51
|
-
const maxLen = Math.max(a.length, b.length);
|
|
52
|
-
if (maxLen === 0)
|
|
53
|
-
return 1;
|
|
54
|
-
return Math.max(0, 1 - levenshtein(a, b) / maxLen);
|
|
11
|
+
/** 老版本密钥存库的 maiUid 常见以 Base64 前缀 MDk(即 ASCII「097…」)开头 */
|
|
12
|
+
function isLegacyMdkMaiUid(boundUid) {
|
|
13
|
+
return String(boundUid).startsWith('MDk');
|
|
55
14
|
}
|
|
56
15
|
/**
|
|
57
|
-
* 校验 preview
|
|
58
|
-
*
|
|
16
|
+
* 校验 preview 与绑定是否为同一街机账号:比较绑定记录的 maiUid 与二维码 preview 的 UserID。
|
|
17
|
+
* 绑定为老格式(maiUid 以 MDk 开头)且与二维码 UID 不一致时,视为同账号升级格式,返回 ok + 迁移信息(由调用方写库并提示)。
|
|
59
18
|
*/
|
|
60
|
-
function verifyPreviewMatchesBinding(binding, preview
|
|
19
|
+
function verifyPreviewMatchesBinding(binding, preview) {
|
|
61
20
|
const pid = normalizePreviewUserId(preview.UserID);
|
|
62
21
|
if (pid === '-1' || preview.UserID === -1) {
|
|
63
|
-
return '❌
|
|
64
|
-
}
|
|
65
|
-
if (String(binding.maiUid) !== pid) {
|
|
66
|
-
return '❌ 当前二维码对应的街机账号与绑定不一致,请使用已绑定账号本人微信获取的二维码。';
|
|
67
|
-
}
|
|
68
|
-
const boundName = binding.boundPlayerName?.trim();
|
|
69
|
-
if (!boundName || preview.UserName === undefined) {
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
const current = String(preview.UserName).trim();
|
|
73
|
-
const na = normalizePlayerNameForMatch(boundName);
|
|
74
|
-
const nb = normalizePlayerNameForMatch(current);
|
|
75
|
-
if (!na) {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
if (!nb) {
|
|
79
|
-
return `❌ 玩家名与绑定记录不一致(绑定为「${boundName}」,当前玩家名为空)。如已改名请使用解绑卡流程后重新绑定。`;
|
|
22
|
+
return { ok: false, message: '❌ 无效或过期的二维码,无法完成验证。请重新获取玩家二维码后重试。' };
|
|
80
23
|
}
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (pct + 1e-9 >= min) {
|
|
85
|
-
return null;
|
|
24
|
+
const boundUid = String(binding.maiUid);
|
|
25
|
+
if (boundUid === pid) {
|
|
26
|
+
return { ok: true };
|
|
86
27
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
28
|
+
if (isLegacyMdkMaiUid(boundUid)) {
|
|
29
|
+
return {
|
|
30
|
+
ok: true,
|
|
31
|
+
migratedToUid: pid,
|
|
32
|
+
notice: `💾 街机账号 UID 不一致:\n` +
|
|
33
|
+
`• 当前绑定记录的 UID:${boundUid}\n` +
|
|
34
|
+
`• 当前二维码对应的 UID:${pid}\n` +
|
|
35
|
+
`已为您自动迁移到新格式。`,
|
|
36
|
+
};
|
|
90
37
|
}
|
|
91
|
-
return
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
message: `❌ 街机账号 UID 不一致:\n` +
|
|
41
|
+
`• 当前绑定记录的 UID:${boundUid}\n` +
|
|
42
|
+
`• 当前二维码对应的 UID:${pid}\n` +
|
|
43
|
+
`若您已更换游戏账号,请使用 /mai解绑 后重新绑定(换绑冷却期内请使用 /mai解绑卡)。`,
|
|
44
|
+
};
|
|
92
45
|
}
|
|
93
46
|
/** lastStateAt:maibot_user_rebind_state.lastBindChangeAt;bindTime:当前绑定记录的 bindTime(无绑定则 0) */
|
|
94
47
|
function msUntilBindChangeAllowed(lastStateAtMs, bindTimeMs, minIntervalDays) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding-verify.js","sourceRoot":"","sources":["../src/binding-verify.ts"],"names":[],"mappings":";;AAEA,wDAEC;
|
|
1
|
+
{"version":3,"file":"binding-verify.js","sourceRoot":"","sources":["../src/binding-verify.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
CHANGED
|
@@ -69,11 +69,6 @@ export interface Config {
|
|
|
69
69
|
minDaysBetweenBindChange: number;
|
|
70
70
|
shopUrl?: string;
|
|
71
71
|
};
|
|
72
|
-
/** SGID / preview 校验时:绑定快照玩家名与当前玩家名的匹配(含 /mai状态、mymai 等) */
|
|
73
|
-
bindingPlayerNameMatch?: {
|
|
74
|
-
/** 0–100:NFKC 规范化后,编辑距离相似度下限;100 为须完全一致。全角如 Milk 与半角 Milk 在 100 下通常视为一致 */
|
|
75
|
-
minSimilarityPercent: number;
|
|
76
|
-
};
|
|
77
72
|
}
|
|
78
73
|
export declare const Config: Schema<Config>;
|
|
79
74
|
export declare function apply(ctx: Context, config: Config): void;
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAW,MAAM,QAAQ,CAAA;AASjD,OAAO,EAoBL,KAAK,sBAAsB,EAC5B,MAAM,qBAAqB,CAAA;AAE5B,eAAO,MAAM,IAAI,WAAW,CAAA;AAC5B,eAAO,MAAM,MAAM,UAAe,CAAA;AAElC,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,MAAM;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE;QAClB,OAAO,EAAE,OAAO,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,aAAa,CAAC,EAAE;QACd,YAAY,EAAE,MAAM,CAAA;QACpB,aAAa,EAAE,MAAM,CAAA;KACtB,CAAA;IACD,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,EAAE,CAAA;QAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;QAClB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,OAAO,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,YAAY,CAAC,EAAE;QACb,OAAO,EAAE,OAAO,CAAA;QAChB,UAAU,EAAE,MAAM,CAAA;KACnB,CAAA;IACD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,4BAA4B,CAAC,EAAE,OAAO,CAAA;IACtC,+CAA+C;IAC/C,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,sBAAsB,CAAA;IACzC,wDAAwD;IACxD,YAAY,CAAC,EAAE;QACb,wBAAwB,EAAE,MAAM,CAAA;QAChC,OAAO,CAAC,EAAE,MAAM,CAAA;KACjB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -123,15 +123,6 @@ exports.Config = koishi_1.Schema.object({
|
|
|
123
123
|
minDaysBetweenBindChange: 30,
|
|
124
124
|
shopUrl: '',
|
|
125
125
|
}),
|
|
126
|
-
bindingPlayerNameMatch: koishi_1.Schema.object({
|
|
127
|
-
minSimilarityPercent: koishi_1.Schema.number()
|
|
128
|
-
.default(100)
|
|
129
|
-
.min(0)
|
|
130
|
-
.max(100)
|
|
131
|
-
.description('玩家名最低相似度(0–100)。先进行 Unicode NFKC 规范化(全角/半角英数字统一)再按编辑距离计算;100 表示须完全一致。略低于 100 可容忍少量字符差异(改名、显示差异等)。'),
|
|
132
|
-
})
|
|
133
|
-
.description('绑定记录中的玩家名与 preview 的校验(maiUid 一致时的第二道校验)')
|
|
134
|
-
.default({ minSimilarityPercent: 100 }),
|
|
135
126
|
});
|
|
136
127
|
// 我认识了很多朋友 以下是我认识的好朋友们!
|
|
137
128
|
// Fracture_Hikaritsu
|
|
@@ -210,6 +201,36 @@ function getSessionCommandUsageHint(session) {
|
|
|
210
201
|
function isMaiPluginCommandName(name) {
|
|
211
202
|
return name.trim().startsWith('mai');
|
|
212
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* <spec:text> 会把「clear -g 群号」整段吃成一个参数;从首尾拆出 -g 群标识,并与 .option('-g') 合并(优先已解析的 -g)。
|
|
206
|
+
*/
|
|
207
|
+
function splitGroupPrioritySpecAndGuild(specRaw, optionGuild) {
|
|
208
|
+
let specStr = (specRaw ?? '').trim();
|
|
209
|
+
let guild = String(optionGuild ?? '').trim();
|
|
210
|
+
const lead = specStr.match(/^\s*-g\s+(\S+)\s+([\s\S]+)$/i);
|
|
211
|
+
if (lead) {
|
|
212
|
+
if (!guild)
|
|
213
|
+
guild = lead[1];
|
|
214
|
+
specStr = lead[2].trim();
|
|
215
|
+
}
|
|
216
|
+
const tail = specStr.match(/^([\s\S]+?)\s+-g\s+(\S+)\s*$/i);
|
|
217
|
+
if (tail) {
|
|
218
|
+
specStr = tail[1].trim();
|
|
219
|
+
if (!guild)
|
|
220
|
+
guild = tail[2];
|
|
221
|
+
}
|
|
222
|
+
return { spec: specStr, guild };
|
|
223
|
+
}
|
|
224
|
+
/** 群优先表里的 guildKey 多为 platform:guildId;仅填数字时按当前会话平台补前缀 */
|
|
225
|
+
function normalizeGuildKeyForPriority(gk, session) {
|
|
226
|
+
const t = gk.trim();
|
|
227
|
+
if (!t)
|
|
228
|
+
return t;
|
|
229
|
+
if (!/^\d+$/.test(t))
|
|
230
|
+
return t;
|
|
231
|
+
const p = String(session.platform || '').trim().toLowerCase();
|
|
232
|
+
return p ? `${p}:${t}` : t;
|
|
233
|
+
}
|
|
213
234
|
async function computeMaiCommandUsageHint(command, session) {
|
|
214
235
|
if (!command || !isMaiPluginCommandName(String(command.name || '')))
|
|
215
236
|
return '';
|
|
@@ -1159,6 +1180,18 @@ async function waitForUserReply(session, ctx, timeout, expectedQuoteMessageIds)
|
|
|
1159
1180
|
}, timeout);
|
|
1160
1181
|
});
|
|
1161
1182
|
}
|
|
1183
|
+
/** 处理 preview 校验结果:拦截错误、老 MDk* maiUid 自动迁移并同步内存中的 binding */
|
|
1184
|
+
async function applyVerifyPreviewBinding(ctx, binding, result, logger) {
|
|
1185
|
+
if (!result.ok)
|
|
1186
|
+
return { blocked: true, message: result.message };
|
|
1187
|
+
if ('migratedToUid' in result) {
|
|
1188
|
+
await ctx.database.set('maibot_bindings', { userId: binding.userId }, { maiUid: result.migratedToUid });
|
|
1189
|
+
binding.maiUid = result.migratedToUid;
|
|
1190
|
+
logger.info(`maiUid 老格式(MDk*) 已自动迁移 userId=${binding.userId}`);
|
|
1191
|
+
return { blocked: false, migrationNotice: result.notice };
|
|
1192
|
+
}
|
|
1193
|
+
return { blocked: false };
|
|
1194
|
+
}
|
|
1162
1195
|
/**
|
|
1163
1196
|
* 获取二维码文本(qr_text)
|
|
1164
1197
|
* 有有效缓存则直接用;缓存过期则直接问用户发送 SGID/链接
|
|
@@ -1174,8 +1207,11 @@ async function getQrText(session, ctx, api, binding, config, timeout = 60000, pr
|
|
|
1174
1207
|
if (cacheAge < cacheValidDuration && binding.lastQrCode.startsWith('SGWCMAID')) {
|
|
1175
1208
|
try {
|
|
1176
1209
|
const previewCached = await api.getPreview(config.machineInfo.clientId, binding.lastQrCode);
|
|
1177
|
-
const
|
|
1178
|
-
|
|
1210
|
+
const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, previewCached);
|
|
1211
|
+
const hv = await applyVerifyPreviewBinding(ctx, binding, vr, logger);
|
|
1212
|
+
if (!hv.blocked) {
|
|
1213
|
+
if (hv.migrationNotice)
|
|
1214
|
+
await session.send(hv.migrationNotice);
|
|
1179
1215
|
if (previewCached.UserName != null && !binding.boundPlayerName?.trim()) {
|
|
1180
1216
|
await ctx.database.set('maibot_bindings', { userId: binding.userId }, {
|
|
1181
1217
|
boundPlayerName: String(previewCached.UserName).trim(),
|
|
@@ -1288,11 +1324,14 @@ async function getQrText(session, ctx, api, binding, config, timeout = 60000, pr
|
|
|
1288
1324
|
return { qrText: '', error: '无效或过期的二维码' };
|
|
1289
1325
|
}
|
|
1290
1326
|
if (binding) {
|
|
1291
|
-
const
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1327
|
+
const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
|
|
1328
|
+
const hv = await applyVerifyPreviewBinding(ctx, binding, vr, logger);
|
|
1329
|
+
if (hv.blocked) {
|
|
1330
|
+
await session.send(hv.message);
|
|
1331
|
+
return { qrText: '', error: hv.message };
|
|
1295
1332
|
}
|
|
1333
|
+
if (hv.migrationNotice)
|
|
1334
|
+
await session.send(hv.migrationNotice);
|
|
1296
1335
|
const patch = {
|
|
1297
1336
|
qrCode: qrText,
|
|
1298
1337
|
lastQrCode: qrText,
|
|
@@ -2258,7 +2297,7 @@ function apply(ctx, config) {
|
|
|
2258
2297
|
/mai管理员取消群组优先 [群标识] — 取消群组优先;省略时在群内则针对当前群
|
|
2259
2298
|
/mai管理员取消个人优先 <@或ID> — 清除个人优先记录
|
|
2260
2299
|
/mai管理员设置个人优先 <@或ID> <spec> — spec:永久、7d、clear 等
|
|
2261
|
-
/mai管理员设置群组优先 <spec> [-g 群标识] —
|
|
2300
|
+
/mai管理员设置群组优先 <spec> [-g 群标识] — spec 与 -g 可同一段输入(如 clear -g qq:群号);纯数字 -g 会按当前平台补前缀;-g 省略且在群内则当前群
|
|
2262
2301
|
/maibypass <@用户|用户ID> — 清除该用户当前全部指令冷却(别名 /mai管理员清除冷却)`;
|
|
2263
2302
|
}
|
|
2264
2303
|
helpText += `
|
|
@@ -3593,10 +3632,13 @@ function apply(ctx, config) {
|
|
|
3593
3632
|
if (preview.UserID === -1 || (typeof preview.UserID === 'string' && preview.UserID === '-1')) {
|
|
3594
3633
|
return '❌ 无效或过期的二维码,请重新发送';
|
|
3595
3634
|
}
|
|
3596
|
-
const
|
|
3597
|
-
|
|
3598
|
-
|
|
3635
|
+
const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
|
|
3636
|
+
const hv = await applyVerifyPreviewBinding(ctx, binding, vr, ctx.logger('maibot'));
|
|
3637
|
+
if (hv.blocked) {
|
|
3638
|
+
return hv.message;
|
|
3599
3639
|
}
|
|
3640
|
+
if (hv.migrationNotice)
|
|
3641
|
+
await session.send(hv.migrationNotice);
|
|
3600
3642
|
const patch = {
|
|
3601
3643
|
lastQrCode: qrCode,
|
|
3602
3644
|
lastQrCodeTime: new Date(),
|
|
@@ -3778,10 +3820,13 @@ function apply(ctx, config) {
|
|
|
3778
3820
|
if (preview.UserID === -1 || (typeof preview.UserID === 'string' && preview.UserID === '-1')) {
|
|
3779
3821
|
return '❌ 无效或过期的二维码,请重新发送';
|
|
3780
3822
|
}
|
|
3781
|
-
const
|
|
3782
|
-
|
|
3783
|
-
|
|
3823
|
+
const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
|
|
3824
|
+
const hv = await applyVerifyPreviewBinding(ctx, binding, vr, ctx.logger('maibot'));
|
|
3825
|
+
if (hv.blocked) {
|
|
3826
|
+
return hv.message;
|
|
3784
3827
|
}
|
|
3828
|
+
if (hv.migrationNotice)
|
|
3829
|
+
await session.send(hv.migrationNotice);
|
|
3785
3830
|
const patch = {
|
|
3786
3831
|
lastQrCode: qrCode,
|
|
3787
3832
|
lastQrCodeTime: new Date(),
|
|
@@ -4208,10 +4253,13 @@ function apply(ctx, config) {
|
|
|
4208
4253
|
if (preview.UserID === -1 || (typeof preview.UserID === 'string' && preview.UserID === '-1')) {
|
|
4209
4254
|
return '❌ 无效或过期的二维码,请重新发送';
|
|
4210
4255
|
}
|
|
4211
|
-
const
|
|
4212
|
-
|
|
4213
|
-
|
|
4256
|
+
const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
|
|
4257
|
+
const hv = await applyVerifyPreviewBinding(ctx, binding, vr, ctx.logger('maibot'));
|
|
4258
|
+
if (hv.blocked) {
|
|
4259
|
+
return hv.message;
|
|
4214
4260
|
}
|
|
4261
|
+
if (hv.migrationNotice)
|
|
4262
|
+
await session.send(hv.migrationNotice);
|
|
4215
4263
|
const patch = {
|
|
4216
4264
|
lastQrCode: qrCode,
|
|
4217
4265
|
lastQrCodeTime: new Date(),
|
|
@@ -4331,10 +4379,13 @@ function apply(ctx, config) {
|
|
|
4331
4379
|
if (preview.UserID === -1 || (typeof preview.UserID === 'string' && preview.UserID === '-1')) {
|
|
4332
4380
|
return '❌ 无效或过期的二维码,请重新发送';
|
|
4333
4381
|
}
|
|
4334
|
-
const
|
|
4335
|
-
|
|
4336
|
-
|
|
4382
|
+
const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
|
|
4383
|
+
const hv = await applyVerifyPreviewBinding(ctx, binding, vr, ctx.logger('maibot'));
|
|
4384
|
+
if (hv.blocked) {
|
|
4385
|
+
return hv.message;
|
|
4337
4386
|
}
|
|
4387
|
+
if (hv.migrationNotice)
|
|
4388
|
+
await session.send(hv.migrationNotice);
|
|
4338
4389
|
const patch = {
|
|
4339
4390
|
lastQrCode: qrCode,
|
|
4340
4391
|
lastQrCodeTime: new Date(),
|
|
@@ -4732,10 +4783,13 @@ function apply(ctx, config) {
|
|
|
4732
4783
|
if (preview.UserID === -1 || (typeof preview.UserID === 'string' && preview.UserID === '-1')) {
|
|
4733
4784
|
return '❌ 无效或过期的二维码,请重新发送';
|
|
4734
4785
|
}
|
|
4735
|
-
const
|
|
4736
|
-
|
|
4737
|
-
|
|
4786
|
+
const vr = (0, binding_verify_1.verifyPreviewMatchesBinding)(binding, preview);
|
|
4787
|
+
const hv = await applyVerifyPreviewBinding(ctx, binding, vr, ctx.logger('maibot'));
|
|
4788
|
+
if (hv.blocked) {
|
|
4789
|
+
return hv.message;
|
|
4738
4790
|
}
|
|
4791
|
+
if (hv.migrationNotice)
|
|
4792
|
+
await session.send(hv.migrationNotice);
|
|
4739
4793
|
const patch = {
|
|
4740
4794
|
lastQrCode: qrCode,
|
|
4741
4795
|
lastQrCodeTime: new Date(),
|
|
@@ -6299,6 +6353,9 @@ function apply(ctx, config) {
|
|
|
6299
6353
|
});
|
|
6300
6354
|
ctx.command('mai管理员设置群组优先 <spec:text>', '直接设置群组优先(-g 指定群,默认当前群)')
|
|
6301
6355
|
.userFields(['authority'])
|
|
6356
|
+
.usage(' 示例:/mai管理员设置群组优先 clear -g qq:5911013814031454\n' +
|
|
6357
|
+
'或:/mai管理员设置群组优先 -g qq:5911013814031454 永久\n' +
|
|
6358
|
+
'(仅数字群号时请写 qq:群号;在群内执行可省略 -g)')
|
|
6302
6359
|
.option('guild', '-g <guildKey:string> 群标识,如 qq:群号')
|
|
6303
6360
|
.action(async ({ session, options }, spec) => {
|
|
6304
6361
|
if (!session)
|
|
@@ -6306,14 +6363,16 @@ function apply(ctx, config) {
|
|
|
6306
6363
|
if ((session.user?.authority ?? 0) < authLevelForCardAdmin) {
|
|
6307
6364
|
return `❌ 权限不足,需要 auth 等级 ${authLevelForCardAdmin} 以上`;
|
|
6308
6365
|
}
|
|
6309
|
-
|
|
6366
|
+
const { spec: specOnly, guild: guildOpt } = splitGroupPrioritySpecAndGuild(spec, options?.guild);
|
|
6367
|
+
if (!specOnly) {
|
|
6310
6368
|
return '❌ 用法:/mai管理员设置群组优先 <永久|7d|clear> [-g 群标识]';
|
|
6311
6369
|
}
|
|
6312
|
-
const sp = (0, priority_cooldown_1.parsePriorityAdminSpec)(
|
|
6370
|
+
const sp = (0, priority_cooldown_1.parsePriorityAdminSpec)(specOnly);
|
|
6313
6371
|
if (sp === null) {
|
|
6314
6372
|
return '❌ 无效的 spec,示例:永久、7d、clear';
|
|
6315
6373
|
}
|
|
6316
|
-
|
|
6374
|
+
let gk = (guildOpt.trim() || (0, priority_cooldown_1.canonicalGuildPriorityKey)(session) || '').trim();
|
|
6375
|
+
gk = normalizeGuildKeyForPriority(gk, session);
|
|
6317
6376
|
if (!gk) {
|
|
6318
6377
|
return '❌ 请使用 -g 指定群标识(platform:guildId),或在群聊内执行。';
|
|
6319
6378
|
}
|