mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
refactor: compile allowlist matchers
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
|
compileAllowlist,
|
||||||
normalizeStringEntries,
|
normalizeStringEntries,
|
||||||
resolveAllowlistMatchByCandidates,
|
resolveAllowlistCandidates,
|
||||||
type AllowlistMatch,
|
type AllowlistMatch,
|
||||||
} from "openclaw/plugin-sdk/matrix";
|
} from "openclaw/plugin-sdk/matrix";
|
||||||
|
|
||||||
@@ -75,11 +76,11 @@ export function resolveMatrixAllowListMatch(params: {
|
|||||||
allowList: string[];
|
allowList: string[];
|
||||||
userId?: string;
|
userId?: string;
|
||||||
}): MatrixAllowListMatch {
|
}): MatrixAllowListMatch {
|
||||||
const allowList = params.allowList;
|
const compiledAllowList = compileAllowlist(params.allowList);
|
||||||
if (allowList.length === 0) {
|
if (compiledAllowList.set.size === 0) {
|
||||||
return { allowed: false };
|
return { allowed: false };
|
||||||
}
|
}
|
||||||
if (allowList.includes("*")) {
|
if (compiledAllowList.wildcard) {
|
||||||
return { allowed: true, matchKey: "*", matchSource: "wildcard" };
|
return { allowed: true, matchKey: "*", matchSource: "wildcard" };
|
||||||
}
|
}
|
||||||
const userId = normalizeMatrixUser(params.userId);
|
const userId = normalizeMatrixUser(params.userId);
|
||||||
@@ -88,7 +89,10 @@ export function resolveMatrixAllowListMatch(params: {
|
|||||||
{ value: userId ? `matrix:${userId}` : "", source: "prefixed-id" },
|
{ value: userId ? `matrix:${userId}` : "", source: "prefixed-id" },
|
||||||
{ value: userId ? `user:${userId}` : "", source: "prefixed-user" },
|
{ value: userId ? `user:${userId}` : "", source: "prefixed-user" },
|
||||||
];
|
];
|
||||||
return resolveAllowlistMatchByCandidates({ allowList, candidates });
|
return resolveAllowlistCandidates({
|
||||||
|
compiledAllowlist: compiledAllowList,
|
||||||
|
candidates,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveMatrixAllowListMatches(params: { allowList: string[]; userId?: string }) {
|
export function resolveMatrixAllowListMatches(params: { allowList: string[]; userId?: string }) {
|
||||||
|
|||||||
@@ -16,22 +16,40 @@ export type AllowlistMatch<TSource extends string = AllowlistMatchSource> = {
|
|||||||
matchSource?: TSource;
|
matchSource?: TSource;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CompiledAllowlist = {
|
||||||
|
set: ReadonlySet<string>;
|
||||||
|
wildcard: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export function formatAllowlistMatchMeta(
|
export function formatAllowlistMatchMeta(
|
||||||
match?: { matchKey?: string; matchSource?: string } | null,
|
match?: { matchKey?: string; matchSource?: string } | null,
|
||||||
): string {
|
): string {
|
||||||
return `matchKey=${match?.matchKey ?? "none"} matchSource=${match?.matchSource ?? "none"}`;
|
return `matchKey=${match?.matchKey ?? "none"} matchSource=${match?.matchSource ?? "none"}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveAllowlistMatchByCandidates<TSource extends string>(params: {
|
export function compileAllowlist(entries: ReadonlyArray<string>): CompiledAllowlist {
|
||||||
allowList: string[];
|
const set = new Set(entries.filter(Boolean));
|
||||||
|
return {
|
||||||
|
set,
|
||||||
|
wildcard: set.has("*"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function compileSimpleAllowlist(entries: ReadonlyArray<string | number>): CompiledAllowlist {
|
||||||
|
return compileAllowlist(
|
||||||
|
entries.map((entry) => String(entry).trim().toLowerCase()).filter(Boolean),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveAllowlistCandidates<TSource extends string>(params: {
|
||||||
|
compiledAllowlist: CompiledAllowlist;
|
||||||
candidates: Array<{ value?: string; source: TSource }>;
|
candidates: Array<{ value?: string; source: TSource }>;
|
||||||
}): AllowlistMatch<TSource> {
|
}): AllowlistMatch<TSource> {
|
||||||
const allowSet = resolveAllowListSet(params.allowList);
|
|
||||||
for (const candidate of params.candidates) {
|
for (const candidate of params.candidates) {
|
||||||
if (!candidate.value) {
|
if (!candidate.value) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (allowSet.has(candidate.value)) {
|
if (params.compiledAllowlist.set.has(candidate.value)) {
|
||||||
return {
|
return {
|
||||||
allowed: true,
|
allowed: true,
|
||||||
matchKey: candidate.value,
|
matchKey: candidate.value,
|
||||||
@@ -42,15 +60,25 @@ export function resolveAllowlistMatchByCandidates<TSource extends string>(params
|
|||||||
return { allowed: false };
|
return { allowed: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resolveAllowlistMatchByCandidates<TSource extends string>(params: {
|
||||||
|
allowList: ReadonlyArray<string>;
|
||||||
|
candidates: Array<{ value?: string; source: TSource }>;
|
||||||
|
}): AllowlistMatch<TSource> {
|
||||||
|
return resolveAllowlistCandidates({
|
||||||
|
compiledAllowlist: compileAllowlist(params.allowList),
|
||||||
|
candidates: params.candidates,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function resolveAllowlistMatchSimple(params: {
|
export function resolveAllowlistMatchSimple(params: {
|
||||||
allowFrom: Array<string | number>;
|
allowFrom: ReadonlyArray<string | number>;
|
||||||
senderId: string;
|
senderId: string;
|
||||||
senderName?: string | null;
|
senderName?: string | null;
|
||||||
allowNameMatching?: boolean;
|
allowNameMatching?: boolean;
|
||||||
}): AllowlistMatch<"wildcard" | "id" | "name"> {
|
}): AllowlistMatch<"wildcard" | "id" | "name"> {
|
||||||
const allowFrom = resolveSimpleAllowFrom(params.allowFrom);
|
const allowFrom = compileSimpleAllowlist(params.allowFrom);
|
||||||
|
|
||||||
if (allowFrom.size === 0) {
|
if (allowFrom.set.size === 0) {
|
||||||
return { allowed: false };
|
return { allowed: false };
|
||||||
}
|
}
|
||||||
if (allowFrom.wildcard) {
|
if (allowFrom.wildcard) {
|
||||||
@@ -58,34 +86,17 @@ export function resolveAllowlistMatchSimple(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const senderId = params.senderId.toLowerCase();
|
const senderId = params.senderId.toLowerCase();
|
||||||
if (allowFrom.set.has(senderId)) {
|
|
||||||
return { allowed: true, matchKey: senderId, matchSource: "id" };
|
|
||||||
}
|
|
||||||
|
|
||||||
const senderName = params.senderName?.toLowerCase();
|
const senderName = params.senderName?.toLowerCase();
|
||||||
if (params.allowNameMatching === true && senderName && allowFrom.set.has(senderName)) {
|
return resolveAllowlistCandidates({
|
||||||
return { allowed: true, matchKey: senderName, matchSource: "name" };
|
compiledAllowlist: allowFrom,
|
||||||
}
|
candidates: [
|
||||||
|
{ value: senderId, source: "id" },
|
||||||
return { allowed: false };
|
...(params.allowNameMatching === true && senderName
|
||||||
}
|
? ([{ value: senderName, source: "name" as const }] satisfies Array<{
|
||||||
|
value?: string;
|
||||||
function resolveAllowListSet(allowList: string[]): Set<string> {
|
source: "id" | "name";
|
||||||
return new Set(allowList);
|
}>)
|
||||||
}
|
: []),
|
||||||
|
],
|
||||||
function resolveSimpleAllowFrom(allowFrom: Array<string | number>): {
|
});
|
||||||
normalized: string[];
|
|
||||||
size: number;
|
|
||||||
wildcard: boolean;
|
|
||||||
set: Set<string>;
|
|
||||||
} {
|
|
||||||
const normalized = allowFrom.map((entry) => String(entry).trim().toLowerCase()).filter(Boolean);
|
|
||||||
const set = new Set(normalized);
|
|
||||||
return {
|
|
||||||
normalized,
|
|
||||||
size: allowFrom.length,
|
|
||||||
wildcard: set.has("*"),
|
|
||||||
set,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,6 +198,16 @@ function appendCronDeliveryInstruction(params: {
|
|||||||
return `${params.commandBody}\n\nReturn your summary as plain text; it will be delivered automatically. If the task explicitly calls for messaging a specific external recipient, note who/where it should go instead of sending it yourself.`.trim();
|
return `${params.commandBody}\n\nReturn your summary as plain text; it will be delivered automatically. If the task explicitly calls for messaging a specific external recipient, note who/where it should go instead of sending it yourself.`.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveCronEmbeddedAgentLane(lane?: string) {
|
||||||
|
const trimmed = lane?.trim();
|
||||||
|
// Cron jobs already execute inside the cron command lane. Reusing that same
|
||||||
|
// lane for the nested embedded-agent run deadlocks: the outer cron task holds
|
||||||
|
// the lane while the inner run waits to reacquire it.
|
||||||
|
if (!trimmed || trimmed === "cron") {
|
||||||
|
return CommandLane.Nested;
|
||||||
|
}
|
||||||
|
return trimmed;
|
||||||
|
}
|
||||||
export async function runCronIsolatedAgentTurn(params: {
|
export async function runCronIsolatedAgentTurn(params: {
|
||||||
cfg: OpenClawConfig;
|
cfg: OpenClawConfig;
|
||||||
deps: CliDeps;
|
deps: CliDeps;
|
||||||
|
|||||||
@@ -209,7 +209,11 @@ export {
|
|||||||
} from "../channels/plugins/config-schema.js";
|
} from "../channels/plugins/config-schema.js";
|
||||||
export type { ChannelDock } from "../channels/dock.js";
|
export type { ChannelDock } from "../channels/dock.js";
|
||||||
export { getChatChannelMeta } from "../channels/registry.js";
|
export { getChatChannelMeta } from "../channels/registry.js";
|
||||||
export { resolveAllowlistMatchByCandidates } from "../channels/allowlist-match.js";
|
export {
|
||||||
|
compileAllowlist,
|
||||||
|
resolveAllowlistCandidates,
|
||||||
|
resolveAllowlistMatchByCandidates,
|
||||||
|
} from "../channels/allowlist-match.js";
|
||||||
export type {
|
export type {
|
||||||
BlockStreamingCoalesceConfig,
|
BlockStreamingCoalesceConfig,
|
||||||
DmPolicy,
|
DmPolicy,
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ export {
|
|||||||
readStringParam,
|
readStringParam,
|
||||||
} from "../agents/tools/common.js";
|
} from "../agents/tools/common.js";
|
||||||
export type { ReplyPayload } from "../auto-reply/types.js";
|
export type { ReplyPayload } from "../auto-reply/types.js";
|
||||||
export { resolveAllowlistMatchByCandidates } from "../channels/allowlist-match.js";
|
export {
|
||||||
|
compileAllowlist,
|
||||||
|
resolveAllowlistCandidates,
|
||||||
|
resolveAllowlistMatchByCandidates,
|
||||||
|
} from "../channels/allowlist-match.js";
|
||||||
export { mergeAllowlist, summarizeMapping } from "../channels/allowlists/resolve-utils.js";
|
export { mergeAllowlist, summarizeMapping } from "../channels/allowlists/resolve-utils.js";
|
||||||
export { resolveControlCommandGate } from "../channels/command-gating.js";
|
export { resolveControlCommandGate } from "../channels/command-gating.js";
|
||||||
export type { NormalizedLocation } from "../channels/location.js";
|
export type { NormalizedLocation } from "../channels/location.js";
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
resolveAllowlistMatchByCandidates,
|
compileAllowlist,
|
||||||
|
resolveAllowlistCandidates,
|
||||||
type AllowlistMatch,
|
type AllowlistMatch,
|
||||||
} from "../../channels/allowlist-match.js";
|
} from "../../channels/allowlist-match.js";
|
||||||
import {
|
import {
|
||||||
@@ -56,11 +57,11 @@ export function resolveSlackAllowListMatch(params: {
|
|||||||
name?: string;
|
name?: string;
|
||||||
allowNameMatching?: boolean;
|
allowNameMatching?: boolean;
|
||||||
}): SlackAllowListMatch {
|
}): SlackAllowListMatch {
|
||||||
const allowList = params.allowList;
|
const compiledAllowList = compileAllowlist(params.allowList);
|
||||||
if (allowList.length === 0) {
|
if (compiledAllowList.set.size === 0) {
|
||||||
return { allowed: false };
|
return { allowed: false };
|
||||||
}
|
}
|
||||||
if (allowList.includes("*")) {
|
if (compiledAllowList.wildcard) {
|
||||||
return { allowed: true, matchKey: "*", matchSource: "wildcard" };
|
return { allowed: true, matchKey: "*", matchSource: "wildcard" };
|
||||||
}
|
}
|
||||||
const id = params.id?.toLowerCase();
|
const id = params.id?.toLowerCase();
|
||||||
@@ -78,7 +79,10 @@ export function resolveSlackAllowListMatch(params: {
|
|||||||
] satisfies Array<{ value?: string; source: SlackAllowListSource }>)
|
] satisfies Array<{ value?: string; source: SlackAllowListSource }>)
|
||||||
: []),
|
: []),
|
||||||
];
|
];
|
||||||
return resolveAllowlistMatchByCandidates({ allowList, candidates });
|
return resolveAllowlistCandidates({
|
||||||
|
compiledAllowlist: compiledAllowList,
|
||||||
|
candidates,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function allowListMatches(params: {
|
export function allowListMatches(params: {
|
||||||
|
|||||||
Reference in New Issue
Block a user