telegix 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/webapp.js ADDED
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Telegix - Telegram Web App InitData Validator
3
+ */
4
+
5
+ import crypto from 'crypto';
6
+
7
+ /**
8
+ * Validates Telegram Web App initData string according to official Telegram documentation
9
+ * @param {string} initDataStr - Raw initData string from Telegram Web App (window.Telegram.WebApp.initData)
10
+ * @param {string} botToken - Telegram Bot Token
11
+ * @param {object} [options] - { maxAgeSeconds?: number } (default 86400 / 24 hours)
12
+ * @returns {object|null} Parsed user data object if valid, or null if invalid
13
+ */
14
+ export function validateWebAppInitData(initDataStr, botToken, options = {}) {
15
+ if (!initDataStr || !botToken) return null;
16
+
17
+ try {
18
+ const params = new URLSearchParams(initDataStr);
19
+ const hash = params.get('hash');
20
+ if (!hash) return null;
21
+
22
+ params.delete('hash');
23
+
24
+ const entries = [];
25
+ for (const [key, value] of params.entries()) {
26
+ entries.push(`${key}=${value}`);
27
+ }
28
+ entries.sort();
29
+ const dataCheckString = entries.join('\n');
30
+
31
+ // Secret key is HMAC-SHA256 of "WebAppData" using bot token as key
32
+ const secretKey = crypto.createHmac('sha256', 'WebAppData').update(botToken).digest();
33
+
34
+ // Calculated hash is HMAC-SHA256 of data-check-string using secret key
35
+ const calculatedHash = crypto.createHmac('sha256', secretKey).update(dataCheckString).digest('hex');
36
+
37
+ if (calculatedHash !== hash) {
38
+ return null;
39
+ }
40
+
41
+ // Optional freshness check (default max age 24 hours)
42
+ const authDate = parseInt(params.get('auth_date') || '0', 10);
43
+ const maxAge = options.maxAgeSeconds !== undefined ? options.maxAgeSeconds : 86400;
44
+ if (maxAge > 0 && authDate > 0) {
45
+ const now = Math.floor(Date.now() / 1000);
46
+ if (now - authDate > maxAge) {
47
+ return null; // Expired
48
+ }
49
+ }
50
+
51
+ // Parse data fields
52
+ const result = {};
53
+ for (const [key, value] of params.entries()) {
54
+ try {
55
+ result[key] = JSON.parse(value);
56
+ } catch {
57
+ result[key] = value;
58
+ }
59
+ }
60
+
61
+ return result;
62
+ } catch (err) {
63
+ return null;
64
+ }
65
+ }
package/lib/webhook.js ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Telegix - Webhook Handler & Adapter
3
+ * @module telegix/webhook
4
+ */
5
+
6
+ /**
7
+ * Creates a webhook HTTP request handler compatible with Node http, Express, Connect, Fastify, etc.
8
+ * @param {import('./telegix.js').Telegix} bot
9
+ * @param {string} [path='/']
10
+ * @param {object} [options]
11
+ * @param {string} [options.secretToken] - Secret token for header verification
12
+ * @returns {Function} Request handler (req, res, next)
13
+ */
14
+ export function createWebhookCallback(bot, path = '/', options = {}) {
15
+ const secretToken = options.secretToken;
16
+
17
+ return async function webhookCallback(req, res, next) {
18
+ // Check path if specified and not root wildcard
19
+ const reqUrl = req.url ? req.url.split('?')[0] : '/';
20
+ if (path && path !== '/' && reqUrl !== path) {
21
+ if (typeof next === 'function') return next();
22
+ res.statusCode = 404;
23
+ res.end('Not Found');
24
+ return;
25
+ }
26
+
27
+ // Check method
28
+ if (req.method !== 'POST') {
29
+ res.statusCode = 405;
30
+ res.end('Method Not Allowed');
31
+ return;
32
+ }
33
+
34
+ // Check secret token if configured
35
+ if (secretToken) {
36
+ const receivedToken =
37
+ req.headers?.['x-telegram-bot-api-secret-token'] ||
38
+ req.headers?.['X-Telegram-Bot-Api-Secret-Token'];
39
+ if (receivedToken !== secretToken) {
40
+ res.statusCode = 403;
41
+ res.end('Forbidden: Invalid Secret Token');
42
+ return;
43
+ }
44
+ }
45
+
46
+ let update = null;
47
+
48
+ try {
49
+ // If body is already parsed (e.g. express.json() middleware)
50
+ if (req.body && typeof req.body === 'object') {
51
+ update = req.body;
52
+ } else {
53
+ // Read stream body
54
+ const chunks = [];
55
+ for await (const chunk of req) {
56
+ chunks.push(chunk);
57
+ }
58
+ const rawBody = Buffer.concat(chunks).toString('utf8');
59
+ update = JSON.parse(rawBody);
60
+ }
61
+
62
+ if (!update || typeof update !== 'object') {
63
+ res.statusCode = 400;
64
+ res.end('Bad Request: Invalid Telegram Update Payload');
65
+ return;
66
+ }
67
+
68
+ // Process update through Telegix pipeline
69
+ await bot.handleUpdate(update);
70
+
71
+ if (!res.writableEnded) {
72
+ res.statusCode = 200;
73
+ res.setHeader('Content-Type', 'application/json');
74
+ res.end(JSON.stringify({ ok: true }));
75
+ }
76
+ } catch (err) {
77
+ if (bot.errorHandler) {
78
+ bot.errorHandler(err);
79
+ }
80
+ if (!res.writableEnded) {
81
+ res.statusCode = 500;
82
+ res.end('Internal Server Error');
83
+ }
84
+ }
85
+ };
86
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "telegix",
3
+ "version": "1.1.1",
4
+ "description": "Lightweight Telegram Bot API framework for Node.js.",
5
+ "type": "module",
6
+ "main": "./index.cjs",
7
+ "module": "./index.js",
8
+ "types": "./index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./index.d.ts",
12
+ "import": "./index.js",
13
+ "require": "./index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "lib",
18
+ "index.js",
19
+ "index.cjs",
20
+ "index.d.ts",
21
+ "README.md",
22
+ "LICENSE"
23
+ ],
24
+ "keywords": [
25
+ "telegram",
26
+ "telegram-bot",
27
+ "telegram-bot-api",
28
+ "bot",
29
+ "bot-api",
30
+ "telegix",
31
+ "telegram-api",
32
+ "node-telegram-bot-api",
33
+ "telegraf",
34
+ "node"
35
+ ],
36
+ "author": "KazeDevID",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/KazeDevID/telegix.git"
41
+ }
42
+ }