* fix(channels): default allowFrom to id-only; add dangerous name opt-in * docs(security): align channel allowFrom docs with id-only default
54 lines
1.4 KiB
TypeScript
54 lines
1.4 KiB
TypeScript
export type AllowlistMatchSource =
|
|
| "wildcard"
|
|
| "id"
|
|
| "name"
|
|
| "tag"
|
|
| "username"
|
|
| "prefixed-id"
|
|
| "prefixed-user"
|
|
| "prefixed-name"
|
|
| "slug"
|
|
| "localpart";
|
|
|
|
export type AllowlistMatch<TSource extends string = AllowlistMatchSource> = {
|
|
allowed: boolean;
|
|
matchKey?: string;
|
|
matchSource?: TSource;
|
|
};
|
|
|
|
export function formatAllowlistMatchMeta(
|
|
match?: { matchKey?: string; matchSource?: string } | null,
|
|
): string {
|
|
return `matchKey=${match?.matchKey ?? "none"} matchSource=${match?.matchSource ?? "none"}`;
|
|
}
|
|
|
|
export function resolveAllowlistMatchSimple(params: {
|
|
allowFrom: Array<string | number>;
|
|
senderId: string;
|
|
senderName?: string | null;
|
|
allowNameMatching?: boolean;
|
|
}): AllowlistMatch<"wildcard" | "id" | "name"> {
|
|
const allowFrom = params.allowFrom
|
|
.map((entry) => String(entry).trim().toLowerCase())
|
|
.filter(Boolean);
|
|
|
|
if (allowFrom.length === 0) {
|
|
return { allowed: false };
|
|
}
|
|
if (allowFrom.includes("*")) {
|
|
return { allowed: true, matchKey: "*", matchSource: "wildcard" };
|
|
}
|
|
|
|
const senderId = params.senderId.toLowerCase();
|
|
if (allowFrom.includes(senderId)) {
|
|
return { allowed: true, matchKey: senderId, matchSource: "id" };
|
|
}
|
|
|
|
const senderName = params.senderName?.toLowerCase();
|
|
if (params.allowNameMatching === true && senderName && allowFrom.includes(senderName)) {
|
|
return { allowed: true, matchKey: senderName, matchSource: "name" };
|
|
}
|
|
|
|
return { allowed: false };
|
|
}
|