fix(onboard): explain DM pairing defaults
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import fs from "node:fs/promises";
|
import fs from "node:fs/promises";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import type { ClawdbotConfig } from "../config/config.js";
|
import type { ClawdbotConfig } from "../config/config.js";
|
||||||
|
import type { DmPolicy } from "../config/types.js";
|
||||||
import { loginWeb } from "../provider-web.js";
|
import { loginWeb } from "../provider-web.js";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
import { normalizeE164 } from "../utils.js";
|
import { normalizeE164 } from "../utils.js";
|
||||||
@@ -27,6 +28,10 @@ async function detectWhatsAppLinked(): Promise<boolean> {
|
|||||||
async function noteProviderPrimer(prompter: WizardPrompter): Promise<void> {
|
async function noteProviderPrimer(prompter: WizardPrompter): Promise<void> {
|
||||||
await prompter.note(
|
await prompter.note(
|
||||||
[
|
[
|
||||||
|
"DM security: default is pairing; unknown DMs get a pairing code.",
|
||||||
|
"Approve with: clawdbot pairing approve --provider <provider> <code>",
|
||||||
|
'Public DMs require dmPolicy="open" + allowFrom=["*"].',
|
||||||
|
"",
|
||||||
"WhatsApp: links via WhatsApp Web (scan QR), stores creds for future sends.",
|
"WhatsApp: links via WhatsApp Web (scan QR), stores creds for future sends.",
|
||||||
"WhatsApp: dedicated second number recommended; primary number OK (self-chat).",
|
"WhatsApp: dedicated second number recommended; primary number OK (self-chat).",
|
||||||
"Telegram: Bot API (token from @BotFather), replies via your bot.",
|
"Telegram: Bot API (token from @BotFather), replies via your bot.",
|
||||||
@@ -153,6 +158,16 @@ async function noteSlackTokenHelp(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setWhatsAppDmPolicy(cfg: ClawdbotConfig, dmPolicy?: DmPolicy) {
|
||||||
|
return {
|
||||||
|
...cfg,
|
||||||
|
whatsapp: {
|
||||||
|
...cfg.whatsapp,
|
||||||
|
dmPolicy,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function setWhatsAppAllowFrom(cfg: ClawdbotConfig, allowFrom?: string[]) {
|
function setWhatsAppAllowFrom(cfg: ClawdbotConfig, allowFrom?: string[]) {
|
||||||
return {
|
return {
|
||||||
...cfg,
|
...cfg,
|
||||||
@@ -168,41 +183,60 @@ async function promptWhatsAppAllowFrom(
|
|||||||
_runtime: RuntimeEnv,
|
_runtime: RuntimeEnv,
|
||||||
prompter: WizardPrompter,
|
prompter: WizardPrompter,
|
||||||
): Promise<ClawdbotConfig> {
|
): Promise<ClawdbotConfig> {
|
||||||
|
const existingPolicy = cfg.whatsapp?.dmPolicy ?? "pairing";
|
||||||
const existingAllowFrom = cfg.whatsapp?.allowFrom ?? [];
|
const existingAllowFrom = cfg.whatsapp?.allowFrom ?? [];
|
||||||
const existingLabel =
|
const existingLabel =
|
||||||
existingAllowFrom.length > 0 ? existingAllowFrom.join(", ") : "unset";
|
existingAllowFrom.length > 0 ? existingAllowFrom.join(", ") : "unset";
|
||||||
|
|
||||||
await prompter.note(
|
await prompter.note(
|
||||||
[
|
[
|
||||||
"WhatsApp direct chats are gated by `whatsapp.allowFrom`.",
|
"WhatsApp direct chats are gated by `whatsapp.dmPolicy` + `whatsapp.allowFrom`.",
|
||||||
'Default (unset) = self-chat only; use "*" to allow anyone.',
|
"- pairing (default): unknown senders get a pairing code; owner approves",
|
||||||
`Current: ${existingLabel}`,
|
"- allowlist: unknown senders are blocked",
|
||||||
|
'- open: public inbound DMs (requires allowFrom to include "*")',
|
||||||
|
"- disabled: ignore WhatsApp DMs",
|
||||||
|
"",
|
||||||
|
`Current: dmPolicy=${existingPolicy}, allowFrom=${existingLabel}`,
|
||||||
].join("\n"),
|
].join("\n"),
|
||||||
"WhatsApp allowlist",
|
"WhatsApp DM access",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const policy = (await prompter.select({
|
||||||
|
message: "WhatsApp DM policy",
|
||||||
|
options: [
|
||||||
|
{ value: "pairing", label: "Pairing (recommended)" },
|
||||||
|
{ value: "allowlist", label: "Allowlist only (block unknown senders)" },
|
||||||
|
{ value: "open", label: "Open (public inbound DMs)" },
|
||||||
|
{ value: "disabled", label: "Disabled (ignore WhatsApp DMs)" },
|
||||||
|
],
|
||||||
|
})) as DmPolicy;
|
||||||
|
|
||||||
|
const next = setWhatsAppDmPolicy(cfg, policy);
|
||||||
|
if (policy === "open") return setWhatsAppAllowFrom(next, ["*"]);
|
||||||
|
if (policy === "disabled") return next;
|
||||||
|
|
||||||
const options =
|
const options =
|
||||||
existingAllowFrom.length > 0
|
existingAllowFrom.length > 0
|
||||||
? ([
|
? ([
|
||||||
{ value: "keep", label: "Keep current" },
|
{ value: "keep", label: "Keep current allowFrom" },
|
||||||
{ value: "self", label: "Self-chat only (unset)" },
|
{
|
||||||
{ value: "list", label: "Specific numbers (recommended)" },
|
value: "unset",
|
||||||
{ value: "any", label: "Anyone (*)" },
|
label: "Unset allowFrom (use pairing approvals only)",
|
||||||
|
},
|
||||||
|
{ value: "list", label: "Set allowFrom to specific numbers" },
|
||||||
] as const)
|
] as const)
|
||||||
: ([
|
: ([
|
||||||
{ value: "self", label: "Self-chat only (default)" },
|
{ value: "unset", label: "Unset allowFrom (default)" },
|
||||||
{ value: "list", label: "Specific numbers (recommended)" },
|
{ value: "list", label: "Set allowFrom to specific numbers" },
|
||||||
{ value: "any", label: "Anyone (*)" },
|
|
||||||
] as const);
|
] as const);
|
||||||
|
|
||||||
const mode = (await prompter.select({
|
const mode = (await prompter.select({
|
||||||
message: "Who can trigger the bot via WhatsApp?",
|
message: "WhatsApp allowFrom (optional pre-allowlist)",
|
||||||
options: options.map((opt) => ({ value: opt.value, label: opt.label })),
|
options: options.map((opt) => ({ value: opt.value, label: opt.label })),
|
||||||
})) as (typeof options)[number]["value"];
|
})) as (typeof options)[number]["value"];
|
||||||
|
|
||||||
if (mode === "keep") return cfg;
|
if (mode === "keep") return next;
|
||||||
if (mode === "self") return setWhatsAppAllowFrom(cfg, undefined);
|
if (mode === "unset") return setWhatsAppAllowFrom(next, undefined);
|
||||||
if (mode === "any") return setWhatsAppAllowFrom(cfg, ["*"]);
|
|
||||||
|
|
||||||
const allowRaw = await prompter.text({
|
const allowRaw = await prompter.text({
|
||||||
message: "Allowed sender numbers (comma-separated, E.164)",
|
message: "Allowed sender numbers (comma-separated, E.164)",
|
||||||
@@ -232,7 +266,7 @@ async function promptWhatsAppAllowFrom(
|
|||||||
part === "*" ? "*" : normalizeE164(part),
|
part === "*" ? "*" : normalizeE164(part),
|
||||||
);
|
);
|
||||||
const unique = [...new Set(normalized.filter(Boolean))];
|
const unique = [...new Set(normalized.filter(Boolean))];
|
||||||
return setWhatsAppAllowFrom(cfg, unique);
|
return setWhatsAppAllowFrom(next, unique);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setupProviders(
|
export async function setupProviders(
|
||||||
|
|||||||
Reference in New Issue
Block a user