Last active
December 23, 2024 06:48
-
-
Save ntkhang03/005663cbbd0306555174f63d64c537db to your computer and use it in GitHub Desktop.
Login Facebook mbasic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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