fix: improve telegram configuration safety

This commit is contained in:
Peter Steinberger
2026-01-11 03:57:44 +01:00
parent 11f897b7df
commit 36a21ae9b0
11 changed files with 177 additions and 19 deletions

View File

@@ -136,6 +136,12 @@ export const CHAT_COMMANDS: ChatCommandDefinition[] = (() => {
description: "Show current status.",
textAlias: "/status",
}),
defineChatCommand({
key: "whoami",
nativeName: "whoami",
description: "Show your sender id.",
textAlias: "/whoami",
}),
defineChatCommand({
key: "config",
nativeName: "config",
@@ -247,6 +253,7 @@ export const CHAT_COMMANDS: ChatCommandDefinition[] = (() => {
];
registerAlias(commands, "status", "/usage");
registerAlias(commands, "whoami", "/id");
registerAlias(commands, "think", "/thinking", "/t");
registerAlias(commands, "verbose", "/v");
registerAlias(commands, "reasoning", "/reason");

View File

@@ -643,6 +643,30 @@ export async function handleCommands(params: {
return { shouldContinue: false, reply };
}
const whoamiRequested = command.commandBodyNormalized === "/whoami";
if (allowTextCommands && whoamiRequested) {
const senderId = ctx.SenderId ?? "";
const senderUsername = ctx.SenderUsername ?? "";
const lines = ["🧭 Identity", `Provider: ${command.provider}`];
if (senderId) lines.push(`User id: ${senderId}`);
if (senderUsername) {
const handle = senderUsername.startsWith("@")
? senderUsername
: `@${senderUsername}`;
lines.push(`Username: ${handle}`);
}
if (ctx.ChatType === "group" && ctx.From) {
lines.push(`Chat: ${ctx.From}`);
}
if (ctx.MessageThreadId != null) {
lines.push(`Thread: ${ctx.MessageThreadId}`);
}
if (senderId) {
lines.push(`AllowFrom: ${senderId}`);
}
return { shouldContinue: false, reply: { text: lines.join("\n") } };
}
const configCommand = allowTextCommands
? parseConfigCommand(command.commandBodyNormalized)
: null;

View File

@@ -470,6 +470,61 @@ async function maybeConfigureDmPolicies(params: {
return cfg;
}
function parseTelegramAllowFromEntries(raw: string): {
entries: string[];
hasUsernames: boolean;
error?: string;
} {
const parts = raw
.split(/[\n,;]+/g)
.map((part) => part.trim())
.filter(Boolean);
if (parts.length === 0) {
return { entries: [], hasUsernames: false, error: "Required" };
}
const entries: string[] = [];
let hasUsernames = false;
for (const part of parts) {
if (part === "*") {
entries.push(part);
continue;
}
const match = part.match(/^(telegram|tg):(.+)$/i);
const value = match ? match[2]?.trim() : part;
if (!value) {
return { entries: [], hasUsernames: false, error: `Invalid entry: ${part}` };
}
if (/^\d+$/.test(value)) {
entries.push(part);
continue;
}
if (value.startsWith("@")) {
const username = value.slice(1);
if (!/^[a-z0-9_]{5,32}$/i.test(username)) {
return {
entries: [],
hasUsernames: false,
error: `Invalid username: ${part}`,
};
}
hasUsernames = true;
entries.push(part);
continue;
}
if (/^[a-z0-9_]{5,32}$/i.test(value)) {
hasUsernames = true;
entries.push(`@${value}`);
continue;
}
return {
entries: [],
hasUsernames: false,
error: `Invalid entry: ${part}`,
};
}
return { entries, hasUsernames };
}
async function promptTelegramAllowFrom(params: {
cfg: ClawdbotConfig;
prompter: WizardPrompter;
@@ -479,22 +534,30 @@ async function promptTelegramAllowFrom(params: {
const resolved = resolveTelegramAccount({ cfg, accountId });
const existingAllowFrom = resolved.config.allowFrom ?? [];
const entry = await prompter.text({
message: "Telegram allowFrom (user id)",
placeholder: "123456789",
message: "Telegram allowFrom (user id or @username)",
placeholder: "123456789, @myhandle",
initialValue: existingAllowFrom[0]
? String(existingAllowFrom[0])
: undefined,
validate: (value) => {
const raw = String(value ?? "").trim();
if (!raw) return "Required";
if (!/^\d+$/.test(raw)) return "Use a numeric Telegram user id";
return undefined;
const parsed = parseTelegramAllowFromEntries(raw);
return parsed.error;
},
});
const normalized = String(entry).trim();
const parsed = parseTelegramAllowFromEntries(String(entry).trim());
if (parsed.hasUsernames) {
await prompter.note(
[
"Usernames can change; numeric user IDs are more stable.",
"Tip: DM the bot and it will reply with your user ID (pairing message).",
].join("\n"),
"Telegram allowFrom",
);
}
const merged = [
...existingAllowFrom.map((item) => String(item).trim()).filter(Boolean),
normalized,
...parsed.entries,
];
const unique = [...new Set(merged)];