diff --git a/Endpoints/TelegramEndpoint.cs b/Endpoints/TelegramEndpoint.cs index 6d382d5..6014b63 100644 --- a/Endpoints/TelegramEndpoint.cs +++ b/Endpoints/TelegramEndpoint.cs @@ -81,8 +81,9 @@ public static class TelegramEndpoint var body = await JsonSerializer.DeserializeAsync(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) }); } diff --git a/Models/SessionRecord.cs b/Models/SessionRecord.cs index a1eca00..85598ec 100644 --- a/Models/SessionRecord.cs +++ b/Models/SessionRecord.cs @@ -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; } diff --git a/Services/DatabaseService.cs b/Services/DatabaseService.cs index dfd9ddb..9a3f7bf 100644 --- a/Services/DatabaseService.cs +++ b/Services/DatabaseService.cs @@ -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) diff --git a/Services/TelegramService.cs b/Services/TelegramService.cs index 4eda3f8..5688028 100644 --- a/Services/TelegramService.cs +++ b/Services/TelegramService.cs @@ -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 ""; diff --git a/wwwroot/index.html b/wwwroot/index.html index 31150f8..565b9d6 100644 --- a/wwwroot/index.html +++ b/wwwroot/index.html @@ -127,6 +127,9 @@ + + + Der verknüpfte Owner ist automatisch erlaubt. Weitere Chat-IDs hier eintragen.
Kein Status verfĂĽgbar
diff --git a/wwwroot/js/api.js b/wwwroot/js/api.js index 3b94419..bdea648 100644 --- a/wwwroot/js/api.js +++ b/wwwroot/js/api.js @@ -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(() => ({})); diff --git a/wwwroot/js/pages/session-page.js b/wwwroot/js/pages/session-page.js index b0929de..b777bf7 100644 --- a/wwwroot/js/pages/session-page.js +++ b/wwwroot/js/pages/session-page.js @@ -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) {