cclawd 1.0.7 → 1.0.8
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/dist/{active-listener-DYmI7imH.js → active-listener-Dkhmfuwx.js} +2 -2
- package/dist/{api-key-rotation-DLU4jvSu.js → api-key-rotation-BOfI3cG3.js} +1 -1
- package/dist/{audio-preflight-C9TMbRb4.js → audio-preflight-CtkZ5SAs.js} +15 -15
- package/dist/{audio-transcription-runner-Q5zG_hYd.js → audio-transcription-runner-CbPqoiHX.js} +10 -10
- package/dist/{audit-membership-runtime-DhxSwFnF.js → audit-membership-runtime-hXUuer4x.js} +6 -6
- package/dist/build-info.json +3 -3
- package/dist/bundled/boot-md/handler.js +35 -35
- package/dist/bundled/bootstrap-extra-files/handler.js +5 -5
- package/dist/bundled/command-logger/handler.js +2 -2
- package/dist/bundled/session-memory/handler.js +35 -35
- package/dist/{channel-activity-Bx08UTAg.js → channel-activity-DWAER4wd.js} +2 -2
- package/dist/{commands-registry-llLVCTH9.js → commands-registry-BUyiA7nE.js} +2 -2
- package/dist/compact.runtime-DpcZpcTl.js +39 -0
- package/dist/{deliver-DJf2ZBpe.js → deliver-aHOaRbkt.js} +19 -19
- package/dist/deliver-runtime-D4bCsr6d.js +19 -0
- package/dist/deps-send-discord.runtime-BziKU-pE.js +19 -0
- package/dist/deps-send-imessage.runtime-CFRnDTqp.js +18 -0
- package/dist/deps-send-signal.runtime-BuOtABJm.js +17 -0
- package/dist/deps-send-slack.runtime-BOLqvMxW.js +17 -0
- package/dist/deps-send-telegram.runtime-DeEoFLv5.js +20 -0
- package/dist/deps-send-whatsapp.runtime-CG1uXYLY.js +43 -0
- package/dist/{diagnostic-BCCMF3O_.js → diagnostic-BdcXX9iJ.js} +2 -2
- package/dist/{env-aYXLHjfZ.js → env-lw2hsIUY.js} +1 -1
- package/dist/{fetch-bvgIiupu.js → fetch-C0iyt-Iz.js} +3 -3
- package/dist/{fetch-DCTUdr1U.js → fetch-D9NUULbj.js} +5 -5
- package/dist/{fetch-guard-CqpEmMQ2.js → fetch-guard-B5ZMnGaN.js} +2 -2
- package/dist/{frontmatter-DjZuS525.js → frontmatter-C_obXuTp.js} +3 -3
- package/dist/{github-copilot-token-CQmATy5E.js → github-copilot-token-8N63GdbE.js} +7 -7
- package/dist/{image-Q8E1-lZn.js → image-4x07m4Jl.js} +4 -4
- package/dist/image-runtime-smkMrIol.js +12 -0
- package/dist/{ir-CzM3SxId.js → ir-CsgNUpOU.js} +6 -6
- package/dist/llm-slug-generator.js +35 -35
- package/dist/{logger-ChbX1G7s.js → logger-CbUVl62f.js} +7 -7
- package/dist/{login-B0mtU11X.js → login-p_O59TVQ.js} +4 -4
- package/dist/{login-qr-DY_i60f5.js → login-qr-BCJpDsAy.js} +10 -10
- package/dist/{manager-FAQPC0uO.js → manager-CwYv8O3T.js} +12 -12
- package/dist/manager-runtime-D_jEoBr9.js +15 -0
- package/dist/{model-selection-wf3OY5DX.js → model-selection-Cv2Puf5z.js} +122 -122
- package/dist/{outbound-Bw0dOVS7.js → outbound-Chpiwybe.js} +6 -6
- package/dist/{outbound-attachment-1R6r9Pg_.js → outbound-attachment-BnAVJDLe.js} +2 -2
- package/dist/{paths-C0HLtPu0.js → paths-CehYKFsO.js} +7 -7
- package/dist/{paths-hfkBoC7i.js → paths-DkxwiA8g.js} +5 -5
- package/dist/{pi-embedded-BAHaY-Oh.js → pi-embedded-CJVNBk0y.js} +150 -150
- package/dist/pi-model-discovery-7IzK0Uc3.js +131 -0
- package/dist/pi-model-discovery-runtime-DABef3qy.js +12 -0
- package/dist/{pi-tools.before-tool-call.runtime-D_mthvtC.js → pi-tools.before-tool-call.runtime-BP2UvGJb.js} +10 -10
- package/dist/plugin-sdk/active-listener-CN-tMEvN.js +35 -0
- package/dist/plugin-sdk/api-key-rotation-CimGYMBc.js +176 -0
- package/dist/plugin-sdk/audio-preflight-C-xXBoE2.js +51 -0
- package/dist/plugin-sdk/audio-transcription-runner-CTIHpebA.js +2173 -0
- package/dist/plugin-sdk/audit-membership-runtime-BFatB2LJ.js +58 -0
- package/dist/plugin-sdk/channel-activity-DO0FEzyj.js +95 -0
- package/dist/plugin-sdk/channel-web-Da-__nUF.js +2238 -0
- package/dist/plugin-sdk/commands-registry-6no2NNrY.js +1118 -0
- package/dist/plugin-sdk/compact.runtime-CCoclu5e.js +35 -0
- package/dist/plugin-sdk/compat.js +35 -35
- package/dist/plugin-sdk/config-B9ODwgpz.js +37426 -0
- package/dist/plugin-sdk/deliver-B1fFpKjV.js +1757 -0
- package/dist/plugin-sdk/deliver-runtime-DB-VRMe1.js +15 -0
- package/dist/plugin-sdk/deps-send-discord.runtime-DklqycYG.js +15 -0
- package/dist/plugin-sdk/deps-send-imessage.runtime-Chs8zeon.js +14 -0
- package/dist/plugin-sdk/deps-send-signal.runtime-clW9aSJP.js +13 -0
- package/dist/plugin-sdk/deps-send-slack.runtime-BUx0LYY1.js +13 -0
- package/dist/plugin-sdk/deps-send-telegram.runtime-LECSHgMG.js +16 -0
- package/dist/plugin-sdk/deps-send-whatsapp.runtime-D2d65fw0.js +40 -0
- package/dist/plugin-sdk/diagnostic-CxIvS-C2.js +315 -0
- package/dist/plugin-sdk/dispatch-BqlR4dPx.js +105863 -0
- package/dist/plugin-sdk/env-b9k1PHMI.js +34 -0
- package/dist/plugin-sdk/fetch-PoxzAANT.js +326 -0
- package/dist/plugin-sdk/fetch-guard-4UVSZ0uS.js +164 -0
- package/dist/plugin-sdk/image-Ch6M4tnJ.js +2420 -0
- package/dist/plugin-sdk/image-runtime-CSh2o5wY.js +8 -0
- package/dist/plugin-sdk/ir-CugsqGH8.js +1312 -0
- package/dist/plugin-sdk/local-roots-adnEg9zb.js +217 -0
- package/dist/plugin-sdk/logger-D6zRubj0.js +1164 -0
- package/dist/plugin-sdk/login-CYvkQ0At.js +54 -0
- package/dist/plugin-sdk/login-qr-ll4NtaT5.js +316 -0
- package/dist/plugin-sdk/manager-CHy8IclH.js +3959 -0
- package/dist/plugin-sdk/manager-runtime-C70EkEr7.js +11 -0
- package/dist/plugin-sdk/outbound-Wzs2iN7X.js +216 -0
- package/dist/plugin-sdk/outbound-attachment-khXJwucX.js +17 -0
- package/dist/plugin-sdk/paths-BtVqCdw4.js +3063 -0
- package/dist/{pi-model-discovery-ItS07aJB.js → plugin-sdk/pi-model-discovery-Dh4ziodY.js} +2 -2
- package/dist/plugin-sdk/pi-model-discovery-runtime-b83Xe-HT.js +8 -0
- package/dist/plugin-sdk/pi-tools.before-tool-call.runtime-C1z5CDBF.js +349 -0
- package/dist/{proxy-fetch-c1ZUFFcO.js → plugin-sdk/proxy-fetch-CJEmoBxi.js} +1 -1
- package/dist/plugin-sdk/pw-ai-Dj3Cvlzl.js +1990 -0
- package/dist/plugin-sdk/qmd-manager-egHUAseQ.js +1581 -0
- package/dist/plugin-sdk/resolve-outbound-target-BiICvIKs.js +38 -0
- package/dist/plugin-sdk/runtime-whatsapp-login.runtime-DNApufzW.js +9 -0
- package/dist/plugin-sdk/runtime-whatsapp-outbound.runtime-CBmtfIQ8.js +13 -0
- package/dist/plugin-sdk/send-CScblaI4.js +532 -0
- package/dist/plugin-sdk/send-CeHhnld6.js +407 -0
- package/dist/plugin-sdk/send-DP_c8JfR.js +3277 -0
- package/dist/plugin-sdk/send-Dc5fI6e8.js +495 -0
- package/dist/plugin-sdk/send-l-77_s1_.js +2507 -0
- package/dist/plugin-sdk/session-CkOKZaqa.js +166 -0
- package/dist/plugin-sdk/signal.js +2 -2
- package/dist/plugin-sdk/skill-commands-BohYCgkq.js +336 -0
- package/dist/plugin-sdk/slash-commands.runtime-DpLfVTM6.js +8 -0
- package/dist/plugin-sdk/slash-dispatch.runtime-CASMHwpm.js +35 -0
- package/dist/plugin-sdk/slash-skill-commands.runtime-D7rrJEci.js +9 -0
- package/dist/plugin-sdk/sqlite-CJE3X7Mv.js +1005 -0
- package/dist/plugin-sdk/subagent-registry-runtime-B1oo5bih.js +35 -0
- package/dist/plugin-sdk/tables-D5VgpTmm.js +53 -0
- package/dist/plugin-sdk/target-errors-C6zZ_OpA.js +191 -0
- package/dist/{tokens-BWDIKewp.js → plugin-sdk/tokens-DUnJnpMS.js} +1 -1
- package/dist/plugin-sdk/web-TfUM1nSi.js +39 -0
- package/dist/plugin-sdk/whatsapp-actions-DuWJ0j1r.js +71 -0
- package/dist/proxy-fetch-BOh1PLOW.js +54 -0
- package/dist/{pw-ai-Ok6KGelf.js → pw-ai-DwH5GpEO.js} +9 -9
- package/dist/{qmd-manager-DhfEz4Ar.js → qmd-manager-DEscZz5_.js} +6 -6
- package/dist/{query-expansion-GqNV2iIE.js → query-expansion-BErUY8P2.js} +4 -4
- package/dist/runtime-whatsapp-login.runtime-BI3U306v.js +13 -0
- package/dist/runtime-whatsapp-outbound.runtime-Bsc2uD09.js +17 -0
- package/dist/{send-DwAoiT2p.js → send-BDnOgWIp.js} +25 -25
- package/dist/{send-CS0ocZHl.js → send-C-Q_WPMf.js} +3 -3
- package/dist/{send-6R8b9zsj.js → send-DUibfNQD.js} +5 -5
- package/dist/{send-DPflcjM5.js → send-DtBvCnPQ.js} +6 -6
- package/dist/{send-CEg4P96c.js → send-ORtn50qg.js} +5 -5
- package/dist/{session-BoIID5UR.js → session-B7imi6T5.js} +7 -7
- package/dist/{skill-commands-DhdiziMs.js → skill-commands-B9brPuiL.js} +9 -9
- package/dist/slash-commands.runtime-Cf6ygfBp.js +12 -0
- package/dist/slash-dispatch.runtime-CsmvhO5K.js +39 -0
- package/dist/slash-skill-commands.runtime-CX7stIEP.js +13 -0
- package/dist/subagent-registry-runtime-B_S1nf7y.js +39 -0
- package/dist/{subsystem-C8z6w6xC.js → subsystem-DfXy5gUB.js} +14 -14
- package/dist/{tables-DQusRhkD.js → tables-CjQqTOdD.js} +1 -1
- package/dist/{target-errors-CfavnC9U.js → target-errors-BZE1mc-W.js} +1 -1
- package/dist/tokens-6ul2IrzG.js +50 -0
- package/dist/{web-CrcrTQ2c.js → web-Cd8yK1Zq.js} +39 -39
- package/dist/{whatsapp-actions-B0u0ZAme.js → whatsapp-actions-CYEzUMBI.js} +15 -15
- package/dist/{workspace-CWDYHR27.js → workspace-DGIcKCCW.js} +20 -20
- package/extensions/cclawd-mfa-auth/README.md +118 -0
- package/extensions/cclawd-mfa-auth/index.ts +382 -0
- package/extensions/cclawd-mfa-auth/openclaw.plugin.json +34 -0
- package/extensions/cclawd-mfa-auth/package.json +27 -0
- package/extensions/cclawd-mfa-auth/src/auth-manager.ts +536 -0
- package/extensions/cclawd-mfa-auth/src/config.ts +82 -0
- package/extensions/cclawd-mfa-auth/src/dabby-client.ts +200 -0
- package/extensions/cclawd-mfa-auth/src/notification-service.ts +417 -0
- package/extensions/cclawd-mfa-auth/src/polling-manager.ts +232 -0
- package/extensions/cclawd-mfa-auth/src/providers/base.ts +25 -0
- package/extensions/cclawd-mfa-auth/src/providers/qr-code.ts +98 -0
- package/extensions/cclawd-mfa-auth/src/sensitive-detector.ts +159 -0
- package/extensions/cclawd-mfa-auth/src/session-resolver.ts +159 -0
- package/extensions/cclawd-mfa-auth/src/types.ts +156 -0
- package/extensions/mfa-auth/index.ts +675 -1028
- package/extensions/mfa-auth/openclaw.plugin.json +1 -1
- package/extensions/mfa-auth/src/notification-service.ts +2 -8
- package/package.json +453 -453
- package/dist/compact.runtime-BEn3giMt.js +0 -39
- package/dist/deliver-runtime-DkQ3XzGv.js +0 -19
- package/dist/deps-send-discord.runtime-BLpqSj6s.js +0 -19
- package/dist/deps-send-imessage.runtime-BFzyYqvR.js +0 -18
- package/dist/deps-send-signal.runtime-DT0TYCy1.js +0 -17
- package/dist/deps-send-slack.runtime-BhaGFfMX.js +0 -17
- package/dist/deps-send-telegram.runtime-B6Cic9NX.js +0 -20
- package/dist/deps-send-whatsapp.runtime-WtEhIq2S.js +0 -43
- package/dist/image-runtime-B1LFYfQ2.js +0 -12
- package/dist/manager-runtime-Da7ME9vS.js +0 -15
- package/dist/pi-model-discovery-runtime-DjM7Z1fx.js +0 -12
- package/dist/runtime-whatsapp-login.runtime-D4BRhQkK.js +0 -13
- package/dist/runtime-whatsapp-outbound.runtime-DJPpS6g-.js +0 -17
- package/dist/slash-commands.runtime-Cu1lTjV9.js +0 -12
- package/dist/slash-dispatch.runtime-DRVJEF4l.js +0 -39
- package/dist/slash-skill-commands.runtime-C373PJjv.js +0 -13
- package/dist/subagent-registry-runtime-D7hWBo1G.js +0 -39
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import "./paths-
|
|
2
|
-
import "./paths-
|
|
3
|
-
import "./subsystem-
|
|
4
|
-
import "./workspace-
|
|
5
|
-
import "./logger-
|
|
6
|
-
import { Dr as normalizeWhatsAppTarget, Er as isWhatsAppGroupJid, dr as resolveWhatsAppAccount } from "./model-selection-
|
|
7
|
-
import "./github-copilot-token-
|
|
1
|
+
import "./paths-CehYKFsO.js";
|
|
2
|
+
import "./paths-DkxwiA8g.js";
|
|
3
|
+
import "./subsystem-DfXy5gUB.js";
|
|
4
|
+
import "./workspace-DGIcKCCW.js";
|
|
5
|
+
import "./logger-CbUVl62f.js";
|
|
6
|
+
import { Dr as normalizeWhatsAppTarget, Er as isWhatsAppGroupJid, dr as resolveWhatsAppAccount } from "./model-selection-Cv2Puf5z.js";
|
|
7
|
+
import "./github-copilot-token-8N63GdbE.js";
|
|
8
8
|
import "./boolean-C7Ct_klp.js";
|
|
9
|
-
import "./env-
|
|
10
|
-
import "./frontmatter-
|
|
11
|
-
import "./fetch-
|
|
12
|
-
import "./fetch-guard-
|
|
13
|
-
import "./ir-
|
|
9
|
+
import "./env-lw2hsIUY.js";
|
|
10
|
+
import "./frontmatter-C_obXuTp.js";
|
|
11
|
+
import "./fetch-D9NUULbj.js";
|
|
12
|
+
import "./fetch-guard-B5ZMnGaN.js";
|
|
13
|
+
import "./ir-CsgNUpOU.js";
|
|
14
14
|
import "./render-IRnn-2gt.js";
|
|
15
|
-
import { f as readReactionParams, h as readStringParam, i as ToolAuthorizationError, l as jsonResult, n as missingTargetError, o as createActionGate } from "./target-errors-
|
|
16
|
-
import "./tables-
|
|
17
|
-
import { r as sendReactionWhatsApp } from "./outbound-
|
|
15
|
+
import { f as readReactionParams, h as readStringParam, i as ToolAuthorizationError, l as jsonResult, n as missingTargetError, o as createActionGate } from "./target-errors-BZE1mc-W.js";
|
|
16
|
+
import "./tables-CjQqTOdD.js";
|
|
17
|
+
import { r as sendReactionWhatsApp } from "./outbound-Chpiwybe.js";
|
|
18
18
|
//#region src/whatsapp/resolve-outbound-target.ts
|
|
19
19
|
function resolveWhatsAppOutboundTarget(params) {
|
|
20
20
|
const trimmed = params.to?.trim() ?? "";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { d as resolveRequiredHomeDir } from "./paths-
|
|
2
|
-
import { l as danger, m as shouldLogVerbose } from "./subsystem-
|
|
3
|
-
import { g as pathExists$1, n as logError, t as logDebug, y as resolveUserPath } from "./logger-
|
|
1
|
+
import { d as resolveRequiredHomeDir } from "./paths-DkxwiA8g.js";
|
|
2
|
+
import { l as danger, m as shouldLogVerbose } from "./subsystem-DfXy5gUB.js";
|
|
3
|
+
import { g as pathExists$1, n as logError, t as logDebug, y as resolveUserPath } from "./logger-CbUVl62f.js";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import os from "node:os";
|
|
6
6
|
import path from "node:path";
|
|
7
|
-
import
|
|
7
|
+
import syncFs from "node:fs";
|
|
8
8
|
import { promisify } from "node:util";
|
|
9
9
|
import { execFile, spawn } from "node:child_process";
|
|
10
10
|
import process$1 from "node:process";
|
|
@@ -566,7 +566,7 @@ function resolveBoundaryPathLexicalSync(params) {
|
|
|
566
566
|
rootCanonicalPath: params.rootCanonicalPath,
|
|
567
567
|
resolveParams: params.params,
|
|
568
568
|
absolutePath: params.absolutePath,
|
|
569
|
-
read: (cursor) =>
|
|
569
|
+
read: (cursor) => syncFs.lstatSync(cursor)
|
|
570
570
|
});
|
|
571
571
|
if (isPromiseLike(maybeStat)) throw new Error("Unexpected async lexical stat");
|
|
572
572
|
const stat = maybeStat;
|
|
@@ -716,15 +716,15 @@ function resolvePathViaExistingAncestorSync(targetPath) {
|
|
|
716
716
|
const normalized = path.resolve(targetPath);
|
|
717
717
|
let cursor = normalized;
|
|
718
718
|
const missingSuffix = [];
|
|
719
|
-
while (!isFilesystemRoot(cursor) && !
|
|
719
|
+
while (!isFilesystemRoot(cursor) && !syncFs.existsSync(cursor)) {
|
|
720
720
|
missingSuffix.unshift(path.basename(cursor));
|
|
721
721
|
const parent = path.dirname(cursor);
|
|
722
722
|
if (parent === cursor) break;
|
|
723
723
|
cursor = parent;
|
|
724
724
|
}
|
|
725
|
-
if (!
|
|
725
|
+
if (!syncFs.existsSync(cursor)) return normalized;
|
|
726
726
|
try {
|
|
727
|
-
const resolvedAncestor = path.resolve(
|
|
727
|
+
const resolvedAncestor = path.resolve(syncFs.realpathSync(cursor));
|
|
728
728
|
if (missingSuffix.length === 0) return resolvedAncestor;
|
|
729
729
|
return path.resolve(resolvedAncestor, ...missingSuffix);
|
|
730
730
|
} catch {
|
|
@@ -749,7 +749,7 @@ function getPathKindSync(absolutePath, preserveFinalSymlink) {
|
|
|
749
749
|
try {
|
|
750
750
|
return {
|
|
751
751
|
exists: true,
|
|
752
|
-
kind: toResolvedKind(preserveFinalSymlink ?
|
|
752
|
+
kind: toResolvedKind(preserveFinalSymlink ? syncFs.lstatSync(absolutePath) : syncFs.statSync(absolutePath))
|
|
753
753
|
};
|
|
754
754
|
} catch (error) {
|
|
755
755
|
if (isNotFoundPathError(error)) return {
|
|
@@ -809,10 +809,10 @@ async function resolveSymlinkHopPath(symlinkPath) {
|
|
|
809
809
|
}
|
|
810
810
|
function resolveSymlinkHopPathSync(symlinkPath) {
|
|
811
811
|
try {
|
|
812
|
-
return path.resolve(
|
|
812
|
+
return path.resolve(syncFs.realpathSync(symlinkPath));
|
|
813
813
|
} catch (error) {
|
|
814
814
|
if (!isNotFoundPathError(error)) throw error;
|
|
815
|
-
const linkTarget =
|
|
815
|
+
const linkTarget = syncFs.readlinkSync(symlinkPath);
|
|
816
816
|
return resolvePathViaExistingAncestorSync(path.resolve(path.dirname(symlinkPath), linkTarget));
|
|
817
817
|
}
|
|
818
818
|
}
|
|
@@ -836,7 +836,7 @@ function sameFileIdentity(left, right) {
|
|
|
836
836
|
return sameFileIdentity$1(left, right);
|
|
837
837
|
}
|
|
838
838
|
function openVerifiedFileSync(params) {
|
|
839
|
-
const ioFs = params.ioFs ??
|
|
839
|
+
const ioFs = params.ioFs ?? syncFs;
|
|
840
840
|
const allowedType = params.allowedType ?? "file";
|
|
841
841
|
const openReadFlags = ioFs.constants.O_RDONLY | (typeof ioFs.constants.O_NOFOLLOW === "number" ? ioFs.constants.O_NOFOLLOW : 0);
|
|
842
842
|
let fd = null;
|
|
@@ -912,7 +912,7 @@ function canUseBoundaryFileOpen(ioFs) {
|
|
|
912
912
|
return typeof ioFs.openSync === "function" && typeof ioFs.closeSync === "function" && typeof ioFs.fstatSync === "function" && typeof ioFs.lstatSync === "function" && typeof ioFs.realpathSync === "function" && typeof ioFs.readFileSync === "function" && typeof ioFs.constants === "object" && ioFs.constants !== null;
|
|
913
913
|
}
|
|
914
914
|
function openBoundaryFileSync(params) {
|
|
915
|
-
const ioFs = params.ioFs ??
|
|
915
|
+
const ioFs = params.ioFs ?? syncFs;
|
|
916
916
|
const resolved = resolveBoundaryFilePathGeneric({
|
|
917
917
|
absolutePath: params.absolutePath,
|
|
918
918
|
resolve: (absolutePath) => resolveBoundaryPathSync({
|
|
@@ -963,7 +963,7 @@ function finalizeBoundaryFileOpen(params) {
|
|
|
963
963
|
});
|
|
964
964
|
}
|
|
965
965
|
async function openBoundaryFile(params) {
|
|
966
|
-
const ioFs = params.ioFs ??
|
|
966
|
+
const ioFs = params.ioFs ?? syncFs;
|
|
967
967
|
const maybeResolved = resolveBoundaryFilePathGeneric({
|
|
968
968
|
absolutePath: params.absolutePath,
|
|
969
969
|
resolve: (absolutePath) => resolveBoundaryPath({
|
|
@@ -1119,7 +1119,7 @@ function resolveNpmArgvForWindows(argv) {
|
|
|
1119
1119
|
if (!cliName) return null;
|
|
1120
1120
|
const nodeDir = path.dirname(process$1.execPath);
|
|
1121
1121
|
const cliPath = path.join(nodeDir, "node_modules", "npm", "bin", cliName);
|
|
1122
|
-
if (!
|
|
1122
|
+
if (!syncFs.existsSync(cliPath)) {
|
|
1123
1123
|
const command = argv[0] ?? "";
|
|
1124
1124
|
return [path.extname(command).toLowerCase() ? command : `${command}.cmd`, ...argv.slice(1)];
|
|
1125
1125
|
}
|
|
@@ -1323,7 +1323,7 @@ async function readPackageName(dir) {
|
|
|
1323
1323
|
}
|
|
1324
1324
|
function readPackageNameSync(dir) {
|
|
1325
1325
|
try {
|
|
1326
|
-
const raw =
|
|
1326
|
+
const raw = syncFs.readFileSync(path.join(dir, "package.json"), "utf-8");
|
|
1327
1327
|
const parsed = JSON.parse(raw);
|
|
1328
1328
|
return typeof parsed.name === "string" ? parsed.name : null;
|
|
1329
1329
|
} catch {
|
|
@@ -1357,7 +1357,7 @@ function candidateDirsFromArgv1(argv1) {
|
|
|
1357
1357
|
const normalized = path.resolve(argv1);
|
|
1358
1358
|
const candidates = [path.dirname(normalized)];
|
|
1359
1359
|
try {
|
|
1360
|
-
const resolved =
|
|
1360
|
+
const resolved = syncFs.realpathSync(normalized);
|
|
1361
1361
|
if (resolved !== normalized) candidates.push(path.dirname(resolved));
|
|
1362
1362
|
} catch {}
|
|
1363
1363
|
const parts = normalized.split(path.sep);
|
|
@@ -1469,14 +1469,14 @@ async function readWorkspaceFileWithGuards(params) {
|
|
|
1469
1469
|
const identity = workspaceFileIdentity(opened.stat, opened.path);
|
|
1470
1470
|
const cached = workspaceFileCache.get(params.filePath);
|
|
1471
1471
|
if (cached && cached.identity === identity) {
|
|
1472
|
-
|
|
1472
|
+
syncFs.closeSync(opened.fd);
|
|
1473
1473
|
return {
|
|
1474
1474
|
ok: true,
|
|
1475
1475
|
content: cached.content
|
|
1476
1476
|
};
|
|
1477
1477
|
}
|
|
1478
1478
|
try {
|
|
1479
|
-
const content =
|
|
1479
|
+
const content = syncFs.readFileSync(opened.fd, "utf-8");
|
|
1480
1480
|
workspaceFileCache.set(params.filePath, {
|
|
1481
1481
|
content,
|
|
1482
1482
|
identity
|
|
@@ -1493,7 +1493,7 @@ async function readWorkspaceFileWithGuards(params) {
|
|
|
1493
1493
|
error
|
|
1494
1494
|
};
|
|
1495
1495
|
} finally {
|
|
1496
|
-
|
|
1496
|
+
syncFs.closeSync(opened.fd);
|
|
1497
1497
|
}
|
|
1498
1498
|
}
|
|
1499
1499
|
function stripFrontMatter(content) {
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Cclawd MFA Auth Plugin
|
|
2
|
+
|
|
3
|
+
OpenClaw 插件,为多渠道提供 MFA(多因素认证)功能。
|
|
4
|
+
|
|
5
|
+
## 功能特性
|
|
6
|
+
|
|
7
|
+
- ✅ **首次对话认证**:用户首次对话时触发 MFA 认证
|
|
8
|
+
- ✅ **敏感操作认证**:敏感操作(如执行命令)需要二次认证
|
|
9
|
+
- ✅ **/reauth 命令**:重置认证状态,重新认证
|
|
10
|
+
- ✅ **多渠道支持**:支持 Web/WebChat 和其他渠道
|
|
11
|
+
- ✅ **轮询认证结果**:自动轮询认证状态,成功后推送通知
|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 配置
|
|
20
|
+
|
|
21
|
+
通过环境变量配置插件:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Dabby API 配置
|
|
25
|
+
MFA_AUTH_API_KEY=your_api_key_here
|
|
26
|
+
DABBY_API_BASE_URL=https://api.dabby.com
|
|
27
|
+
|
|
28
|
+
# 认证有效期(毫秒)
|
|
29
|
+
MFA_VERIFICATION_DURATION=120000 # 敏感操作认证有效期,默认 2 分钟
|
|
30
|
+
MFA_FIRST_MESSAGE_AUTH_DURATION=86400000 # 首次认证有效期,默认 24 小时
|
|
31
|
+
|
|
32
|
+
# 功能开关
|
|
33
|
+
MFA_REQUIRE_AUTH_ON_FIRST_MESSAGE=true # 启用首次消息认证
|
|
34
|
+
MFA_REQUIRE_AUTH_ON_SENSITIVE_OPERATION=true # 启用敏感操作认证
|
|
35
|
+
|
|
36
|
+
# 敏感关键词(逗号分隔)
|
|
37
|
+
MFA_SENSITIVE_KEYWORDS=rm,delete,drop,shutdown
|
|
38
|
+
|
|
39
|
+
# Gateway 配置
|
|
40
|
+
MFA_GATEWAY_HOST=127.0.0.1 # Gateway 主机地址
|
|
41
|
+
MFA_ENABLE_AUTH_NOTIFICATION=true # 启用认证成功通知
|
|
42
|
+
|
|
43
|
+
# 状态持久化目录
|
|
44
|
+
MFA_AUTH_STATE_DIR=~/.openclaw/cclawd-mfa-auth/
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 使用
|
|
48
|
+
|
|
49
|
+
### 1. 首次对话认证
|
|
50
|
+
|
|
51
|
+
用户首次发送消息时,插件会自动触发认证流程:
|
|
52
|
+
|
|
53
|
+
1. 生成二维码认证链接
|
|
54
|
+
2. 推送认证链接给用户
|
|
55
|
+
3. 轮询认证状态
|
|
56
|
+
4. 认证成功后推送通知
|
|
57
|
+
|
|
58
|
+
### 2. 敏感操作认证
|
|
59
|
+
|
|
60
|
+
当用户执行敏感操作(如 bash 命令包含敏感关键词)时:
|
|
61
|
+
|
|
62
|
+
1. 拦截操作
|
|
63
|
+
2. 要求二次认证
|
|
64
|
+
3. 认证成功后允许执行
|
|
65
|
+
|
|
66
|
+
### 3. /reauth 命令
|
|
67
|
+
|
|
68
|
+
用户可以随时发送 `/reauth` 命令重新认证:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
/reauth
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 认证流程
|
|
75
|
+
|
|
76
|
+
```mermaid
|
|
77
|
+
sequenceDiagram
|
|
78
|
+
participant User
|
|
79
|
+
participant Plugin
|
|
80
|
+
participant AuthManager
|
|
81
|
+
participant DabbyAPI
|
|
82
|
+
participant NotificationService
|
|
83
|
+
|
|
84
|
+
User->>Plugin: 发送消息
|
|
85
|
+
Plugin->>AuthManager: 检查认证状态
|
|
86
|
+
alt 未认证
|
|
87
|
+
AuthManager->>DabbyAPI: 获取二维码
|
|
88
|
+
DabbyAPI-->>AuthManager: certToken + qrCodeUrl
|
|
89
|
+
AuthManager->>NotificationService: 推送认证链接
|
|
90
|
+
NotificationService-->>User: 显示二维码
|
|
91
|
+
loop 轮询认证结果
|
|
92
|
+
AuthManager->>DabbyAPI: 检查认证状态
|
|
93
|
+
DabbyAPI-->>AuthManager: 返回状态
|
|
94
|
+
end
|
|
95
|
+
AuthManager->>NotificationService: 推送成功消息
|
|
96
|
+
NotificationService-->>User: 认证成功
|
|
97
|
+
end
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## 支持的渠道
|
|
101
|
+
|
|
102
|
+
- ✅ Web/WebChat
|
|
103
|
+
- ✅ Feishu(飞书)
|
|
104
|
+
- 🚧 其他渠道(可扩展)
|
|
105
|
+
|
|
106
|
+
## 开发
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# 开发模式
|
|
110
|
+
pnpm dev
|
|
111
|
+
|
|
112
|
+
# 构建
|
|
113
|
+
pnpm build
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
MIT
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cclawd MFA Auth Plugin - Main Entry
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { OpenClawPluginApi } from 'openclaw/plugin-sdk';
|
|
6
|
+
import { authManager } from './src/auth-manager.js';
|
|
7
|
+
import { config } from './src/config.js';
|
|
8
|
+
import { NotificationService } from './src/notification-service.js';
|
|
9
|
+
import { pollingManager } from './src/polling-manager.js';
|
|
10
|
+
import { SessionResolver } from './src/session-resolver.js';
|
|
11
|
+
import { sensitiveDetector } from './src/sensitive-detector.js';
|
|
12
|
+
import { qrCodeAuthProvider } from './src/providers/qr-code.js';
|
|
13
|
+
import type { AuthSession, PendingAuthContext } from './src/types.js';
|
|
14
|
+
|
|
15
|
+
const notificationService = NotificationService.getInstance();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 发送认证消息
|
|
19
|
+
*/
|
|
20
|
+
async function sendAuthMessage(
|
|
21
|
+
channel: string | undefined,
|
|
22
|
+
accountId: string | undefined,
|
|
23
|
+
to: string,
|
|
24
|
+
message: string,
|
|
25
|
+
userId: string,
|
|
26
|
+
overrideSessionKey?: string,
|
|
27
|
+
): Promise<void> {
|
|
28
|
+
const session: AuthSession = {
|
|
29
|
+
userId,
|
|
30
|
+
sessionId: 'notification',
|
|
31
|
+
authMethod: 'qr-code',
|
|
32
|
+
timestamp: Date.now(),
|
|
33
|
+
originalContext: {
|
|
34
|
+
sessionKey: overrideSessionKey || `${channel || 'web'}:${accountId || ''}:${userId}`,
|
|
35
|
+
senderId: userId,
|
|
36
|
+
commandBody: '',
|
|
37
|
+
channel: channel || 'web',
|
|
38
|
+
accountId: accountId || '',
|
|
39
|
+
to,
|
|
40
|
+
toolName: 'notification',
|
|
41
|
+
toolParams: {},
|
|
42
|
+
timestamp: Date.now(),
|
|
43
|
+
triggerType: 'sensitive_operation',
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
await notificationService.sendAuthNotification(session, message);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 插件注册函数
|
|
52
|
+
*/
|
|
53
|
+
export default function register(api: OpenClawPluginApi) {
|
|
54
|
+
console.log('[cclawd-mfa-auth] Plugin registration started');
|
|
55
|
+
authManager.registerProvider(qrCodeAuthProvider);
|
|
56
|
+
|
|
57
|
+
notificationService.setConfig(api.config);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 处理消息接收事件 - 首次对话认证
|
|
61
|
+
*/
|
|
62
|
+
api.on('message_received', async (event, ctx) => {
|
|
63
|
+
await authManager.ensureInitialized();
|
|
64
|
+
|
|
65
|
+
api.logger.info(
|
|
66
|
+
`[cclawd-mfa-auth] First message auth check: config.requireAuthOnFirstMessage=${config.requireAuthOnFirstMessage}`,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (!config.requireAuthOnFirstMessage) {
|
|
70
|
+
api.logger.warn(`[cclawd-mfa-auth] First message auth is disabled in config, skipping.`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const content = event.content || '';
|
|
75
|
+
const isReauthCommand = content.trim() === '/reauth';
|
|
76
|
+
|
|
77
|
+
if (isReauthCommand) {
|
|
78
|
+
api.logger.info(`[cclawd-mfa-auth] /reauth command detected, skipping first message auth check`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 解析会话信息
|
|
83
|
+
// metadata.senderId 是 WebChat 的真实用户标识
|
|
84
|
+
const metadataSenderId = event.metadata?.senderId as string | undefined;
|
|
85
|
+
|
|
86
|
+
const resolved = SessionResolver.resolveFromContext({
|
|
87
|
+
sessionKey: ctx.sessionKey,
|
|
88
|
+
channelId: ctx.channelId,
|
|
89
|
+
conversationId: ctx.conversationId,
|
|
90
|
+
accountId: ctx.accountId,
|
|
91
|
+
from: event.from,
|
|
92
|
+
senderId: metadataSenderId || ctx.senderId,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const userId = resolved.userId;
|
|
96
|
+
|
|
97
|
+
api.logger.info(`[cclawd-mfa-auth] Extracted userId="${userId}", sessionKey="${resolved.sessionKey}"`);
|
|
98
|
+
|
|
99
|
+
// 检查是否已认证
|
|
100
|
+
if (authManager.isUserVerifiedForFirstMessage(userId)) {
|
|
101
|
+
api.logger.info(`[cclawd-mfa-auth] User ${userId} already verified for first message`);
|
|
102
|
+
|
|
103
|
+
const notificationInfo = authManager.checkAndConsumeNotification(userId);
|
|
104
|
+
if (notificationInfo) {
|
|
105
|
+
const messageText = notificationInfo.isReauth
|
|
106
|
+
? '✅ 重新认证成功,请继续对话。'
|
|
107
|
+
: '✅ 首次认证成功,请继续对话。';
|
|
108
|
+
|
|
109
|
+
await sendAuthMessage(
|
|
110
|
+
resolved.channel,
|
|
111
|
+
resolved.accountId,
|
|
112
|
+
event.metadata?.to as string | undefined || event.from || userId,
|
|
113
|
+
messageText,
|
|
114
|
+
userId,
|
|
115
|
+
resolved.sessionKey,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
api.logger.info(`[cclawd-mfa-auth] First message from unauthenticated user ${userId}, requiring auth`);
|
|
122
|
+
|
|
123
|
+
// 生成认证会话
|
|
124
|
+
const session = await authManager.generateSession(userId, {
|
|
125
|
+
sessionKey: resolved.sessionKey,
|
|
126
|
+
senderId: userId,
|
|
127
|
+
commandBody: event.content || '',
|
|
128
|
+
channel: resolved.channel,
|
|
129
|
+
to: event.metadata?.to as string | undefined || event.from,
|
|
130
|
+
accountId: resolved.accountId,
|
|
131
|
+
toolName: '',
|
|
132
|
+
toolParams: {},
|
|
133
|
+
timestamp: Date.now(),
|
|
134
|
+
triggerType: 'first_message',
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
if (!session) {
|
|
138
|
+
api.logger.error(`[cclawd-mfa-auth] Failed to generate first message auth session for user ${userId}`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
api.logger.info(`[cclawd-mfa-auth] Blocking first message from ${userId}`);
|
|
143
|
+
|
|
144
|
+
// 发送认证链接
|
|
145
|
+
const messageText = `🔐 首次对话需要进行认证
|
|
146
|
+
|
|
147
|
+
为了您的账户安全,首次对话前需要完成身份验证。
|
|
148
|
+
|
|
149
|
+
📱 请点击以下链接完成扫码认证:
|
|
150
|
+
${session.qrCodeUrl}
|
|
151
|
+
|
|
152
|
+
验证有效期: ${Math.floor(config.timeout / 60000)} 分钟`;
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
await sendAuthMessage(
|
|
156
|
+
resolved.channel,
|
|
157
|
+
resolved.accountId,
|
|
158
|
+
event.metadata?.to as string | undefined || event.from || userId,
|
|
159
|
+
messageText,
|
|
160
|
+
userId,
|
|
161
|
+
resolved.sessionKey,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// 启动轮询
|
|
165
|
+
pollingManager.startPolling(api, userId, session.sessionId, {
|
|
166
|
+
triggerType: 'first_message',
|
|
167
|
+
isReauth: false,
|
|
168
|
+
channel: resolved.channel,
|
|
169
|
+
accountId: resolved.accountId,
|
|
170
|
+
to: event.metadata?.to as string | undefined,
|
|
171
|
+
sessionKey: resolved.sessionKey,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
api.logger.info(`[cclawd-mfa-auth] Sent first message auth notification`);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
api.logger.error(`[cclawd-mfa-auth] Failed to send first message auth notification: ${String(error)}`);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* 处理工具调用前事件 - 敏感操作认证
|
|
182
|
+
*/
|
|
183
|
+
api.on('before_tool_call', async (event, ctx) => {
|
|
184
|
+
await authManager.ensureInitialized();
|
|
185
|
+
if (!config.requireAuthOnSensitiveOperation) {
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const { toolName, params } = event;
|
|
190
|
+
|
|
191
|
+
api.logger.info(`[cclawd-mfa-auth] Tool call detected: ${toolName}`);
|
|
192
|
+
|
|
193
|
+
// 检查是否为敏感操作
|
|
194
|
+
const sensitiveCheck = sensitiveDetector.checkToolCall(toolName, params || {});
|
|
195
|
+
if (!sensitiveCheck.isSensitive) {
|
|
196
|
+
api.logger.info(`[cclawd-mfa-auth] Tool ${toolName} is not sensitive, allowing`);
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// 解析会话信息
|
|
201
|
+
const resolved = SessionResolver.resolveFromContext({
|
|
202
|
+
sessionKey: ctx.sessionKey,
|
|
203
|
+
channelId: ctx.channelId,
|
|
204
|
+
conversationId: ctx.conversationId,
|
|
205
|
+
accountId: ctx.accountId,
|
|
206
|
+
from: ctx.from,
|
|
207
|
+
senderId: ctx.senderId,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const userId = resolved.userId;
|
|
211
|
+
|
|
212
|
+
// 检查是否已认证
|
|
213
|
+
if (authManager.isUserVerifiedForSensitiveOps(userId)) {
|
|
214
|
+
api.logger.info(`[cclawd-mfa-auth] User ${userId} is verified for sensitive ops, allowing`);
|
|
215
|
+
|
|
216
|
+
const notificationInfo = authManager.checkAndConsumeNotification(userId);
|
|
217
|
+
if (notificationInfo) {
|
|
218
|
+
await sendAuthMessage(
|
|
219
|
+
resolved.channel,
|
|
220
|
+
resolved.accountId,
|
|
221
|
+
resolved.to || userId,
|
|
222
|
+
'✅ 二次认证成功,请重新发送之前的命令(或回复"确认")即可执行。',
|
|
223
|
+
userId,
|
|
224
|
+
resolved.sessionKey,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
api.logger.info(`[cclawd-mfa-auth] User ${userId} is NOT verified for sensitive ops.`);
|
|
232
|
+
|
|
233
|
+
// 生成认证会话
|
|
234
|
+
const session = await authManager.generateSession(userId, {
|
|
235
|
+
sessionKey: resolved.sessionKey,
|
|
236
|
+
senderId: userId,
|
|
237
|
+
commandBody: sensitiveCheck.preview,
|
|
238
|
+
channel: resolved.channel,
|
|
239
|
+
to: resolved.to,
|
|
240
|
+
accountId: resolved.accountId,
|
|
241
|
+
toolName,
|
|
242
|
+
toolParams: params || {},
|
|
243
|
+
timestamp: Date.now(),
|
|
244
|
+
triggerType: 'sensitive_operation',
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if (!session) {
|
|
248
|
+
api.logger.error(`[cclawd-mfa-auth] Failed to generate session for user ${userId}`);
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
api.logger.info(`[cclawd-mfa-auth] Blocking sensitive tool call: ${toolName} from ${userId}`);
|
|
253
|
+
|
|
254
|
+
// 发送认证链接
|
|
255
|
+
const messageText = `🔐 该操作需要二次认证
|
|
256
|
+
|
|
257
|
+
检测到敏感操作: ${sensitiveCheck.preview}
|
|
258
|
+
|
|
259
|
+
📱 请点击以下链接完成扫码认证:
|
|
260
|
+
${session.qrCodeUrl}
|
|
261
|
+
|
|
262
|
+
验证有效期: ${Math.floor(config.timeout / 60000)} 分钟
|
|
263
|
+
|
|
264
|
+
验证成功后,请回复"确认"或者重新发送之前的命令以继续执行。`;
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
await sendAuthMessage(
|
|
268
|
+
resolved.channel,
|
|
269
|
+
resolved.accountId,
|
|
270
|
+
resolved.to || userId,
|
|
271
|
+
messageText,
|
|
272
|
+
userId,
|
|
273
|
+
resolved.sessionKey,
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
// 启动轮询
|
|
277
|
+
pollingManager.startPolling(api, userId, session.sessionId, {
|
|
278
|
+
triggerType: 'sensitive_operation',
|
|
279
|
+
isReauth: false,
|
|
280
|
+
channel: resolved.channel,
|
|
281
|
+
accountId: resolved.accountId,
|
|
282
|
+
to: resolved.to,
|
|
283
|
+
sessionKey: resolved.sessionKey,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
api.logger.info(`[cclawd-mfa-auth] Sent sensitive operation auth notification`);
|
|
287
|
+
} catch (error) {
|
|
288
|
+
api.logger.error(`[cclawd-mfa-auth] Failed to send sensitive operation auth notification: ${String(error)}`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// 注册待执行操作
|
|
292
|
+
authManager.registerPendingExecution(userId, session.sessionId);
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
block: true,
|
|
296
|
+
blockReason: `🔐 该操作需要二次认证`,
|
|
297
|
+
};
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* 注册 /reauth 命令
|
|
302
|
+
*/
|
|
303
|
+
api.registerCommand({
|
|
304
|
+
name: 'reauth',
|
|
305
|
+
description: '重新进行首次对话认证',
|
|
306
|
+
acceptsArgs: false,
|
|
307
|
+
requireAuth: false,
|
|
308
|
+
handler: async (ctx) => {
|
|
309
|
+
const userId = ctx.from || ctx.senderId || 'unknown';
|
|
310
|
+
api.logger.info(`[cclawd-mfa-auth] /reauth command received. userId=${userId}`);
|
|
311
|
+
|
|
312
|
+
// 清除首次消息认证状态
|
|
313
|
+
authManager.clearFirstMessageAuth(userId);
|
|
314
|
+
|
|
315
|
+
// 解析会话信息
|
|
316
|
+
const resolved = SessionResolver.resolveFromContext({
|
|
317
|
+
sessionKey: ctx.sessionKey,
|
|
318
|
+
channelId: ctx.channel,
|
|
319
|
+
accountId: ctx.accountId,
|
|
320
|
+
from: ctx.from,
|
|
321
|
+
senderId: ctx.senderId,
|
|
322
|
+
to: ctx.to,
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// 生成认证会话
|
|
326
|
+
const session = await authManager.generateSession(userId, {
|
|
327
|
+
sessionKey: resolved.sessionKey,
|
|
328
|
+
senderId: userId,
|
|
329
|
+
commandBody: '/reauth',
|
|
330
|
+
channel: resolved.channel,
|
|
331
|
+
to: resolved.to,
|
|
332
|
+
accountId: resolved.accountId,
|
|
333
|
+
toolName: '',
|
|
334
|
+
toolParams: {},
|
|
335
|
+
timestamp: Date.now(),
|
|
336
|
+
triggerType: 'first_message',
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
if (!session) {
|
|
340
|
+
api.logger.error(`[cclawd-mfa-auth] Failed to generate reauth session for user ${userId}`);
|
|
341
|
+
return { text: '❌ 认证会话创建失败,请稍后重试。' };
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
api.logger.info(`[cclawd-mfa-auth] Reauth requested by user ${userId}, session=${session.sessionId}`);
|
|
345
|
+
|
|
346
|
+
const messageText = `🔐 重新认证
|
|
347
|
+
|
|
348
|
+
📱 请点击以下链接完成扫码认证:
|
|
349
|
+
${session.qrCodeUrl}
|
|
350
|
+
|
|
351
|
+
验证有效期: ${Math.floor(config.timeout / 60000)} 分钟`;
|
|
352
|
+
|
|
353
|
+
try {
|
|
354
|
+
await sendAuthMessage(
|
|
355
|
+
resolved.channel,
|
|
356
|
+
resolved.accountId,
|
|
357
|
+
resolved.to || userId,
|
|
358
|
+
messageText,
|
|
359
|
+
userId,
|
|
360
|
+
resolved.sessionKey,
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
// 启动轮询
|
|
364
|
+
pollingManager.startPolling(api, userId, session.sessionId, {
|
|
365
|
+
triggerType: 'first_message',
|
|
366
|
+
isReauth: true,
|
|
367
|
+
channel: resolved.channel,
|
|
368
|
+
accountId: resolved.accountId,
|
|
369
|
+
to: resolved.to,
|
|
370
|
+
sessionKey: resolved.sessionKey,
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
return { text: '📱 认证链接已发送,请查看最新消息。' };
|
|
374
|
+
} catch (error) {
|
|
375
|
+
api.logger.error(`[cclawd-mfa-auth] Failed to send reauth link: ${String(error)}`);
|
|
376
|
+
return { text: '❌ 认证链接发送失败,请稍后重试。' };
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
api.logger.info('[cclawd-mfa-auth] Plugin loaded successfully');
|
|
382
|
+
}
|