UNPKG

telegram-tghub-better-new

Version:

NodeJS/Browser MTProto API Telegram client library,

905 lines (904 loc) 40.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CustomError = exports.AnalyzeTData = exports.clearEmptyBy = exports.oldTelegram = exports.defaultConfig = exports.cFingerpting = exports.saveStringSession = exports.getInitConnection = exports.formatInitParams = exports.StoreSession = exports.defaultDc = void 0; exports.formatInputString = formatInputString; exports.formatProxyTemplate = formatProxyTemplate; exports.formatProxy = formatProxy; exports.identifyTheDirectory = identifyTheDirectory; exports.clearEmpty = clearEmpty; exports.isValidInternationalPhoneNumber = isValidInternationalPhoneNumber; exports.getCountryByPhone = getCountryByPhone; exports.getLangCode = getLangCode; exports.getDefaultJson = getDefaultJson; exports.formatJsonAndSession = formatJsonAndSession; exports.checkImportData = checkImportData; exports.getFileName = getFileName; exports.formatErrorMessage = formatErrorMessage; exports.getError = getError; exports.clientDestroy = clientDestroy; exports.returnSingleSimpleClient = returnSingleSimpleClient; exports.createSingleSimpleClient = createSingleSimpleClient; // @ts-nocheck const lodash_1 = __importDefault(require("lodash")); const better_sqlite3_1 = __importDefault(require("better-sqlite3")); const dayjs_1 = __importDefault(require("dayjs")); const moment_timezone_1 = __importDefault(require("moment-timezone")); const path_1 = __importDefault(require("path")); const adm_zip_1 = __importDefault(require("adm-zip")); const iconv_lite_1 = __importDefault(require("iconv-lite")); const crypto = __importStar(require("crypto")); const string_template_1 = __importDefault(require("string-template")); const iso_lang_codes_1 = __importDefault(require("iso-lang-codes")); const libphonenumber_js_1 = require("libphonenumber-js"); const __1 = require("../"); const IGE_1 = require("../crypto/IGE"); const model_js_1 = __importDefault(require("./model.js")); const { asleep } = __1.helpers; const { StringSession } = __1.sessions; const { BinaryReader } = __1.extensions; exports.defaultDc = { id: 1, ip: "149.154.175.57", ipAddress: "149.154.175.57", port: 443, ipv6: false, }; class StoreSession extends StringSession { constructor() { super(); this.sessionInfo = {}; } async init() { const isAlive = ["authKey", "dcId", "port", "serverAddress"].every((i) => !!this.sessionInfo[i]); if (isAlive) { const { authKey, dcId, port, serverAddress } = this.sessionInfo; this._dcId = dcId; this._port = port; this._serverAddress = serverAddress; this._key = authKey; } else { this.setDC(exports.defaultDc.id, exports.defaultDc.ip, exports.defaultDc.port); } } } exports.StoreSession = StoreSession; const formatInitParams = (list) => { const params = list.map((item) => { switch (item._) { case "jsonString": return new __1.Api.JsonObjectValue({ key: item.key, value: new __1.Api.JsonString({ value: item.value, }), }); case "jsonNumber": return new __1.Api.JsonObjectValue({ key: item.key, value: new __1.Api.JsonNumber({ value: item.value, }), }); case "jsonObject": return new __1.Api.JsonObjectValue({ key: item.key, value: new __1.Api.JsonObject({ value: (0, exports.formatInitParams)(item.value), }), }); default: break; } }); return params; }; exports.formatInitParams = formatInitParams; const getInitConnection = (sessionInfo) => { const { deviceToken, cFingerpting, installer, packageId, tzOffset, apiHash, apiId, langPack, appVersion, systemVersion, deviceModel, langCode, systemLangCode, perfCat, } = sessionInfo; const defaultInitConnectionParams = [ { _: "jsonString", key: "device_token", value: deviceToken || "", }, { _: "jsonString", key: "data", value: cFingerpting || tg4cFingerpting, }, { _: "jsonString", key: "installer", value: installer || "", }, { _: "jsonString", key: "package_id", value: packageId || "org.telegram.messenger", }, { _: "jsonNumber", key: "tz_offset", value: Number(tzOffset || 0), }, { _: "jsonNumber", key: "perf_cat", value: perfCat || lodash_1.default.random(1, 2), }, ]; const params = (0, exports.formatInitParams)(defaultInitConnectionParams); const initRequest = { apiId, apiHash, langPack, langCode, systemLangCode, appVersion, systemVersion, deviceModel, params: new __1.Api.JsonObject({ value: params, }), }; return initRequest; }; exports.getInitConnection = getInitConnection; function serializeGramjsSession(session) { const authKey = Buffer.from(session.authKey); if (authKey.length !== 256) { throw new Error("authKey must be 256 bytes long"); } const ipEncoded = Buffer.from(session.ipAddress, "utf-8"); const u8 = Buffer.alloc(261 + ipEncoded.length); let pos = 0; pos = u8.writeUInt8(session.dcId, pos); pos = u8.writeUInt16BE(ipEncoded.length, pos); ipEncoded.copy(u8, pos); pos += ipEncoded.length; pos = u8.writeUInt16BE(session.port, pos); authKey.copy(u8, pos); return `1${u8.toString("base64")}`; } const saveStringSession = (data) => { const stringSession = serializeGramjsSession(lodash_1.default.assign({}, lodash_1.default.pick(data, ["dcId", "port", "ipAddress", "authKey"]), { ipv6: false, })); return stringSession; }; exports.saveStringSession = saveStringSession; exports.cFingerpting = "49C1522548EBACD46CE322B6FD47F6092BB745D0F88082145CAF35E14DCC38E1"; exports.defaultConfig = { cFingerpting: exports.cFingerpting, enablePushConnection: false, configPath: "/data/user/0/org.telegram.messenger/files", langCode: "en", }; function formatInputString(inputString) { var _a; let counter = 0; let list = []; const replacedString = (_a = inputString === null || inputString === void 0 ? void 0 : inputString.replace) === null || _a === void 0 ? void 0 : _a.call(inputString, /\{([^}]+)\}/g, () => { const result = "{" + counter + "}"; counter++; return result; }); const matches = inputString.match(/\{([^}]+)\}/g); if (matches) { // 提取匹配到的文本,去除花括号 const extractedTexts = matches.map((match) => match.substring(1, match.length - 1)); // 将数字根据非数字字符拆分成长度为2的数组 list = extractedTexts.flatMap((text) => { const numbers = text.split(/[^0-9]+/).filter(Boolean); // 匹配非数字字符并拆分 const result = []; for (let i = 0; i < numbers.length; i += 2) { result.push(numbers.slice(i, i + 2)); } return result; }); } return (0, string_template_1.default)(replacedString, list.map((rests) => lodash_1.default.random(...rests))); } function formatProxyTemplate(proxy = {}) { const formatProxyData = lodash_1.default.forOwn(lodash_1.default.cloneDeep(proxy), (value, key, obj) => { obj[key] = formatInputString(String(value || "")); }); return lodash_1.default.assign({}, formatProxyData, { password: String(lodash_1.default.get(formatProxyData, "password", "")), port: Number(lodash_1.default.get(formatProxyData, "port", 0)), }); } function formatProxy(proxy = {}) { return lodash_1.default.assign({}, formatProxyTemplate(proxy), { socksType: 5, timeout: 10, }); } const getModel = () => { return model_js_1.default[lodash_1.default.random(0, model_js_1.default.length - 1)]; }; const oldTelegram = () => { const { deviceBrand, deviceModel, model } = getModel(); const conf = Object.assign(Object.assign({}, exports.defaultConfig), { deviceBrand, deviceModel, model, apiHash: "014b35b6184100b085b0d0572f9b5103", apiId: 4, langPack: "android", appVersion: "10.13.2 (48509)", cFingerpting: exports.cFingerpting, systemVersion: `SDK ${lodash_1.default.random(28, 34)}`, installer: "com.google.android.packageinstaller", packageId: "org.telegram.messenger.web", deviceToken: "__FIREBASE_FAILED__" }); return conf; }; exports.oldTelegram = oldTelegram; function identifyTheDirectory(path) { const parts = lodash_1.default.split(path, "/"); const directories = []; // Build each level of the path for (let i = 0; i < parts.length - 1; i++) { const dirPath = lodash_1.default.slice(parts, 0, i + 1).join("/") + "/"; directories.push(dirPath); } return directories; } const clearEmptyBy = (value) => { // 排除 null、undefined 和空字符串 if (lodash_1.default.isNil(value) || value === "") { return false; } // 对于对象和数组,进一步检查是否为空 if (lodash_1.default.isObject(value) && lodash_1.default.isEmpty(value)) { return false; } // 其他情况保留 return true; }; exports.clearEmptyBy = clearEmptyBy; function clearEmpty(obj) { return lodash_1.default.pickBy(obj, exports.clearEmptyBy); } function isValidInternationalPhoneNumber(phoneNumber) { // 正则表达式匹配以加号开头,随后是一个或多个数字的字符串 return /^\+\d+$/.test(phoneNumber) && (0, libphonenumber_js_1.isValidPhoneNumber)(phoneNumber); } function getCountryByPhone(phone) { if (isValidInternationalPhoneNumber(phone)) { const parsedNumber = (0, libphonenumber_js_1.parsePhoneNumber)(phone); return lodash_1.default.get(parsedNumber, "country"); } } function getLangCode(props) { var _a, _b; const phone = lodash_1.default.get(props, "phone"); const country = getCountryByPhone(phone); if (country) { const systemLangCodes = iso_lang_codes_1.default.findCountryLocales(country); if (!lodash_1.default.isEmpty(systemLangCodes)) { const index = lodash_1.default.random(0, systemLangCodes.length - 1); const systemLangCode = ((_b = (_a = systemLangCodes === null || systemLangCodes === void 0 ? void 0 : systemLangCodes[index]) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase) === null || _b === void 0 ? void 0 : _b.call(_a)) || "en-us"; const langCodes = iso_lang_codes_1.default.findCountryLanguages(country); const langCode = (langCodes === null || langCodes === void 0 ? void 0 : langCodes[index]) || "en"; const [timezone] = moment_timezone_1.default.tz.zonesForCountry(country, true); const offset = lodash_1.default.get(timezone, "offset"); const option = { country, systemLangCode, systemLangPack: systemLangCode, langCode, tzOffset: offset ? offset * 60 : 10800, }; return option; } } return { country, langCode: "en", systemLangCode: "en-us", systemLangPack: "en-us", tzOffset: 10800, }; } class AnalyzeTData { constructor(props) { const { buffers, phone, sessionInfo } = props; this.buffers = buffers; this.phone = phone; this.sessionInfo = sessionInfo; } run() { this.getTwoFa(); const old_session_key = "data"; const tDataList = lodash_1.default.filter(this.buffers, (item) => lodash_1.default.get(item, "originalname", "").includes("tdata")); const tDataItem = lodash_1.default.minBy(tDataList, (item) => lodash_1.default.size(item.originalname)); const tDataPath = lodash_1.default.get(tDataItem, "originalname", ""); const partOneMd5 = this.tdesktopMd5(old_session_key).slice(0, 16); const tdesktopUserBasePath = tDataPath + partOneMd5; const pathKey = "key_" + old_session_key; const openPath = tDataPath + pathKey; const data = this.openTDesktopBuffer(openPath); const salt = this.tdesktopReadBuffer(data); if (salt.length !== 32) { throw new Error("Length of salt is wrong!"); } const encryptedKey = this.tdesktopReadBuffer(data); const encryptedInfo = this.tdesktopReadBuffer(data); const hash = crypto .createHash("sha512") .update(salt) .update("") .update(salt) .digest(); const passKey = crypto.pbkdf2Sync(hash, salt, 1, 256, "sha512"); const key = this.tdesktopReadBuffer(this.tdesktopDecrypt(new BinaryReader(encryptedKey), passKey)); const info = this.tdesktopReadBuffer(this.tdesktopDecrypt(new BinaryReader(encryptedInfo), key)); const count = info.readUInt32BE(); if (count !== 1) { throw new Error("Currently only supporting one account at a time"); } const main = this.tdesktopOpenEncrypted(tdesktopUserBasePath, key); const magic = main.read(4).reverse().readUInt32LE(); if (magic !== 75) { throw new Error("Unsupported magic version"); } const final = new BinaryReader(this.tdesktopReadBuffer(main)); final.read(12); final.read(4).reverse().readUInt32LE(); const mainDc = final.read(4).reverse().readUInt32LE(); const length = final.read(4).reverse().readUInt32LE(); for (let i = 0; i < length; i++) { const dc = final.read(4).reverse().readUInt32LE(); const authKey = final.read(256); if (dc === mainDc) { this.sessionInfo.dcId = mainDc; this.sessionInfo.authKey = authKey; this.sessionInfo.serverAddress = this.getServerAddress(mainDc); this.sessionInfo.port = 443; this.getDefaultParams(); } } } openTDesktopBuffer(name) { const filesToTry = []; for (const i of ["0", "1", "s"]) { const existsItem = lodash_1.default.find(this.buffers, (item) => lodash_1.default.get(item, "originalname", "").includes(name + i)); if (!lodash_1.default.isEmpty(existsItem)) { const buffer = lodash_1.default.get(existsItem, "buffer"); filesToTry.push(new BinaryReader(buffer)); } } return this.tdesktopOpenAfter(filesToTry); } tdesktopOpenAfter(filesToTry) { for (const fileToTry of filesToTry) { const magic = fileToTry.read(4).toString("utf-8"); if (magic !== "TDF$") { console.error("WRONG MAGIC"); continue; } const versionBytes = fileToTry.read(4); let data = fileToTry.read(); const md5 = data.slice(-16).toString("hex"); data = data.slice(0, -16); const length = Buffer.alloc(4); length.writeInt32LE(data.length, 0); const toCompare = Buffer.concat([ data, length, versionBytes, Buffer.from("TDF$", "utf-8"), ]); const hash = crypto .createHash("md5") .update(toCompare) .digest("hex"); if (hash !== md5) { throw new Error("Wrong MD5"); } const result = new BinaryReader(data); return result; } } tdesktopReadBuffer(buffer) { const length = buffer.read(4).reverse().readInt32LE(); const result = length > 0 ? buffer.read(length, false) : Buffer.alloc(0); return result; } tdesktopDecrypt(data, auth_key) { const message_key = data.read(16); const encrypted_data = data.read(); const [aes_key, aes_iv] = this.calcKey(auth_key, message_key, false); const ige = new IGE_1.IGE(aes_key, aes_iv); const decrypted_data = ige.decryptIge(encrypted_data); if (message_key.toString("hex") !== this.sha1(decrypted_data).slice(0, 16).toString("hex")) { throw new Error("msg_key mismatch"); } return new BinaryReader(decrypted_data); } calcKey(authKey, msgKey, client) { const x = client ? 0 : 8; const sha1_a = this.sha1(Buffer.concat([msgKey, authKey.slice(x, x + 32)])); const sha1_b = this.sha1(Buffer.concat([ authKey.slice(32 + x, 32 + x + 16), msgKey, authKey.slice(48 + x, 48 + x + 16), ])); const sha1_c = this.sha1(Buffer.concat([authKey.slice(64 + x, 64 + x + 32), msgKey])); const sha1_d = this.sha1(Buffer.concat([msgKey, authKey.slice(96 + x, 96 + x + 32)])); const aes_key = Buffer.concat([ sha1_a.slice(0, 8), sha1_b.slice(8, 8 + 12), sha1_c.slice(4, 4 + 12), ]); const aes_iv = Buffer.concat([ sha1_a.slice(8, 8 + 12), sha1_b.slice(0, 8), sha1_c.slice(16, 16 + 4), sha1_d.slice(0, 8), ]); return [aes_key, aes_iv]; } tdesktopOpenEncrypted(fileName, tdesktopKey) { const f = this.openTDesktopBuffer(fileName); const data = this.tdesktopReadBuffer(f); const res = this.tdesktopDecrypt(new BinaryReader(data), tdesktopKey); const length = res.readInt(false); if (length > res.getBuffer().length || length < 4) { throw new Error("Wrong length"); } return res; } tdesktopMd5(data) { let result = ""; const hash = crypto.createHash("md5").update(data).digest("hex"); for (let i = 0; i < hash.length; i += 2) { result += hash[i + 1] + hash[i]; } return result.toUpperCase(); } getServerAddress(dcId) { switch (dcId) { case 1: return "149.154.175.50"; case 2: return "95.161.76.100"; case 3: return "149.154.175.100"; case 4: return "149.154.167.91"; case 5: return "149.154.171.5"; default: throw new Error("Invalid DC"); } } sha1(buf) { return crypto.createHash("sha1").update(buf).digest(); } getDefaultParams() { var _a, _b; const phone = (_b = (_a = this === null || this === void 0 ? void 0 : this.phone) === null || _a === void 0 ? void 0 : _a.replace) === null || _b === void 0 ? void 0 : _b.call(_a, /^(\+)?(\d+)/, "+$2"); this.sessionInfo = lodash_1.default.assign({}, this.sessionInfo, getLangCode({ phone }), { apiHash: "b18441a1ff607e10a989891a5462e627", apiId: 2040, langPack: "tdesktop", deviceToken: "__FIREBASE_FAILED__", systemVersion: "Windows 11", appVersion: "5.2.3 x64", deviceModel: "Desktop", langCode: "en", systemLangCode: "en-US", tzOffset: 28800, phone, }); } getTwoFa() { var _a, _b, _c, _d; const passwordTwoFA = lodash_1.default.find(this.buffers, (item) => ["password", "fa", "pwd"].some((name) => lodash_1.default.get(item, "originalname", "").toLowerCase().includes(name)) && lodash_1.default.get(item, "originalname", "").includes("txt")); this.sessionInfo.password = ((_d = (_c = (_b = (_a = lodash_1.default.get(passwordTwoFA, "buffer")) === null || _a === void 0 ? void 0 : _a.toString) === null || _b === void 0 ? void 0 : _b.call(_a, "utf8")) === null || _c === void 0 ? void 0 : _c.replace) === null || _d === void 0 ? void 0 : _d.call(_c, /[\b\f\n\r\t\v]/g, "")) || null; } } exports.AnalyzeTData = AnalyzeTData; function getDefaultJson(phoneNumber = "") { var _a; const phone = (_a = phoneNumber === null || phoneNumber === void 0 ? void 0 : phoneNumber.replace) === null || _a === void 0 ? void 0 : _a.call(phoneNumber, /^(\+)?(\d+)/, "+$2"); const defaultJsonObject = lodash_1.default.assign({}, (0, exports.oldTelegram)(), getLangCode({ phone })); return defaultJsonObject; } function formatJsonAndSession(props = {}) { let { session, json, remark } = props; if (!lodash_1.default.isEmpty(json) && Array.isArray(json)) { json = lodash_1.default.map(lodash_1.default.filter(json, Boolean), (item) => { var _a, _b; let jsonObject = {}; const originalname = iconv_lite_1.default.decode(Buffer.from(lodash_1.default.get(item, "originalname", ""), "binary"), "utf-8"); const extname = path_1.default.extname(originalname); const sessionFile = path_1.default.basename(originalname, extname); try { jsonObject = lodash_1.default.mapKeys(JSON.parse(lodash_1.default.get(item, "buffer", []).toString()), (value, key) => lodash_1.default.camelCase(key)); } catch (error) { return {}; } const phone = (_b = (_a = lodash_1.default.get(jsonObject, "phone", "")) === null || _a === void 0 ? void 0 : _a.replace) === null || _b === void 0 ? void 0 : _b.call(_a, /^(\+)?(\d+)/, "+$2"); const defaultJsonObject = getDefaultJson(phone); const { appId: apiId, appHash: apiHash, device: deviceModel, systemLangPack: systemLangCode, twoFa, sdk: systemVersion, deviceToken, langPack, tzOffset, appVersion, langCode, cFingerpting, installer, packageId, email, userId, password, password2Fa, } = jsonObject; let jsonBetterData = { sessionFile, phone: sessionFile || phone, apiId, apiHash, deviceModel, systemLangCode, deviceToken, langPack, tzOffset, appVersion, systemVersion, password: twoFa || password || password2Fa, langCode, cFingerpting, installer, packageId, email, userId, }; jsonBetterData = lodash_1.default.mapValues(jsonBetterData, (value, key) => { return value || defaultJsonObject[key]; }); jsonBetterData.isUseProxy = 2; jsonBetterData.proxy = {}; const sessionLength = Object.values(jsonBetterData).length; const nextSessionLength = lodash_1.default.filter(Object.values(jsonBetterData), exports.clearEmptyBy).length; if (sessionLength - nextSessionLength >= 5) { return {}; } return jsonBetterData; }); } if (!lodash_1.default.isEmpty(session) && Array.isArray(session)) { session = lodash_1.default.map(lodash_1.default.filter(session, Boolean), (item) => { const originalname = iconv_lite_1.default.decode(Buffer.from(lodash_1.default.get(item, "originalname", ""), "binary"), "utf-8"); const extname = path_1.default.extname(originalname); const sessionFile = path_1.default.basename(originalname, extname); try { const buffer = lodash_1.default.get(item, "buffer", []); const db = new better_sqlite3_1.default(buffer); let result = db.prepare("SELECT * FROM sessions").get(); db.close(); const currentTime = (0, dayjs_1.default)(new Date()).format("YYYY-MM-DD HH:mm:ss"); result = lodash_1.default.mapKeys(result, (value, key) => lodash_1.default.camelCase(key)); const { authKey, port, dcId, serverAddress } = result; const sessionObject = { sessionFile, authKey, port, dcId, serverAddress, remark: remark || `${currentTime}-导入`, accountStatus: 2, }; if (lodash_1.default.isNil(authKey) || lodash_1.default.isNil(dcId)) { return {}; } // if (!serverAddress || !port) { // const { ipAddress, port } = _.keyBy(androidDcList, 'id')[dcId] || {}; // sessionObject.serverAddress = ipAddress; // sessionObject.port = port; // } const sessionLength = Object.values(sessionObject).length; const nextSessionLength = lodash_1.default.filter(Object.values(sessionObject), exports.clearEmptyBy).length; if (sessionLength - nextSessionLength >= 1) { return {}; } return sessionObject; } catch (error) { return {}; } }); } const sessions = lodash_1.default.values(lodash_1.default.merge(lodash_1.default.keyBy(session, "sessionFile"), lodash_1.default.keyBy(json, "sessionFile"))); const result = lodash_1.default.reduce(sessions, (result, item) => { var _a, _b; if (!lodash_1.default.isEmpty(item) && !lodash_1.default.isNil(lodash_1.default.get(item, "authKey"))) { const defaultJsonObject = getDefaultJson(item.phone); const phone = (_b = (_a = lodash_1.default.get(item, "phone", lodash_1.default.get(item, "sessionFile"))) === null || _a === void 0 ? void 0 : _a.replace) === null || _b === void 0 ? void 0 : _b.call(_a, /^(\+)?(\d+)/, "+$2"); result.push(lodash_1.default.assign(defaultJsonObject, item, { phone, country: getCountryByPhone(phone) || "未知", remark, })); } return result; }, []); return result; } function checkImportData(props = {}) { var _a; let { json = [], session = [], zip = [], tdata = [], remark } = props; const fileList = [...json, ...session, ...zip, ...tdata]; //校验格式是否正确 const isHaveCanResolve = (_a = ["session", "zip"]) === null || _a === void 0 ? void 0 : _a.some((field) => fileList === null || fileList === void 0 ? void 0 : fileList.some((item) => { var _a, _b; return (_b = (_a = ((item === null || item === void 0 ? void 0 : item.originalname) || "")) === null || _a === void 0 ? void 0 : _a.endsWith) === null || _b === void 0 ? void 0 : _b.call(_a, field); })); if (!isHaveCanResolve) { return { code: 403, msg: "请正确上传会话文件", info: {}, }; } if (!lodash_1.default.isEmpty(zip) && Array.isArray(zip)) { zip = lodash_1.default.flattenDeep(lodash_1.default.map(zip, (item) => { const buffer = lodash_1.default.get(item, "buffer", []); const zip = new adm_zip_1.default(buffer); const zipEntries = zip.getEntries(); const zipFiles = lodash_1.default.map(zipEntries, (zipEntry) => { const originalname = iconv_lite_1.default.decode(Buffer.from(lodash_1.default.get(zipEntry, "entryName", ""), "binary"), "utf-8"); const ext = path_1.default.extname(originalname); const sessionFile = path_1.default.basename(originalname, ext); const buffer = zipEntry.getData(); return { sessionFile, buffer, originalname, size: buffer.length, ext, }; }); const groups = lodash_1.default.map(lodash_1.default.groupBy(zipFiles, (item) => item.sessionFile), (list) => { return lodash_1.default.reduce(list, (pre, cur) => { if (lodash_1.default.get(cur, "ext", "").endsWith("json")) { return lodash_1.default.assign({}, pre, { json: cur, }); } if (lodash_1.default.get(cur, "ext", "").endsWith("session")) { return lodash_1.default.assign({}, pre, { session: cur, }); } return pre; }, {}); }); return formatJsonAndSession({ json: lodash_1.default.map(groups, "json", []), session: lodash_1.default.map(groups, "session", []), remark, }); })); } if (!lodash_1.default.isEmpty(tdata) && Array.isArray(tdata)) { tdata = lodash_1.default.flattenDeep(lodash_1.default.map(tdata, (item) => { const buffer = lodash_1.default.get(item, "buffer", []); const zip = new adm_zip_1.default(buffer); const zipEntries = zip.getEntries(); const zipFiles = lodash_1.default.map(zipEntries, (zipEntry) => { var _a; let originalname = iconv_lite_1.default.decode(Buffer.from(lodash_1.default.get(zipEntry, "entryName", ""), "binary"), "utf-8"); originalname = (_a = originalname === null || originalname === void 0 ? void 0 : originalname.replace) === null || _a === void 0 ? void 0 : _a.call(originalname, /\/{2,}/g, "/"); const ext = path_1.default.extname(originalname); const sessionFile = path_1.default.basename(originalname, ext); const buffer = zipEntry.getData(); return { sessionFile, buffer, originalname, size: buffer.length, ext, isDirectory: zipEntry.isDirectory, }; }); let rootList = lodash_1.default.filter(zipFiles, (item) => !!item.isDirectory); if (lodash_1.default.isEmpty(rootList)) { zipFiles.push(...lodash_1.default.map(lodash_1.default.compact([ ...new Set(lodash_1.default.flattenDeep(lodash_1.default.map(zipFiles, (item) => identifyTheDirectory(lodash_1.default.get(item, "originalname", ""))))), ]), (originalname) => { return { originalname, sessionFile: lodash_1.default.last(lodash_1.default.compact(lodash_1.default.split(originalname, "/"))), isDirectory: true, }; })); rootList = lodash_1.default.filter(zipFiles, (item) => !!item.isDirectory); } const tdataMaps = rootList.reduce((result, curItem) => { var _a; const phone = lodash_1.default.get(curItem, "sessionFile", ""); const phoneNumber = (_a = phone === null || phone === void 0 ? void 0 : phone.replace) === null || _a === void 0 ? void 0 : _a.call(phone, /^(\+)?(\d+)/, "+$2"); if (isValidInternationalPhoneNumber(phoneNumber)) { result[phone] = lodash_1.default.filter(zipFiles, (item) => lodash_1.default.get(item, "originalname", "").includes(phone)); } return result; }, {}); const results = lodash_1.default.reduce(lodash_1.default.entries(tdataMaps), (all, [phone, buffers]) => { try { const newTData = new AnalyzeTData({ phone, buffers, sessionInfo: { remark, sessionFile: phone, }, }); newTData.run(); all.push(lodash_1.default.get(newTData, "sessionInfo", {})); } catch (error) { } return all; }, []); return results; })); } const sessions = lodash_1.default.uniqBy(lodash_1.default.merge(formatJsonAndSession({ session, json, remark, }), zip, tdata), "sessionFile"); return sessions; } function getFileName(props = {}) { let { json = [], session = [], zip = [], tdata = [] } = props; const fileList = [...json, ...session, ...zip, ...tdata]; let params = { sessionFile: "", extName: [], }; lodash_1.default.forEach(fileList, (item) => { let originalname = lodash_1.default.get(item, "originalname", ""); originalname = iconv_lite_1.default.decode(Buffer.from(originalname, "utf8"), // 直接使用正确的编码方式 "utf-8"); const extName = path_1.default.extname(originalname); const sessionFile = path_1.default.basename(originalname, extName); params.sessionFile = sessionFile; params.extName.push(extName); }); params.extName = params.extName.join("|"); return params; } function formatErrorMessage(message) { return lodash_1.default.reduce(Object.entries(errorMsgMaps), (msg, [key, val]) => { var _a, _b; return ((_b = (_a = message === null || message === void 0 ? void 0 : message.toLocaleLowerCase()) === null || _a === void 0 ? void 0 : _a.indexOf) === null || _b === void 0 ? void 0 : _b.call(_a, key.toLocaleLowerCase())) !== -1 ? `${val}${message}` : msg; }, message); } function getError(error) { const propertyNames = Object.getOwnPropertyNames(error); return lodash_1.default.reduce(propertyNames, (err, key) => lodash_1.default.assign({}, err, { [key]: error[key] }), {}); } class CustomError extends Error { constructor(props) { const { msg } = props; super(msg); // 调用父类的constructor,设置错误消息 lodash_1.default.assign(this, props); } } exports.CustomError = CustomError; async function clientDestroy(client) { var _a, _b; try { await ((_a = client === null || client === void 0 ? void 0 : client.disconnect) === null || _a === void 0 ? void 0 : _a.call(client)); await ((_b = client === null || client === void 0 ? void 0 : client.destroy) === null || _b === void 0 ? void 0 : _b.call(client)); if (!!(client === null || client === void 0 ? void 0 : client.disconnect) && !(client === null || client === void 0 ? void 0 : client.disconnected)) { return await clientDestroy(client); } } catch (error) { if (!!(client === null || client === void 0 ? void 0 : client.disconnect) && !(client === null || client === void 0 ? void 0 : client.disconnected)) { return await clientDestroy(client); } } } async function returnSingleSimpleClient(props) { let { sessionInfo = {} } = lodash_1.default.cloneDeep(props); let { phone, proxy } = sessionInfo; sessionInfo.phone = phone.replace(/^(\+)?(\d+)/, "+$2"); const session = new StoreSession(); sessionInfo = lodash_1.default.assign({}, (0, exports.oldTelegram)(), getLangCode({ phone }), sessionInfo, { phone, proxy, }); if (!lodash_1.default.isEmpty(proxy)) { sessionInfo.proxy = formatProxy(proxy); } else { sessionInfo = lodash_1.default.omit(sessionInfo, ["proxy"]); } session.sessionInfo = sessionInfo; await session.init(); const { apiHash, apiId } = sessionInfo; const client = new __1.TelegramClient(session, apiId, apiHash, Object.assign(Object.assign({}, sessionInfo), { floodSleepThreshold: 5, connectionRetries: 1, requestRetries: 5, retryDelay: 0, useWSS: true })); client.sessionInfo = sessionInfo; client.setLogLevel("none"); const initRequest = (0, exports.getInitConnection)(sessionInfo); client._initRequest = new __1.Api.InitConnection(initRequest); try { const preConnect = Date.now(); const result = await Promise.race([client.connect(), asleep(50000)]); const curConnect = Math.ceil((Date.now() - preConnect) / 1000); console.log(`${phone}---使用${curConnect}秒连接客户端-${!!result}`); return client; } catch (error) { await clientDestroy(client); throw new CustomError(lodash_1.default.assign({}, getError(error), { phone, })); } } async function createSingleSimpleClient(props) { let { sessionInfo = {}, callback } = lodash_1.default.cloneDeep(props); let { phone, proxy } = sessionInfo; sessionInfo.phone = phone.replace(/^(\+)?(\d+)/, "+$2"); const session = new StoreSession(); sessionInfo = lodash_1.default.assign({}, (0, exports.oldTelegram)(), getLangCode({ phone }), sessionInfo, { phone, proxy, }); if (!lodash_1.default.isEmpty(proxy)) { sessionInfo.proxy = formatProxy(proxy); } else { sessionInfo = lodash_1.default.omit(sessionInfo, ["proxy"]); } session.sessionInfo = sessionInfo; await session.init(); const { apiHash, apiId } = sessionInfo; const client = new __1.TelegramClient(session, apiId, apiHash, Object.assign(Object.assign({}, sessionInfo), { floodSleepThreshold: 5, connectionRetries: 1, requestRetries: 5, retryDelay: 0, useWSS: true })); client.sessionInfo = sessionInfo; client.setLogLevel("none"); const initRequest = (0, exports.getInitConnection)(sessionInfo); client._initRequest = new __1.Api.InitConnection(initRequest); try { const preConnect = Date.now(); const connectResult = await Promise.race([ client.connect(), asleep(60000), ]); const curConnect = Math.ceil((Date.now() - preConnect) / 1000); console.log(`${phone}---使用${curConnect}秒连接客户端-${!!connectResult}`); const result = await Promise.race([callback(client), asleep(140000)]); await clientDestroy(client); if (lodash_1.default.isNull(result)) { throw new CustomError({ code: 504, msg: "TG呆滞时间过久", info: {}, phone, }); } return lodash_1.default.assign({}, result, { phone, }); } catch (error) { await clientDestroy(client); throw new CustomError(lodash_1.default.assign({}, getError(error), { phone, })); } }