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

@@ -257,6 +257,7 @@ export class ClawdbotApp extends LitElement {
@state() telegramForm: TelegramForm = {
token: "",
requireMention: true,
groupsWildcardEnabled: false,
allowFrom: "",
proxy: "",
webhookUrl: "",

View File

@@ -20,6 +20,7 @@ import {
const baseTelegramForm: TelegramForm = {
token: "",
requireMention: true,
groupsWildcardEnabled: false,
allowFrom: "",
proxy: "",
webhookUrl: "",

View File

@@ -129,6 +129,7 @@ export function applyConfigSnapshot(state: ConfigState, snapshot: ConfigSnapshot
telegramGroups["*"] && typeof telegramGroups["*"] === "object"
? (telegramGroups["*"] as Record<string, unknown>)
: {};
const telegramHasWildcard = Boolean(telegramGroups["*"]);
const allowFrom = Array.isArray(telegram.allowFrom)
? toList(telegram.allowFrom)
: typeof telegram.allowFrom === "string"
@@ -141,6 +142,7 @@ export function applyConfigSnapshot(state: ConfigState, snapshot: ConfigSnapshot
typeof telegramDefaultGroup.requireMention === "boolean"
? telegramDefaultGroup.requireMention
: true,
groupsWildcardEnabled: telegramHasWildcard,
allowFrom,
proxy: typeof telegram.proxy === "string" ? telegram.proxy : "",
webhookUrl: typeof telegram.webhookUrl === "string" ? telegram.webhookUrl : "",

View File

@@ -181,6 +181,15 @@ export async function saveTelegramConfig(state: ConnectionsState) {
state.telegramSaving = true;
state.telegramConfigStatus = null;
try {
if (state.telegramForm.groupsWildcardEnabled) {
const confirmed = window.confirm(
'Telegram groups wildcard "*" allows all groups. Continue?',
);
if (!confirmed) {
state.telegramConfigStatus = "Save cancelled.";
return;
}
}
const base = state.configSnapshot?.config ?? {};
const config = { ...base } as Record<string, unknown>;
const telegram = { ...(config.telegram ?? {}) } as Record<string, unknown>;
@@ -196,16 +205,22 @@ export async function saveTelegramConfig(state: ConnectionsState) {
unknown
>)
: {};
const defaultGroup =
groups["*"] && typeof groups["*"] === "object"
? ({ ...(groups["*"] as Record<string, unknown>) } as Record<
string,
unknown
>)
: {};
defaultGroup.requireMention = state.telegramForm.requireMention;
groups["*"] = defaultGroup;
telegram.groups = groups;
if (state.telegramForm.groupsWildcardEnabled) {
const defaultGroup =
groups["*"] && typeof groups["*"] === "object"
? ({ ...(groups["*"] as Record<string, unknown>) } as Record<
string,
unknown
>)
: {};
defaultGroup.requireMention = state.telegramForm.requireMention;
groups["*"] = defaultGroup;
telegram.groups = groups;
} else if (groups["*"]) {
delete groups["*"];
if (Object.keys(groups).length > 0) telegram.groups = groups;
else delete telegram.groups;
}
delete telegram.requireMention;
const allowFrom = parseList(state.telegramForm.allowFrom);
if (allowFrom.length > 0) telegram.allowFrom = allowFrom;

View File

@@ -1,6 +1,7 @@
export type TelegramForm = {
token: string;
requireMention: boolean;
groupsWildcardEnabled: boolean;
allowFrom: string;
proxy: string;
webhookUrl: string;

View File

@@ -356,10 +356,25 @@ function renderProvider(
})}
/>
</label>
<label class="field">
<span>Apply default group rules</span>
<select
.value=${props.telegramForm.groupsWildcardEnabled ? "yes" : "no"}
@change=${(e: Event) =>
props.onTelegramChange({
groupsWildcardEnabled:
(e.target as HTMLSelectElement).value === "yes",
})}
>
<option value="no">No</option>
<option value="yes">Yes (allow all groups)</option>
</select>
</label>
<label class="field">
<span>Require mention in groups</span>
<select
.value=${props.telegramForm.requireMention ? "yes" : "no"}
?disabled=${!props.telegramForm.groupsWildcardEnabled}
@change=${(e: Event) =>
props.onTelegramChange({
requireMention: (e.target as HTMLSelectElement).value === "yes",
@@ -377,7 +392,7 @@ function renderProvider(
props.onTelegramChange({
allowFrom: (e.target as HTMLInputElement).value,
})}
placeholder="123456789, @team"
placeholder="123456789, @team, tg:123"
/>
</label>
<label class="field">
@@ -426,12 +441,33 @@ function renderProvider(
</label>
</div>
<div class="callout" style="margin-top: 12px;">
Allow from supports numeric user IDs (recommended) or @usernames. DM the bot
to get your ID, or run /whoami.
</div>
${props.telegramTokenLocked
? html`<div class="callout" style="margin-top: 12px;">
TELEGRAM_BOT_TOKEN is set in the environment. Config edits will not override it.
</div>`
: nothing}
${props.telegramForm.groupsWildcardEnabled
? html`<div class="callout danger" style="margin-top: 12px;">
This writes telegram.groups["*"] and allows all groups. Remove it
if you only want specific groups.
<div class="row" style="margin-top: 8px;">
<button
class="btn"
@click=${() =>
props.onTelegramChange({ groupsWildcardEnabled: false })}
>
Remove wildcard
</button>
</div>
</div>`
: nothing}
${props.telegramStatus
? html`<div class="callout" style="margin-top: 12px;">
${props.telegramStatus}