mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-25 23:47:20 +00:00
Security: require Feishu webhook encrypt key (#44087)
* Feishu: require webhook encrypt key in schema * Feishu: cover encrypt key webhook validation * Feishu: enforce encrypt key at startup * Feishu: add webhook forgery regression test * Feishu: collect encrypt key during onboarding * Docs: require Feishu webhook encrypt key * Changelog: note Feishu webhook hardening * Docs: clarify Feishu encrypt key screenshot * Feishu: treat webhook encrypt key as secret input * Feishu: resolve encrypt key only in webhook mode
This commit is contained in:
@@ -801,6 +801,31 @@ function collectFeishuAssignments(params: {
|
||||
: baseConnectionMode;
|
||||
return accountMode === "webhook";
|
||||
});
|
||||
const topLevelEncryptKeyActive = !surface.channelEnabled
|
||||
? false
|
||||
: !surface.hasExplicitAccounts
|
||||
? baseConnectionMode === "webhook"
|
||||
: surface.accounts.some(({ account, enabled }) => {
|
||||
if (!enabled || hasOwnProperty(account, "encryptKey")) {
|
||||
return false;
|
||||
}
|
||||
const accountMode = hasOwnProperty(account, "connectionMode")
|
||||
? normalizeSecretStringValue(account.connectionMode)
|
||||
: baseConnectionMode;
|
||||
return accountMode === "webhook";
|
||||
});
|
||||
collectSecretInputAssignment({
|
||||
value: feishu.encryptKey,
|
||||
path: "channels.feishu.encryptKey",
|
||||
expected: "string",
|
||||
defaults: params.defaults,
|
||||
context: params.context,
|
||||
active: topLevelEncryptKeyActive,
|
||||
inactiveReason: "no enabled Feishu webhook-mode surface inherits this top-level encryptKey.",
|
||||
apply: (value) => {
|
||||
feishu.encryptKey = value;
|
||||
},
|
||||
});
|
||||
collectSecretInputAssignment({
|
||||
value: feishu.verificationToken,
|
||||
path: "channels.feishu.verificationToken",
|
||||
@@ -818,6 +843,23 @@ function collectFeishuAssignments(params: {
|
||||
return;
|
||||
}
|
||||
for (const { accountId, account, enabled } of surface.accounts) {
|
||||
if (hasOwnProperty(account, "encryptKey")) {
|
||||
const accountMode = hasOwnProperty(account, "connectionMode")
|
||||
? normalizeSecretStringValue(account.connectionMode)
|
||||
: baseConnectionMode;
|
||||
collectSecretInputAssignment({
|
||||
value: account.encryptKey,
|
||||
path: `channels.feishu.accounts.${accountId}.encryptKey`,
|
||||
expected: "string",
|
||||
defaults: params.defaults,
|
||||
context: params.context,
|
||||
active: enabled && accountMode === "webhook",
|
||||
inactiveReason: "Feishu account is disabled or not running in webhook mode.",
|
||||
apply: (value) => {
|
||||
account.encryptKey = value;
|
||||
},
|
||||
});
|
||||
}
|
||||
if (!hasOwnProperty(account, "verificationToken")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,9 @@ function buildConfigForOpenClawTarget(entry: SecretRegistryEntry, envId: string)
|
||||
if (entry.id === "channels.feishu.verificationToken") {
|
||||
setPathCreateStrict(config, ["channels", "feishu", "connectionMode"], "webhook");
|
||||
}
|
||||
if (entry.id === "channels.feishu.encryptKey") {
|
||||
setPathCreateStrict(config, ["channels", "feishu", "connectionMode"], "webhook");
|
||||
}
|
||||
if (entry.id === "channels.feishu.accounts.*.verificationToken") {
|
||||
setPathCreateStrict(
|
||||
config,
|
||||
@@ -78,6 +81,13 @@ function buildConfigForOpenClawTarget(entry: SecretRegistryEntry, envId: string)
|
||||
"webhook",
|
||||
);
|
||||
}
|
||||
if (entry.id === "channels.feishu.accounts.*.encryptKey") {
|
||||
setPathCreateStrict(
|
||||
config,
|
||||
["channels", "feishu", "accounts", "sample", "connectionMode"],
|
||||
"webhook",
|
||||
);
|
||||
}
|
||||
if (entry.id === "tools.web.search.gemini.apiKey") {
|
||||
setPathCreateStrict(config, ["tools", "web", "search", "provider"], "gemini");
|
||||
}
|
||||
|
||||
@@ -173,6 +173,17 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
|
||||
includeInConfigure: true,
|
||||
includeInAudit: true,
|
||||
},
|
||||
{
|
||||
id: "channels.feishu.accounts.*.encryptKey",
|
||||
targetType: "channels.feishu.accounts.*.encryptKey",
|
||||
configFile: "openclaw.json",
|
||||
pathPattern: "channels.feishu.accounts.*.encryptKey",
|
||||
secretShape: SECRET_INPUT_SHAPE,
|
||||
expectedResolvedValue: "string",
|
||||
includeInPlan: true,
|
||||
includeInConfigure: true,
|
||||
includeInAudit: true,
|
||||
},
|
||||
{
|
||||
id: "channels.feishu.accounts.*.verificationToken",
|
||||
targetType: "channels.feishu.accounts.*.verificationToken",
|
||||
@@ -195,6 +206,17 @@ const SECRET_TARGET_REGISTRY: SecretTargetRegistryEntry[] = [
|
||||
includeInConfigure: true,
|
||||
includeInAudit: true,
|
||||
},
|
||||
{
|
||||
id: "channels.feishu.encryptKey",
|
||||
targetType: "channels.feishu.encryptKey",
|
||||
configFile: "openclaw.json",
|
||||
pathPattern: "channels.feishu.encryptKey",
|
||||
secretShape: SECRET_INPUT_SHAPE,
|
||||
expectedResolvedValue: "string",
|
||||
includeInPlan: true,
|
||||
includeInConfigure: true,
|
||||
includeInAudit: true,
|
||||
},
|
||||
{
|
||||
id: "channels.feishu.verificationToken",
|
||||
targetType: "channels.feishu.verificationToken",
|
||||
|
||||
Reference in New Issue
Block a user