var log = require("../lib/log"); var utils = require("./utils"); var fs = require("fs"); var globalOptions = global.mira.config.facebookAPIsOptions; function buildAPIs(body, jar, whiteID, proxy, loginCount) { var infoCookies = jar .getCookies("https://www.facebook.com") .reduce(function (form, cookies) { var [name, value] = cookies.cookieString().split("="); form[name] = value; return form; }, {}); if (!infoCookies.i_user && !infoCookies.c_user) { log.warn("facebook.login.notUser"); if (globalOptions.forceLogin) { log.warn("facebook.relogin.force"); return Login(false, loginCount += 1); } else process.exit(1); } var userID = whiteID === infoCookies.i_user ? infoCookies.i_user : infoCookies.c_user; log.info("facebook.login.user", userID); var clientID = (Math.random() * 2147483648 | 0).toString(16); var apis = { getAppState: function getAppState() { return jar .getCookies("https://www.facebook.com") .concat(jar.getCookies("https://www.messenger.com")); } } var endpoint, region, syncToken; var endpointExec = /"appID":219994525426954,"endpoint":"(.+?)"/g.exec(body); if (endpointExec) { endpoint = endpointExec[1].replace(/\\\//g, "/"); region = new URL(endpoint).searchParams.get("region").toUpperCase(); log.info("facebook.login.region", region); } else log.warn("facebook.login.notRegion"); var ctx = { userID, region, endpoint, clientID, jar, get globalOptions() { return global.mira.config.facebookAPIsOptions; }, isLogin: true, lastSeqID: null, clientMutationID: 0, proxy } var http = utils.makeDefaults(body, userID, ctx); fs.readdirSync(__dirname + "/lib") .filter(item => item.endsWith(".js")) .map(function (item) { apis[item.replace(".js", "")] = require("./lib/" + item)(http, apis, ctx); }); log.info("facebook.apis", Object.keys(apis).length); global.mira.apis = apis; var checkLogin = setInterval(function () { if (ctx.isLogin) return; log.warn("facebook.login.logout"); if (globalOptions.autoReconnect) { log.warn("facebook.login.reconnect"); clearInterval(checkLogin); return Login(false, loginCount += 1); } }, 5000); return utils .post("https://www.facebook.com/v1.0/dialog/oauth/confirm", ctx.jar, { fb_dtsg: /\["DTSGInitData",\[],{"token":"(\S+)","async_get_token"/g.exec(body)[1], app_id: "124024574287414", redirect_uri: "fbconnect://success", display: "popup", return_format: "access_token", }) .then(function (res) { var body = res.body; var token = body.match(/access_token=(.+?)&/); if (token && token[1]) { ctx.token = token[1]; log.info("facebook.access.token", token[1]); } else throw new Error("Token is undefined."); }) .catch(function (error) { log.warn("facebook.access.error", error.message); console.log(error); }); } async function makeLogin(email, password, proxy) { var Browser; var Pup = require("puppeteer"); var Proxy = utils.parseProxy(proxy); if (Proxy && Proxy.length > 0) { Browser = await Pup.launch({ headless: true, args: ["--proxy-server=" + proxy] }); } else Browser = await Pup.launch({ headless: false }); var Page = await Browser.newPage(); if (Proxy && Proxy[0] && Proxy[1]) await Page.authenticate({ username: Proxy[0], password: Proxy[1] }); await Page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"); await Page.goto("https://www.facebook.com"); await Page.type("input[name=\"email\"]", email); await Page.type("input[name=\"pass\"]", password); await Page.click("button[name=\"login\"]"); var waitForLoad = Page.waitForNavigation({ waitUntil: "networkidle0" }); await new Promise(resolve => setTimeout(resolve, 5000)); var currentUrl = Page.url(); if (currentUrl.indexOf("/two_step_verification/two_factor/") > -1 || currentUrl.indexOf("/checkpoint/465803052217681") > -1) { log.warn("facebook.login.checkpoint"); var timeoutCheckpoint = setTimeout(function () { log.warn("facebook.login.missTimeCheckpoint"); process.exit(1); }, 2 * 60 * 1000); if (await Page.evaluate(_ => document.querySelectorAll("input").length) === 1) { async function waitForCheckpointSMS(length) { var NotChangeURL = _ => currentUrl === Page.url(); var ReClick = _ => Page.click("span[class=\"x1lliihq x193iq5w x6ikm8r x10wlt62 xlyipyv xuxw1ft\"]"); var GetCodeSMS = _ => log.input("facebook.access.codeSMS", "yellow", 60 * 1000); var EnterCodeSMS = SMS => length === 0 ? Page.type("input[dir=\"ltr\"", SMS) : Page.evaluate(SMS => { var input = document.querySelector("input[dir=\"ltr\""); if (input) { input.value = SMS; input.dispatchEvent(new Event("input", { bubbles: true })); } }, SMS); if (length > 2) throw new Error("Cant Authenticated With CodeSMS."); var SMS = await GetCodeSMS(); if (SMS) { await EnterCodeSMS(SMS); await ReClick(); await new Promise(resolve => setTimeout(resolve, 2000)); if (NotChangeURL()) { log.warn("facebook.access.wrongSMS"); return waitForCheckpointSMS(length + 1); } } else throw new Error("CodeSMS is undefined."); } await waitForCheckpointSMS(0); } else { var intervalCheckURL; var waitForCheckpoint = new Promise(resolve => { intervalCheckURL = setInterval(function () { var currentURL = Page.url(); if (currentURL.indexOf("/two_factor/remember_browser/") > -1) resolve(); }, 5000); }); await waitForCheckpoint; clearInterval(intervalCheckURL); } clearTimeout(timeoutCheckpoint); await Page.click("div[class=\"x1n2onr6 x1ja2u2z x78zum5 x2lah0s xl56j7k x6s0dn4 xozqiw3 x1q0g3np x9f619 xi112ho x17zwfj4 x585lrc x1403ito x1qhmfi1 x1s9qjmn x39innc x7gj0x1 x1mpseq2 x13fuv20 xu3j5b3 x1q0q8m5 x26u7qi x178xt8z xm81vs4 xso031l xy80clv x1fq8qgq x1ghtduv x1oktzhs\""); } if (currentUrl.indexOf("/two_step_verification/authentication/") > -1) { log.warn("facebook.login.checkpointImage"); process.exit(1); } if (currentUrl.indexOf("/login/") > -1) { log.warn("facebook.login.wrong"); process.exit(1); } await waitForLoad; var appState = await Page.cookies(); await Browser.close(); return appState; } function LoginHelper(appState, email, password, proxy, whiteID, loginCount) { if (appState) { var jar = utils.getJar(); if (typeof appState === "string") { appState = decodeURIComponent(appState).split("; ").map(item => { var [key, value] = item.split("="); return { key, value, domain: "facebook.com", path: "/", expires: new Date().getTime() + 1000 * 60 * 60 * 24 * 365 } }); } appState.map(item => { var string = [ (item.key || item.name) + "=" + item.value, "expires=" + item.expires, "domain=" + item.domain, "path=" + item.path ].join("; "); jar.setCookie(utils.cookie(string), "http://" + item.domain); }); return utils .get("https://www.facebook.com", jar, null, null, { noRef: true }) .then(function (res) { var reg = /]+>/; var redirect = reg.exec(res.body); if (redirect && redirect[1]) { return utils .get(redirect[1], jar); } return res; }) .then(res => buildAPIs(res.body, jar, whiteID, proxy, loginCount)) .catch(function (error) { log.error("facebook.login.error"); console.log(error); process.exit(1); }); } else if (email && email.length > 0 && password && password.length > 0) { return makeLogin(email, password, proxy) .then(fbState => LoginHelper(fbState, email, password, proxy, whiteID, loginCount)); } else { log.warn("facebook.missing"); process.exit(1); } } function Login(firstLogin = true, loginCount = 1) { if (loginCount >= 3) { log.warn("facebook.relogin.error"); process.exit(1); } var appState; var { email, password, cookies, facebookState, proxy, whiteID } = global.mira.config.facebookAccountOptions; var path = __dirname + "/../../" + facebookState; if (facebookState && facebookState.length > 0 && fs.existsSync(path)) appState = require(path); else if (cookies && cookies.length > 0) appState = cookies; if (proxy && proxy.length > 0) utils.setProxy(proxy); proxy = proxy || ""; appState = firstLogin ? appState : null; return LoginHelper(appState, email, password, proxy, whiteID, loginCount); } module.exports = Login;