mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 20:28:29 +00:00
refactor: share allow-from merge and sender-id checks
This commit is contained in:
69
src/channels/allow-from.test.ts
Normal file
69
src/channels/allow-from.test.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { firstDefined, isSenderIdAllowed, mergeAllowFromSources } from "./allow-from.js";
|
||||||
|
|
||||||
|
describe("mergeAllowFromSources", () => {
|
||||||
|
it("merges, trims, and filters empty values", () => {
|
||||||
|
expect(
|
||||||
|
mergeAllowFromSources({
|
||||||
|
allowFrom: [" line:user:abc ", "", 123],
|
||||||
|
storeAllowFrom: [" ", "telegram:456"],
|
||||||
|
}),
|
||||||
|
).toEqual(["line:user:abc", "123", "telegram:456"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("firstDefined", () => {
|
||||||
|
it("returns the first non-undefined value", () => {
|
||||||
|
expect(firstDefined(undefined, undefined, "x", "y")).toBe("x");
|
||||||
|
expect(firstDefined(undefined, 0, 1)).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("isSenderIdAllowed", () => {
|
||||||
|
it("supports per-channel empty-list defaults and wildcard/id matches", () => {
|
||||||
|
expect(
|
||||||
|
isSenderIdAllowed(
|
||||||
|
{
|
||||||
|
entries: [],
|
||||||
|
hasEntries: false,
|
||||||
|
hasWildcard: false,
|
||||||
|
},
|
||||||
|
"123",
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
isSenderIdAllowed(
|
||||||
|
{
|
||||||
|
entries: [],
|
||||||
|
hasEntries: false,
|
||||||
|
hasWildcard: false,
|
||||||
|
},
|
||||||
|
"123",
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
).toBe(false);
|
||||||
|
expect(
|
||||||
|
isSenderIdAllowed(
|
||||||
|
{
|
||||||
|
entries: ["111", "222"],
|
||||||
|
hasEntries: true,
|
||||||
|
hasWildcard: true,
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
isSenderIdAllowed(
|
||||||
|
{
|
||||||
|
entries: ["111", "222"],
|
||||||
|
hasEntries: true,
|
||||||
|
hasWildcard: false,
|
||||||
|
},
|
||||||
|
"222",
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
34
src/channels/allow-from.ts
Normal file
34
src/channels/allow-from.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
export function mergeAllowFromSources(params: {
|
||||||
|
allowFrom?: Array<string | number>;
|
||||||
|
storeAllowFrom?: string[];
|
||||||
|
}): string[] {
|
||||||
|
return [...(params.allowFrom ?? []), ...(params.storeAllowFrom ?? [])]
|
||||||
|
.map((value) => String(value).trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function firstDefined<T>(...values: Array<T | undefined>) {
|
||||||
|
for (const value of values) {
|
||||||
|
if (typeof value !== "undefined") {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSenderIdAllowed(
|
||||||
|
allow: { entries: string[]; hasWildcard: boolean; hasEntries: boolean },
|
||||||
|
senderId: string | undefined,
|
||||||
|
allowWhenEmpty: boolean,
|
||||||
|
): boolean {
|
||||||
|
if (!allow.hasEntries) {
|
||||||
|
return allowWhenEmpty;
|
||||||
|
}
|
||||||
|
if (allow.hasWildcard) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!senderId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return allow.entries.includes(senderId);
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { firstDefined, isSenderIdAllowed, mergeAllowFromSources } from "../channels/allow-from.js";
|
||||||
|
|
||||||
export type NormalizedAllowFrom = {
|
export type NormalizedAllowFrom = {
|
||||||
entries: string[];
|
entries: string[];
|
||||||
hasWildcard: boolean;
|
hasWildcard: boolean;
|
||||||
@@ -28,33 +30,14 @@ export const normalizeAllowFrom = (list?: Array<string | number>): NormalizedAll
|
|||||||
export const normalizeAllowFromWithStore = (params: {
|
export const normalizeAllowFromWithStore = (params: {
|
||||||
allowFrom?: Array<string | number>;
|
allowFrom?: Array<string | number>;
|
||||||
storeAllowFrom?: string[];
|
storeAllowFrom?: string[];
|
||||||
}): NormalizedAllowFrom => {
|
}): NormalizedAllowFrom => normalizeAllowFrom(mergeAllowFromSources(params));
|
||||||
const combined = [...(params.allowFrom ?? []), ...(params.storeAllowFrom ?? [])];
|
|
||||||
return normalizeAllowFrom(combined);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const firstDefined = <T>(...values: Array<T | undefined>) => {
|
|
||||||
for (const value of values) {
|
|
||||||
if (typeof value !== "undefined") {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isSenderAllowed = (params: {
|
export const isSenderAllowed = (params: {
|
||||||
allow: NormalizedAllowFrom;
|
allow: NormalizedAllowFrom;
|
||||||
senderId?: string;
|
senderId?: string;
|
||||||
}): boolean => {
|
}): boolean => {
|
||||||
const { allow, senderId } = params;
|
const { allow, senderId } = params;
|
||||||
if (!allow.hasEntries) {
|
return isSenderIdAllowed(allow, senderId, false);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (allow.hasWildcard) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!senderId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return allow.entries.includes(senderId);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { firstDefined };
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { firstDefined, isSenderIdAllowed, mergeAllowFromSources } from "../channels/allow-from.js";
|
||||||
import type { AllowlistMatch } from "../channels/allowlist-match.js";
|
import type { AllowlistMatch } from "../channels/allowlist-match.js";
|
||||||
|
|
||||||
export type NormalizedAllowFrom = {
|
export type NormalizedAllowFrom = {
|
||||||
@@ -53,21 +54,7 @@ export const normalizeAllowFrom = (list?: Array<string | number>): NormalizedAll
|
|||||||
export const normalizeAllowFromWithStore = (params: {
|
export const normalizeAllowFromWithStore = (params: {
|
||||||
allowFrom?: Array<string | number>;
|
allowFrom?: Array<string | number>;
|
||||||
storeAllowFrom?: string[];
|
storeAllowFrom?: string[];
|
||||||
}): NormalizedAllowFrom => {
|
}): NormalizedAllowFrom => normalizeAllowFrom(mergeAllowFromSources(params));
|
||||||
const combined = [...(params.allowFrom ?? []), ...(params.storeAllowFrom ?? [])]
|
|
||||||
.map((value) => String(value).trim())
|
|
||||||
.filter(Boolean);
|
|
||||||
return normalizeAllowFrom(combined);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const firstDefined = <T>(...values: Array<T | undefined>) => {
|
|
||||||
for (const value of values) {
|
|
||||||
if (typeof value !== "undefined") {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isSenderAllowed = (params: {
|
export const isSenderAllowed = (params: {
|
||||||
allow: NormalizedAllowFrom;
|
allow: NormalizedAllowFrom;
|
||||||
@@ -75,18 +62,11 @@ export const isSenderAllowed = (params: {
|
|||||||
senderUsername?: string;
|
senderUsername?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { allow, senderId } = params;
|
const { allow, senderId } = params;
|
||||||
if (!allow.hasEntries) {
|
return isSenderIdAllowed(allow, senderId, true);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (allow.hasWildcard) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (senderId && allow.entries.includes(senderId)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { firstDefined };
|
||||||
|
|
||||||
export const resolveSenderAllowMatch = (params: {
|
export const resolveSenderAllowMatch = (params: {
|
||||||
allow: NormalizedAllowFrom;
|
allow: NormalizedAllowFrom;
|
||||||
senderId?: string;
|
senderId?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user