refactor: share allow-from merge and sender-id checks

This commit is contained in:
Peter Steinberger
2026-02-19 14:14:02 +00:00
parent ba538c98c7
commit ffd4e85873
4 changed files with 114 additions and 48 deletions

View 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);
});
});

View 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);
}

View File

@@ -1,3 +1,5 @@
import { firstDefined, isSenderIdAllowed, mergeAllowFromSources } from "../channels/allow-from.js";
export type NormalizedAllowFrom = {
entries: string[];
hasWildcard: boolean;
@@ -28,33 +30,14 @@ export const normalizeAllowFrom = (list?: Array<string | number>): NormalizedAll
export const normalizeAllowFromWithStore = (params: {
allowFrom?: Array<string | number>;
storeAllowFrom?: string[];
}): NormalizedAllowFrom => {
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;
};
}): NormalizedAllowFrom => normalizeAllowFrom(mergeAllowFromSources(params));
export const isSenderAllowed = (params: {
allow: NormalizedAllowFrom;
senderId?: string;
}): boolean => {
const { allow, senderId } = params;
if (!allow.hasEntries) {
return false;
}
if (allow.hasWildcard) {
return true;
}
if (!senderId) {
return false;
}
return allow.entries.includes(senderId);
return isSenderIdAllowed(allow, senderId, false);
};
export { firstDefined };

View File

@@ -1,3 +1,4 @@
import { firstDefined, isSenderIdAllowed, mergeAllowFromSources } from "../channels/allow-from.js";
import type { AllowlistMatch } from "../channels/allowlist-match.js";
export type NormalizedAllowFrom = {
@@ -53,21 +54,7 @@ export const normalizeAllowFrom = (list?: Array<string | number>): NormalizedAll
export const normalizeAllowFromWithStore = (params: {
allowFrom?: Array<string | number>;
storeAllowFrom?: string[];
}): NormalizedAllowFrom => {
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;
};
}): NormalizedAllowFrom => normalizeAllowFrom(mergeAllowFromSources(params));
export const isSenderAllowed = (params: {
allow: NormalizedAllowFrom;
@@ -75,18 +62,11 @@ export const isSenderAllowed = (params: {
senderUsername?: string;
}) => {
const { allow, senderId } = params;
if (!allow.hasEntries) {
return true;
}
if (allow.hasWildcard) {
return true;
}
if (senderId && allow.entries.includes(senderId)) {
return true;
}
return false;
return isSenderIdAllowed(allow, senderId, true);
};
export { firstDefined };
export const resolveSenderAllowMatch = (params: {
allow: NormalizedAllowFrom;
senderId?: string;