fix: gate reset auth and infer whatsapp sender
This commit is contained in:
@@ -41,6 +41,7 @@
|
|||||||
- Docs: clarify Slack manifest scopes (current vs optional) with references. Thanks @jarvis-medmatic for PR #235.
|
- Docs: clarify Slack manifest scopes (current vs optional) with references. Thanks @jarvis-medmatic for PR #235.
|
||||||
- Control UI: avoid Slack config ReferenceError by reading slack config snapshots. Thanks @sreekaransrinath for PR #249.
|
- Control UI: avoid Slack config ReferenceError by reading slack config snapshots. Thanks @sreekaransrinath for PR #249.
|
||||||
- Telegram: honor routing.groupChat.mentionPatterns for group mention gating. Thanks @regenrek for PR #242.
|
- Telegram: honor routing.groupChat.mentionPatterns for group mention gating. Thanks @regenrek for PR #242.
|
||||||
|
- Auto-reply: block unauthorized `/reset` and infer WhatsApp senders from E.164 inputs.
|
||||||
|
|
||||||
### Maintenance
|
### Maintenance
|
||||||
- Deps: bump pi-* stack, Slack SDK, discord-api-types, file-type, zod, and Biome.
|
- Deps: bump pi-* stack, Slack SDK, discord-api-types, file-type, zod, and Biome.
|
||||||
|
|||||||
@@ -18,16 +18,23 @@ export function resolveCommandAuthorization(params: {
|
|||||||
}): CommandAuthorization {
|
}): CommandAuthorization {
|
||||||
const { ctx, cfg, commandAuthorized } = params;
|
const { ctx, cfg, commandAuthorized } = params;
|
||||||
const surface = (ctx.Surface ?? "").trim().toLowerCase();
|
const surface = (ctx.Surface ?? "").trim().toLowerCase();
|
||||||
const isWhatsAppSurface =
|
const from = (ctx.From ?? "").replace(/^whatsapp:/, "");
|
||||||
surface === "whatsapp" ||
|
const to = (ctx.To ?? "").replace(/^whatsapp:/, "");
|
||||||
|
const hasWhatsappPrefix =
|
||||||
(ctx.From ?? "").startsWith("whatsapp:") ||
|
(ctx.From ?? "").startsWith("whatsapp:") ||
|
||||||
(ctx.To ?? "").startsWith("whatsapp:");
|
(ctx.To ?? "").startsWith("whatsapp:");
|
||||||
|
const looksLikeE164 = (value: string) =>
|
||||||
|
Boolean(value && /^\+?\d{3,}$/.test(value.replace(/[^\d+]/g, "")));
|
||||||
|
const inferWhatsApp =
|
||||||
|
!surface &&
|
||||||
|
Boolean(cfg.whatsapp?.allowFrom?.length) &&
|
||||||
|
(looksLikeE164(from) || looksLikeE164(to));
|
||||||
|
const isWhatsAppSurface =
|
||||||
|
surface === "whatsapp" || hasWhatsappPrefix || inferWhatsApp;
|
||||||
|
|
||||||
const configuredAllowFrom = isWhatsAppSurface
|
const configuredAllowFrom = isWhatsAppSurface
|
||||||
? cfg.whatsapp?.allowFrom
|
? cfg.whatsapp?.allowFrom
|
||||||
: undefined;
|
: undefined;
|
||||||
const from = (ctx.From ?? "").replace(/^whatsapp:/, "");
|
|
||||||
const to = (ctx.To ?? "").replace(/^whatsapp:/, "");
|
|
||||||
const allowFromList =
|
const allowFromList =
|
||||||
configuredAllowFrom?.filter((entry) => entry?.trim()) ?? [];
|
configuredAllowFrom?.filter((entry) => entry?.trim()) ?? [];
|
||||||
const allowAll =
|
const allowAll =
|
||||||
@@ -35,7 +42,9 @@ export function resolveCommandAuthorization(params: {
|
|||||||
allowFromList.length === 0 ||
|
allowFromList.length === 0 ||
|
||||||
allowFromList.some((entry) => entry.trim() === "*");
|
allowFromList.some((entry) => entry.trim() === "*");
|
||||||
|
|
||||||
const senderE164 = normalizeE164(ctx.SenderE164 ?? "");
|
const senderE164 = normalizeE164(
|
||||||
|
ctx.SenderE164 ?? (isWhatsAppSurface ? from : ""),
|
||||||
|
);
|
||||||
const ownerCandidates =
|
const ownerCandidates =
|
||||||
isWhatsAppSurface && !allowAll
|
isWhatsAppSurface && !allowAll
|
||||||
? allowFromList.filter((entry) => entry !== "*")
|
? allowFromList.filter((entry) => entry !== "*")
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ export async function handleCommands(params: {
|
|||||||
shouldContinue: boolean;
|
shouldContinue: boolean;
|
||||||
}> {
|
}> {
|
||||||
const {
|
const {
|
||||||
|
ctx,
|
||||||
cfg,
|
cfg,
|
||||||
command,
|
command,
|
||||||
directives,
|
directives,
|
||||||
@@ -193,6 +194,18 @@ export async function handleCommands(params: {
|
|||||||
isGroup,
|
isGroup,
|
||||||
} = params;
|
} = params;
|
||||||
|
|
||||||
|
const resetRequested =
|
||||||
|
command.commandBodyNormalized === "/reset" ||
|
||||||
|
command.commandBodyNormalized === "reset" ||
|
||||||
|
command.commandBodyNormalized === "/new" ||
|
||||||
|
command.commandBodyNormalized === "new";
|
||||||
|
if (resetRequested && !command.isAuthorizedSender) {
|
||||||
|
logVerbose(
|
||||||
|
`Ignoring /reset from unauthorized sender: ${command.senderE164 || "<unknown>"}`,
|
||||||
|
);
|
||||||
|
return { shouldContinue: false };
|
||||||
|
}
|
||||||
|
|
||||||
const activationCommand = parseActivationCommand(
|
const activationCommand = parseActivationCommand(
|
||||||
command.commandBodyNormalized,
|
command.commandBodyNormalized,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user