feat(telegram): Zugriffskontrolle mit Chat-ID-Whitelist
- TelegramService: IsChatIdAllowed() prüft Owner + Whitelist - /start von unbekannter ChatId: Zugriff verweigert + ChatId angezeigt - Owner wird bei Zugriffsanfrage benachrichtigt (Username + ChatId) - Alle Commands/Messages prüfen Whitelist vor Verarbeitung - Neues Feld telegram_allowed_chat_ids in sessions-Tabelle - Frontend: Input für erlaubte Chat-IDs in Session-Telegram-Settings - API: allowedChatIds in Save/Get durchgereicht
This commit is contained in:
1 parent
5661e55898
commit
011b26c37f
7 files changed
+91
-10
No files matched your search
@@ -81,8 +81,9 @@ public static class TelegramEndpoint
|
||||
var body = await JsonSerializer.DeserializeAsync<JsonElement>(req.Body);
|
||||
var botToken = body.TryGetProperty("botToken", out var t) ? t.GetString() : null;
|
||||
var webhookSecret = body.TryGetProperty("webhookSecret", out var s) ? s.GetString() : null;
|
||||
var allowedChatIds = body.TryGetProperty("allowedChatIds", out var a) ? a.GetString() : session.TelegramAllowedChatIds;
|
||||
|
||||
await db.UpdateSessionTelegram(sessionId, botToken, webhookSecret, session.TelegramChatId);
|
||||
await db.UpdateSessionTelegram(sessionId, botToken, webhookSecret, session.TelegramChatId, allowedChatIds);
|
||||
await res.WriteAsJsonAsync(new { ok = true });
|
||||
}
|
||||
|
||||
@@ -102,6 +103,7 @@ public static class TelegramEndpoint
|
||||
botToken = session.TelegramBotToken ?? "",
|
||||
webhookSecret = session.TelegramWebhookSecret ?? "",
|
||||
chatId = session.TelegramChatId ?? "",
|
||||
allowedChatIds = session.TelegramAllowedChatIds ?? "",
|
||||
configured = !string.IsNullOrEmpty(session.TelegramBotToken)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ public class SessionRecord
|
||||
public string TelegramBotToken { get; set; }
|
||||
public string TelegramWebhookSecret { get; set; }
|
||||
public string TelegramChatId { get; set; }
|
||||
public string TelegramAllowedChatIds { get; set; }
|
||||
public double AvatarScale { get; set; } = 1.0;
|
||||
public string CreatedAt { get; set; }
|
||||
public string UpdatedAt { get; set; }
|
||||
|
||||
@@ -162,6 +162,7 @@ public class DatabaseService
|
||||
TryAddColumn(conn, "sessions", "telegram_bot_token", "TEXT");
|
||||
TryAddColumn(conn, "sessions", "telegram_webhook_secret", "TEXT");
|
||||
TryAddColumn(conn, "sessions", "telegram_chat_id", "TEXT");
|
||||
TryAddColumn(conn, "sessions", "telegram_allowed_chat_ids", "TEXT");
|
||||
TryAddColumn(conn, "agents", "user_id", "TEXT");
|
||||
TryAddColumn(conn, "users", "is_admin", "INTEGER NOT NULL DEFAULT 0");
|
||||
TryAddColumn(conn, "users", "persona", "TEXT");
|
||||
@@ -956,14 +957,14 @@ public class DatabaseService
|
||||
new { chatId = chatId.ToString() });
|
||||
}
|
||||
|
||||
public async Task UpdateSessionTelegram(string sessionId, string botToken, string webhookSecret, string chatId)
|
||||
public async Task UpdateSessionTelegram(string sessionId, string botToken, string webhookSecret, string chatId, string allowedChatIds = null)
|
||||
{
|
||||
using var conn = CreateConnection();
|
||||
await conn.ExecuteAsync(@"
|
||||
UPDATE sessions SET telegram_bot_token = @botToken, telegram_webhook_secret = @webhookSecret,
|
||||
telegram_chat_id = @chatId, updated_at = @now
|
||||
telegram_chat_id = @chatId, telegram_allowed_chat_ids = @allowedChatIds, updated_at = @now
|
||||
WHERE session_id = @sessionId",
|
||||
new { sessionId, botToken, webhookSecret, chatId, now = DateTime.UtcNow.ToString("o") });
|
||||
new { sessionId, botToken, webhookSecret, chatId, allowedChatIds, now = DateTime.UtcNow.ToString("o") });
|
||||
}
|
||||
|
||||
public async Task SetSessionTelegramChatId(string sessionId, string chatId)
|
||||
|
||||
@@ -60,7 +60,46 @@ public class TelegramService
|
||||
|
||||
if (text.StartsWith("/start"))
|
||||
{
|
||||
await _db.SetSessionTelegramChatId(session.SessionId, chatId.ToString());
|
||||
if (!IsChatIdAllowed(session, chatId))
|
||||
{
|
||||
// Telegram-Username aus dem Update extrahieren
|
||||
var username = "";
|
||||
if (message.TryGetProperty("from", out var from))
|
||||
{
|
||||
if (from.TryGetProperty("username", out var uname))
|
||||
username = uname.GetString() ?? "";
|
||||
else if (from.TryGetProperty("first_name", out var fname))
|
||||
username = fname.GetString() ?? "";
|
||||
}
|
||||
|
||||
await SendMessage(chatId, botToken,
|
||||
"🔒 Zugriff verweigert.\n\n" +
|
||||
"Du bist nicht für diesen Bot freigegeben. " +
|
||||
"Bitte kontaktiere den Inhaber und teile deine Chat-ID mit:\n\n" +
|
||||
$"📋 Deine Chat-ID: `{chatId}`",
|
||||
parseMode: "Markdown");
|
||||
|
||||
// Owner benachrichtigen (wenn chatId gesetzt)
|
||||
if (!string.IsNullOrEmpty(session.TelegramChatId))
|
||||
{
|
||||
var ownerChatId = long.Parse(session.TelegramChatId);
|
||||
var requesterInfo = string.IsNullOrEmpty(username) ? chatId.ToString() : $"@{username} ({chatId})";
|
||||
await SendMessage(ownerChatId, botToken,
|
||||
$"🔔 *Zugriffsanfrage*\n\n" +
|
||||
$"Benutzer {EscapeMd(requesterInfo)} möchte diesen Bot nutzen\\.\n\n" +
|
||||
$"Chat\\-ID: `{chatId}`\n\n" +
|
||||
"Zum Freigeben: Chat\\-ID in den Session\\-Einstellungen unter _Erlaubte Chat\\-IDs_ hinzufügen\\.",
|
||||
parseMode: "MarkdownV2");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Erste Verbindung: chatId als Owner setzen (wenn noch keine gesetzt)
|
||||
if (string.IsNullOrEmpty(session.TelegramChatId))
|
||||
{
|
||||
await _db.SetSessionTelegramChatId(session.SessionId, chatId.ToString());
|
||||
}
|
||||
|
||||
var sessionName = session.Name ?? session.SessionId;
|
||||
await SendMessage(chatId, botToken,
|
||||
$"✅ *Verbunden mit Session: {EscapeMd(sessionName)}*\n\n" +
|
||||
@@ -73,6 +112,13 @@ public class TelegramService
|
||||
return;
|
||||
}
|
||||
|
||||
// Alle anderen Befehle/Nachrichten: Zugriff prüfen
|
||||
if (!IsChatIdAllowed(session, chatId))
|
||||
{
|
||||
await SendMessage(chatId, botToken, "🔒 Du bist nicht für diesen Bot freigegeben. Sende /start für mehr Informationen.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (text.StartsWith("/"))
|
||||
{
|
||||
await HandleCommand(chatId, text, botToken, session);
|
||||
@@ -122,9 +168,9 @@ public class TelegramService
|
||||
|
||||
private async Task HandleMessage(long chatId, string userText, string botToken, SessionRecord session)
|
||||
{
|
||||
if (session.TelegramChatId != chatId.ToString())
|
||||
if (!IsChatIdAllowed(session, chatId))
|
||||
{
|
||||
await SendMessage(chatId, botToken, "❌ Bitte sende zuerst /start um dich mit dieser Session zu verbinden.");
|
||||
await SendMessage(chatId, botToken, "🔒 Du bist nicht für diesen Bot freigegeben. Sende /start für mehr Informationen.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -280,6 +326,30 @@ public class TelegramService
|
||||
|
||||
// ── Helper ──
|
||||
|
||||
private static bool IsChatIdAllowed(SessionRecord session, long chatId)
|
||||
{
|
||||
var chatIdStr = chatId.ToString();
|
||||
|
||||
// Owner (die primäre verknüpfte chatId) ist immer erlaubt
|
||||
if (session.TelegramChatId == chatIdStr) return true;
|
||||
|
||||
// Wenn noch kein Owner gesetzt und keine Whitelist → erster User wird Owner
|
||||
if (string.IsNullOrEmpty(session.TelegramChatId) && string.IsNullOrEmpty(session.TelegramAllowedChatIds))
|
||||
return true;
|
||||
|
||||
// Whitelist prüfen
|
||||
if (!string.IsNullOrEmpty(session.TelegramAllowedChatIds))
|
||||
{
|
||||
var allowed = session.TelegramAllowedChatIds.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
foreach (var id in allowed)
|
||||
{
|
||||
if (id == chatIdStr) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string EscapeMd(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text)) return "";
|
||||
|
||||
@@ -127,6 +127,9 @@
|
||||
<input type="text" id="sessionTelegramToken" placeholder="123456:ABC-DEF..." autocomplete="off">
|
||||
<label>Webhook-Secret</label>
|
||||
<input type="text" id="sessionTelegramSecret" readonly style="opacity: var(--semi-transparent); ">
|
||||
<label>Erlaubte Chat-IDs</label>
|
||||
<input type="text" id="sessionTelegramAllowed" placeholder="Kommagetrennt, z.B. 123456,789012">
|
||||
<small class="form-hint">Der verknüpfte Owner ist automatisch erlaubt. Weitere Chat-IDs hier eintragen.</small>
|
||||
<label>Status</label>
|
||||
<div id="sessionTelegramStatusBox" class="telegram-status-box">Kein Status verfügbar</div>
|
||||
<div class="telegram-actions">
|
||||
|
||||
+2
-2
@@ -271,11 +271,11 @@ async function apiSessionTelegramGet(sessionId) {
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
async function apiSessionTelegramSave(sessionId, botToken, webhookSecret) {
|
||||
async function apiSessionTelegramSave(sessionId, botToken, webhookSecret, allowedChatIds) {
|
||||
const resp = await fetch(`/api/sessions/${sessionId}/telegram`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ botToken, webhookSecret })
|
||||
body: JSON.stringify({ botToken, webhookSecret, allowedChatIds })
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const err = await resp.json().catch(() => ({}));
|
||||
|
||||
@@ -180,6 +180,7 @@ registerPage('session', {
|
||||
function initSessionTelegram(sessionId) {
|
||||
var tokenInput = document.getElementById('sessionTelegramToken');
|
||||
var secretInput = document.getElementById('sessionTelegramSecret');
|
||||
var allowedInput = document.getElementById('sessionTelegramAllowed');
|
||||
var registerBtn = document.getElementById('sessionTelegramRegisterBtn');
|
||||
var deleteBtn = document.getElementById('sessionTelegramDeleteBtn');
|
||||
var statusBox = document.getElementById('sessionTelegramStatusBox');
|
||||
@@ -187,6 +188,7 @@ function initSessionTelegram(sessionId) {
|
||||
// Vorhandene Config laden + Status abrufen
|
||||
apiSessionTelegramGet(sessionId).then(async function(config) {
|
||||
if (config.botToken) tokenInput.value = config.botToken;
|
||||
if (config.allowedChatIds) allowedInput.value = config.allowedChatIds;
|
||||
if (config.webhookSecret) {
|
||||
secretInput.value = config.webhookSecret;
|
||||
} else {
|
||||
@@ -294,7 +296,9 @@ async function refreshTelegramStatus(sessionId, statusBox, registerBtn, deleteBt
|
||||
async function saveTelegramConfig(sessionId, tokenInput, secretInput) {
|
||||
var token = tokenInput.value.trim();
|
||||
var secret = secretInput.value.trim();
|
||||
await apiSessionTelegramSave(sessionId, token, secret);
|
||||
var allowedInput = document.getElementById('sessionTelegramAllowed');
|
||||
var allowed = allowedInput ? allowedInput.value.trim() : '';
|
||||
await apiSessionTelegramSave(sessionId, token, secret, allowed);
|
||||
}
|
||||
|
||||
function escapeHtml(str) {
|
||||
|
||||
Reference in new issue
Block a user