feat: expand dm allowlist onboarding

This commit is contained in:
Peter Steinberger
2026-01-18 22:51:01 +00:00
parent a7be3a9649
commit ace8a1b44e
7 changed files with 512 additions and 15 deletions

View File

@@ -9,6 +9,7 @@ import {
resolveSignalAccount,
} from "../../../signal/accounts.js";
import { formatDocsLink } from "../../../terminal/links.js";
import { normalizeE164 } from "../../../utils.js";
import type { ChannelOnboardingAdapter, ChannelOnboardingDmPolicy } from "../onboarding-types.js";
import { addWildcardAllowFrom, promptAccountId } from "./helpers.js";
@@ -30,6 +31,107 @@ function setSignalDmPolicy(cfg: ClawdbotConfig, dmPolicy: DmPolicy) {
};
}
function setSignalAllowFrom(
cfg: ClawdbotConfig,
accountId: string,
allowFrom: string[],
): ClawdbotConfig {
if (accountId === DEFAULT_ACCOUNT_ID) {
return {
...cfg,
channels: {
...cfg.channels,
signal: {
...cfg.channels?.signal,
allowFrom,
},
},
};
}
return {
...cfg,
channels: {
...cfg.channels,
signal: {
...cfg.channels?.signal,
accounts: {
...cfg.channels?.signal?.accounts,
[accountId]: {
...cfg.channels?.signal?.accounts?.[accountId],
allowFrom,
},
},
},
},
};
}
function parseSignalAllowFromInput(raw: string): string[] {
return raw
.split(/[\n,;]+/g)
.map((entry) => entry.trim())
.filter(Boolean);
}
function isUuidLike(value: string): boolean {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
}
async function promptSignalAllowFrom(params: {
cfg: ClawdbotConfig;
prompter: WizardPrompter;
accountId?: string;
}): Promise<ClawdbotConfig> {
const accountId =
params.accountId && normalizeAccountId(params.accountId)
? normalizeAccountId(params.accountId) ?? DEFAULT_ACCOUNT_ID
: resolveDefaultSignalAccountId(params.cfg);
const resolved = resolveSignalAccount({ cfg: params.cfg, accountId });
const existing = resolved.config.allowFrom ?? [];
await params.prompter.note(
[
"Allowlist Signal DMs by sender id.",
"Examples:",
"- +15555550123",
"- uuid:123e4567-e89b-12d3-a456-426614174000",
"Multiple entries: comma-separated.",
`Docs: ${formatDocsLink("/signal", "signal")}`,
].join("\n"),
"Signal allowlist",
);
const entry = await params.prompter.text({
message: "Signal allowFrom (E.164 or uuid)",
placeholder: "+15555550123, uuid:123e4567-e89b-12d3-a456-426614174000",
initialValue: existing[0] ? String(existing[0]) : undefined,
validate: (value) => {
const raw = String(value ?? "").trim();
if (!raw) return "Required";
const parts = parseSignalAllowFromInput(raw);
for (const part of parts) {
if (part === "*") continue;
if (part.toLowerCase().startsWith("uuid:")) {
if (!part.slice("uuid:".length).trim()) return "Invalid uuid entry";
continue;
}
if (isUuidLike(part)) continue;
if (!normalizeE164(part)) return `Invalid entry: ${part}`;
}
return undefined;
},
});
const parts = parseSignalAllowFromInput(String(entry));
const normalized = parts
.map((part) => {
if (part === "*") return "*";
if (part.toLowerCase().startsWith("uuid:")) return `uuid:${part.slice(5).trim()}`;
if (isUuidLike(part)) return `uuid:${part}`;
return normalizeE164(part);
})
.filter(Boolean);
const unique = [...new Set(normalized)];
return setSignalAllowFrom(params.cfg, accountId, unique);
}
const dmPolicy: ChannelOnboardingDmPolicy = {
label: "Signal",
channel,
@@ -37,6 +139,7 @@ const dmPolicy: ChannelOnboardingDmPolicy = {
allowFromKey: "channels.signal.allowFrom",
getCurrent: (cfg) => cfg.channels?.signal?.dmPolicy ?? "pairing",
setPolicy: (cfg, policy) => setSignalDmPolicy(cfg, policy),
promptAllowFrom: promptSignalAllowFrom,
};
export const signalOnboardingAdapter: ChannelOnboardingAdapter = {