UNPKG

tlgbot

Version:

TLGbot is a javascript framework to create telegram robot application

322 lines (303 loc) 10.4 kB
const https = require('https'), url = require('url'), FormData = require('form-data'), fs = require('fs'), events = require('events'), event = new events.EventEmitter(), ipchecker = require('./core/ip.js'), invite = require('./core/invite'), menu = require('./core/menu'), _storage = require("./core/storage") _storage.location = require.main.path + "/app.json" const storage = _storage.read({ users: {}, invites: {} }) const badrq = 'HTTP/1.1 400 Bad Request\r\n\r\n' var options = {} var post var get menu.send = send menu.log = log menu.storage = storage invite.storage = storage event.on("file", menu.onfile) event.on("message", menu.onmessage) event.on("query", menu.onquery) event.on("command", menu.oncommand) event.on("button", menu.onbutton) // =================================== server const check = ipchecker.checker( [ '173.245.48.0/20', '103.21.244.0/22', '103.22.200.0/22', '103.31.4.0/22', '141.101.64.0/18', '108.162.192.0/18', '190.93.240.0/20', '188.114.96.0/20', '197.234.240.0/22', '198.41.128.0/17', '162.158.0.0/15', '104.16.0.0/12', '172.64.0.0/13', '131.0.72.0/22' ], [ '2400:cb00::/32', '2606:4700::/32', '2803:f800::/32', '2405:b500::/32', '2405:8100::/32', '2a06:98c0::/29', '2c0f:f248::/32' ] ) function check_telegram_server(sip) { var ip = sip.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/); if (ip) { var eip = (+ip[1] << 24) + (+ip[2] << 16) + (+ip[3] << 8) + (+ip[4]); return ((eip & (-1 << (32 - 20))) == -1785028608) || ((eip & (-1 << (32 - 22))) == 1533805568) } return false } async function server(req, res) { try { if (!check(req.connection.remoteAddress)) { req.socket.end(badrq); return; } if (req.method == "POST" && req.url) { if (check_telegram_server(req.headers['cf-connecting-ip'])) { res.end(); var wstream = Buffer.alloc(0) req.on('data', function (chunk) { wstream = Buffer.concat([wstream, chunk]); }); req.once('end', function () { try { const data = JSON.parse(wstream) event.emit("data", data) if ("message" in data) { if ('text' in data.message) { if (data.message.entities && data.message.entities[0].type == "bot_command") { event.emit("command", data) } else event.emit("message", data) } else { event.emit("file", data) } } else if ("callback_query" in data || "chosen_inline_result" in data) { event.emit("button", data) } else if ("inline_query" in data) { event.emit("query", data) } } catch (e) { return; } }); } else if (post) { const queryData = url.parse(req.url, true); const key = getkey(queryData.pathname) var data = Buffer.alloc(0); req.on('data', function (chunk) { data = Buffer.concat([data, chunk]) }) req.on("close", async function () { try { data = JSON.parse(data.toString() || "{}") if (key != "") { const out = await post_open(key, data, req, res) if (out) return res.end(out); else if (out == false) req.socket.end(badrq); } } catch (error) { } req.socket.end(badrq); }) } else req.socket.end(badrq); } else if (req.method == "GET" && get) { const queryData = url.parse(req.url, true); const out = await get_open(getkey(queryData.pathname), queryData.query, req, res) if (out) res.end(out); else if (out == false) req.socket.end(badrq); } else req.socket.end(badrq); } catch (error) { log(error) } }; function getkey(url) { url = url.substring(1) if (url.includes("/")) return url.substring(0, url.indexOf("/")) return url } function post_open(key, data, req, res) { if (key in post && typeof post[key] == "function") { return post[key](data || {}, req, res) } return false } function get_open(key, data, req, res) { if (key in get && typeof get[key] == "function") { return get[key](data || {}, req, res) } return false } const bad = { ok: false } // ================================================================== functions async function send(method, data = {}) { try { data = JSON.stringify(data); const res = (await request({ host: 'api.telegram.org', path: options.api + method, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) } }, data)).body.toString() try { var out = JSON.parse(res); } catch (error) { var out = bad } if (!out.ok && !(out.error_code == 400 && out.description == 'Bad Request: message is not modified: specified new message content and reply markup are exactly the same as a current content and reply markup of the message')) log(out) return out } catch (error) { log(error) return bad } } function sendFile(method, data = {}) { var form = new FormData(); for (const i in data) { if (typeof data[i] == "object" && data[i].length == 2) form.append(i, data[i][0], data[i][1]); else form.append(i, data[i]); } return new Promise(function (resolve, reject) { const res = { ok: false } form.on('error', function (e) { log(e) resolve(res) }) form.submit('https://api.telegram.org' + options.api + method, function (err, pushResponse) { if (err) { log(err) return resolve(res) } var responseText = Buffer.alloc(0) pushResponse.on('data', function (chunk) { responseText = Buffer.concat([responseText, chunk]); }); pushResponse.on('error', function (e) { log(e) resolve(res) }); pushResponse.on('end', function () { try { var out = JSON.parse(responseText) } catch (error) { log(error) resolve(res); } if (!out.ok) { log(err) } resolve(out); }); }); }) } function getFile(file, fileid) { return new Promise((resolve, reject) => { request({ host: 'api.telegram.org', path: options.api + 'getFile?file_id=' + fileid, method: 'GET', }).then(function (response) { response = JSON.parse(response.body) if (response.ok) { if (typeof file == "string") file = fs.createWriteStream(file); https.get('https://api.telegram.org/file' + options.api + response.result.file_path, function (res) { res.pipe(file); res.once('end', resolve); }); } }); }) } const nullarray = [] function request(obj = {}, end) { const http_option = { host: obj.host, path: obj.path, method: obj.method || "GET", headers: obj.headers || (end ? { 'Content-Length': end.length, } : {}) } return new Promise(function (resolve, reject) { https.request(http_option, function (pushResponse) { var responseText = Buffer.alloc(0) pushResponse.on('data', function (chunk) { responseText = Buffer.concat([responseText, chunk]); }); pushResponse.on('error', function (e) { resolve({ error: e, body: '', headers: nullarray }); }); pushResponse.on('end', function () { resolve({ statusCode: pushResponse.statusCode, body: responseText, headers: pushResponse.headers }); }); }).on('error', function (e) { resolve({ error: e, body: '', headers: nullarray }); }).end(end); }); } function init(opt) { post = opt.post get = opt.get options = opt options.api = "/bot" + options.token + "/" var httpsServer = https.createServer(options.tls, server); httpsServer.listen(options.port || 443); menu.menu = opt.menu menu.query = opt.query menu.init() event.emit("init") } function log(...a) { if (options.debug) console.error(...a) } module.exports = { on: event.on.bind(event), menu: menu.custom, storage, invite, location: _storage.location, init, send, sendFile, getFile, }