@openclaw/feishu 2026.5.2 → 2026.5.3-beta.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/dist/accounts-Ba3-WP1z.js +423 -0
- package/dist/api.js +2280 -0
- package/dist/app-registration-B8qc1MCM.js +184 -0
- package/dist/audio-preflight.runtime-BPlzkO3l.js +7 -0
- package/dist/card-interaction-BfRLgvw_.js +96 -0
- package/dist/channel-CSD_Jt8I.js +1668 -0
- package/dist/channel-entry.js +22 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel.runtime-DYsXcD36.js +700 -0
- package/dist/client-DBVoQL5w.js +157 -0
- package/dist/contract-api.js +9 -0
- package/dist/conversation-id-DWS3Ep2A.js +139 -0
- package/dist/directory.static-f3EeoRJd.js +44 -0
- package/dist/drive-C5eJLJr7.js +883 -0
- package/dist/index.js +68 -0
- package/dist/monitor-CT189QfR.js +60 -0
- package/dist/monitor.account-dJV2jO8C.js +4990 -0
- package/dist/monitor.state-DYM02ipp.js +100 -0
- package/dist/policy-D6c-wMPl.js +118 -0
- package/dist/probe-BNzzU_uR.js +149 -0
- package/dist/rolldown-runtime-DUslC3ob.js +14 -0
- package/dist/runtime-CG0DuRCy.js +8 -0
- package/dist/runtime-api.js +14 -0
- package/dist/secret-contract-Dm4Z_zQN.js +119 -0
- package/dist/secret-contract-api.js +2 -0
- package/dist/security-audit-DqJdocrN.js +11 -0
- package/dist/security-audit-shared-ByuMx9cJ.js +38 -0
- package/dist/security-contract-api.js +2 -0
- package/dist/send-DowxxbpH.js +1218 -0
- package/dist/session-conversation-B4nrW-vo.js +27 -0
- package/dist/session-key-api.js +2 -0
- package/dist/setup-api.js +2 -0
- package/dist/setup-entry.js +15 -0
- package/dist/subagent-hooks-C3UhPVLV.js +227 -0
- package/dist/subagent-hooks-api.js +23 -0
- package/dist/targets-JMFJRKSe.js +48 -0
- package/dist/thread-bindings-BmS6TLes.js +222 -0
- package/package.json +15 -6
- package/api.ts +0 -31
- package/channel-entry.ts +0 -20
- package/channel-plugin-api.ts +0 -1
- package/contract-api.ts +0 -16
- package/index.ts +0 -82
- package/runtime-api.ts +0 -55
- package/secret-contract-api.ts +0 -5
- package/security-contract-api.ts +0 -1
- package/session-key-api.ts +0 -1
- package/setup-api.ts +0 -3
- package/setup-entry.test.ts +0 -14
- package/setup-entry.ts +0 -13
- package/src/accounts.test.ts +0 -459
- package/src/accounts.ts +0 -326
- package/src/app-registration.ts +0 -331
- package/src/approval-auth.test.ts +0 -24
- package/src/approval-auth.ts +0 -25
- package/src/async.test.ts +0 -35
- package/src/async.ts +0 -104
- package/src/audio-preflight.runtime.ts +0 -9
- package/src/bitable.test.ts +0 -131
- package/src/bitable.ts +0 -762
- package/src/bot-content.ts +0 -474
- package/src/bot-group-name.test.ts +0 -108
- package/src/bot-runtime-api.ts +0 -12
- package/src/bot-sender-name.ts +0 -125
- package/src/bot.broadcast.test.ts +0 -463
- package/src/bot.card-action.test.ts +0 -577
- package/src/bot.checkBotMentioned.test.ts +0 -265
- package/src/bot.helpers.test.ts +0 -118
- package/src/bot.stripBotMention.test.ts +0 -126
- package/src/bot.test.ts +0 -3040
- package/src/bot.ts +0 -1559
- package/src/card-action.ts +0 -447
- package/src/card-interaction.test.ts +0 -129
- package/src/card-interaction.ts +0 -159
- package/src/card-test-helpers.ts +0 -47
- package/src/card-ux-approval.ts +0 -65
- package/src/card-ux-launcher.test.ts +0 -99
- package/src/card-ux-launcher.ts +0 -121
- package/src/card-ux-shared.ts +0 -33
- package/src/channel-runtime-api.ts +0 -16
- package/src/channel.runtime.ts +0 -47
- package/src/channel.test.ts +0 -959
- package/src/channel.ts +0 -1313
- package/src/chat-schema.ts +0 -25
- package/src/chat.test.ts +0 -196
- package/src/chat.ts +0 -188
- package/src/client.test.ts +0 -433
- package/src/client.ts +0 -290
- package/src/comment-dispatcher-runtime-api.ts +0 -6
- package/src/comment-dispatcher.test.ts +0 -169
- package/src/comment-dispatcher.ts +0 -107
- package/src/comment-handler-runtime-api.ts +0 -3
- package/src/comment-handler.test.ts +0 -486
- package/src/comment-handler.ts +0 -309
- package/src/comment-reaction.test.ts +0 -166
- package/src/comment-reaction.ts +0 -259
- package/src/comment-shared.test.ts +0 -182
- package/src/comment-shared.ts +0 -406
- package/src/comment-target.ts +0 -44
- package/src/config-schema.test.ts +0 -309
- package/src/config-schema.ts +0 -333
- package/src/conversation-id.test.ts +0 -18
- package/src/conversation-id.ts +0 -199
- package/src/dedup-runtime-api.ts +0 -1
- package/src/dedup.ts +0 -141
- package/src/directory.static.ts +0 -61
- package/src/directory.test.ts +0 -136
- package/src/directory.ts +0 -124
- package/src/doc-schema.ts +0 -182
- package/src/docx-batch-insert.test.ts +0 -91
- package/src/docx-batch-insert.ts +0 -223
- package/src/docx-color-text.ts +0 -154
- package/src/docx-table-ops.test.ts +0 -53
- package/src/docx-table-ops.ts +0 -316
- package/src/docx-types.ts +0 -38
- package/src/docx.account-selection.test.ts +0 -79
- package/src/docx.test.ts +0 -685
- package/src/docx.ts +0 -1616
- package/src/drive-schema.ts +0 -92
- package/src/drive.test.ts +0 -1219
- package/src/drive.ts +0 -829
- package/src/dynamic-agent.ts +0 -137
- package/src/event-types.ts +0 -45
- package/src/external-keys.test.ts +0 -20
- package/src/external-keys.ts +0 -19
- package/src/lifecycle.test-support.ts +0 -220
- package/src/media.test.ts +0 -900
- package/src/media.ts +0 -861
- package/src/mention-target.types.ts +0 -5
- package/src/mention.ts +0 -114
- package/src/message-action-contract.ts +0 -13
- package/src/monitor-state-runtime-api.ts +0 -7
- package/src/monitor-transport-runtime-api.ts +0 -7
- package/src/monitor.account.ts +0 -468
- package/src/monitor.acp-init-failure.lifecycle.test-support.ts +0 -219
- package/src/monitor.bot-identity.ts +0 -86
- package/src/monitor.bot-menu-handler.ts +0 -165
- package/src/monitor.bot-menu.lifecycle.test-support.ts +0 -224
- package/src/monitor.bot-menu.test.ts +0 -178
- package/src/monitor.broadcast.reply-once.lifecycle.test-support.ts +0 -264
- package/src/monitor.card-action.lifecycle.test-support.ts +0 -373
- package/src/monitor.cleanup.test.ts +0 -376
- package/src/monitor.comment-notice-handler.ts +0 -105
- package/src/monitor.comment.test.ts +0 -937
- package/src/monitor.comment.ts +0 -1386
- package/src/monitor.lifecycle.test.ts +0 -4
- package/src/monitor.message-handler.ts +0 -339
- package/src/monitor.reaction.lifecycle.test-support.ts +0 -68
- package/src/monitor.reaction.test.ts +0 -713
- package/src/monitor.startup.test.ts +0 -192
- package/src/monitor.startup.ts +0 -74
- package/src/monitor.state.defaults.test.ts +0 -46
- package/src/monitor.state.ts +0 -170
- package/src/monitor.synthetic-error.ts +0 -18
- package/src/monitor.test-mocks.ts +0 -45
- package/src/monitor.transport.ts +0 -424
- package/src/monitor.ts +0 -100
- package/src/monitor.webhook-e2e.test.ts +0 -272
- package/src/monitor.webhook-security.test.ts +0 -264
- package/src/monitor.webhook.test-helpers.ts +0 -116
- package/src/outbound-runtime-api.ts +0 -1
- package/src/outbound.test.ts +0 -935
- package/src/outbound.ts +0 -718
- package/src/perm-schema.ts +0 -52
- package/src/perm.ts +0 -170
- package/src/pins.ts +0 -108
- package/src/policy.test.ts +0 -334
- package/src/policy.ts +0 -236
- package/src/post.test.ts +0 -105
- package/src/post.ts +0 -275
- package/src/probe.test.ts +0 -275
- package/src/probe.ts +0 -166
- package/src/processing-claims.ts +0 -59
- package/src/qr-terminal.ts +0 -1
- package/src/reactions.ts +0 -123
- package/src/reasoning-preview.test.ts +0 -59
- package/src/reasoning-preview.ts +0 -20
- package/src/reply-dispatcher-runtime-api.ts +0 -7
- package/src/reply-dispatcher.test.ts +0 -1144
- package/src/reply-dispatcher.ts +0 -650
- package/src/runtime.ts +0 -9
- package/src/secret-contract.ts +0 -145
- package/src/secret-input.ts +0 -1
- package/src/security-audit-shared.ts +0 -69
- package/src/security-audit.test.ts +0 -61
- package/src/security-audit.ts +0 -1
- package/src/send-result.ts +0 -29
- package/src/send-target.test.ts +0 -80
- package/src/send-target.ts +0 -35
- package/src/send.reply-fallback.test.ts +0 -292
- package/src/send.test.ts +0 -550
- package/src/send.ts +0 -800
- package/src/sequential-key.test.ts +0 -72
- package/src/sequential-key.ts +0 -28
- package/src/sequential-queue.test.ts +0 -92
- package/src/sequential-queue.ts +0 -16
- package/src/session-conversation.ts +0 -42
- package/src/session-route.ts +0 -48
- package/src/setup-core.ts +0 -51
- package/src/setup-surface.test.ts +0 -174
- package/src/setup-surface.ts +0 -581
- package/src/streaming-card.test.ts +0 -190
- package/src/streaming-card.ts +0 -490
- package/src/subagent-hooks.test.ts +0 -603
- package/src/subagent-hooks.ts +0 -397
- package/src/targets.ts +0 -97
- package/src/test-support/lifecycle-test-support.ts +0 -453
- package/src/thread-bindings.test.ts +0 -143
- package/src/thread-bindings.ts +0 -330
- package/src/tool-account-routing.test.ts +0 -187
- package/src/tool-account.test.ts +0 -44
- package/src/tool-account.ts +0 -93
- package/src/tool-factory-test-harness.ts +0 -79
- package/src/tool-result.test.ts +0 -32
- package/src/tool-result.ts +0 -16
- package/src/tools-config.test.ts +0 -21
- package/src/tools-config.ts +0 -22
- package/src/types.ts +0 -104
- package/src/typing.test.ts +0 -144
- package/src/typing.ts +0 -214
- package/src/wiki-schema.ts +0 -55
- package/src/wiki.ts +0 -227
- package/subagent-hooks-api.ts +0 -31
- package/tsconfig.json +0 -16
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { t as probeFeishu } from "./probe-BNzzU_uR.js";
|
|
2
|
+
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime";
|
|
3
|
+
import { WEBHOOK_ANOMALY_COUNTER_DEFAULTS, WEBHOOK_RATE_LIMIT_DEFAULTS, createFixedWindowRateLimiter, createWebhookAnomalyTracker } from "openclaw/plugin-sdk/webhook-ingress";
|
|
4
|
+
//#region extensions/feishu/src/monitor.startup.ts
|
|
5
|
+
const FEISHU_STARTUP_BOT_INFO_TIMEOUT_DEFAULT_MS = 3e4;
|
|
6
|
+
const FEISHU_STARTUP_BOT_INFO_TIMEOUT_ENV = "OPENCLAW_FEISHU_STARTUP_PROBE_TIMEOUT_MS";
|
|
7
|
+
function resolveStartupProbeTimeoutMs() {
|
|
8
|
+
const raw = process.env[FEISHU_STARTUP_BOT_INFO_TIMEOUT_ENV];
|
|
9
|
+
if (raw) {
|
|
10
|
+
const parsed = Number(raw);
|
|
11
|
+
if (Number.isFinite(parsed) && parsed > 0) return Math.floor(parsed);
|
|
12
|
+
console.warn(`[feishu] ${FEISHU_STARTUP_BOT_INFO_TIMEOUT_ENV}="${raw}" is invalid; using default ${FEISHU_STARTUP_BOT_INFO_TIMEOUT_DEFAULT_MS}ms`);
|
|
13
|
+
}
|
|
14
|
+
return FEISHU_STARTUP_BOT_INFO_TIMEOUT_DEFAULT_MS;
|
|
15
|
+
}
|
|
16
|
+
const FEISHU_STARTUP_BOT_INFO_TIMEOUT_MS = resolveStartupProbeTimeoutMs();
|
|
17
|
+
function isTimeoutErrorMessage(message) {
|
|
18
|
+
const lower = normalizeLowercaseStringOrEmpty(message);
|
|
19
|
+
return lower.includes("timeout") || lower.includes("timed out");
|
|
20
|
+
}
|
|
21
|
+
function isAbortErrorMessage(message) {
|
|
22
|
+
return normalizeLowercaseStringOrEmpty(message).includes("aborted");
|
|
23
|
+
}
|
|
24
|
+
async function fetchBotIdentityForMonitor(account, options = {}) {
|
|
25
|
+
if (options.abortSignal?.aborted) return {};
|
|
26
|
+
const timeoutMs = options.timeoutMs ?? FEISHU_STARTUP_BOT_INFO_TIMEOUT_MS;
|
|
27
|
+
const result = await probeFeishu(account, {
|
|
28
|
+
timeoutMs,
|
|
29
|
+
abortSignal: options.abortSignal
|
|
30
|
+
});
|
|
31
|
+
if (result.ok) return {
|
|
32
|
+
botOpenId: result.botOpenId,
|
|
33
|
+
botName: result.botName
|
|
34
|
+
};
|
|
35
|
+
const probeError = result.error ?? void 0;
|
|
36
|
+
if (options.abortSignal?.aborted || isAbortErrorMessage(probeError)) return {};
|
|
37
|
+
if (isTimeoutErrorMessage(probeError)) (options.runtime?.error ?? console.error)(`feishu[${account.accountId}]: bot info probe timed out after ${timeoutMs}ms; continuing startup`);
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region extensions/feishu/src/monitor.state.ts
|
|
42
|
+
const wsClients = /* @__PURE__ */ new Map();
|
|
43
|
+
const httpServers = /* @__PURE__ */ new Map();
|
|
44
|
+
const botOpenIds = /* @__PURE__ */ new Map();
|
|
45
|
+
const botNames = /* @__PURE__ */ new Map();
|
|
46
|
+
const FEISHU_WEBHOOK_MAX_BODY_BYTES = 64 * 1024;
|
|
47
|
+
const FEISHU_WEBHOOK_BODY_TIMEOUT_MS = 5e3;
|
|
48
|
+
const FEISHU_WEBHOOK_RATE_LIMIT_FALLBACK_DEFAULTS = {
|
|
49
|
+
windowMs: 6e4,
|
|
50
|
+
maxRequests: 120,
|
|
51
|
+
maxTrackedKeys: 4096
|
|
52
|
+
};
|
|
53
|
+
const FEISHU_WEBHOOK_ANOMALY_FALLBACK_DEFAULTS = {
|
|
54
|
+
maxTrackedKeys: 4096,
|
|
55
|
+
ttlMs: 360 * 6e4,
|
|
56
|
+
logEvery: 25
|
|
57
|
+
};
|
|
58
|
+
function coercePositiveInt(value, fallback) {
|
|
59
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
60
|
+
const normalized = Math.floor(value);
|
|
61
|
+
return normalized > 0 ? normalized : fallback;
|
|
62
|
+
}
|
|
63
|
+
function resolveFeishuWebhookRateLimitDefaultsForTest(defaults) {
|
|
64
|
+
const resolved = defaults;
|
|
65
|
+
return {
|
|
66
|
+
windowMs: coercePositiveInt(resolved?.windowMs, FEISHU_WEBHOOK_RATE_LIMIT_FALLBACK_DEFAULTS.windowMs),
|
|
67
|
+
maxRequests: coercePositiveInt(resolved?.maxRequests, FEISHU_WEBHOOK_RATE_LIMIT_FALLBACK_DEFAULTS.maxRequests),
|
|
68
|
+
maxTrackedKeys: coercePositiveInt(resolved?.maxTrackedKeys, FEISHU_WEBHOOK_RATE_LIMIT_FALLBACK_DEFAULTS.maxTrackedKeys)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function resolveFeishuWebhookAnomalyDefaultsForTest(defaults) {
|
|
72
|
+
const resolved = defaults;
|
|
73
|
+
return {
|
|
74
|
+
maxTrackedKeys: coercePositiveInt(resolved?.maxTrackedKeys, FEISHU_WEBHOOK_ANOMALY_FALLBACK_DEFAULTS.maxTrackedKeys),
|
|
75
|
+
ttlMs: coercePositiveInt(resolved?.ttlMs, FEISHU_WEBHOOK_ANOMALY_FALLBACK_DEFAULTS.ttlMs),
|
|
76
|
+
logEvery: coercePositiveInt(resolved?.logEvery, FEISHU_WEBHOOK_ANOMALY_FALLBACK_DEFAULTS.logEvery)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const feishuWebhookRateLimitDefaults = resolveFeishuWebhookRateLimitDefaultsForTest(WEBHOOK_RATE_LIMIT_DEFAULTS);
|
|
80
|
+
const feishuWebhookAnomalyDefaults = resolveFeishuWebhookAnomalyDefaultsForTest(WEBHOOK_ANOMALY_COUNTER_DEFAULTS);
|
|
81
|
+
const feishuWebhookRateLimiter = createFixedWindowRateLimiter({
|
|
82
|
+
windowMs: feishuWebhookRateLimitDefaults.windowMs,
|
|
83
|
+
maxRequests: feishuWebhookRateLimitDefaults.maxRequests,
|
|
84
|
+
maxTrackedKeys: feishuWebhookRateLimitDefaults.maxTrackedKeys
|
|
85
|
+
});
|
|
86
|
+
const feishuWebhookAnomalyTracker = createWebhookAnomalyTracker({
|
|
87
|
+
maxTrackedKeys: feishuWebhookAnomalyDefaults.maxTrackedKeys,
|
|
88
|
+
ttlMs: feishuWebhookAnomalyDefaults.ttlMs,
|
|
89
|
+
logEvery: feishuWebhookAnomalyDefaults.logEvery
|
|
90
|
+
});
|
|
91
|
+
function recordWebhookStatus(runtime, accountId, path, statusCode) {
|
|
92
|
+
feishuWebhookAnomalyTracker.record({
|
|
93
|
+
key: `${accountId}:${path}:${statusCode}`,
|
|
94
|
+
statusCode,
|
|
95
|
+
log: runtime?.log ?? console.log,
|
|
96
|
+
message: (count) => `feishu[${accountId}]: webhook anomaly path=${path} status=${statusCode} count=${count}`
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
export { feishuWebhookRateLimiter as a, wsClients as c, botOpenIds as i, fetchBotIdentityForMonitor as l, FEISHU_WEBHOOK_MAX_BODY_BYTES as n, httpServers as o, botNames as r, recordWebhookStatus as s, FEISHU_WEBHOOK_BODY_TIMEOUT_MS as t };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { t as detectIdType } from "./targets-JMFJRKSe.js";
|
|
2
|
+
import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
|
|
3
|
+
import { normalizeAccountId, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
|
|
4
|
+
import { evaluateSenderGroupAccessForPolicy } from "openclaw/plugin-sdk/group-access";
|
|
5
|
+
//#region extensions/feishu/src/policy.ts
|
|
6
|
+
const FEISHU_PROVIDER_PREFIX_RE = /^(feishu|lark):/i;
|
|
7
|
+
function stripRepeatedFeishuProviderPrefixes(raw) {
|
|
8
|
+
let normalized = raw.trim();
|
|
9
|
+
while (FEISHU_PROVIDER_PREFIX_RE.test(normalized)) normalized = normalized.replace(FEISHU_PROVIDER_PREFIX_RE, "").trim();
|
|
10
|
+
return normalized;
|
|
11
|
+
}
|
|
12
|
+
function canonicalizeFeishuAllowlistKey(params) {
|
|
13
|
+
const value = params.value.trim();
|
|
14
|
+
if (!value) return "";
|
|
15
|
+
if (value === "*") return "*";
|
|
16
|
+
return `${params.kind}:${value}`;
|
|
17
|
+
}
|
|
18
|
+
function normalizeFeishuAllowEntry(raw) {
|
|
19
|
+
const trimmed = raw.trim();
|
|
20
|
+
if (!trimmed) return "";
|
|
21
|
+
if (trimmed === "*") return "*";
|
|
22
|
+
const withoutProviderPrefix = stripRepeatedFeishuProviderPrefixes(trimmed);
|
|
23
|
+
if (withoutProviderPrefix === "*") return "*";
|
|
24
|
+
const lowered = normalizeOptionalLowercaseString(withoutProviderPrefix) ?? "";
|
|
25
|
+
if (!lowered) return "";
|
|
26
|
+
if (lowered.startsWith("chat:") || lowered.startsWith("group:") || lowered.startsWith("channel:")) return canonicalizeFeishuAllowlistKey({
|
|
27
|
+
kind: "chat",
|
|
28
|
+
value: withoutProviderPrefix.slice(withoutProviderPrefix.indexOf(":") + 1)
|
|
29
|
+
});
|
|
30
|
+
if (lowered.startsWith("user:") || lowered.startsWith("dm:")) return canonicalizeFeishuAllowlistKey({
|
|
31
|
+
kind: "user",
|
|
32
|
+
value: withoutProviderPrefix.slice(withoutProviderPrefix.indexOf(":") + 1)
|
|
33
|
+
});
|
|
34
|
+
if (lowered.startsWith("open_id:")) return canonicalizeFeishuAllowlistKey({
|
|
35
|
+
kind: "user",
|
|
36
|
+
value: withoutProviderPrefix.slice(withoutProviderPrefix.indexOf(":") + 1)
|
|
37
|
+
});
|
|
38
|
+
const detectedType = detectIdType(withoutProviderPrefix);
|
|
39
|
+
if (detectedType === "chat_id") return canonicalizeFeishuAllowlistKey({
|
|
40
|
+
kind: "chat",
|
|
41
|
+
value: withoutProviderPrefix
|
|
42
|
+
});
|
|
43
|
+
if (detectedType === "open_id" || detectedType === "user_id") return canonicalizeFeishuAllowlistKey({
|
|
44
|
+
kind: "user",
|
|
45
|
+
value: withoutProviderPrefix
|
|
46
|
+
});
|
|
47
|
+
return "";
|
|
48
|
+
}
|
|
49
|
+
function resolveFeishuAllowlistMatch(params) {
|
|
50
|
+
const allowFrom = params.allowFrom.map((entry) => normalizeFeishuAllowEntry(String(entry))).filter(Boolean);
|
|
51
|
+
if (allowFrom.length === 0) return { allowed: false };
|
|
52
|
+
if (allowFrom.includes("*")) return {
|
|
53
|
+
allowed: true,
|
|
54
|
+
matchKey: "*",
|
|
55
|
+
matchSource: "wildcard"
|
|
56
|
+
};
|
|
57
|
+
const senderCandidates = [params.senderId, ...params.senderIds ?? []].map((entry) => normalizeFeishuAllowEntry(entry ?? "")).filter(Boolean);
|
|
58
|
+
for (const senderId of senderCandidates) if (allowFrom.includes(senderId)) return {
|
|
59
|
+
allowed: true,
|
|
60
|
+
matchKey: senderId,
|
|
61
|
+
matchSource: "id"
|
|
62
|
+
};
|
|
63
|
+
return { allowed: false };
|
|
64
|
+
}
|
|
65
|
+
function resolveFeishuGroupConfig(params) {
|
|
66
|
+
const groups = params.cfg?.groups ?? {};
|
|
67
|
+
const wildcard = groups["*"];
|
|
68
|
+
const groupId = params.groupId?.trim();
|
|
69
|
+
if (!groupId) return;
|
|
70
|
+
const direct = groups[groupId];
|
|
71
|
+
if (direct) return direct;
|
|
72
|
+
const lowered = normalizeOptionalLowercaseString(groupId) ?? "";
|
|
73
|
+
const matchKey = Object.keys(groups).find((key) => normalizeOptionalLowercaseString(key) === lowered);
|
|
74
|
+
if (matchKey) return groups[matchKey];
|
|
75
|
+
return wildcard;
|
|
76
|
+
}
|
|
77
|
+
function hasExplicitFeishuGroupConfig(params) {
|
|
78
|
+
const groups = params.cfg?.groups ?? {};
|
|
79
|
+
const groupId = params.groupId?.trim();
|
|
80
|
+
if (!groupId) return false;
|
|
81
|
+
if (Object.prototype.hasOwnProperty.call(groups, groupId) && groupId !== "*") return true;
|
|
82
|
+
const lowered = normalizeOptionalLowercaseString(groupId) ?? "";
|
|
83
|
+
return Object.keys(groups).some((key) => key !== "*" && normalizeOptionalLowercaseString(key) === lowered);
|
|
84
|
+
}
|
|
85
|
+
function resolveFeishuGroupToolPolicy(params) {
|
|
86
|
+
const cfg = params.cfg.channels?.feishu;
|
|
87
|
+
if (!cfg) return;
|
|
88
|
+
return resolveFeishuGroupConfig({
|
|
89
|
+
cfg,
|
|
90
|
+
groupId: params.groupId
|
|
91
|
+
})?.tools;
|
|
92
|
+
}
|
|
93
|
+
function isFeishuGroupAllowed(params) {
|
|
94
|
+
return evaluateSenderGroupAccessForPolicy({
|
|
95
|
+
groupPolicy: params.groupPolicy === "allowall" ? "open" : params.groupPolicy,
|
|
96
|
+
groupAllowFrom: params.allowFrom.map((entry) => String(entry)),
|
|
97
|
+
senderId: params.senderId,
|
|
98
|
+
isSenderAllowed: () => resolveFeishuAllowlistMatch(params).allowed
|
|
99
|
+
}).allowed;
|
|
100
|
+
}
|
|
101
|
+
function resolveFeishuReplyPolicy(params) {
|
|
102
|
+
if (params.isDirectMessage) return { requireMention: false };
|
|
103
|
+
const feishuCfg = params.cfg.channels?.feishu;
|
|
104
|
+
const resolvedCfg = resolveMergedAccountConfig({
|
|
105
|
+
channelConfig: feishuCfg,
|
|
106
|
+
accounts: feishuCfg?.accounts,
|
|
107
|
+
accountId: normalizeAccountId(params.accountId),
|
|
108
|
+
normalizeAccountId,
|
|
109
|
+
omitKeys: ["defaultAccount"]
|
|
110
|
+
});
|
|
111
|
+
const groupRequireMention = resolveFeishuGroupConfig({
|
|
112
|
+
cfg: resolvedCfg,
|
|
113
|
+
groupId: params.groupId
|
|
114
|
+
})?.requireMention;
|
|
115
|
+
return { requireMention: typeof groupRequireMention === "boolean" ? groupRequireMention : typeof resolvedCfg.requireMention === "boolean" ? resolvedCfg.requireMention : params.groupPolicy !== "open" };
|
|
116
|
+
}
|
|
117
|
+
//#endregion
|
|
118
|
+
export { resolveFeishuGroupToolPolicy as a, resolveFeishuGroupConfig as i, isFeishuGroupAllowed as n, resolveFeishuReplyPolicy as o, resolveFeishuAllowlistMatch as r, hasExplicitFeishuGroupConfig as t };
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-DUslC3ob.js";
|
|
2
|
+
import { r as createFeishuClient } from "./client-DBVoQL5w.js";
|
|
3
|
+
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
4
|
+
//#region extensions/feishu/src/async.ts
|
|
5
|
+
const RACE_TIMEOUT = Symbol("race-timeout");
|
|
6
|
+
const RACE_ABORT = Symbol("race-abort");
|
|
7
|
+
async function raceWithTimeoutAndAbort(promise, options = {}) {
|
|
8
|
+
if (options.abortSignal?.aborted) return { status: "aborted" };
|
|
9
|
+
if (options.timeoutMs === void 0 && !options.abortSignal) return {
|
|
10
|
+
status: "resolved",
|
|
11
|
+
value: await promise
|
|
12
|
+
};
|
|
13
|
+
let timeoutHandle;
|
|
14
|
+
let abortHandler;
|
|
15
|
+
const contenders = [promise];
|
|
16
|
+
if (options.timeoutMs !== void 0) contenders.push(new Promise((resolve) => {
|
|
17
|
+
timeoutHandle = setTimeout(() => resolve(RACE_TIMEOUT), options.timeoutMs);
|
|
18
|
+
}));
|
|
19
|
+
if (options.abortSignal) contenders.push(new Promise((resolve) => {
|
|
20
|
+
abortHandler = () => resolve(RACE_ABORT);
|
|
21
|
+
options.abortSignal?.addEventListener("abort", abortHandler, { once: true });
|
|
22
|
+
}));
|
|
23
|
+
try {
|
|
24
|
+
const result = await Promise.race(contenders);
|
|
25
|
+
if (result === RACE_TIMEOUT) return { status: "timeout" };
|
|
26
|
+
if (result === RACE_ABORT) return { status: "aborted" };
|
|
27
|
+
return {
|
|
28
|
+
status: "resolved",
|
|
29
|
+
value: result
|
|
30
|
+
};
|
|
31
|
+
} finally {
|
|
32
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
33
|
+
if (abortHandler) options.abortSignal?.removeEventListener("abort", abortHandler);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function waitForAbortableDelay(delayMs, abortSignal) {
|
|
37
|
+
if (abortSignal?.aborted) return Promise.resolve(false);
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
let settled = false;
|
|
40
|
+
let timer;
|
|
41
|
+
let handleAbort;
|
|
42
|
+
const finish = (value) => {
|
|
43
|
+
if (settled) return;
|
|
44
|
+
settled = true;
|
|
45
|
+
if (timer) clearTimeout(timer);
|
|
46
|
+
if (handleAbort) abortSignal?.removeEventListener("abort", handleAbort);
|
|
47
|
+
resolve(value);
|
|
48
|
+
};
|
|
49
|
+
handleAbort = () => {
|
|
50
|
+
finish(false);
|
|
51
|
+
};
|
|
52
|
+
abortSignal?.addEventListener("abort", handleAbort, { once: true });
|
|
53
|
+
if (abortSignal?.aborted) {
|
|
54
|
+
finish(false);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
timer = setTimeout(() => finish(true), delayMs);
|
|
58
|
+
timer.unref?.();
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region extensions/feishu/src/probe.ts
|
|
63
|
+
var probe_exports = /* @__PURE__ */ __exportAll({
|
|
64
|
+
FEISHU_PROBE_REQUEST_TIMEOUT_MS: () => FEISHU_PROBE_REQUEST_TIMEOUT_MS,
|
|
65
|
+
probeFeishu: () => probeFeishu
|
|
66
|
+
});
|
|
67
|
+
/** Cache probe results to reduce repeated health-check calls.
|
|
68
|
+
* Gateway health checks call probeFeishu() every minute; without caching this
|
|
69
|
+
* burns ~43,200 calls/month, easily exceeding Feishu's free-tier quota.
|
|
70
|
+
* Successful bot info is effectively static, while failures are cached briefly
|
|
71
|
+
* to avoid hammering the API during transient outages. */
|
|
72
|
+
const probeCache = /* @__PURE__ */ new Map();
|
|
73
|
+
const PROBE_SUCCESS_TTL_MS = 600 * 1e3;
|
|
74
|
+
const PROBE_ERROR_TTL_MS = 60 * 1e3;
|
|
75
|
+
const MAX_PROBE_CACHE_SIZE = 64;
|
|
76
|
+
const FEISHU_PROBE_REQUEST_TIMEOUT_MS = 1e4;
|
|
77
|
+
function setCachedProbeResult(cacheKey, result, ttlMs) {
|
|
78
|
+
probeCache.set(cacheKey, {
|
|
79
|
+
result,
|
|
80
|
+
expiresAt: Date.now() + ttlMs
|
|
81
|
+
});
|
|
82
|
+
if (probeCache.size > MAX_PROBE_CACHE_SIZE) {
|
|
83
|
+
const oldest = probeCache.keys().next().value;
|
|
84
|
+
if (oldest !== void 0) probeCache.delete(oldest);
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
async function probeFeishu(creds, options = {}) {
|
|
89
|
+
if (!creds?.appId || !creds?.appSecret) return {
|
|
90
|
+
ok: false,
|
|
91
|
+
error: "missing credentials (appId, appSecret)"
|
|
92
|
+
};
|
|
93
|
+
if (options.abortSignal?.aborted) return {
|
|
94
|
+
ok: false,
|
|
95
|
+
appId: creds.appId,
|
|
96
|
+
error: "probe aborted"
|
|
97
|
+
};
|
|
98
|
+
const timeoutMs = options.timeoutMs ?? 1e4;
|
|
99
|
+
const cacheKey = creds.accountId ?? `${creds.appId}:${creds.appSecret.slice(0, 8)}`;
|
|
100
|
+
const cached = probeCache.get(cacheKey);
|
|
101
|
+
if (cached && cached.expiresAt > Date.now()) return cached.result;
|
|
102
|
+
try {
|
|
103
|
+
const responseResult = await raceWithTimeoutAndAbort(createFeishuClient(creds).request({
|
|
104
|
+
method: "POST",
|
|
105
|
+
url: "/open-apis/bot/v1/openclaw_bot/ping",
|
|
106
|
+
data: { needBotInfo: true },
|
|
107
|
+
timeout: timeoutMs
|
|
108
|
+
}), {
|
|
109
|
+
timeoutMs,
|
|
110
|
+
abortSignal: options.abortSignal
|
|
111
|
+
});
|
|
112
|
+
if (responseResult.status === "aborted") return {
|
|
113
|
+
ok: false,
|
|
114
|
+
appId: creds.appId,
|
|
115
|
+
error: "probe aborted"
|
|
116
|
+
};
|
|
117
|
+
if (responseResult.status === "timeout") return setCachedProbeResult(cacheKey, {
|
|
118
|
+
ok: false,
|
|
119
|
+
appId: creds.appId,
|
|
120
|
+
error: `probe timed out after ${timeoutMs}ms`
|
|
121
|
+
}, PROBE_ERROR_TTL_MS);
|
|
122
|
+
const response = responseResult.value;
|
|
123
|
+
if (options.abortSignal?.aborted) return {
|
|
124
|
+
ok: false,
|
|
125
|
+
appId: creds.appId,
|
|
126
|
+
error: "probe aborted"
|
|
127
|
+
};
|
|
128
|
+
if (response.code !== 0) return setCachedProbeResult(cacheKey, {
|
|
129
|
+
ok: false,
|
|
130
|
+
appId: creds.appId,
|
|
131
|
+
error: `API error: ${response.msg || `code ${response.code}`}`
|
|
132
|
+
}, PROBE_ERROR_TTL_MS);
|
|
133
|
+
const botInfo = response.data?.pingBotInfo;
|
|
134
|
+
return setCachedProbeResult(cacheKey, {
|
|
135
|
+
ok: true,
|
|
136
|
+
appId: creds.appId,
|
|
137
|
+
botName: botInfo?.botName,
|
|
138
|
+
botOpenId: botInfo?.botID
|
|
139
|
+
}, PROBE_SUCCESS_TTL_MS);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
return setCachedProbeResult(cacheKey, {
|
|
142
|
+
ok: false,
|
|
143
|
+
appId: creds.appId,
|
|
144
|
+
error: formatErrorMessage(err)
|
|
145
|
+
}, PROBE_ERROR_TTL_MS);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//#endregion
|
|
149
|
+
export { waitForAbortableDelay as i, probe_exports as n, raceWithTimeoutAndAbort as r, probeFeishu as t };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __exportAll = (all, no_symbols) => {
|
|
5
|
+
let target = {};
|
|
6
|
+
for (var name in all) __defProp(target, name, {
|
|
7
|
+
get: all[name],
|
|
8
|
+
enumerable: true
|
|
9
|
+
});
|
|
10
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
11
|
+
return target;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { __exportAll as t };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
|
2
|
+
//#region extensions/feishu/src/runtime.ts
|
|
3
|
+
const { setRuntime: setFeishuRuntime, getRuntime: getFeishuRuntime } = createPluginRuntimeStore({
|
|
4
|
+
pluginId: "feishu",
|
|
5
|
+
errorMessage: "Feishu runtime not initialized"
|
|
6
|
+
});
|
|
7
|
+
//#endregion
|
|
8
|
+
export { setFeishuRuntime as n, getFeishuRuntime as t };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { n as setFeishuRuntime } from "./runtime-CG0DuRCy.js";
|
|
2
|
+
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
|
|
3
|
+
import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
|
|
4
|
+
import { PAIRING_APPROVED_MESSAGE, buildProbeChannelStatusSummary, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/channel-status";
|
|
5
|
+
import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
|
|
6
|
+
import { DEFAULT_ACCOUNT_ID, buildChannelConfigSchema, createActionGate, createDedupeCache } from "openclaw/plugin-sdk/core";
|
|
7
|
+
import { buildAgentMediaPayload } from "openclaw/plugin-sdk/agent-media-payload";
|
|
8
|
+
import { createReplyPrefixContext } from "openclaw/plugin-sdk/channel-reply-pipeline";
|
|
9
|
+
import { evaluateSupplementalContextVisibility, filterSupplementalContextItems, resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
|
|
10
|
+
import { loadSessionStore, resolveSessionStoreEntry } from "openclaw/plugin-sdk/session-store-runtime";
|
|
11
|
+
import { readJsonFileWithFallback } from "openclaw/plugin-sdk/json-store";
|
|
12
|
+
import { createPersistentDedupe } from "openclaw/plugin-sdk/persistent-dedupe";
|
|
13
|
+
import { isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText } from "openclaw/plugin-sdk/webhook-ingress";
|
|
14
|
+
export { DEFAULT_ACCOUNT_ID, PAIRING_APPROVED_MESSAGE, buildAgentMediaPayload, buildChannelConfigSchema, buildProbeChannelStatusSummary, chunkTextForOutbound, createActionGate, createChannelPairingController, createDedupeCache, createDefaultChannelRuntimeState, createPersistentDedupe, createReplyPrefixContext, evaluateSupplementalContextVisibility, filterSupplementalContextItems, isRequestBodyLimitError, loadSessionStore, normalizeAgentId, readJsonFileWithFallback, readRequestBodyWithLimit, requestBodyErrorToText, resolveChannelContextVisibilityMode, resolveSessionStoreEntry, setFeishuRuntime };
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { collectConditionalChannelFieldAssignments, collectSimpleChannelFieldAssignments, getChannelSurface, hasOwnProperty, normalizeSecretStringValue } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
2
|
+
//#region extensions/feishu/src/secret-contract.ts
|
|
3
|
+
const secretTargetRegistryEntries = [
|
|
4
|
+
{
|
|
5
|
+
id: "channels.feishu.accounts.*.appSecret",
|
|
6
|
+
targetType: "channels.feishu.accounts.*.appSecret",
|
|
7
|
+
configFile: "openclaw.json",
|
|
8
|
+
pathPattern: "channels.feishu.accounts.*.appSecret",
|
|
9
|
+
secretShape: "secret_input",
|
|
10
|
+
expectedResolvedValue: "string",
|
|
11
|
+
includeInPlan: true,
|
|
12
|
+
includeInConfigure: true,
|
|
13
|
+
includeInAudit: true
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "channels.feishu.accounts.*.encryptKey",
|
|
17
|
+
targetType: "channels.feishu.accounts.*.encryptKey",
|
|
18
|
+
configFile: "openclaw.json",
|
|
19
|
+
pathPattern: "channels.feishu.accounts.*.encryptKey",
|
|
20
|
+
secretShape: "secret_input",
|
|
21
|
+
expectedResolvedValue: "string",
|
|
22
|
+
includeInPlan: true,
|
|
23
|
+
includeInConfigure: true,
|
|
24
|
+
includeInAudit: true
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "channels.feishu.accounts.*.verificationToken",
|
|
28
|
+
targetType: "channels.feishu.accounts.*.verificationToken",
|
|
29
|
+
configFile: "openclaw.json",
|
|
30
|
+
pathPattern: "channels.feishu.accounts.*.verificationToken",
|
|
31
|
+
secretShape: "secret_input",
|
|
32
|
+
expectedResolvedValue: "string",
|
|
33
|
+
includeInPlan: true,
|
|
34
|
+
includeInConfigure: true,
|
|
35
|
+
includeInAudit: true
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "channels.feishu.appSecret",
|
|
39
|
+
targetType: "channels.feishu.appSecret",
|
|
40
|
+
configFile: "openclaw.json",
|
|
41
|
+
pathPattern: "channels.feishu.appSecret",
|
|
42
|
+
secretShape: "secret_input",
|
|
43
|
+
expectedResolvedValue: "string",
|
|
44
|
+
includeInPlan: true,
|
|
45
|
+
includeInConfigure: true,
|
|
46
|
+
includeInAudit: true
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "channels.feishu.encryptKey",
|
|
50
|
+
targetType: "channels.feishu.encryptKey",
|
|
51
|
+
configFile: "openclaw.json",
|
|
52
|
+
pathPattern: "channels.feishu.encryptKey",
|
|
53
|
+
secretShape: "secret_input",
|
|
54
|
+
expectedResolvedValue: "string",
|
|
55
|
+
includeInPlan: true,
|
|
56
|
+
includeInConfigure: true,
|
|
57
|
+
includeInAudit: true
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: "channels.feishu.verificationToken",
|
|
61
|
+
targetType: "channels.feishu.verificationToken",
|
|
62
|
+
configFile: "openclaw.json",
|
|
63
|
+
pathPattern: "channels.feishu.verificationToken",
|
|
64
|
+
secretShape: "secret_input",
|
|
65
|
+
expectedResolvedValue: "string",
|
|
66
|
+
includeInPlan: true,
|
|
67
|
+
includeInConfigure: true,
|
|
68
|
+
includeInAudit: true
|
|
69
|
+
}
|
|
70
|
+
];
|
|
71
|
+
function collectRuntimeConfigAssignments(params) {
|
|
72
|
+
const resolved = getChannelSurface(params.config, "feishu");
|
|
73
|
+
if (!resolved) return;
|
|
74
|
+
const { channel: feishu, surface } = resolved;
|
|
75
|
+
collectSimpleChannelFieldAssignments({
|
|
76
|
+
channelKey: "feishu",
|
|
77
|
+
field: "appSecret",
|
|
78
|
+
channel: feishu,
|
|
79
|
+
surface,
|
|
80
|
+
defaults: params.defaults,
|
|
81
|
+
context: params.context,
|
|
82
|
+
topInactiveReason: "no enabled account inherits this top-level Feishu appSecret.",
|
|
83
|
+
accountInactiveReason: "Feishu account is disabled."
|
|
84
|
+
});
|
|
85
|
+
const baseConnectionMode = normalizeSecretStringValue(feishu.connectionMode) === "webhook" ? "webhook" : "websocket";
|
|
86
|
+
const resolveAccountMode = (account) => hasOwnProperty(account, "connectionMode") ? normalizeSecretStringValue(account.connectionMode) : baseConnectionMode;
|
|
87
|
+
collectConditionalChannelFieldAssignments({
|
|
88
|
+
channelKey: "feishu",
|
|
89
|
+
field: "encryptKey",
|
|
90
|
+
channel: feishu,
|
|
91
|
+
surface,
|
|
92
|
+
defaults: params.defaults,
|
|
93
|
+
context: params.context,
|
|
94
|
+
topLevelActiveWithoutAccounts: baseConnectionMode === "webhook",
|
|
95
|
+
topLevelInheritedAccountActive: ({ account, enabled }) => enabled && !hasOwnProperty(account, "encryptKey") && resolveAccountMode(account) === "webhook",
|
|
96
|
+
accountActive: ({ account, enabled }) => enabled && resolveAccountMode(account) === "webhook",
|
|
97
|
+
topInactiveReason: "no enabled Feishu webhook-mode surface inherits this top-level encryptKey.",
|
|
98
|
+
accountInactiveReason: "Feishu account is disabled or not running in webhook mode."
|
|
99
|
+
});
|
|
100
|
+
collectConditionalChannelFieldAssignments({
|
|
101
|
+
channelKey: "feishu",
|
|
102
|
+
field: "verificationToken",
|
|
103
|
+
channel: feishu,
|
|
104
|
+
surface,
|
|
105
|
+
defaults: params.defaults,
|
|
106
|
+
context: params.context,
|
|
107
|
+
topLevelActiveWithoutAccounts: baseConnectionMode === "webhook",
|
|
108
|
+
topLevelInheritedAccountActive: ({ account, enabled }) => enabled && !hasOwnProperty(account, "verificationToken") && resolveAccountMode(account) === "webhook",
|
|
109
|
+
accountActive: ({ account, enabled }) => enabled && resolveAccountMode(account) === "webhook",
|
|
110
|
+
topInactiveReason: "no enabled Feishu webhook-mode surface inherits this top-level verificationToken.",
|
|
111
|
+
accountInactiveReason: "Feishu account is disabled or not running in webhook mode."
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const channelSecrets = {
|
|
115
|
+
secretTargetRegistryEntries,
|
|
116
|
+
collectRuntimeConfigAssignments
|
|
117
|
+
};
|
|
118
|
+
//#endregion
|
|
119
|
+
export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import "./security-audit-shared-ByuMx9cJ.js";
|
|
2
|
+
//#region extensions/feishu/src/message-action-contract.ts
|
|
3
|
+
const messageActionTargetAliases = {
|
|
4
|
+
read: { aliases: ["messageId"] },
|
|
5
|
+
pin: { aliases: ["messageId"] },
|
|
6
|
+
unpin: { aliases: ["messageId"] },
|
|
7
|
+
"list-pins": { aliases: ["chatId"] },
|
|
8
|
+
"channel-info": { aliases: ["chatId"] }
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { messageActionTargetAliases as t };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { hasConfiguredSecretInput } from "openclaw/plugin-sdk/secret-input";
|
|
2
|
+
//#region extensions/feishu/src/security-audit-shared.ts
|
|
3
|
+
function asRecord(value) {
|
|
4
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
5
|
+
}
|
|
6
|
+
function hasNonEmptyString(value) {
|
|
7
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
8
|
+
}
|
|
9
|
+
function isFeishuDocToolEnabled(cfg) {
|
|
10
|
+
const feishu = asRecord(asRecord(cfg.channels)?.feishu);
|
|
11
|
+
if (!feishu || feishu.enabled === false) return false;
|
|
12
|
+
const baseTools = asRecord(feishu.tools);
|
|
13
|
+
const baseDocEnabled = baseTools?.doc !== false;
|
|
14
|
+
const baseAppId = hasNonEmptyString(feishu.appId);
|
|
15
|
+
const baseAppSecret = hasConfiguredSecretInput(feishu.appSecret, cfg.secrets?.defaults);
|
|
16
|
+
const baseConfigured = baseAppId && baseAppSecret;
|
|
17
|
+
const accounts = asRecord(feishu.accounts);
|
|
18
|
+
if (!accounts || Object.keys(accounts).length === 0) return baseDocEnabled && baseConfigured;
|
|
19
|
+
for (const accountValue of Object.values(accounts)) {
|
|
20
|
+
const account = asRecord(accountValue) ?? {};
|
|
21
|
+
if (account.enabled === false) continue;
|
|
22
|
+
if (!((asRecord(account.tools) ?? baseTools)?.doc !== false)) continue;
|
|
23
|
+
if ((hasNonEmptyString(account.appId) || baseAppId) && (hasConfiguredSecretInput(account.appSecret, cfg.secrets?.defaults) || baseAppSecret)) return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
function collectFeishuSecurityAuditFindings(params) {
|
|
28
|
+
if (!isFeishuDocToolEnabled(params.cfg)) return [];
|
|
29
|
+
return [{
|
|
30
|
+
checkId: "channels.feishu.doc_owner_open_id",
|
|
31
|
+
severity: "warn",
|
|
32
|
+
title: "Feishu doc create can grant requester permissions",
|
|
33
|
+
detail: "channels.feishu tools include \"doc\"; feishu_doc action \"create\" can grant document access to the trusted requesting Feishu user.",
|
|
34
|
+
remediation: "Disable channels.feishu.tools.doc when not needed, and restrict tool access for untrusted prompts."
|
|
35
|
+
}];
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { collectFeishuSecurityAuditFindings as t };
|