From bdb6be17021be801f6059714ce0808c73898eb1d Mon Sep 17 00:00:00 2001 From: Kibi Kelburton Date: Wed, 15 Jul 2026 19:33:49 +0200 Subject: [PATCH] telegram --- src/inc/trigger/parser.mjs | 11 +++-- src/inc/trigger/telegram_link.mjs | 78 +++++++++++++++++++++++++++++++ src/index.mjs | 1 + views/settings.html | 11 +++-- 4 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 src/inc/trigger/telegram_link.mjs diff --git a/src/inc/trigger/parser.mjs b/src/inc/trigger/parser.mjs index f703792..a6b99f6 100644 --- a/src/inc/trigger/parser.mjs +++ b/src/inc/trigger/parser.mjs @@ -187,9 +187,10 @@ export default async bot => { // --- LINKED ACCOUNT CHECK --- let websiteUser = null; - if (e.type === 'matrix' || e.type === 'discord') { - // Identify lookup key + if (e.type === 'matrix' || e.type === 'discord' || e.type === 'tg') { + // Identify lookup key and type // Matrix: Use unique ID (MXID) + // Telegram: Use numeric user ID (most stable, never changes) // Discord: Use Nick or Username (Legacy) - TODO: Migration to ID recommended later let lookupAlias = e.user.nick || e.user.username; let lookupType = 'discord'; // default check @@ -197,6 +198,9 @@ export default async bot => { if (e.type === 'matrix') { lookupAlias = e.user.account; // MXID lookupType = 'matrix'; + } else if (e.type === 'tg') { + lookupAlias = e.user.account; // numeric Telegram user ID as string + lookupType = 'telegram'; } // Check DB @@ -220,7 +224,8 @@ export default async bot => { // Enforce Link for !w command if (isWCommand && !websiteUser) { - await e.reply(`You must link your account to use this command. Go to ${cfg.main.url.full}/settings to link your ${e.type} account.`); + const linkType = e.type === 'tg' ? 'Telegram' : e.type; + await e.reply(`You must link your account to use this command. Go to ${cfg.main.url.full}/settings to link your ${linkType} account. Then send !link to this bot.`); return false; } } diff --git a/src/inc/trigger/telegram_link.mjs b/src/inc/trigger/telegram_link.mjs new file mode 100644 index 0000000..12ada54 --- /dev/null +++ b/src/inc/trigger/telegram_link.mjs @@ -0,0 +1,78 @@ +import db from "../sql.mjs"; +import cfg from "../config.mjs"; + +export default async self => { + return [{ + name: "telegram_link", + call: /^!link(?:\s+(.+))?$/i, + active: true, + clients: ["tg"], + f: async e => { + // Only for Telegram + if (e.type !== 'tg') return false; + + let token = (e.args[0] || '').trim().toUpperCase(); + + // Scenario 1: User typed "!link" only (no token) + if (!token) { + await e.reply(`Please generate a link token on the website at ${cfg.main.url.full}/settings and then send: !link `); + return true; + } + + // Scenario 2: Processing a token + try { + // Find token in DB + const linkData = (await db` + SELECT user_id FROM link_token WHERE token = ${token} + `)[0]; + + if (!linkData) { + return await e.reply("Invalid or expired token. Please generate a new one at the website settings page."); + } + + // Use the Telegram numeric user ID as the alias (most stable identifier) + const alias = e.user.account; // e.g. "123456789" + + // Check if already linked to THIS user + const existing = await db` + SELECT 1 FROM user_alias + WHERE userid = ${linkData.user_id} + AND alias = ${alias} + AND type = 'telegram' + `; + + if (existing.length > 0) { + return await e.reply("This Telegram account is already linked to your website profile."); + } + + // Check if this Telegram account is linked to ANOTHER user (prevent hijacking) + const taken = await db` + SELECT 1 FROM user_alias + WHERE alias = ${alias} + AND type = 'telegram' + `; + + if (taken.length > 0) { + return await e.reply("This Telegram account is already linked to a different website profile."); + } + + // Perform Link + await db` + INSERT INTO user_alias (userid, alias, type) + VALUES (${linkData.user_id}, ${alias}, 'telegram') + ON CONFLICT DO NOTHING + `; + + // Delete used token + await db`DELETE FROM link_token WHERE token = ${token}`; + + const tgUsername = e.user.username ? `@${e.user.username}` : e.user.nick; + return await e.reply(`Successfully linked Telegram account ${tgUsername} (ID: ${alias}) to your website profile!`); + + } catch (err) { + console.error("[Telegram Link] Error:", err); + return await e.reply("An internal error occurred while linking your account."); + } + } + }]; +}; diff --git a/src/index.mjs b/src/index.mjs index 75c471e..30fab78 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -1227,6 +1227,7 @@ process.on('uncaughtException', err => { get cleanup_start_date() { return getCleanupStartDate(); }, get cleanup_end_date() { return getCleanupEndDate(); }, matrix_enabled: cfg.clients.find(c => c.type === 'matrix')?.enabled || false, + telegram_enabled: cfg.clients.find(c => c.type === 'tg')?.enabled || false, ts: Date.now(), get default_layout() { return getDefaultLayout(); }, show_koepfe: !!cfg.websrv.show_koepfe, diff --git a/views/settings.html b/views/settings.html index 76187c0..7280915 100644 --- a/views/settings.html +++ b/views/settings.html @@ -12,7 +12,7 @@ {{ t('settings.export_data_title') }} @endif {{ t('settings.account') }} - @if(matrix_enabled) + @if(matrix_enabled || telegram_enabled) {{ t('settings.linked_accounts') }} @endif @if(enable_user_api_keys) @@ -517,7 +517,7 @@ - @if(matrix_enabled) + @if(matrix_enabled || telegram_enabled)

{{ t('settings.linked_accounts') }}

@@ -532,9 +532,14 @@