838 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			838 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const { fetch } = require("fetch-h2");
 | |
| const tls = require("tls");
 | |
| const crypto = require('crypto');
 | |
| const nacl = require('tweetnacl');
 | |
| const sealedbox = require('tweetnacl-sealedbox-js');
 | |
| const zlib = require("zlib");
 | |
| const mqtt = require("mqtt-packet");
 | |
| const WebSocket = require("ws");
 | |
| const user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:135.0) Gecko/20100101 Firefox/135.0';
 | |
| 
 | |
| // config
 | |
| config = {
 | |
| 	email: "yourmail@gmail.com",
 | |
| 	pass: "yourpass"
 | |
| };
 | |
| 
 | |
| // firefox bypass
 | |
| const agent = {
 | |
| 	secureProtocol: "TLS_method",
 | |
| 	minVersion: "TLSv1.2",
 | |
| 	maxVersion: "TLSv1.3",
 | |
| 	ciphers: [
 | |
| 		"TLS_AES_128_GCM_SHA256",
 | |
| 		"TLS_AES_256_GCM_SHA384",
 | |
| 		"TLS_CHACHA20_POLY1305_SHA256",
 | |
| 		"ECDHE-ECDSA-AES128-GCM-SHA256",
 | |
| 		"ECDHE-ECDSA-AES256-GCM-SHA384",
 | |
| 		"ECDHE-RSA-AES128-GCM-SHA256",
 | |
| 		"ECDHE-RSA-AES256-GCM-SHA384",
 | |
| 		"ECDHE-ECDSA-CHACHA20-POLY1305",
 | |
| 		"ECDHE-RSA-CHACHA20-POLY1305"
 | |
| 	].join(":"),
 | |
| 	honorCipherOrder: true
 | |
| };
 | |
| 
 | |
| // consts
 | |
| const POST_URLENCODE = 0;
 | |
| const POST_JSON = 1;
 | |
| const POST_RAW = 2;
 | |
| 
 | |
| //
 | |
| // Helper functions
 | |
| //
 | |
| 
 | |
| function merge_headers(headers){
 | |
| 	
 | |
| 	var base_headers = {
 | |
| 		'User-Agent': user_agent,
 | |
| 		'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
 | |
| 		'Accept-Language': 'en-US,en;q=0.5',
 | |
| 		'Accept-Encoding': 'gzip',
 | |
| 		'Referer': 'https://www.messenger.com/',
 | |
| 		//'Content-Type': 'application/x-www-form-urlencoded',
 | |
| 		//'Content-Length': '317',
 | |
| 		'Origin': 'https://www.messenger.com',
 | |
| 		'DNT': '1',
 | |
| 		'Sec-GPC': '1',
 | |
| 		//'Connection': 'keep-alive',
 | |
| 		//'Cookie': 'datr=Kh69Z0FC3H-Stoj1M5vR7tXx; wd=1011x1000',
 | |
| 		'Upgrade-Insecure-Requests': '1',
 | |
| 		'Sec-Fetch-Dest': 'document',
 | |
| 		'Sec-Fetch-Mode': 'navigate',
 | |
| 		'Sec-Fetch-Site': 'same-origin',
 | |
| 		'Sec-Fetch-User': '?1',
 | |
| 		'Priority': 'u=0, i',
 | |
| 		'TE': 'trailers'
 | |
| 	};
 | |
| 	
 | |
| 	for(let key in headers){
 | |
| 		
 | |
| 		base_headers[key] = headers[key];
 | |
| 	}
 | |
| 	
 | |
| 	return base_headers;
 | |
| }
 | |
| 
 | |
| function make_guid(){
 | |
| 	var date = Date.now();
 | |
| 	
 | |
| 	return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
 | |
| 		const r = Math.floor((date + Math.random() * 16) % 16);
 | |
| 		return (c == 'x' ? r : (r & 7) | 8).toString(16);
 | |
| 	});
 | |
| }
 | |
| 
 | |
| function make_otid(){
 | |
| 	
 | |
| 	const rand = Math.floor(Math.random() * 4294967295);
 | |
| 	const str = ('0000000000000000000000' + rand.toString(2)).slice(-22);
 | |
| 	const msgs = Date.now().toString(2) + str;
 | |
| 	return binaryToDecimal(msgs);
 | |
| }
 | |
