Trouble Logging In To Google with Headless Chrome / Puppeteer - javascript

I'm trying to automate certain tasks for work. We have a portal that requires you to sign in through Google. I've created a Puppeteer instance that navigates to the Google auth page, types in my email and password, then stores the cookies so I can navigate through and manipulate the portal.
This works perfectly on my local environment, but I've deployed it to Heroku and Google adds a sign in challenge. After entering the password, I'm given the 'Verify it's you' page that says 'This device isn't recognized' and asks me to complete 2-FA auth.
I know I can't turn off 2-FA, so what would be the best way to bypass this?
Alternatively, is there an easier way to log in to a website guarded by Google auth and store the session cookies?
Here's my puppeteer code, any help would be much appreciated:
async function getCookies() {
const browser = await puppeteer.launch({
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-gpu'
]
})
const page = await browser.newPage()
await page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36')
await page.goto(process.env.URL)
await page.waitForSelector('#identifierId')
await page.type('#identifierId', process.env.EMAIL, { delay: 5 })
await page.click('#identifierNext')
await page.waitForSelector('#password input[type="password"]', { visible: true });
await page.type('#password input[type="password"]', process.env.PASS, { delay: 5 })
await page.click('#passwordNext')
await page.waitFor(3000)
const cookies = await page.cookies()
await browser.close()
return cookies
}

