mirror of https://github.com/openclaw/openclaw.git
171 lines
6.6 KiB
TypeScript
171 lines
6.6 KiB
TypeScript
import { createAllowlistProviderRestrictSendersWarningCollector } from "../channels/plugins/group-policy-warnings.js";
|
|
import type { ChannelSecurityAdapter } from "../channels/plugins/types.adapters.js";
|
|
import type { OpenClawConfig } from "../config/config.js";
|
|
import { collectProviderDangerousNameMatchingScopes } from "../config/dangerous-name-matching.js";
|
|
import type { GroupPolicy } from "../config/types.base.js";
|
|
import { sanitizeForLog } from "../terminal/ansi.js";
|
|
import { createScopedDmSecurityResolver } from "./channel-config-helpers.js";
|
|
/** Shared policy warnings and DM/group policy helpers for channel plugins. */
|
|
export type {
|
|
GroupToolPolicyBySenderConfig,
|
|
GroupToolPolicyConfig,
|
|
} from "../config/types.tools.js";
|
|
export {
|
|
composeAccountWarningCollectors,
|
|
buildOpenGroupPolicyConfigureRouteAllowlistWarning,
|
|
composeWarningCollectors,
|
|
createAllowlistProviderGroupPolicyWarningCollector,
|
|
createConditionalWarningCollector,
|
|
createAllowlistProviderOpenWarningCollector,
|
|
createAllowlistProviderRouteAllowlistWarningCollector,
|
|
createOpenGroupPolicyRestrictSendersWarningCollector,
|
|
createOpenProviderGroupPolicyWarningCollector,
|
|
createOpenProviderConfiguredRouteWarningCollector,
|
|
buildOpenGroupPolicyRestrictSendersWarning,
|
|
buildOpenGroupPolicyWarning,
|
|
collectAllowlistProviderGroupPolicyWarnings,
|
|
collectAllowlistProviderRestrictSendersWarnings,
|
|
collectOpenGroupPolicyRestrictSendersWarnings,
|
|
collectOpenGroupPolicyRouteAllowlistWarnings,
|
|
collectOpenProviderGroupPolicyWarnings,
|
|
projectAccountConfigWarningCollector,
|
|
projectAccountWarningCollector,
|
|
projectConfigAccountIdWarningCollector,
|
|
projectConfigWarningCollector,
|
|
projectWarningCollector,
|
|
} from "../channels/plugins/group-policy-warnings.js";
|
|
export { buildAccountScopedDmSecurityPolicy } from "../channels/plugins/helpers.js";
|
|
export {
|
|
resolveChannelGroupRequireMention,
|
|
resolveChannelGroupToolsPolicy,
|
|
resolveToolsBySender,
|
|
} from "../config/group-policy.js";
|
|
export {
|
|
DM_GROUP_ACCESS_REASON,
|
|
readStoreAllowFromForDmPolicy,
|
|
resolveDmGroupAccessWithLists,
|
|
resolveEffectiveAllowFromLists,
|
|
} from "../security/dm-policy-shared.js";
|
|
export { createAllowlistProviderRestrictSendersWarningCollector };
|
|
|
|
export type ChannelMutableAllowlistCandidate = {
|
|
pathLabel: string;
|
|
list: unknown;
|
|
};
|
|
|
|
type ChannelMutableAllowlistHit = {
|
|
path: string;
|
|
entry: string;
|
|
dangerousFlagPath: string;
|
|
};
|
|
|
|
function collectMutableAllowlistWarningLines(
|
|
hits: ChannelMutableAllowlistHit[],
|
|
channel: string,
|
|
): string[] {
|
|
if (hits.length === 0) {
|
|
return [];
|
|
}
|
|
const exampleLines = hits
|
|
.slice(0, 8)
|
|
.map((hit) => `- ${sanitizeForLog(hit.path)}: ${sanitizeForLog(hit.entry)}`);
|
|
const remaining =
|
|
hits.length > 8 ? `- +${hits.length - 8} more mutable allowlist entries.` : null;
|
|
const flagPaths = Array.from(new Set(hits.map((hit) => hit.dangerousFlagPath)));
|
|
const flagHint =
|
|
flagPaths.length === 1
|
|
? sanitizeForLog(flagPaths[0] ?? "")
|
|
: `${sanitizeForLog(flagPaths[0] ?? "")} (and ${flagPaths.length - 1} other scope flags)`;
|
|
return [
|
|
`- Found ${hits.length} mutable allowlist ${hits.length === 1 ? "entry" : "entries"} across ${channel} while name matching is disabled by default.`,
|
|
...exampleLines,
|
|
...(remaining ? [remaining] : []),
|
|
`- Option A (break-glass): enable ${flagHint}=true to keep name/email/nick matching.`,
|
|
"- Option B (recommended): resolve names/emails/nicks to stable sender IDs and rewrite the allowlist entries.",
|
|
];
|
|
}
|
|
|
|
export function createDangerousNameMatchingMutableAllowlistWarningCollector(params: {
|
|
channel: string;
|
|
detector: (entry: string) => boolean;
|
|
collectLists: (scope: {
|
|
prefix: string;
|
|
account: Record<string, unknown>;
|
|
dangerousFlagPath: string;
|
|
}) => ChannelMutableAllowlistCandidate[];
|
|
}) {
|
|
return ({ cfg }: { cfg: OpenClawConfig }): string[] => {
|
|
const hits: ChannelMutableAllowlistHit[] = [];
|
|
for (const scope of collectProviderDangerousNameMatchingScopes(cfg, params.channel)) {
|
|
if (scope.dangerousNameMatchingEnabled) {
|
|
continue;
|
|
}
|
|
for (const candidate of params.collectLists(scope)) {
|
|
if (!Array.isArray(candidate.list)) {
|
|
continue;
|
|
}
|
|
for (const entry of candidate.list) {
|
|
const text = String(entry).trim();
|
|
if (!text || text === "*" || !params.detector(text)) {
|
|
continue;
|
|
}
|
|
hits.push({
|
|
path: candidate.pathLabel,
|
|
entry: text,
|
|
dangerousFlagPath: scope.dangerousFlagPath,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
return collectMutableAllowlistWarningLines(hits, params.channel);
|
|
};
|
|
}
|
|
|
|
/** Compose the common DM policy resolver with restrict-senders group warnings. */
|
|
export function createRestrictSendersChannelSecurity<
|
|
ResolvedAccount extends { accountId?: string | null },
|
|
>(params: {
|
|
channelKey: string;
|
|
resolveDmPolicy: (account: ResolvedAccount) => string | null | undefined;
|
|
resolveDmAllowFrom: (account: ResolvedAccount) => Array<string | number> | null | undefined;
|
|
resolveGroupPolicy: (account: ResolvedAccount) => GroupPolicy | null | undefined;
|
|
surface: string;
|
|
openScope: string;
|
|
groupPolicyPath: string;
|
|
groupAllowFromPath: string;
|
|
mentionGated?: boolean;
|
|
providerConfigPresent?: (cfg: OpenClawConfig) => boolean;
|
|
resolveFallbackAccountId?: (account: ResolvedAccount) => string | null | undefined;
|
|
defaultDmPolicy?: string;
|
|
allowFromPathSuffix?: string;
|
|
policyPathSuffix?: string;
|
|
approveChannelId?: string;
|
|
approveHint?: string;
|
|
normalizeDmEntry?: (raw: string) => string;
|
|
}): ChannelSecurityAdapter<ResolvedAccount> {
|
|
return {
|
|
resolveDmPolicy: createScopedDmSecurityResolver<ResolvedAccount>({
|
|
channelKey: params.channelKey,
|
|
resolvePolicy: params.resolveDmPolicy,
|
|
resolveAllowFrom: params.resolveDmAllowFrom,
|
|
resolveFallbackAccountId: params.resolveFallbackAccountId,
|
|
defaultPolicy: params.defaultDmPolicy,
|
|
allowFromPathSuffix: params.allowFromPathSuffix,
|
|
policyPathSuffix: params.policyPathSuffix,
|
|
approveChannelId: params.approveChannelId,
|
|
approveHint: params.approveHint,
|
|
normalizeEntry: params.normalizeDmEntry,
|
|
}),
|
|
collectWarnings: createAllowlistProviderRestrictSendersWarningCollector<ResolvedAccount>({
|
|
providerConfigPresent:
|
|
params.providerConfigPresent ?? ((cfg) => cfg.channels?.[params.channelKey] !== undefined),
|
|
resolveGroupPolicy: params.resolveGroupPolicy,
|
|
surface: params.surface,
|
|
openScope: params.openScope,
|
|
groupPolicyPath: params.groupPolicyPath,
|
|
groupAllowFromPath: params.groupAllowFromPath,
|
|
mentionGated: params.mentionGated,
|
|
}),
|
|
};
|
|
}
|