UNPKG

icqq

Version:

QQ protocol for NodeJS!

448 lines (447 loc) 15.6 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.getPacker = void 0; const crypto = __importStar(require("crypto")); const tea = __importStar(require("./tea")); const pb = __importStar(require("./protobuf")); const writer_1 = __importDefault(require("./writer")); const constants_1 = require("./constants"); const enctyption_1 = require("../internal/enctyption"); const device_1 = require("./device"); function packTlv(tag, ...args) { const t = map[tag].apply(this, args); const lbuf = Buffer.allocUnsafe(2); lbuf.writeUInt16BE(t.readableLength); t.unshift(lbuf); const tbuf = Buffer.allocUnsafe(2); tbuf.writeUInt16BE(tag); t.unshift(tbuf); return t.read(); } function createSalt(n) { const subCmd = parseInt(n.split('_')[1]); if (['810_9'].includes(n)) return new writer_1.default() .writeU32(0) .writeBytes(this.device.guid) .writeBytes(this.apk.sdkver) .writeU32(subCmd) .writeU32(0) .read(); return new writer_1.default() .writeU32(this.uin) .writeBytes(this.device.guid) .writeBytes(this.apk.sdkver) .writeU32(subCmd) .read(); } const map = { 0x01: function () { return new writer_1.default() .writeU16(1) // ip ver .writeBytes(crypto.randomBytes(4)) .writeU32(this.uin) .write32((Date.now() / 1000) & 0xffffffff) .writeBytes(this.device.ip_address) //ip .writeU16(0); }, 0x08: function () { return new writer_1.default() .writeU16(0) .writeU32(2052) //localId .writeU16(0); }, 0x16: function () { const Watch = this.getApkInfo(device_1.Platform.Watch); return new writer_1.default() .writeU32(Watch.ssover) .writeU32(Watch.appid) .writeU32(Watch.subid) .writeBytes(this.device.guid) .writeTlv(Watch.id) .writeTlv(Watch.ver) .writeTlv(Watch.sign); }, 0x18: function () { return new writer_1.default() .writeU16(1) // ping ver .writeU32(1536) .writeU32(this.apk.appid) .writeU32(0) // app client ver .writeU32(this.uin) .writeU16(0) .writeU16(0); }, 0x1B: function () { return new writer_1.default() .writeU32(0) .writeU32(0) .writeU32(3) .writeU32(4) .writeU32(72) .writeU32(2) .writeU32(2) .writeU16(0); }, 0x1D: function () { return new writer_1.default() .writeU8(1) .writeU32(this.apk.bitmap) .writeU32(0) .writeU8(0) .writeU32(0); }, 0x1F: function () { return new writer_1.default() .writeU8(0) // isRoot .writeTlv("android") // OS type .writeTlv("7.1.2") // OS version .writeU16(2) // Network Type .writeTlv("China Mobile GSM") // simOperatorName .writeTlv(constants_1.BUF0) .writeTlv("wifi"); // APN }, 0x33: function () { return new writer_1.default().writeBytes(this.device.guid); }, 0x35: function (deviceType) { return new writer_1.default().writeU32(deviceType); }, 0x100: function (sub_id) { return new writer_1.default() .writeU16(1) // db buf ver .writeU32(this.apk.ssover) // sso ver .write32(this.apk.appid) .writeU32(sub_id || this.apk.subid) .writeU32(0) // app client ver .writeU32(this.apk.main_sig_map); }, 0x104: function () { return new writer_1.default().writeBytes(this.sig.t104); }, 0x106: function (md5pass) { const body = new writer_1.default() .writeU16(4) // tgtgt ver .writeBytes(crypto.randomBytes(4)) .writeU32(this.apk.ssover) // sso ver .writeU32(this.apk.appid) .writeU32(0) // app client ver .writeU64(this.uin) .write32((Date.now() / 1000) & 0xffffffff) .writeBytes(Buffer.alloc(4)) // dummy ip .writeU8(1) // save password .writeBytes(md5pass) .writeBytes(this.sig.tgtgt) .writeU32(0) .writeU8(1) // guid available .writeBytes(this.device.guid) .writeU32(this.apk.subid) .writeU32(1) // login type password .writeTlv(String(this.uin)) .writeU16(0) .read(); const buf = Buffer.alloc(4); buf.writeUInt32BE(this.uin); const key = (0, constants_1.md5)(Buffer.concat([ md5pass, Buffer.alloc(4), buf ])); return new writer_1.default().writeBytes(tea.encrypt(body, key)); }, 0x107: function () { return new writer_1.default() .writeU16(0) // pic type .writeU8(0) // captcha type .writeU16(0) // pic size .writeU8(1); // ret type }, 0x108: function () { return new writer_1.default().writeBytes(this.sig.ksid || Buffer.from(`|${this.device.imei}|${this.apk.name}`)); }, 0x109: function () { return new writer_1.default().writeBytes((0, constants_1.md5)(this.device.imei)); }, 0x10a: function () { return new writer_1.default().writeBytes(this.sig.tgt); }, 0x112: function () { return new writer_1.default().writeTlv(String(this.uin)); }, 0x116: function () { return new writer_1.default() .writeU8(0) .writeU32(this.apk.bitmap) .writeU32(this.apk.sub_sig_map) // sub sigmap .writeU8(1) // size of app id list .writeU32(1600000226); // app id list[0] }, 0x124: function () { return new writer_1.default() .writeTlv(this.device.os_type.slice(0, 16)) .writeTlv(this.device.version.release.slice(0, 16)) .writeU16(2) // network type .writeTlv(this.device.sim.slice(0, 16)) .writeU16(0) .writeTlv(this.device.apn.slice(0, 16)); }, 0x128: function () { return new writer_1.default() .writeU16(0) .writeU8(0) // guid new .writeU8(1) // guid available .writeU8(0) // guid changed .writeU32(16777216) // guid flag .writeTlv(this.device.model.slice(0, 32)) .writeTlv(this.device.guid.slice(0, 16)) .writeTlv(this.device.brand.slice(0, 16)); }, 0x141: function () { return new writer_1.default() .writeU16(1) // ver .writeTlv(this.device.sim) .writeU16(2) // network type .writeTlv(this.device.apn); }, 0x142: function () { return new writer_1.default() .writeU16(0) .writeTlv(this.apk.id.slice(0, 32)); }, 0x143: function () { return new writer_1.default().writeBytes(this.sig.d2); }, 0x144: function () { const body = new writer_1.default() .writeU16(5) // tlv cnt .writeBytes(packTlv.call(this, 0x109)) .writeBytes(packTlv.call(this, 0x52d)) .writeBytes(packTlv.call(this, 0x124)) .writeBytes(packTlv.call(this, 0x128)) .writeBytes(packTlv.call(this, 0x16e)); return new writer_1.default().writeBytes(tea.encrypt(body.read(), this.sig.tgtgt)); }, 0x145: function () { return new writer_1.default().writeBytes(this.device.guid); }, 0x147: function () { return new writer_1.default() .writeU32(this.apk.appid).writeTlv(this.apk.ver) .writeTlv(this.apk.sign); }, 0x154: function () { return new writer_1.default().writeU32(this.sig.seq + 1); }, 0x16a: function (srm_token) { return new writer_1.default().writeBytes(srm_token || this.sig.srm_token); }, 0x16e: function () { return new writer_1.default().writeBytes(this.device.model); }, 0x174: function () { return new writer_1.default().writeBytes(this.sig.t174); }, 0x177: function () { return new writer_1.default() .writeU8(0x01) .writeU32(this.apk.buildtime) .writeTlv(this.apk.sdkver); }, 0x17a: function () { return new writer_1.default().writeU32(9); }, 0x17c: function (code) { return new writer_1.default().writeTlv(code); }, 0x187: function () { return new writer_1.default().writeBytes((0, constants_1.md5)(this.device.mac_address)); }, 0x188: function () { return new writer_1.default().writeBytes((0, constants_1.md5)(this.device.android_id)); }, 0x191: function () { return new writer_1.default().writeU8(0x82); }, 0x193: function (ticket) { return new writer_1.default().writeBytes(ticket); }, 0x194: function () { return new writer_1.default().writeBytes(this.device.imsi); }, 0x197: function () { return new writer_1.default().writeTlv(Buffer.alloc(1)); }, 0x198: function () { return new writer_1.default().writeTlv(Buffer.alloc(1)); }, 0x202: function () { return new writer_1.default() .writeTlv(this.device.wifi_bssid.slice(0, 16)) .writeTlv(this.device.wifi_ssid.slice(0, 32)); }, 0x400: function () { return new writer_1.default() .writeU16(1) .writeU64(this.uin) .writeBytes(this.device.guid) .writeBytes(crypto.randomBytes(16)) .write32(1) .write32(16) .write32((Date.now() / 1000) & 0xffffffff) .writeBytes(Buffer.alloc(0)); }, 0x401: function () { return new writer_1.default().writeBytes(crypto.randomBytes(16)); }, 0x511: function () { const domains = new Set([ "aq.qq.com", // "buluo.qq.com", "connect.qq.com", "docs.qq.com", "game.qq.com", "gamecenter.qq.com", // "graph.qq.com", "haoma.qq.com", "id.qq.com", // "imgcache.qq.com", "kg.qq.com", "mail.qq.com", "mma.qq.com", "office.qq.com", // "om.qq.com", "openmobile.qq.com", "qqweb.qq.com", "qun.qq.com", "qzone.qq.com", "ti.qq.com", "v.qq.com", "vip.qq.com", "y.qq.com", ]); const stream = new writer_1.default().writeU16(domains.size); for (let v of domains) stream.writeU8(0x01).writeTlv(v); return stream; }, 0x516: function () { return new writer_1.default().writeU32(0); }, 0x521: function (type) { return new writer_1.default() .writeU32(type) // product type .writeU16(0); // const }, 0x525: function () { return new writer_1.default() .writeU16(1) // tlv cnt .writeU16(0x536) // tag .writeTlv(Buffer.from([0x2, 0x1, 0x0])); // zero }, 0x523: function () { return new writer_1.default() .writeTlv(Buffer.from([0x1, 0x0])); }, 0x52d: function () { const d = this.device; const buf = pb.encode({ 1: d.bootloader, 2: d.proc_version, 3: d.version.codename, 4: d.version.incremental, 5: d.fingerprint, 6: d.boot_id, 7: d.android_id, 8: d.baseband, 9: d.version.incremental, }); return new writer_1.default().writeBytes(buf); }, 0x542: function () { return new writer_1.default().writeBytes(Buffer.from([0x4A, 0x02, 0x60, 0x01])); }, 0x544: function (v, subCmd, signData = constants_1.BUF0) { if (v == -1) { return new writer_1.default().writeBytes(signData); } const salt = new writer_1.default(); if (v === 2) { salt.writeU32(0); salt.writeTlv(this.device.guid); salt.writeTlv(Buffer.from(this.apk.sdkver)); salt.writeU32(subCmd); salt.writeU32(0); } else { salt.writeU64(this.uin); salt.writeTlv(this.device.guid); salt.writeTlv(Buffer.from(this.apk.sdkver)); salt.writeU32(subCmd); } return new writer_1.default().writeBytes((0, enctyption_1.sign)((new Date()).getTime(), salt.read())); }, 0x545: function (qImei) { return new writer_1.default().writeBytes(Buffer.from(qImei || this.device.imei)); }, 0x547: function () { return new writer_1.default().writeBytes(this.sig.t547); }, 0x548: function () { // copy from https://github.com/Icalingua-plus-plus/oicq-icalingua-plus-plus/blob/master/lib/wtlogin/tlv.js const src = crypto.randomBytes(128); while (src[0] === 0 || src[0] === 255) src[0] = crypto.randomBytes(1)[0]; const srcNum = BigInt('0x' + src.toString("hex")); const cnt = 10000; const dstNum = srcNum + BigInt(cnt); const dst = Buffer.from(dstNum.toString(16).padStart(256, "0"), "hex"); const tgt = crypto.createHash("sha256").update(dst).digest(); const writer = new writer_1.default() .writeU8(1) //version .writeU8(2) //typ .writeU8(1) //hashType .writeU8(2) //ok .writeU16(10) //maxIndex .writeBytes(Buffer.from([0, 0])) //reserveBytes .writeTlv(src) .writeTlv(tgt); const cpy = writer.read(); const t546 = writer .writeBytes(cpy) .writeTlv(cpy) .read(); const t548 = this.calcPoW(t546); return new writer_1.default().writeBytes(t548); }, 0x553: function () { return new writer_1.default().writeBytes(this.sig.t553); } }; function getPacker(c) { return packTlv.bind(c); } exports.getPacker = getPacker;