Not possible I am afraid and not the answer you want.
I know I can't turn off 2-FA, so what would be the best way to bypass
this?`
If it was possible to bypass then it kinda opens the door for hackers as Two-factor authentication works as an extra step in the process, a second security layer, that will reconfirm your identity. Its purpose is to make attackers' life harder and reduce fraud risks!

I would have added an Android app in the mix too. You can set up the 2FA with SMS codes and an Android app with SMS read permission can read the SMS and connect with a backend.
The backend can send push message, probably using Firebase Cloud Messaging to the local Node.js instance where the headless Chrome is running to input it in the 2FA screen.
I don't think there's any other way to do it. Although I would recommend not doing it, since it may open some backdoor for security issues.

I is actually possible using Twilio API within Puppeteer to programatically receive the SMS code. You will have to setup a special Google account for this to work with the Twilio number as mobile phone OR change your current Google account primary mobile number for the Twilio number, and use your regular number as a secondary contact in your Google account info.

My working solution (needs some refactoring)
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false, // for debugging only
ignoreHTTPSErrors: true // This happens when you use a self signed certificate locally
})
const page = await browser.newPage()
await page.setViewport({ width: 1280, height: 800 })
await page.goto('https://myawesomesystem/loginFrm01')
const navigationPromise = page.waitForNavigation()
// Clicks on the login button
const googleLoginButtonSelector = 'body > section > ... > div'
await page.waitForSelector( googleLoginButtonSelector )
await page.click( googleLoginButtonSelector )
// wait for the google oauth page to open
const googleOAuthTarget = await browser.waitForTarget( target => {
// console.log( target.url() ); // debugging
return target.url().indexOf('https://accounts.google.com/signin/oauth/identifier') !== -1
})
const googleOAuthPage = await googleOAuthTarget.page()
await googleOAuthPage.waitForSelector('#identifierId')
await googleOAuthPage.type('#identifierId', CRED.user, { delay: 5 } )
await googleOAuthPage.click('#identifierNext')
await googleOAuthPage.waitForSelector('input[type="password"]', { visible: true })
await googleOAuthPage.type('input[type="password"]', CRED.pass )
await googleOAuthPage.waitForSelector('#passwordNext', { visible: true })
await googleOAuthPage.click('#passwordNext')
await navigationPromise
// HERE:
// the user has been authenticated
// or login window was closed
// or whatever else, please check
await browser.close()
})()

Related

Puppeteer React/NodeJS form submissions automation with a database

So I'm trying to test a recaptcha implementation by writing my own spambot using React and Puppeteer. I got the script ready to do a single form submission after executing the script, but what I'm actually hoping for is to have my script loop through a database with form submission details, and then reiterate every row of the csv file until it's depleted the database.
So far I have the following script:
const puppeteer = require('puppeteer');
// Server Authentication
const username = "username";
const password = 'password';
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Pass server side authentication needed for website when accessing url
await page.authenticate({ username, password});
// Load page with form and take screenshot to confirm page has been reached
await page.goto('https://pagewiththeformimtryingtosubmit.com');
await page.screenshot({path: 'example2.png'});
// Click away cookie pop-up banner, take screenshot after
page.keyboard.press('Escape');
await page.screenshot({path: 'cookiebotcleared.png', fullPage: true});
// Fill in first form fields, screenshot to see if it works
await page.type('#firstname', 'Somename', {delay:500});
await page.type('#lastname', 'Somelastname', {delay:500});
await page.type('#telephone', '123456789', {delay:500});
await page.type('#email_address', 'somename.lastname#gmail.com', {delay:500});
await page.type('#password', 'Chooseapassword', {delay:500});
await page.type('#password-confirmation', 'Chooseapassword', {delay:500});
await page.click('.consent', {delay:500});
await page.click('.submit', {delay: 500});
// Take screenshot after form submission to see if it has worked
await page.screenshot({path: 'formfillout.png', fullPage: true}, {delay: 500});
await browser.close();
})();
What I'm trying to do, is take a CSV with all the data I've randomized, and then have this script run but take elements from the csv for the various form inputs and loop that over.
I've tried working with CSVToJSON in order to process the csv database into objects that I should then be able to use in my code:
const CSVToJSON = require('csvtojson')
CSVToJSON().fromFile('formbot_database.csv')
.then(users => {
console.log(users);
console.log(users.firstname);
}).catch(err => {
console.log(err);
});
Here's where my first troubles start: I want to take the row headers of my database to map them to variables, so I can process those variables within my script. I first tried users.firstname, but when I console log that, it gives me undefined.
If anyone has any suggestion on how I can work this through, that'd be great. I've tried visiting multiple resources but can't figure it out I'm afraid.
Thanks in advance!

trying to sign into a bank account with headless browser

I'm trying to use a puppeteer to access my bank in this scenario capital one. Although when I try I get "There was an issue accessing your account, please try again, if you continue to see this message, give us a call so we can help." I'm not too surprised that they don't appreciate me trying to log in with a headless browser.
this is the code I'm using
async function credit(creditcost) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://www.capitalone.com/');
await page.mouse.click(167, 121, {button: 'left'})
await page.keyboard.type('username')
await page.mouse.click(431, 123, {button: 'left'})
await page.keyboard.type('password')
await page.mouse.click(672, 121, {button: 'left'})
await delay(5000);
await page.screenshot({ path: './test/example.png' });
await browser.close();
}
Is there any way to get around this issue, or a possibly better option? I'm trying to get balances and transfer funds.
I'm not sure if that is the smartest/safest way to do this, but remember to make sure that your credentials are safe. The first thing is that the website does probably detect the headless browser.
You may want to try puppeteer-extra, (the Stealth package) when using headless mode.
Next thing - since you're using headless mode, you may want to click the elements using their selectors or id's instead of using mouse coordinates. page.$() or page.waitForSelector() should suffice.
More about puppeteer-extra-plugin-stealth here.

Signing into Office with Puppeteer not working?

Whenever I try to use Puppeteer to sign into an Office account, it always says to "Enter a valid email address" on the logging in site (and I know the email is valid, I have tested it). I looked through some other questions, and one of them mentioned that they might have login preventions for Puppeteer, Selenium, etc, though I am not sure. I am able to login if I do it manually.
Here's the code that handles all of that:
var email = "myemail#outlook.com"
await page.evaluate((em)=>{
document.querySelector(`[type="email"]`).value = em;
},email);
await page.screenshot({
path:"./email_input.png"
})
await page.waitForTimeout(1000);
await page.evaluate((em)=>{
var interval = setInterval(() => {
if(document.querySelector(`[type="email"]`).value === em){
document.querySelector(`[type="submit"]`).dispatchEvent(new Event('click'));
clearInterval(interval);
}
});
},email);
await page.screenshot({
path:"./sign_in_email.png"
})
edit to ManuelMB's comment: It was just a check to make sure that the value was actually the email. It still doesn't work without it.

Playwright Javascript skip fill selector in Google Form

I use Playwright framework on JS to autofill unknow Google form (which means i dont know Xpath to specify the answer, i just know to question. In my situation, form ask about address, name, size, phone number).
const { webkit } = require('playwright');
const URL = 'https://forms.gle/B4r6qZKdyxZCApTWA';
(async () => {
const browser = await webkit.launch({ headless: false });
const page = await browser.newPage();
await page.goto(URL);
await page.fill('input:below(:has-text("Họ và tên"))','name');
await page.fill('input:below(:has-text("Số điện thoại"))','phone number');
await page.fill('input:below(:has-text("Địa chỉ"))','Address');
await page.fill('input:below(:has-text("CMND"))','id');
await page.fill('input:below(:has-text("Game"))','LOL');
await page.pause();
await browser.close();
})();
URL: https://forms.gle/B4r6qZKdyxZCApTWA
The name and number field is fine but in the address field, things get mess up. It skip and jump to the id field and fill 'address'->'LOL'->'id'
The answer field of Google Form has 2 kind: input and textarea. I just need to change it. But any better way to do more "general" to fit that kind of GForm?

Testcafe tests crash after login (corporate website redirection fails)

I am having this issue since a couple of days. I started using testcafe but i can't login properly. Here is my first test :
const role = Role('https://mywebsite.com', async t => {
await t.typeText(authenticationPage.loginInputBox, user.login)
.typeText(authenticationPage.passwordInputBox, user.password)
.click(authenticationPage.signInButton);
}, { preserveUrl: true });
export default async () => {
await navigate_as();
};
async function navigate_as() {
await t
.setTestSpeed(0.1)
.useRole(role)
.navigateTo("https://mywebsite.com/#/dashboard");
await t
.click(portfolioPage.navigateAs)
.typeText(portfolioPage.navigateAsInput, "John Doe")
.expect(portfolioPage.navigateAsAutocomplete.exists).notOk({timeout: 10000});
}
The problem is that the server usually redirects to the dashboard, but with testcafe after the first login redirection to the dashboard, it stays here 1 second and redirects to an error page. It says 502 bad gateway like below (so the tests crash after that) :
Is there anyone who had this problem and could tell me what's happening ? Is it something I can do with testcafe configuration to work around this ?
I am using last version of node (v10.4.1) and tried with IE, Firefox and Chrome, same result with tescafe (v0.18.6) (Windows 7 OS)
The code without using roles is the following, it gives the same result:
async function sign_in_with_sso() {
await t
.setTestSpeed(1)
.typeText(authenticationPage.loginInputBox, user.login)
.typeText(authenticationPage.passwordInputBox, user.password)
.click(authenticationPage.signInButton)
.expect(authenticationPage.formIsLoading.exists).notOk({timeout: 10000});
}
Thank you,

Categories