| 
 | |
| function binaryToDecimal(data){
 | |
| 	let ret = '';
 | |
| 	while (data !== '0') {
 | |
| 		let end = 0;
 | |
| 		let fullName = '';
 | |
| 		let i = 0;
 | |
| 		for (; i < data.length; i++) {
 | |
| 			end = 2 * end + parseInt(data[i], 10);
 | |
| 			if (end >= 10) {
 | |
| 				fullName += '1';
 | |
| 				end -= 10;
 | |
| 			} else {
 | |
| 				fullName += '0';
 | |
| 			}
 | |
| 		}
 | |
| 		ret = end.toString() + ret;
 | |
| 		data = fullName.slice(fullName.indexOf('1'));
 | |
| 	}
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| function http_build_query(array){
 | |
| 	
 | |
| 	var str = [];
 | |
| 	
 | |
| 	for(let key in array){
 | |
| 		
 | |
| 		str.push(encodeURIComponent(key) + "=" + encodeURIComponent(array[key]));
 | |
| 	}
 | |
| 	
 | |
| 	return str.join("&");
 | |
| }
 | |
| 
 | |
| async function get_data(url, headers = {}){
 | |
| 		
 | |
| 	const data = await fetch(
 | |
| 		url,
 | |
| 		{
 | |
| 			headers: merge_headers(headers),
 | |
| 			httpsOptions: agent,
 | |
| 			allowForbiddenHeaders: true
 | |
| 		}
 | |
| 	);
 | |
| 	
 | |
| 	const body = await data.text();
 | |
| 	
 | |
| 	return {
 | |
| 		status: data.status,
 | |
| 		headers: data.headers._data,
 | |
| 		data: body
 | |
| 	};
 | |
| }
 | |
| 
 | |
| async function post_data(url, data, encode_as, headers = {}){
 | |
| 	
 | |
| 	switch(encode_as){
 | |
| 		
 | |
| 		case POST_URLENCODE:
 | |
| 			data = http_build_query(data);
 | |
| 			headers["Content-Type"] = "application/x-www-form-urlencoded";
 | |
| 			break;
 | |
| 		
 | |
| 		case POST_JSON:
 | |
| 			data = JSON.stringify(data);
 | |
| 			headers["Content-Type"] = "application/json";
 | |
| 			break;
 | |
| 	}
 | |
| 	
 | |
| 	headers["Content-Length"] = data.length;
 | |
| 	
 | |
| 	const res = await fetch(
 | |
| 		url,
 | |
| 		{
 | |
| 			method: "POST",
 | |
| 			headers: merge_headers(headers),
 | |
| 			body: data,
 | |
| 			httpsOptions: agent,
 | |
| 			allowForbiddenHeaders: true
 | |
| 		}
 | |
| 	);
 | |
| 	
 | |
| 	const body = await res.text();
 | |
| 	
 | |
| 	return {
 | |
| 		status: res.status,
 | |
| 		headers: res.headers._data,
 | |
| 		data: body
 | |
| 	};
 | |
| }
 | |
| 
 | |
| //
 | |
| // Facebook login
 | |
| //
 | |
| 
 | |
| init_login();
 | |
| async function init_login(){
 | |
| 	
 | |
| 	login(get_init_data());
 | |
| }
 | |
| 
 | |
| 
 | |
| async function get_init_data(){
 | |
| 	
 | |
| 	console.log("(info) Getting FB public key");
 | |
| 	
 | |
| 	//
 | |
| 	// Step 1
 | |
| 	// get keyId, publicKey, initial_request_id & other shits
 | |
| 	//
 | |
| 	var keys =
 | |
| 		await get_data(
 | |
| 			"https://www.messenger.com/"
 | |
| 		);
 | |
| 	
 | |
| 	var keyId = keys.data.match(/"keyId":([0-9]+)/);
 | |
| 	if(keyId === null){
 | |
| 		
 | |
| 		throw new Error("Could not grep keyId");
 | |
| 	}
 | |
| 	
 | |
| 	keyId = parseInt(keyId[1]);
 | |
| 	console.log("(debug) Got keyId=" + keyId);
 | |
| 	
 | |
| 	// get publicKey
 | |
| 	var publicKey = keys.data.match(/"publicKey":"([A-Za-z0-9]+)"/);
 | |
| 	if(publicKey === null){
 | |
| 		
 | |
| 		throw new Error("Could not grep publicKey");
 | |
| 	}
 | |
| 	console.log("(debug) publicKey=" + publicKey[1]);
 | |
| 	
 | |
| 	// convert public key to binary
 | |
| 	publicKey = publicKey[1];
 | |
| 	
 | |
| 	// get initial_request_id
 | |
| 	var initial_request_id = keys.data.match(/(?:name|id)=\"initial_request_id\" value=\"([A-Za-z0-9_-]+)\"/);
 | |
| 	if(initial_request_id === null){
 | |
| 		
 | |
| 		throw new Error("Could not grep initial_request_id");
 | |
| 	}
 | |
| 	
 | |
| 	console.log("(debug) Got initial_request_id=" + initial_request_id[1]);
 | |
| 	initial_request_id = initial_request_id[1];
 | |
| 
 | |
| 	// get lgnrnd
 | |
| 	var lgnrnd = keys.data.match(/(?:name|id)=\"lgnrnd\" value=\"([A-Za-z0-9_-]+)\"/);
 | |
| 	if(lgnrnd === null){
 | |
| 		
 | |
| 		throw new Error("Could not grep initial_request_id");
 | |
| 	}
 | |
| 	
 | |
| 	console.log("(debug) Got lgnrnd=" + lgnrnd[1]);
 | |
| 	lgnrnd = lgnrnd[1];
 | |
| 	
 | |
| 	// get LSD token
 | |
| 	var lsd = keys.data.match(/\["LSD"(?:,\[\])?,{"token":"([A-Za-z0-9_-]+)"}/);
 | |
| 	if(lsd === null){
 | |
| 		
 | |
| 		throw new Error("Could not grep lsd");
 | |
| 	}
 | |
| 	
 | |
| 	console.log("(debug) Got lsd=" + lsd[1]);
 | |
| 	lsd = lsd[1];
 | |
| 	
 | |
| 	return {
 | |
| 		keyId: keyId,
 | |
| 		publicKey: publicKey,
 | |
| 		initial_request_id: initial_request_id,
 | |
| 		lgnrnd: lgnrnd,
 | |
| 		lsd: lsd
 | |
| 	};
 | |
| }
 | |
| 
 | |
| 	
 | |
| async function login(init){
 | |
| 	
 | |
| 	init = await init;
 | |
| 	
 | |
| 	//
 | |
| 	// Step 2.
 | |
| 	// Encrypt form data
 | |
| 	//
 | |
| 	const time = Math.floor(Date.now() / 1000);
 | |
| 	const key = crypto.randomBytes(32);
 | |
| 	const iv = Buffer.alloc(12, 0);
 | |
| 	
 | |
| 	// Create AES-GCM cipher
 | |
| 	const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
 | |
| 	cipher.setAAD(Buffer.from(time.toString(), "utf-8"));
 | |
| 	
 | |
| 	// Encrypt password
 | |
| 	let encryptedPassword = cipher.update(config.pass, "utf8", "binary");
 | |
| 	encryptedPassword += cipher.final("binary");
 | |
| 	encryptedPassword = Buffer.from(encryptedPassword, "binary");
 | |
| 	const cipherTag = cipher.getAuthTag();
 | |
| 	
 | |
| 	// Encrypt AES key with public key
 | |
| 	const publicKey_d = Buffer.from(init.publicKey, "hex");
 | |
| 	const sealedBox = sealedbox.seal(key, publicKey_d);
 | |
| 	const encryptedKey = Buffer.from(sealedBox);
 | |
| 	
 | |
| 	// Build final payload
 | |
| 	const keyIdBuffer = Buffer.from([1, init.keyId]);
 | |
| 	const lengthBuffer = Buffer.alloc(2);
 | |
| 	lengthBuffer.writeUInt16LE(encryptedKey.length, 0);
 | |
| 	
 | |
| 	const data = Buffer.concat([
 | |
| 		keyIdBuffer,
 | |
| 		lengthBuffer,
 | |
| 		encryptedKey,
 | |
| 		cipherTag,
 | |
| 		encryptedPassword
 | |
| 	]);
 | |
| 	
 | |
|     // Base64 encode and format
 | |
|     const encrypted_data = data.toString("base64");
 | |
| 	
 | |
| 	//
 | |
| 	// Step 3
 | |
| 	// Send login req
 | |
| 	//
 | |
| 	
 | |
| 	console.log("(info) Initiating login in 10 seconds using " + encrypted_data);
 | |
| 	setTimeout(async function(){
 | |
| 		
 | |
| 		console.log("(info) Sending login information");
 | |
| 		var redirect =
 | |
| 			await post_data(
 | |
| 				"https://www.messenger.com/login/password/",
 | |
| 				{
 | |
| 					jazoest: "21035",
 | |
| 					lsd: init.lsd,
 | |
| 					initial_request_id: init.initial_request_id,
 | |
| 					timezone: "300",
 | |
| 					lgndim: btoa('{"w":1920,"h":1080,"aw":1920,"ah":1080,"c":24}'),
 | |
| 					lgnrnd: init.lgnrnd,
 | |
| 					lgnjs: "n",
 | |
| 					email: config.email,
 | |
| 					pass: "#PWD_BROWSER:5:" + time + ":" + encrypted_data,
 | |
| 					default_persistent: ""
 | |
| 				},
 | |
| 				POST_URLENCODE,
 | |
| 				{
 | |
| 					"Cookie": "datr=m5vDZzGXLy2_XEtAGDrB6Cgi; wd=1920x1080"
 | |
| 				}
 | |
| 			);
 | |
| 		
 | |
| 		//
 | |
| 		// Check if login was successful
 | |
| 		//
 | |
| 		if(
 | |
| 			redirect.headers.has("location") === false ||
 | |
| 			(
 | |
| 				redirect.headers.get("location") != "https://www.messenger.com/" &&
 | |
| 				redirect.headers.get("location") != "https://www.messenger.com"
 | |
| 			)
 | |
| 		){
 | |
| 			
 | |
| 			throw new Error("Did not obtain correct redirect value");
 | |
| 		}
 | |
| 		
 | |
| 		//
 | |
| 		// Get cookies
 | |
| 		//
 | |
| 		if(redirect.headers.has("set-cookie") === false){
 | |
| 			
 | |
| 			throw new Error("Did not obtain any cookies");
 | |
| 		}
 | |
| 		
 | |
| 		const cookies_raw = redirect.headers.get("set-cookie");
 | |
| 		var cookies = [];
 | |
| 		
 | |
| 		for(var i=0; i<cookies_raw.length; i++){
 | |
| 			
 | |
| 			var value = cookies_raw[i].match(/[A-Za-z0-9]+=[^;]+/);
 | |
| 			if(value[0].match(/^user=/)){
 | |
| 				
 | |
| 				cookies.push("c_" + value);
 | |
| 				continue;
 | |
| 			}
 | |
| 			
 | |
| 			if(value[0].match(/^l=|^n=/)){
 | |
| 				
 | |
| 				cookies.push("ps_" + value);
 | |
| 				continue;
 | |
| 			}
 | |
| 			
 | |
| 			cookies.push(value[0]);
 | |
| 		}
 | |
| 		
 | |
| 		cookies = cookies.join("; ");
 | |
| 		
 | |
| 		console.log("(debug) Got cookies: " + cookies);
 | |
| 		
 | |
| 		fetch_main(cookies);
 | |
| 		
 | |
| 	}, 10000);
 | |
| }
 | |
| 
 | |
| async function fetch_main(cookies){
 | |
| 	
 | |
| 	console.log("(info) Getting main chat page");
 | |
| 	
 | |
| 	// fetch main page
 | |
| 	var main_page =
 | |
| 		await get_data(
 | |
| 			"https://www.messenger.com/",
 | |
| 			{
 | |
| 				"Cookie": cookies
 | |
| 			}
 | |
| 		);
 | |
| 	
 | |
| 	if(main_page.headers.has("location")){
 | |
| 		
 | |
| 		console.log("(info) Getting main chat page through redirect");
 | |
| 		
 | |
| 		main_page =
 | |
| 			await get_data(
 | |
| 				main_page.headers.get("location")[0],
 | |
| 				{
 | |
| 					"Cookie": cookies
 | |
| 				}
 | |
| 			);
 | |
| 	}
 | |
| 	
 | |
| 	console.log("(info) Got main page");
 | |
| 	/*
 | |
| 	// get clientID !!!!!!there are multiple!!!!!
 | |
| 	var clientIDs_r = main_page.data.matchAll(/"clientID":"([A-Za-z0-9_-]+)"/g);
 | |
| 	var clientIDs = Array.from(clientIDs_r, m => m[1]);
 | |
| 	
 | |
| 	if(clientIDs === null){
 | |
| 		
 | |
| 		throw new Error("Could not grep clientID(s)");
 | |
| 	}
 | |
| 	
 | |
| 	console.log("(debug) Got " + clientIDs.length + " clientIDs: [" + clientIDs.join(", ") + "]");
 | |
| 	*/
 | |
| 	
 | |
| 	// get appIDs for websocket edges
 | |
| 	var appID_status = main_page.data.match(/"appId":([0-9]+)/);
 | |
| 	if(appID_status === null){
 | |
| 		
 | |
| 		throw new Error("Failed to grep appId for status websocket");
 | |
| 	}
 | |
| 	appID_status = parseInt(appID_status[1]);
 | |
| 	console.log("(debug) Got appID_status " + appID_status);
 | |
| 	
 | |
| 	var appID_msg = main_page.data.match(/"appID":([0-9]+)/);
 | |
| 	if(appID_msg === null){
 | |
| 		
 | |
| 		throw new Error("Failed to grep appId for msg websocket");
 | |
| 	}
 | |
| 	appID_msg = parseInt(appID_msg[1]);
 | |
| 	console.log("(debug) Got appID_msg " + appID_msg);
 | |
| 	
 | |
| 	// get version
 | |
| 	var version = main_page.data.match(/\\"version\\":([0-9]{4,})/);
 | |
| 	if(version === null){
 | |
| 		
 | |
| 		throw new Error("Failed to grep version");
 | |
| 	}
 | |
| 	version = version[1];
 | |
| 	console.log("(debug) Got version " + version);
 | |
| 	
 | |
| 	//
 | |
| 	// Connect to the websocket edges
 | |
| 	//
 | |
| 	
 | |
| 	// connect to the status server (random GUID, no foreground)
 | |
| 	//ws_connect("status", cookies, appID_status, make_guid(), false);
 | |
| 	
 | |
| 	// connect to the message server (defined GUID, has foreground, version)
 | |
| 	ws_connect("msg", cookies, appID_status, make_guid(), true, version);
 | |
| }
 | |
| 
 | |
| async function ws_connect(ident, cookies, appID, edgeName, foreground, version){
 | |
| 	
 | |
| 	var msg_c = 0
 | |
| 	var task_id = 1;
 | |
| 	
 | |
| 	//
 | |
| 	// Split up cookies
 | |
| 	//
 | |
| 	cookies_s = cookies.split(";");
 | |
| 	cookies_a = [];
 | |
| 	
 | |
| 	for(var i=0; i<cookies_s.length; i++){
 | |
| 		
 | |
| 		var tmp = cookies_s[i].split(/=(.+)/).slice(0, 2);
 | |
| 		cookies_a[tmp[0].trim()] = tmp[1].trim();
 | |
| 	}
 | |
| 	
 | |
| 	// connect to this shit
 | |
| 	// wss://edge-chat.messenger.com/chat?region=atn&sid=2270495435128831&cid=36e7527a-1e3b-4cab-b522-6177131a26b1
 | |
| 	const sessionID = Math.floor(Math.random() * 9007199254740991) + 1;
 | |
| 	
 | |
| 	const ws = new WebSocket(
 | |
| 		"wss://edge-chat.messenger.com/chat?region=atn&sid=" + sessionID + "&cid=" + edgeName,
 | |
| 		{
 | |
| 			headers: {
 | |
| 				'User-Agent': user_agent,
 | |
| 				'Accept': '*/*',
 | |
| 				'Accept-Language': 'en-US,en;q=0.5',
 | |
| 				'Accept-Encoding': 'gzip, deflate, br, zstd',
 | |
| 				'Sec-WebSocket-Version': '13',
 | |
| 				'Origin': 'https://www.messenger.com',
 | |
| 				'Sec-WebSocket-Extensions': 'permessage-deflate',
 | |
| 				//'Sec-WebSocket-Key': '3VLUf/lsgASJEUYl9dQbIQ==',
 | |
| 				'DNT': '1',
 | |
| 				'Sec-GPC': '1',
 | |
| 				'Connection': 'keep-alive, Upgrade',
 | |
| 				'Cookie': cookies,
 | |
| 				'Sec-Fetch-Dest': 'empty',
 | |
| 				'Sec-Fetch-Mode': 'websocket',
 | |
| 				'Sec-Fetch-Site': 'same-site',
 | |
| 				'Pragma': 'no-cache',
 | |
| 				'Cache-Control': 'no-cache',
 | |
| 				'Upgrade': 'websocket'
 | |
| 			}
 | |
| 		}
 | |
| 	);
 | |
| 	
 | |
| 	// @TODO: send ping packet
 | |
| 	// c000
 | |
| 	
 | |
| 	var conn_open = false;
 | |
| 	ws.on("open", async function(){
 | |
| 		
 | |
| 		console.log("(ws-" + ident + ") Sending login info");
 | |
| 		
 | |
| 		setInterval(function(){
 | |
| 			
 | |
| 			ws.send(Buffer.from([0xc0, 0x00]));
 | |
| 			console.log("ping");
 | |
| 		}, 10000);
 | |
| 		
 | |
| 		// server reply: yes
 | |
| 		await ws.send(
 | |
| 			mqtt.generate({
 | |
| 				cmd: "connect",
 | |
| 				protocolId: "MQIsdp",
 | |
| 				protocolVersion: 3,
 | |
| 				clean: true,
 | |
| 				clientId: "mqttwsclient",
 | |
| 				reschedulePings: true,
 | |
| 				keepalive: 60,
 | |
| 				username: JSON.stringify({
 | |
| 					a: user_agent,
 | |
| 					asi: null,
 | |
| 					aid: appID, // token from messenger, INTEGER
 | |
| 					aids: null,
 | |
| 					chat_on: false,
 | |
| 					cp: 3,
 | |
| 					ct: "websocket",
 | |
| 					d: edgeName, // @TODO sometimes completely random
 | |
| 					dc: "",
 | |
| 					ecp: 10,
 | |
| 					fg: foreground,
 | |
| 					gas: null,
 | |
| 					mqtt_sid: "",
 | |
| 					no_auto_fg: true,
 | |
| 					p: null,
 | |
| 					pack: [],
 | |
| 					php_override: "",
 | |
| 					pm: [],
 | |
| 					s: sessionID, // WE GENERATE THIS (also known as sid), INTEGER
 | |
| 					st: [],
 | |
| 					u: cookies_a.c_user
 | |
| 				}),
 | |
| 				password: null
 | |
| 			})
 | |
| 		);
 | |
| 		
 | |
| 		// server reply: yes
 | |
| 		await ws.send(
 | |
| 			mqtt.generate({
 | |
| 				cmd: "publish",
 | |
| 				retain: false,
 | |
| 				qos: 1,
 | |
| 				dup: false,
 | |
| 				topic: "/ls_app_settings",
 | |
| 				payload: JSON.stringify({
 | |
| 					ls_fdid: "",
 | |
| 					ls_sv: version
 | |
| 				}),
 | |
| 				messageId: msg_c++,
 | |
| 			})
 | |
| 		);
 | |
| 		
 | |
| 		// server reply: no
 | |
| 		await ws.send(
 | |
| 			mqtt.generate({
 | |
| 				cmd: "subscribe",
 | |
| 				retain: false,
 | |
| 				qos: 1,
 | |
| 				dup: false,
 | |
| 				topic: null,
 | |
| 				payload: null,
 | |
| 				subscriptions: [
 | |
| 					{ topic: "/ls_foreground_state", qos: 0 }
 | |
| 				],
 | |
| 				messageId: msg_c++
 | |
| 			})
 | |
| 		);
 | |
| 		
 | |
| 		// server reply: no
 | |
| 		await ws.send(
 | |
| 			mqtt.generate({
 | |
| 				cmd: "subscribe",
 | |
| 				retain: false,
 | |
| 				qos: 1,
 | |
| 				dup: false,
 | |
| 				topic: null,
 | |
| 				payload: null,
 | |
| 				subscriptions: [
 | |
| 					{ topic: "/ls_resp", qos: 0 }
 | |
| 				],
 | |
| 				messageId: msg_c++
 | |
| 			})
 | |
| 		);
 | |
| 		
 | |
| 		//
 | |
| 		// @FUNCTION
 | |
| 		// GET FRIEND LIST
 | |
| 		//
 | |
| 		/*
 | |
| 		await ws.send(
 | |
| 			mqtt.generate({
 | |
| 				cmd: "publish",
 | |
| 				retain: false,
 | |
| 				qos: 1,
 | |
| 				dup: false,
 | |
| 				topic: "/ls_req",
 | |
| 				messageId: msg_c++,
 | |
| 				payload: JSON.stringify({
 | |
| 					app_id: appID.toString(),
 | |
| 					payload: JSON.stringify({
 | |
| 						epoch_id: 7303517515494497649,
 | |
| 						tasks: [
 | |
| 							{
 | |
| 								failure_count: null,
 | |
| 								label: "452",
 | |
| 								payload: JSON.stringify({ limit: 100 }),
 | |
| 								queue_name: JSON.stringify(["search_contacts", Date.now().toString()]),
 | |
| 								task_id: task_id++
 | |
| 							}
 | |
| 						],
 | |
| 						version_id: version
 | |
| 					}),					
 | |
| 					request_id: 21,
 | |
| 					type: 3
 | |
| 				})
 | |
| 			})
 | |
| 		);*/
 | |
| 		
 | |
| 		//
 | |
| 		// @FUNCTION
 | |
| 		// RESOLVE USERID TO USERNAME
 | |
| 		//
 | |
| 		/*
 | |
| 		await ws.send(
 | |
| 			mqtt.generate({
 | |
| 				cmd: "publish",
 | |
| 				retain: false,
 | |
| 				qos: 1,
 | |
| 				dup: false,
 | |
| 				topic: "/ls_req",
 | |
| 				payload: JSON.stringify({
 | |
| 					app_id: appID.toString(),
 | |
| 					payload: JSON.stringify({ // yeah.. we need to re-json it
 | |
| 						epoch_id: 7302231049254668045,
 | |
| 						tasks: [
 | |
| 							{
 | |
| 								failure_count: null,
 | |
| 								label: "207",
 | |
| 								payload: JSON.stringify({ // AGAIN!!
 | |
| 									contact_id: 0
 | |
| 								}),
 | |
| 								queue_name: "cpq_v2",
 | |
| 								task_id: task_id++
 | |
| 							},
 | |
| 							{
 | |
| 								failure_count: null,
 | |
| 								label: "207",
 | |
| 								payload: JSON.stringify({ // AGAIN!!
 | |
| 									contact_id: 0
 | |
| 								}),
 | |
| 								queue_name: "cpq_v2",
 | |
| 								task_id: task_id++
 | |
| 							}
 | |
| 						],
 | |
| 						version_id: version
 | |
| 					}),
 | |
| 					request_id: 4,
 | |
| 					type: 3
 | |
| 				}),
 | |
| 				messageId: msg_c++
 | |
| 			})
 | |
| 		);*/
 | |
| 		
 | |
| 		//
 | |
| 		// @FUNCTION
 | |
| 		// send a message by thread ID
 | |
| 		//
 | |
| 		/*
 | |
| 		await ws.send(
 | |
| 			mqtt.generate({
 | |
| 				cmd: "publish",
 | |
| 				retain: false,
 | |
| 				qos: 1,
 | |
| 				dup: false,
 | |
| 				topic: "/ls_req",
 | |
| 				messageId: msg_c++,
 | |
| 				payload: JSON.stringify({
 | |
| 					app_id: appID.toString(),
 | |
| 					payload: JSON.stringify({
 | |
| 						epoch_id: parseInt(make_otid()),
 | |
| 						tasks: [
 | |
| 							{
 | |
| 								failure_count: null,
 | |
| 								label: "46",
 | |
| 								payload: JSON.stringify({
 | |
| 									thread_id: 0,
 | |
| 									otid: make_otid(),
 | |
| 									source: 65537,
 | |
| 									send_type: 1,
 | |
| 									sync_group: 1,
 | |
| 									mark_thread_read: 1,
 | |
| 									text: "https://lolcat.ca",
 | |
| 									initiating_source: 1,
 | |
| 									skip_url_preview_gen: 0,
 | |
| 									text_has_links: 0,
 | |
| 									multitab_env: 0
 | |
| 								}),
 | |
| 								queue_name: "0",
 | |
| 								task_id: task_id++
 | |
| 							},
 | |
| 							{ // optional garbage
 | |
| 								failure_count: null,
 | |
| 								label: "21",
 | |
| 								payload: JSON.stringify({
 | |
| 									thread_id: 0,
 | |
| 									last_read_watermark_ts: Date.now(),
 | |
| 									sync_group: 1
 | |
| 								}),
 | |
| 								queue_name: "0",
 | |
| 								task_id: task_id++
 | |
| 							}
 | |
| 						],
 | |
| 						version_id: version,
 | |
| 						data_trace_id: null
 | |
| 					}),					
 | |
| 					request_id: msg_c,
 | |
| 					type: 3
 | |
| 				}),
 | |
| 			})
 | |
| 		);*/
 | |
| 		
 | |
| 		// broken shit
 | |
| 		/*
 | |
| 		await ws.send(
 | |
| 			mqtt.generate({
 | |
| 				cmd: "publish",
 | |
| 				retain: false,
 | |
| 				qos: 1,
 | |
| 				dup: false,
 | |
| 				topic: "/ls_req",
 | |
| 				messageId: msg_c++,
 | |
| 				payload: JSON.stringify({
 | |
| 					app_id: appID.toString(),
 | |
| 					payload: JSON.stringify({
 | |
| 						epoch_id: parseInt(make_otid()),
 | |
| 						tasks: [
 | |
| 							{
 | |
| 								failure_count: null,
 | |
| 								label: "145",
 | |
| 								payload: JSON.stringify({
 | |
| 									is_after: 0,
 | |
| 									parent_thread_key: -12,
 | |
| 									reference_thread_key: 0,
 | |
| 									reference_activity_timestamp: 9999999999999,
 | |
| 									additional_pages_to_fetch: 0,
 | |
| 									cursor: null,
 | |
| 									messaging_tag: null,
 | |
| 									sync_group: 1
 | |
| 								}),
 | |
| 								queue_name: "trq",
 | |
| 								task_id: task_id++
 | |
| 							},
 | |
| 							{
 | |
| 								failure_count: null,
 | |
| 								label: "145",
 | |
| 								payload: JSON.stringify({
 | |
| 									is_after: 0,
 | |
| 									parent_thread_key: -12,
 | |
| 									reference_thread_key: 0,
 | |
| 									reference_activity_timestamp: 9999999999999,
 | |
| 									additional_pages_to_fetch: 0,
 | |
| 									messaging_tag: null,
 | |
| 									sync_group: 95
 | |
| 								}),
 | |
| 								queue_name: "trq",
 | |
| 								task_id: task_id++
 | |
| 							}
 | |
| 						],
 | |
| 						version_id: version
 | |
| 					}),
 | |
| 					request_id: msg_c,
 | |
| 					type: 3
 | |
| 				})
 | |
| 			})
 | |
| 		);*/
 | |
| 	});
 | |
| 	
 | |
| 	ws.on("message", function(message){
 | |
| 		/*
 | |
| 		//
 | |
| 		// Handle message acknowledge packet
 | |
| 		//
 | |
| 		if(
 | |
| 			conn_open === false &&
 | |
| 			message.equals(Buffer.from([0x20, 0x02, 0x00, 0x00]))
 | |
| 		){
 | |
| 			
 | |
| 			conn_open = true;
 | |
| 			console.log("(ws-" + ident + ") FB ack");
 | |
| 			return;
 | |
| 		}*/
 | |
| 		
 | |
| 		console.log(message.toString("hex"));
 | |
| 		//console.log(message);
 | |
| 	});
 | |
| 	
 | |
| 	ws.on("error", function(error){
 | |
| 		
 | |
| 		console.log("(ws-" + ident + ") Error: ", error);
 | |
| 	});
 | |
| 	
 | |
| 	ws.on("close", function(){
 | |
| 		
 | |
| 		console.log("(ws-" + ident + ") Closed");
 | |
| 	});
 | |
| }
 |