Skip to content

Instantly share code, notes, and snippets.

@ntkhang03
Last active December 23, 2024 06:48
Show Gist options
  • Save ntkhang03/005663cbbd0306555174f63d64c537db to your computer and use it in GitHub Desktop.
Save ntkhang03/005663cbbd0306555174f63d64c537db to your computer and use it in GitHub Desktop.
Login Facebook mbasic
const cheerio = require("cheerio");
let totp = require("totp-generator"); // version "totp-generator": "^0.0.13",
// check is function or not
if (typeof totp !== "function") {
totp = function (secretKey) {
return totp.TOTP.generate(secretKey).otp;
};
}
const requestPromise = require("request-promise");
const targetCookie = "https://mbasic.facebook.com/";
const headers = {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "vi,en;q=0.9,en-GB;q=0.8,en-US;q=0.7",
"sec-ch-ua": "\"\"",
"sec-ch-ua-mobile": "?1",
"sec-ch-ua-platform": "\"\"",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"origin": "https://mbasic.facebook.com",
"user-agent": "Mozilla/5.0 (Linux; Android 12; M2102J20SG) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Mobile Safari/537.36"
};
async function loginMbasic({
email,
pass,
twoFactorSecretOrCode,
userAgent,
proxy,
maxTry = 3,
currentTry = 0
}) {
if (userAgent)
headers['user-agent'] = userAgent;
const defaultOptions = {
headers,
// resolveWithFullResponse: true,
simple: false,
jar: true
};
if (proxy) {
defaultOptions.proxy = proxy;
}
const _request = requestPromise.defaults(defaultOptions);
const request = (options) => new Promise((resolve, reject) => {
_request(options, (err, res) => {
if (err)
return reject(err);
resolve(res);
});
});
const jar = requestPromise.jar();
jar.setCookie("locale=en_US;", targetCookie);
const resLoginPage = await request({
method: "GET",
url: "https://mbasic.facebook.com/",
jar: jar
});
const $ = cheerio.load(resLoginPage.body);
const formLoginInput = [
"li", "try_number",
"lsd", "jazoest", "m_ts",
"unrecognized_tries", "bi_xrwh"
].reduce((acc, key) => {
acc[key] = $(`input[name='${key}']`).val();
return acc;
}, {});
formLoginInput.login = $("#login_form input[name='login']").val();
formLoginInput.pass = pass;
formLoginInput.email = email;
const formLoginAction = $("#login_form").attr("action");
const resPostLogin = await request({
method: 'POST',
url: "https://mbasic.facebook.com" + formLoginAction,
jar: jar,
form: formLoginInput
});
const newLocation = resPostLogin.headers.location;
let lastResponse = resPostLogin;
if (newLocation) {
const resNewLocation = await request({
method: 'GET',
url: newLocation,
jar: jar
});
if (
resNewLocation.body.includes("facebook_login_pw_error")
|| resNewLocation.body.includes("The password that you entered is incorrect")
) {
const error = new Error("Password is incorrect");
error.name = "PASSWORD_INCORRECT";
throw error;
}
// Sorry, something went wrong.
if (resNewLocation.body.includes("Sorry, something went wrong.")) {
if (currentTry >= maxTry) {
const error = new Error("Sorry, something went wrong. Retry login...");
error.name = "MAX_TRY_REACHED";
throw error;
}
return loginMbasic({
email,
pass,
twoFactorSecretOrCode,
userAgent,
proxy,
maxTry,
currentTry: currentTry + 1
});
}
// Have a code sent to your email address
if (resNewLocation.body.includes("Have a code sent to your email address")) {
const error = new Error("Have a code sent to your email address");
error.name = "CODE_SENT_TO_EMAIL";
throw error;
}
// check if page has 2FA code input
// name="approvals_code"
const $ = cheerio.load(resNewLocation.body);
const approvalsCodeInput = $("input[name='approvals_code']");
if (approvalsCodeInput.length > 0) {
if (!twoFactorSecretOrCode) {
const error = new Error("2FA code is required but not provided");
error.name = "2FA_CODE_REQUIRED";
}
let otpCode;
if (twoFactorSecretOrCode.length >= 32) {
twoFactorSecretOrCode = twoFactorSecretOrCode.replace(/\s/g, '');
otpCode = totp(twoFactorSecretOrCode);
}
else {
otpCode = twoFactorSecretOrCode;
}
const form2FAInput = [
"fb_dtsg", "jazoest", "checkpoint_data",
"codes_submitted", "submit[Submit Code]",
"nh"
].reduce((acc, key) => {
acc[key] = $(`input[name='${key}']`).val();
return acc;
}, {});
form2FAInput.approvals_code = otpCode;
const form2FAAction = $("form[method='post']").first().attr("action");
const resPost2FA = await request({
method: 'POST',
url: "https://mbasic.facebook.com" + form2FAAction,
jar: jar,
form: form2FAInput
});
lastResponse = resPost2FA;
}
else if (resNewLocation.headers.location?.match(/checkpoint\/\d+\//)) {
const error = new Error("Your account is locked, please verify your identity");
error.name = "CHECKPOINT_REQUIRED";
error.checkpointUrl = resNewLocation.headers.location;
}
else {
const responseUri = resNewLocation.request.uri.href;
if (responseUri.match(/checkpoint\/\d+\//)) {
const error = new Error("Your account is locked, please verify your identity");
error.name = "CHECKPOINT_REQUIRED";
error.checkpointUrl = responseUri;
error.cookies = jar.getCookies(targetCookie);
throw error;
}
}
}
// eslint-disable-next-line no-constant-condition
while (true) {
const $ = cheerio.load(lastResponse.body);
const submitContinueButton = $("input[name='submit[Continue]']");
const submitThisWasMeButton = $("input[name='submit[This was me]']");
if (
submitContinueButton.length > 0
|| submitThisWasMeButton.length > 0
) {
const firstFormPost = $("form[method='post']").first();
const formCheckpointInput = {};
// find input not in another form
const formInputs = firstFormPost.find("input").toArray();
// if input is radio, then get value of checked radio
formInputs.forEach(input => {
const $input = $(input);
const name = $input.attr("name");
const type = $input.attr("type");
if (type === "radio") {
const checkedRadio = $(`input[name='${name}']:checked`);
if (checkedRadio.length > 0) {
formCheckpointInput[name] = checkedRadio.val();
}
}
else {
formCheckpointInput[name] = $input.val();
}
});
const keysNotSubmit = [
"submit[logout-button-with-confirm]",
"submit[This wasn't me]",
"undefined"
];
for (const key of keysNotSubmit) {
delete formCheckpointInput[key];
}
const resPostCheckpoint = await request({
method: 'POST',
url: "https://mbasic.facebook.com" + firstFormPost.attr("action"),
jar: jar,
form: formCheckpointInput
});
lastResponse = resPostCheckpoint;
}
else {
break;
}
}
const cookies = jar.getCookies(targetCookie);
const cookiesString = cookies.map((cookie) => {
return `${cookie.key}=${cookie.value}`;
});
// use this cookie to require home page
const cookieString = cookiesString.join("; ");
const resHomePage = await request({
method: "GET",
url: "https://mbasic.facebook.com/me",
headers: {
cookie: cookieString
}
});
const responseUri = resHomePage.request.uri.href;
if (responseUri.match(/checkpoint\/\d+\//)) {
const error = new Error("Your account is locked, please verify your identity");
error.name = "CHECKPOINT_REQUIRED";
error.checkpointUrl = responseUri;
throw error;
}
return cookies.map(e => ({
name: e.key,
value: e.value,
domain: "facebook.com",
path: "/",
hostOnly: false,
creation: new Date().toISOString(),
lastAccessed: new Date().toISOString()
}));
}
module.exports = loginMbasic;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment