fix: normalize pairing aliases and webhook guard (#991) (thanks @longmaba)
This commit is contained in:
@@ -8,10 +8,16 @@ const pairingIdLabels: Record<string, string> = {
|
||||
telegram: "telegramUserId",
|
||||
discord: "discordUserId",
|
||||
};
|
||||
const normalizeChannelId = vi.fn((raw: string) => {
|
||||
if (!raw) return null;
|
||||
if (raw === "imsg") return "imessage";
|
||||
if (["telegram", "discord", "imessage"].includes(raw)) return raw;
|
||||
return null;
|
||||
});
|
||||
const getPairingAdapter = vi.fn((channel: string) => ({
|
||||
idLabel: pairingIdLabels[channel] ?? "userId",
|
||||
}));
|
||||
const listPairingChannels = vi.fn(() => ["telegram", "discord"]);
|
||||
const listPairingChannels = vi.fn(() => ["telegram", "discord", "imessage"]);
|
||||
|
||||
vi.mock("../pairing/pairing-store.js", () => ({
|
||||
listChannelPairingRequests,
|
||||
@@ -24,6 +30,10 @@ vi.mock("../channels/plugins/pairing.js", () => ({
|
||||
getPairingAdapter,
|
||||
}));
|
||||
|
||||
vi.mock("../channels/plugins/index.js", () => ({
|
||||
normalizeChannelId,
|
||||
}));
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
loadConfig: vi.fn().mockReturnValue({}),
|
||||
}));
|
||||
@@ -63,6 +73,32 @@ describe("pairing cli", () => {
|
||||
expect(listChannelPairingRequests).toHaveBeenCalledWith("telegram");
|
||||
});
|
||||
|
||||
it("normalizes channel aliases", async () => {
|
||||
const { registerPairingCli } = await import("./pairing-cli.js");
|
||||
listChannelPairingRequests.mockResolvedValueOnce([]);
|
||||
|
||||
const program = new Command();
|
||||
program.name("test");
|
||||
registerPairingCli(program);
|
||||
await program.parseAsync(["pairing", "list", "imsg"], { from: "user" });
|
||||
|
||||
expect(normalizeChannelId).toHaveBeenCalledWith("imsg");
|
||||
expect(listChannelPairingRequests).toHaveBeenCalledWith("imessage");
|
||||
});
|
||||
|
||||
it("accepts extension channels outside the registry", async () => {
|
||||
const { registerPairingCli } = await import("./pairing-cli.js");
|
||||
listChannelPairingRequests.mockResolvedValueOnce([]);
|
||||
|
||||
const program = new Command();
|
||||
program.name("test");
|
||||
registerPairingCli(program);
|
||||
await program.parseAsync(["pairing", "list", "zalo"], { from: "user" });
|
||||
|
||||
expect(normalizeChannelId).toHaveBeenCalledWith("zalo");
|
||||
expect(listChannelPairingRequests).toHaveBeenCalledWith("zalo");
|
||||
});
|
||||
|
||||
it("labels Discord ids as discordUserId", async () => {
|
||||
const { registerPairingCli } = await import("./pairing-cli.js");
|
||||
listChannelPairingRequests.mockResolvedValueOnce([
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
listPairingChannels,
|
||||
notifyPairingApproved,
|
||||
} from "../channels/plugins/pairing.js";
|
||||
import { normalizeChannelId } from "../channels/plugins/index.js";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import { resolvePairingIdLabel } from "../pairing/pairing-labels.js";
|
||||
import {
|
||||
@@ -17,9 +18,25 @@ const CHANNELS: PairingChannel[] = listPairingChannels();
|
||||
|
||||
/** Parse channel, allowing extension channels not in core registry. */
|
||||
function parseChannel(raw: unknown): PairingChannel {
|
||||
const value = String(raw ?? "").trim().toLowerCase();
|
||||
const value = (
|
||||
typeof raw === "string"
|
||||
? raw
|
||||
: typeof raw === "number" || typeof raw === "boolean"
|
||||
? String(raw)
|
||||
: ""
|
||||
)
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (!value) throw new Error("Channel required");
|
||||
if (CHANNELS.includes(value as PairingChannel)) return value as PairingChannel;
|
||||
|
||||
const normalized = normalizeChannelId(value);
|
||||
if (normalized) {
|
||||
if (!CHANNELS.includes(normalized as PairingChannel)) {
|
||||
throw new Error(`Channel ${normalized} does not support pairing`);
|
||||
}
|
||||
return normalized as PairingChannel;
|
||||
}
|
||||
|
||||
// Allow extension channels: validate format but don't require registry
|
||||
if (/^[a-z][a-z0-9_-]{0,63}$/.test(value)) return value as PairingChannel;
|
||||
throw new Error(`Invalid channel: ${value}`);
|
||||
|
||||
Reference in New Issue
Block a user