fix: guard WhatsApp setup prompt values (#67895) (thanks @lawrence3699)

* fix(whatsapp): guard setup prompt values

* fix(whatsapp): preserve allowFrom invalid input details

* fix: guard WhatsApp setup prompt values (#67895) (thanks @lawrence3699)

---------

Co-authored-by: lawrence3699 <lawrence3699@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
This commit is contained in:
chaoliang yan
2026-04-17 12:42:55 +10:00
committed by GitHub
parent 685f9903ec
commit a189394590
3 changed files with 40 additions and 4 deletions

View File

@@ -8,6 +8,7 @@ Docs: https://docs.openclaw.ai
- Onboarding/non-interactive: preserve existing gateway auth tokens during re-onboard so active local gateway clients are not disconnected by an implicit token rotation. (#67821) Thanks @BKF-Gitty.
- OpenAI Codex/Responses: unify native Responses API capability detection so Codex OAuth requests emit the required `store: false` field on the native Responses path. (#67918) Thanks @obviyus.
- WhatsApp/setup: guard personal-phone and allowlist prompt values so setup fails with clear validation errors instead of crashing on undefined prompt text. (#67895) Thanks @lawrence3699.
## 2026.4.15

View File

@@ -169,6 +169,19 @@ describe("whatsapp setup wizard", () => {
expectWhatsAppAllowlistModeSetup(result.cfg);
});
it("throws a user-facing error instead of crashing when allowlist input is undefined", async () => {
const harness = createSeparatePhoneHarness({
selectValues: ["separate", "allowlist", "list"],
});
harness.text.mockResolvedValueOnce(undefined as never);
await expect(
runConfigureWithHarness({
harness,
}),
).rejects.toThrow("Invalid WhatsApp allowFrom list");
});
it("enables allowlist self-chat mode for personal-phone setup", async () => {
hoisted.pathExists.mockResolvedValue(true);
const harness = createWhatsAppPersonalPhoneHarness(createQueuedWizardPrompter);
@@ -180,6 +193,18 @@ describe("whatsapp setup wizard", () => {
expectWhatsAppPersonalPhoneSetup(result.cfg);
});
it("throws a user-facing error instead of crashing when personal-phone input is undefined", async () => {
hoisted.pathExists.mockResolvedValue(true);
const harness = createWhatsAppPersonalPhoneHarness(createQueuedWizardPrompter);
harness.text.mockResolvedValueOnce(undefined as never);
await expect(
runConfigureWithHarness({
harness,
}),
).rejects.toThrow("Invalid WhatsApp owner number");
});
it("forces wildcard allowFrom for open policy without allowFrom follow-up prompts", async () => {
hoisted.pathExists.mockResolvedValue(true);
const harness = createSeparatePhoneHarness({

View File

@@ -23,6 +23,10 @@ type SetupRuntime = Parameters<NonNullable<ChannelSetupWizard["finalize"]>>[0]["
type WhatsAppConfig = NonNullable<NonNullable<OpenClawConfig["channels"]>["whatsapp"]>;
type WhatsAppAccountConfig = NonNullable<NonNullable<WhatsAppConfig["accounts"]>[string]>;
function trimPromptText(value: string | null | undefined): string {
return value?.trim() ?? "";
}
function mergeWhatsAppConfig(
cfg: OpenClawConfig,
accountId: string,
@@ -124,7 +128,7 @@ async function promptWhatsAppOwnerAllowFrom(params: {
placeholder: "+15555550123",
initialValue: existingAllowFrom[0],
validate: (value) => {
const raw = value.trim();
const raw = trimPromptText(value);
if (!raw) {
return "Required";
}
@@ -136,7 +140,7 @@ async function promptWhatsAppOwnerAllowFrom(params: {
},
});
const normalized = normalizeE164(entry.trim());
const normalized = normalizeE164(trimPromptText(entry));
if (!normalized) {
throw new Error("Invalid WhatsApp owner number (expected E.164 after validation).");
}
@@ -311,7 +315,7 @@ async function promptWhatsAppDmAccess(params: {
message: "Allowed sender numbers (comma-separated, E.164)",
placeholder: "+15555550123, +447700900123",
validate: (value) => {
const raw = value.trim();
const raw = trimPromptText(value);
if (!raw) {
return "Required";
}
@@ -326,7 +330,13 @@ async function promptWhatsAppDmAccess(params: {
},
});
const parsed = parseWhatsAppAllowFromEntries(allowRaw);
const parsed = parseWhatsAppAllowFromEntries(trimPromptText(allowRaw));
if (parsed.invalidEntry) {
throw new Error(`Invalid number: ${parsed.invalidEntry}`);
}
if (parsed.entries.length === 0) {
throw new Error("Invalid WhatsApp allowFrom list (expected at least one E.164 number).");
}
return setWhatsAppAllowFrom(next, accountId, parsed.entries);
}