telegram
This commit is contained in:
@@ -187,9 +187,10 @@ export default async bot => {
|
|||||||
// --- LINKED ACCOUNT CHECK ---
|
// --- LINKED ACCOUNT CHECK ---
|
||||||
let websiteUser = null;
|
let websiteUser = null;
|
||||||
|
|
||||||
if (e.type === 'matrix' || e.type === 'discord') {
|
if (e.type === 'matrix' || e.type === 'discord' || e.type === 'tg') {
|
||||||
// Identify lookup key
|
// Identify lookup key and type
|
||||||
// Matrix: Use unique ID (MXID)
|
// 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
|
// Discord: Use Nick or Username (Legacy) - TODO: Migration to ID recommended later
|
||||||
let lookupAlias = e.user.nick || e.user.username;
|
let lookupAlias = e.user.nick || e.user.username;
|
||||||
let lookupType = 'discord'; // default check
|
let lookupType = 'discord'; // default check
|
||||||
@@ -197,6 +198,9 @@ export default async bot => {
|
|||||||
if (e.type === 'matrix') {
|
if (e.type === 'matrix') {
|
||||||
lookupAlias = e.user.account; // MXID
|
lookupAlias = e.user.account; // MXID
|
||||||
lookupType = 'matrix';
|
lookupType = 'matrix';
|
||||||
|
} else if (e.type === 'tg') {
|
||||||
|
lookupAlias = e.user.account; // numeric Telegram user ID as string
|
||||||
|
lookupType = 'telegram';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check DB
|
// Check DB
|
||||||
@@ -220,7 +224,8 @@ export default async bot => {
|
|||||||
|
|
||||||
// Enforce Link for !w command
|
// Enforce Link for !w command
|
||||||
if (isWCommand && !websiteUser) {
|
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 <TOKEN> to this bot.`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
78
src/inc/trigger/telegram_link.mjs
Normal file
78
src/inc/trigger/telegram_link.mjs
Normal file
@@ -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 <TOKEN>`);
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
};
|
||||||
@@ -1227,6 +1227,7 @@ process.on('uncaughtException', err => {
|
|||||||
get cleanup_start_date() { return getCleanupStartDate(); },
|
get cleanup_start_date() { return getCleanupStartDate(); },
|
||||||
get cleanup_end_date() { return getCleanupEndDate(); },
|
get cleanup_end_date() { return getCleanupEndDate(); },
|
||||||
matrix_enabled: cfg.clients.find(c => c.type === 'matrix')?.enabled || false,
|
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(),
|
ts: Date.now(),
|
||||||
get default_layout() { return getDefaultLayout(); },
|
get default_layout() { return getDefaultLayout(); },
|
||||||
show_koepfe: !!cfg.websrv.show_koepfe,
|
show_koepfe: !!cfg.websrv.show_koepfe,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<a href="#export">{{ t('settings.export_data_title') }}</a>
|
<a href="#export">{{ t('settings.export_data_title') }}</a>
|
||||||
@endif
|
@endif
|
||||||
<a href="#account">{{ t('settings.account') }}</a>
|
<a href="#account">{{ t('settings.account') }}</a>
|
||||||
@if(matrix_enabled)
|
@if(matrix_enabled || telegram_enabled)
|
||||||
<a href="#linked">{{ t('settings.linked_accounts') }}</a>
|
<a href="#linked">{{ t('settings.linked_accounts') }}</a>
|
||||||
@endif
|
@endif
|
||||||
@if(enable_user_api_keys)
|
@if(enable_user_api_keys)
|
||||||
@@ -517,7 +517,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if(matrix_enabled)
|
@if(matrix_enabled || telegram_enabled)
|
||||||
<!-- ═══════════════════════════════ LINKED ACCOUNTS ═══════════════════════════════ -->
|
<!-- ═══════════════════════════════ LINKED ACCOUNTS ═══════════════════════════════ -->
|
||||||
<h2 id="linked">{{ t('settings.linked_accounts') }}</h2>
|
<h2 id="linked">{{ t('settings.linked_accounts') }}</h2>
|
||||||
<div class="linked-accounts-wrapper">
|
<div class="linked-accounts-wrapper">
|
||||||
@@ -532,9 +532,14 @@
|
|||||||
|
|
||||||
<div class="link-action-area">
|
<div class="link-action-area">
|
||||||
<h4 style="margin-top: 20px;">{{ t('settings.add_new_link') }}</h4>
|
<h4 style="margin-top: 20px;">{{ t('settings.add_new_link') }}</h4>
|
||||||
<p style="margin-bottom: 15px; color: var(--text-muted); font-size: 0.9em;">
|
<p style="margin-bottom: 10px; color: var(--text-muted); font-size: 0.9em;">
|
||||||
{!! t('settings.matrix_instructions') !!}
|
{!! t('settings.matrix_instructions') !!}
|
||||||
</p>
|
</p>
|
||||||
|
@if(telegram_enabled)
|
||||||
|
<p style="margin-bottom: 15px; color: var(--text-muted); font-size: 0.9em;">
|
||||||
|
<strong>Telegram:</strong> Generate a token below, then send <code>!link <TOKEN></code> to the Telegram bot.
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
|
||||||
<div id="token-display-area" style="display: none; margin-bottom: 15px;">
|
<div id="token-display-area" style="display: none; margin-bottom: 15px;">
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
|
|||||||
Reference in New Issue
Block a user