mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-29 09:41:08 +00:00
fix(security): centralize dm/group allowlist auth composition
This commit is contained in:
@@ -44,7 +44,7 @@ export function isMattermostSenderAllowed(params: {
|
||||
allowFrom: string[];
|
||||
allowNameMatching?: boolean;
|
||||
}): boolean {
|
||||
const allowFrom = params.allowFrom;
|
||||
const allowFrom = normalizeMattermostAllowList(params.allowFrom);
|
||||
if (allowFrom.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -37,11 +37,7 @@ import {
|
||||
type MattermostPost,
|
||||
type MattermostUser,
|
||||
} from "./client.js";
|
||||
import {
|
||||
isMattermostSenderAllowed,
|
||||
normalizeMattermostAllowList,
|
||||
resolveMattermostEffectiveAllowFromLists,
|
||||
} from "./monitor-auth.js";
|
||||
import { isMattermostSenderAllowed, normalizeMattermostAllowList } from "./monitor-auth.js";
|
||||
import {
|
||||
createDedupeCache,
|
||||
formatInboundFromLabel,
|
||||
@@ -360,18 +356,32 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
|
||||
senderId;
|
||||
const rawText = post.message?.trim() || "";
|
||||
const dmPolicy = account.config.dmPolicy ?? "pairing";
|
||||
const normalizedAllowFrom = normalizeMattermostAllowList(account.config.allowFrom ?? []);
|
||||
const normalizedGroupAllowFrom = normalizeMattermostAllowList(
|
||||
account.config.groupAllowFrom ?? [],
|
||||
);
|
||||
const storeAllowFrom = normalizeMattermostAllowList(
|
||||
dmPolicy === "allowlist"
|
||||
? []
|
||||
: await core.channel.pairing.readAllowFromStore("mattermost").catch(() => []),
|
||||
);
|
||||
const { effectiveAllowFrom, effectiveGroupAllowFrom } =
|
||||
resolveMattermostEffectiveAllowFromLists({
|
||||
dmPolicy,
|
||||
allowFrom: account.config.allowFrom,
|
||||
groupAllowFrom: account.config.groupAllowFrom,
|
||||
storeAllowFrom,
|
||||
});
|
||||
const accessDecision = resolveDmGroupAccessWithLists({
|
||||
isGroup: kind !== "direct",
|
||||
dmPolicy,
|
||||
groupPolicy,
|
||||
allowFrom: normalizedAllowFrom,
|
||||
groupAllowFrom: normalizedGroupAllowFrom,
|
||||
storeAllowFrom,
|
||||
isSenderAllowed: (allowFrom) =>
|
||||
isMattermostSenderAllowed({
|
||||
senderId,
|
||||
senderName,
|
||||
allowFrom,
|
||||
allowNameMatching,
|
||||
}),
|
||||
});
|
||||
const effectiveAllowFrom = accessDecision.effectiveAllowFrom;
|
||||
const effectiveGroupAllowFrom = accessDecision.effectiveGroupAllowFrom;
|
||||
const allowTextCommands = core.channel.commands.shouldHandleTextCommands({
|
||||
cfg,
|
||||
surface: "mattermost",
|
||||
@@ -404,17 +414,15 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
|
||||
hasControlCommand,
|
||||
});
|
||||
const commandAuthorized =
|
||||
kind === "direct"
|
||||
? dmPolicy === "open" || senderAllowedForCommands
|
||||
: commandGate.commandAuthorized;
|
||||
kind === "direct" ? accessDecision.decision === "allow" : commandGate.commandAuthorized;
|
||||
|
||||
if (kind === "direct") {
|
||||
if (dmPolicy === "disabled") {
|
||||
logVerboseMessage(`mattermost: drop dm (dmPolicy=disabled sender=${senderId})`);
|
||||
return;
|
||||
}
|
||||
if (dmPolicy !== "open" && !senderAllowedForCommands) {
|
||||
if (dmPolicy === "pairing") {
|
||||
if (accessDecision.decision !== "allow") {
|
||||
if (kind === "direct") {
|
||||
if (accessDecision.reason === "dmPolicy=disabled") {
|
||||
logVerboseMessage(`mattermost: drop dm (dmPolicy=disabled sender=${senderId})`);
|
||||
return;
|
||||
}
|
||||
if (accessDecision.decision === "pairing") {
|
||||
const { code, created } = await core.channel.pairing.upsertPairingRequest({
|
||||
channel: "mattermost",
|
||||
id: senderId,
|
||||
@@ -437,26 +445,27 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
|
||||
logVerboseMessage(`mattermost: pairing reply failed for ${senderId}: ${String(err)}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logVerboseMessage(`mattermost: drop dm sender=${senderId} (dmPolicy=${dmPolicy})`);
|
||||
return;
|
||||
}
|
||||
logVerboseMessage(`mattermost: drop dm sender=${senderId} (dmPolicy=${dmPolicy})`);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (groupPolicy === "disabled") {
|
||||
if (accessDecision.reason === "groupPolicy=disabled") {
|
||||
logVerboseMessage("mattermost: drop group message (groupPolicy=disabled)");
|
||||
return;
|
||||
}
|
||||
if (groupPolicy === "allowlist") {
|
||||
if (effectiveGroupAllowFrom.length === 0) {
|
||||
logVerboseMessage("mattermost: drop group message (no group allowlist)");
|
||||
return;
|
||||
}
|
||||
if (!groupAllowedForCommands) {
|
||||
logVerboseMessage(`mattermost: drop group sender=${senderId} (not in groupAllowFrom)`);
|
||||
return;
|
||||
}
|
||||
if (accessDecision.reason === "groupPolicy=allowlist (empty allowlist)") {
|
||||
logVerboseMessage("mattermost: drop group message (no group allowlist)");
|
||||
return;
|
||||
}
|
||||
if (accessDecision.reason === "groupPolicy=allowlist (not allowlisted)") {
|
||||
logVerboseMessage(`mattermost: drop group sender=${senderId} (not in groupAllowFrom)`);
|
||||
return;
|
||||
}
|
||||
logVerboseMessage(
|
||||
`mattermost: drop group message (groupPolicy=${groupPolicy} reason=${accessDecision.reason})`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (kind !== "direct" && commandGate.shouldBlock) {
|
||||
@@ -852,14 +861,14 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
|
||||
isGroup: kind !== "direct",
|
||||
dmPolicy,
|
||||
groupPolicy,
|
||||
allowFrom: account.config.allowFrom,
|
||||
groupAllowFrom: account.config.groupAllowFrom,
|
||||
allowFrom: normalizeMattermostAllowList(account.config.allowFrom ?? []),
|
||||
groupAllowFrom: normalizeMattermostAllowList(account.config.groupAllowFrom ?? []),
|
||||
storeAllowFrom,
|
||||
isSenderAllowed: (allowFrom) =>
|
||||
isMattermostSenderAllowed({
|
||||
senderId: userId,
|
||||
senderName,
|
||||
allowFrom: normalizeMattermostAllowList(allowFrom),
|
||||
allowFrom,
|
||||
allowNameMatching,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -146,18 +146,15 @@ export function createMSTeamsMessageHandler(deps: MSTeamsMessageHandlerDeps) {
|
||||
});
|
||||
const effectiveDmAllowFrom = resolvedAllowFromLists.effectiveAllowFrom;
|
||||
if (isDirectMessage && msteamsCfg) {
|
||||
const allowFrom = dmAllowFrom;
|
||||
|
||||
if (dmPolicy === "disabled") {
|
||||
log.debug?.("dropping dm (dms disabled)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dmPolicy !== "open") {
|
||||
const effectiveAllowFrom = [...allowFrom.map((v) => String(v)), ...storedAllowFrom];
|
||||
const allowNameMatching = isDangerousNameMatchingEnabled(msteamsCfg);
|
||||
const allowMatch = resolveMSTeamsAllowlistMatch({
|
||||
allowFrom: effectiveAllowFrom,
|
||||
allowFrom: effectiveDmAllowFrom,
|
||||
senderId,
|
||||
senderName,
|
||||
allowNameMatching,
|
||||
|
||||
Reference in New Issue
Block a user