Twitch: reject reserved setup account ids

This commit is contained in:
Gustavo Madeira Santana
2026-04-17 13:12:00 -04:00
parent bb7ba83550
commit 59305356a0
2 changed files with 49 additions and 15 deletions

View File

@@ -313,20 +313,40 @@ describe("setup surface helpers", () => {
});
describe("setup wizard account routing", () => {
it("normalizes account ids before using them as config keys", () => {
const cfg = setTwitchAccount(
{} as Parameters<typeof setTwitchAccount>[0],
{
username: "normalized-bot",
accessToken: "oauth:normalized",
clientId: "normalized-client",
channel: "#normalized",
},
"__proto__",
);
it("rejects reserved account ids before using them as config keys", () => {
expect(() =>
setTwitchAccount(
{} as Parameters<typeof setTwitchAccount>[0],
{
username: "reserved-bot",
accessToken: "oauth:reserved",
clientId: "reserved-client",
channel: "#reserved",
},
"__proto__",
),
).toThrow("Invalid Twitch account id");
expect(cfg.channels?.twitch?.accounts?.default?.username).toBe("normalized-bot");
expect(Object.prototype).not.toHaveProperty("username");
});
it("rejects reserved account ids before env-token writes", async () => {
await expect(
configureWithEnvToken(
{} as Parameters<typeof configureWithEnvToken>[0],
mockPrompter,
null,
"oauth:fromenv",
false,
{} as Parameters<typeof configureWithEnvToken>[5],
"__proto__",
),
).rejects.toThrow("Invalid Twitch account id");
expect(mockPromptConfirm).not.toHaveBeenCalled();
});
it("normalizes account ids before rendering status lines", () => {
expect(
twitchSetupWizard.status?.resolveStatusLines?.({
cfg: {},

View File

@@ -2,6 +2,7 @@
* Twitch setup wizard surface for CLI setup.
*/
import { normalizeOptionalAccountId } from "openclaw/plugin-sdk/account-id";
import { getChatChannelMeta, type ChannelPlugin } from "openclaw/plugin-sdk/core";
import {
formatDocsLink,
@@ -23,11 +24,20 @@ import type { TwitchAccountConfig, TwitchRole } from "./types.js";
import { isAccountConfigured } from "./utils/twitch.js";
const channel = "twitch" as const;
const INVALID_ACCOUNT_ID_MESSAGE = "Invalid Twitch account id";
function normalizeRequestedSetupAccountId(accountId: string): string {
const normalized = normalizeOptionalAccountId(accountId);
if (!normalized) {
throw new Error(INVALID_ACCOUNT_ID_MESSAGE);
}
return normalized;
}
function resolveSetupAccountId(cfg: OpenClawConfig, requestedAccountId?: string): string {
const requested = requestedAccountId?.trim();
if (requested) {
return normalizeAccountId(requested);
return normalizeRequestedSetupAccountId(requested);
}
const preferred = cfg.channels?.twitch?.defaultAccount?.trim();
@@ -39,7 +49,9 @@ export function setTwitchAccount(
account: Partial<TwitchAccountConfig>,
accountId: string = resolveSetupAccountId(cfg),
): OpenClawConfig {
const resolvedAccountId = normalizeAccountId(accountId);
const resolvedAccountId = accountId.trim()
? normalizeRequestedSetupAccountId(accountId)
: resolveSetupAccountId(cfg);
const existing = getAccountConfig(cfg, resolvedAccountId);
const merged: TwitchAccountConfig = {
username: account.username ?? existing?.username ?? "",
@@ -208,7 +220,9 @@ export async function configureWithEnvToken(
dmPolicy: ChannelSetupDmPolicy,
accountId: string = resolveSetupAccountId(cfg),
): Promise<{ cfg: OpenClawConfig } | null> {
const resolvedAccountId = normalizeAccountId(accountId);
const resolvedAccountId = accountId.trim()
? normalizeRequestedSetupAccountId(accountId)
: resolveSetupAccountId(cfg);
if (resolvedAccountId !== DEFAULT_ACCOUNT_ID) {
return null;
}