1245 lines
50 KiB
JavaScript
1245 lines
50 KiB
JavaScript
const {SolveCaptcha, TWO_CAPTCHA_CONNECTION_FAILED} = require("./SolveCaptcha");
|
|
const ReserveResultPojo = require("../models/ReserveResultPojo");
|
|
const appointmentLogger = require("../utiles/LoggerUtils")
|
|
const OCRResult = require("../models/OCRResult");
|
|
const PublishType = require("../models/PublishType");
|
|
const puppeteer = require('puppeteer');
|
|
const GeoCaptchaSolver = require("./GeoCaptchaSolver");
|
|
const SlidingCaptchaSolver = require("./SlidingCaptchaSolver");
|
|
const OCRChecker = require("./OCRChecker");
|
|
const {exec} = require("child_process");
|
|
const {openUrlWithAdb} = require("../utiles/CmdUtils");
|
|
// const RDV_URL = "http://192.168.0.44:8000/test_appointment.html"
|
|
const RDV_URL = "https://rendezvousparis.hermes.com/client/register";
|
|
const BLANK_URL = "about:blank"
|
|
const ERROR_CAPTCHA_UNSOLVABLE = "ERROR_CAPTCHA_UNSOLVABLE";
|
|
|
|
const COUNTRY_ID = "#phone_country"
|
|
const PHONE_NUMBER = "#phone_number"
|
|
const EMAIL_ID = "#email"
|
|
const PREFER_STORE = "#prefer"
|
|
const LAST_NAME = "#surname"
|
|
const FIRST_NAME = "#name"
|
|
const CGU_ID = "#cgu"
|
|
const PROCESSING_ID = "#processing"
|
|
const PASSPORT_ID = "#passport_id"
|
|
const CAPTCHA_CONTAINER = "#captcha-container";
|
|
|
|
const TIME_OUT = 60 * 1000 * 4//4 mins
|
|
|
|
const EMPTY_RESPONSE_ERROR = "ERR_EMPTY_RESPONSE"
|
|
const MESSAGE_URL_VALIDATION_FR = "Nous avons envoyé un lien par e-mail."
|
|
const MESSAGE_URL_VALIDATION_EN = "Please click on the link we sent by email"
|
|
const REGEX_RDV_URL = "https:\/\/rendezvousparis\.hermes\.com\/client\/register\/[A-Z0-9]+"
|
|
const DEFAULT_STORE = 'faubourg';
|
|
const timeout = (prom, time) =>
|
|
Promise.race([prom, new Promise((_r, rej) => setTimeout(rej, time))]);
|
|
|
|
function delay(delayInMs) {
|
|
return new Promise(resolve => {
|
|
setTimeout(() => {
|
|
resolve(2);
|
|
}, delayInMs);
|
|
});
|
|
}
|
|
|
|
function getRandom() {
|
|
return Math.floor(Math.random() * 3);
|
|
}
|
|
|
|
function getRandomWaitTime() {
|
|
return getRandom() * 1000
|
|
}
|
|
|
|
function log(message) {
|
|
appointmentLogger.log({level: "info", message: message})
|
|
}
|
|
|
|
async function clearApp(device, packageName) {
|
|
let cmd = `adb -s ${device.serial()} shell pm clear ${packageName}`
|
|
logWithDevice("cmd is " + cmd, device)
|
|
await exec(cmd);
|
|
}
|
|
|
|
async function exceutShellCmd(device, cmdToExecut) {
|
|
let cmd = `adb -s ${device.serial()} shell ${cmdToExecut}`
|
|
logWithDevice("cmd is " + cmd, device)
|
|
await exec(cmd);
|
|
}
|
|
|
|
function logWithDevice(message, device) {
|
|
appointmentLogger.log({level: "info", message: device.model() + ":" + device.serial() + ":" + message})
|
|
}
|
|
|
|
class CommandorPage {
|
|
constructor(contact, device, mongoManager, selectedStore = DEFAULT_STORE, audioAnalyse = false, alertBeep = false, port = 9000) {
|
|
this.contact = contact;
|
|
this.device = device;
|
|
this.mongoManager = mongoManager;
|
|
this.selectedStore = selectedStore;
|
|
this.choosedStore = selectedStore;
|
|
this.port = port;
|
|
this.ocrChecker = new OCRChecker(this.device, this.contact);
|
|
this.browserPackageName = "com.brave.browser";
|
|
// this.browserPackageName = "com.android.chrome";
|
|
this.isFillingFields = false;
|
|
this.isTerminated = false;
|
|
this.cguChecked = false;
|
|
this.isNameInput = false;
|
|
this.isEmailFilled = false;
|
|
this.isCountryChoosen = false;
|
|
this.isPhoneInput = false;
|
|
this.firstStart = true;
|
|
}
|
|
|
|
async connect_to_browser(ocrResult) {
|
|
console.log("connect_to_browser() called");
|
|
if (this.browser === undefined) {
|
|
this.isTerminated = true
|
|
return
|
|
}
|
|
console.log("browser.isConnected: " + this.browser.isConnected());
|
|
if (!this.browser.isConnected()) {
|
|
this.browser = await puppeteer.connect({
|
|
browserWSEndpoint: "ws://127.0.0.1:" + this.port + "/devtools/browser",
|
|
headless: false, defaultViewport: null
|
|
})
|
|
}
|
|
let pages = await this.browser.pages();
|
|
// 0 is the last page
|
|
pages.forEach((currentPage) => {
|
|
let url = currentPage.url()
|
|
if (url.includes(RDV_URL)) {
|
|
this.page = currentPage
|
|
}
|
|
})
|
|
logWithDevice("pageUrl is " + this.page.url(), this.device)
|
|
// this.page = pages[pages.length - 1];
|
|
switch (ocrResult) {
|
|
case OCRResult.SUCCESS:
|
|
// get url and push to server
|
|
await this.push_message_to_queue(PublishType.SUCCESS)
|
|
break;
|
|
case OCRResult.RECAPTCHA_ERROR:
|
|
// get url and push to server
|
|
await this.fillFields()
|
|
break;
|
|
case OCRResult.SLIDING_CAPTCHA_REFRESH:
|
|
pages.forEach((currentPage) => {
|
|
currentPage.close()
|
|
})
|
|
break;
|
|
case OCRResult.TO_REFRESH:
|
|
logWithDevice("will reload page", this.device)
|
|
let cmd = "input swipe 382 682 382 1682"
|
|
logWithDevice("will send cmd:" + cmd, this.device)
|
|
this.device.shell(cmd);
|
|
await delay(3000);
|
|
await this.clickOnConfirmBtn();
|
|
await this.checkResultWithOcr();
|
|
break;
|
|
}
|
|
}
|
|
|
|
async checkIfSuccessful() {
|
|
let content = await this.page.content();
|
|
if (content.includes(MESSAGE_URL_VALIDATION_FR) || content.includes(MESSAGE_URL_VALIDATION_EN)) {
|
|
log("successful");
|
|
await this.push_message_to_queue(PublishType.SUCCESS);
|
|
return true;
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
async loadPage() {
|
|
logWithDevice(this.device.serial() + ":loadPage() called, with port:" + this.port, this.device);
|
|
try {
|
|
// let cmd = 'adb -s ' + device.serial() + " forward tcp:" + attributedPort + " localabstract:chrome_devtools_remote";
|
|
await exceutShellCmd(this.device, " forward tcp:" + this.port + " localabstract:chrome_devtools_remote")
|
|
await delay(1 * 1000);
|
|
// await this.startPage(this.device, this.browserPackageName + "/com.google.android.apps.chrome.Main")
|
|
await delay(4 * 1000);
|
|
} catch (e) {
|
|
console.log(e)
|
|
this.isTerminated = true;
|
|
}
|
|
// await this.acceptCookies();
|
|
await this.enableDisableAirPlanMode();
|
|
// await delay(10 * 1000);
|
|
await openUrlWithAdb(RDV_URL, this.device)
|
|
await delay(15000)
|
|
await this.checkResultWithOcr()
|
|
// await this.clickOnlineAppointment();
|
|
// } else {
|
|
// this.isTerminated = true;
|
|
// }
|
|
|
|
let cancel
|
|
const intervalTask = setInterval(async () => {
|
|
if (this.isTerminated) {
|
|
log(this.device.model() + ":request terminated, send cancel()");
|
|
try {
|
|
if (this.page !== undefined) {
|
|
await this.page.close()
|
|
}
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
this.disconnectBrowser();
|
|
clearInterval(intervalTask)
|
|
cancel()
|
|
} else {
|
|
}
|
|
}, 10 * 1000)//interval of 10 seconds
|
|
|
|
await new Promise(function (fulfill, reject) {
|
|
cancel = function () {
|
|
fulfill(Promise.resolve())
|
|
}
|
|
setTimeout(fulfill, TIME_OUT, 5)
|
|
}).then(log)
|
|
}
|
|
|
|
async clickOnlineAppointment() {
|
|
try {
|
|
logWithDevice("will click on rdv link", this.device);
|
|
await this.connectBrowserIfNecessary();
|
|
const [button] = await this.page.$x("//a[contains(., 'rendezvousparis')]");
|
|
console.log("button is " + button)
|
|
if (button) {
|
|
console.log("will click on the button")
|
|
try {
|
|
await button.click();
|
|
if (this.firstStart) {
|
|
this.disconnectBrowser()
|
|
}
|
|
await delay(2000)
|
|
await this.checkResultWithOcr();
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.log(e)
|
|
await this.checkResultWithOcr();
|
|
}
|
|
}
|
|
|
|
async acceptCookies() {
|
|
logWithDevice("will accept Cookies", this.device);
|
|
if (this.browser.isConnected() && !this.page.isClosed()) {
|
|
try {
|
|
await this.page.evaluate(() => {
|
|
let buttons = document.getElementsByTagName('button');
|
|
for (let i = 0; i < buttons.length; i++) {
|
|
let button = buttons[i];
|
|
let txt = button.textContent || button.innerText;
|
|
if (txt.includes("Tout accepter")) {
|
|
button.click()
|
|
}
|
|
console.log(txt);
|
|
}
|
|
})
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
async chooseCountry(page) {
|
|
logWithDevice("chooseCountry", this.device)
|
|
if (this.browser.isConnected() && !this.isTerminated) {
|
|
try {
|
|
if (!this.isCountryChoosen) {
|
|
// await page.focus(COUNTRY_ID);
|
|
// await delay(getRandomWaitTime())
|
|
// await page.click(COUNTRY_ID);
|
|
// await delay(getRandomWaitTime())
|
|
await page.select(COUNTRY_ID, 'FR');
|
|
await delay(getRandomWaitTime())
|
|
this.isCountryChoosen = true;
|
|
}
|
|
} catch (e) {
|
|
log(e);
|
|
this.isTerminated = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
async fillEmail(page) {
|
|
logWithDevice("fillEmail", this.device)
|
|
try {
|
|
if (this.browser.isConnected() && !this.isTerminated) {
|
|
if (!this.isEmailFilled) {
|
|
await page.focus(EMAIL_ID);
|
|
await delay(getRandomWaitTime())
|
|
console.log("will clear email field");
|
|
await page.evaluate((email) => {
|
|
let field = document.getElementById("email");
|
|
if (field) {
|
|
field.value = email
|
|
}
|
|
}, this.contact.mail)
|
|
// await page.evaluate(() => {
|
|
// let field = document.getElementById("email");
|
|
// if (field) {
|
|
// field.value = ""
|
|
// }
|
|
// })
|
|
// await delay(1000);
|
|
// await page.keyboard.type(this.contact.mail);
|
|
this.isEmailFilled = true;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
log(e)
|
|
}
|
|
}
|
|
|
|
async inputPhoneNumber(page) {
|
|
logWithDevice("inputPhoneNumber", this.device)
|
|
try {
|
|
if (this.browser.isConnected() && !this.isTerminated) {
|
|
if (!this.isPhoneInput) {
|
|
await page.focus(PHONE_NUMBER);
|
|
console.log("will clear phone_number field");
|
|
await page.evaluate((phone) => {
|
|
let field = document.getElementById("phone_number");
|
|
if (field) {
|
|
field.value = phone
|
|
}
|
|
}, "" + this.contact.phoneNumber)
|
|
// }, "0" + this.contact.phoneNumber)
|
|
// 如果需要显示键盘的话,使用下面方法
|
|
// await page.evaluate(() => {
|
|
// let field = document.getElementById("phone_number");
|
|
// if (field) {
|
|
// field.value = ""
|
|
// }
|
|
// })
|
|
// await delay(1000);
|
|
// await page.keyboard.type("0" + this.contact.phoneNumber);
|
|
this.isPhoneInput = true;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
log(e);
|
|
this.isTerminated = true;
|
|
}
|
|
|
|
}
|
|
|
|
async inputName(page) {
|
|
logWithDevice("inputName", this.device)
|
|
await delay(getRandomWaitTime());
|
|
try {
|
|
logWithDevice("input name called with this.browser.isConnected=" + this.browser.isConnected(), this.device)
|
|
logWithDevice("input name called with this.isNameInput=" + this.isNameInput, this.device)
|
|
if (this.browser.isConnected() && !this.isTerminated && !this.page.isClosed()) {
|
|
if (!this.isNameInput) {
|
|
await page.focus(LAST_NAME);
|
|
await delay(getRandomWaitTime());
|
|
console.log("will clear surname field");
|
|
await page.evaluate(() => {
|
|
let field = document.getElementById("surname");
|
|
if (field) {
|
|
field.value = ""
|
|
}
|
|
})
|
|
await delay(1000);
|
|
// await page.keyboard.type(this.contact.lastName);
|
|
await page.evaluate((lastName) => {
|
|
let field = document.getElementById("surname");
|
|
if (field) {
|
|
field.value = lastName
|
|
}
|
|
}, this.contact.lastName)
|
|
await page.focus(FIRST_NAME);
|
|
await delay(getRandomWaitTime());
|
|
// console.log("will clear name field");
|
|
await page.evaluate((firstName) => {
|
|
let field = document.getElementById("name");
|
|
if (field) {
|
|
field.value = firstName;
|
|
// field.value = ""
|
|
}
|
|
}, this.contact.firstName)
|
|
// await page.keyboard.type(this.contact.firstName);
|
|
this.isNameInput = true;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
logWithDevice("exception while inputting name", this.device)
|
|
console.log(e);
|
|
this.isTerminated = true
|
|
}
|
|
}
|
|
|
|
async getRawAppointmentInfo(page) {
|
|
let passportId = await page.evaluate(() => {
|
|
let field = document.getElementById("passport_id");
|
|
return field.value
|
|
})
|
|
|
|
let lastName = await page.evaluate(() => {
|
|
let field = document.getElementById("surname");
|
|
return field.value
|
|
})
|
|
let firstName = await page.evaluate(() => {
|
|
let field = document.getElementById("name");
|
|
return field.value
|
|
})
|
|
let phone = await page.evaluate(() => {
|
|
let field = document.getElementById("phone_number");
|
|
return field.value
|
|
})
|
|
|
|
let email = await page.evaluate(() => {
|
|
let field = document.getElementById("email");
|
|
return field.value
|
|
})
|
|
return new ReserveResultPojo(email, phone, passportId, email, lastName, firstName, "random", "", PublishType.PENDING)
|
|
}
|
|
|
|
async inputPassportId(page) {
|
|
logWithDevice("inputPassportId", this.device)
|
|
try {
|
|
if (this.browser.isConnected() && !this.isTerminated) {
|
|
if (!this.isPasspordInput) {
|
|
await page.focus(PASSPORT_ID);
|
|
await delay(getRandomWaitTime());
|
|
console.log("will clear passport_id field");
|
|
await page.evaluate((passport) => {
|
|
let field = document.getElementById("passport_id");
|
|
if (field) {
|
|
field.value = passport
|
|
}
|
|
}, this.contact.passportNumber.toString())
|
|
// await page.evaluate(() => {
|
|
// let field = document.getElementById("passport_id");
|
|
// if (field) {
|
|
// field.value = ""
|
|
// }
|
|
// })
|
|
// await delay(1000);
|
|
// await page.keyboard.type(this.contact.passportNumber.toString());
|
|
this.isPasspordInput = true;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
log(e);
|
|
this.isTerminated = true;
|
|
}
|
|
|
|
}
|
|
|
|
async checkCGU(page) {
|
|
logWithDevice("checkCGU", this.device)
|
|
try {
|
|
if (this.browser.isConnected() && !this.isTerminated && !this.page.isClosed()) {
|
|
if (!this.cguChecked) {
|
|
await page.focus(CGU_ID);
|
|
await page.evaluate(() => {
|
|
if (!document.querySelector("#cgu").checked) {
|
|
document.querySelector("#cgu").checked = true
|
|
}
|
|
});
|
|
// await page.click(CGU_ID);
|
|
await delay(getRandomWaitTime());
|
|
await page.focus(PROCESSING_ID);
|
|
// await page.click(PROCESSING_ID)
|
|
await page.evaluate(() => {
|
|
if (!document.querySelector("#processing").checked) {
|
|
document.querySelector("#processing").checked = true
|
|
}
|
|
});
|
|
this.cguChecked = true;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
log(e);
|
|
this.isTerminated = true;
|
|
}
|
|
}
|
|
|
|
async chooseStore(page) {
|
|
logWithDevice("chooseStore", this.device)
|
|
await delay(getRandomWaitTime())
|
|
try {
|
|
if (!this.page.isClosed() && !this.isTerminated) {
|
|
if (this.contact.store === undefined || this.contact.store.length === 0) {
|
|
this.contact.store = this.selectedStore;
|
|
} else {
|
|
this.selectedStore = this.contact.store;
|
|
}
|
|
if (this.contact.store !== "random") {
|
|
// page.focus(PREFER_STORE);
|
|
await delay(500)
|
|
// page.click(PREFER_STORE);
|
|
let stores = this.contact.store.split(":")
|
|
this.choosedStore = stores[Math.floor(Math.random() * stores.length)]
|
|
await page.select(PREFER_STORE, this.choosedStore);
|
|
}
|
|
}
|
|
} catch (e) {
|
|
log(e);
|
|
// this.isTerminated = true;
|
|
}
|
|
}
|
|
|
|
|
|
async fillFields(page) {
|
|
logWithDevice("fillFields called for contact: " + this.contact.mail, this.device)
|
|
logWithDevice("this.isFillingFields: " + this.isFillingFields, this.device);
|
|
logWithDevice("this.isTerminated: " + this.isTerminated, this.device);
|
|
if (!this.isFillingFields && !this.isTerminated && !this.page.isClosed()) {
|
|
this.isFillingFields = true;
|
|
await this.chooseStore(page);
|
|
await this.inputName(page);
|
|
// await this.chooseCountry(page);
|
|
await this.inputPhoneNumber(page)
|
|
await this.fillEmail(page)
|
|
await this.inputPassportId(page)
|
|
await this.checkCGU(page)
|
|
let pageContent = await page.content()
|
|
let hasCaptcha = pageContent.includes("g-recaptcha-response")
|
|
if (hasCaptcha) {
|
|
await this.resolveCaptcha(page);
|
|
await delay(getRandomWaitTime());
|
|
this.isFillingFields = false;
|
|
} else {
|
|
await delay(getRandomWaitTime())
|
|
try {
|
|
await this.clickValid();
|
|
} catch (e) {
|
|
this.isTerminated = true;
|
|
console.log(e)
|
|
}
|
|
this.isFillingFields = false
|
|
}
|
|
}
|
|
}
|
|
|
|
async clickValid() {
|
|
logWithDevice("clickValid() called.", this.device);
|
|
await delay(getRandomWaitTime())
|
|
this.isFillingFields = false
|
|
try {
|
|
if (!this.page.isClosed()) {
|
|
if (!this.page.isClosed()) {
|
|
try {
|
|
// remove debug flag
|
|
// const validElement = await page.$('.btn');
|
|
logWithDevice("will click on valid button", this.device);
|
|
logWithDevice("isTerminated is " + this.isTerminated, this.device);
|
|
if (!this.isTerminated) {
|
|
if (!this.page.isClosed()) {
|
|
let raw = await this.getRawAppointmentInfo(this.page)
|
|
if (raw.email !== undefined) {
|
|
this.contact.mail = raw.email
|
|
}
|
|
if (raw.passportNumber !== undefined) {
|
|
this.contact.passportNumber = raw.passportNumber
|
|
}
|
|
if (raw.lastName !== undefined) {
|
|
this.contact.lastName = raw.lastName
|
|
}
|
|
if (raw.phoneNumber !== undefined) {
|
|
this.contact.phoneNumber = raw.phoneNumber
|
|
}
|
|
if (raw.firstName !== undefined) {
|
|
this.contact.firstName = raw.firstName
|
|
}
|
|
await this.page.evaluate(() => {
|
|
document.getElementsByClassName("btn")[0].click();
|
|
})
|
|
if (this.firstStart) {
|
|
this.disconnectBrowser();
|
|
await delay(3000);
|
|
await this.checkResultWithOcr();
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
log(e);
|
|
await this.checkResultWithOcr()
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
logWithDevice("exception received", this.device)
|
|
log(e)
|
|
}
|
|
}
|
|
|
|
async resolveCaptcha(page) {
|
|
logWithDevice("resolveCaptcha", this.device)
|
|
if (RDV_URL.includes("192")) {
|
|
// await this.push_message_to_queue(PublishType.SUCCESS)
|
|
await delay(100000)
|
|
return
|
|
}
|
|
try {
|
|
//check whether there is captcha
|
|
let pageContent = await page.content()
|
|
let hasCaptcha = pageContent.includes("g-recaptcha-response")
|
|
logWithDevice("hasCaptcha = " + hasCaptcha, this.device)
|
|
if (hasCaptcha) {
|
|
// await this.clickCheckbox()
|
|
await delay(1000)
|
|
this.captchaSolver = new SolveCaptcha(page);
|
|
await this.captchaSolver.start((solution) => {
|
|
logWithDevice("solution is: " + solution, this.device);
|
|
if (solution !== ERROR_CAPTCHA_UNSOLVABLE && solution !== TWO_CAPTCHA_CONNECTION_FAILED) {
|
|
try {
|
|
if (!page.isClosed() && !this.isTerminated) {
|
|
if (this.browser.isConnected()) {
|
|
page.evaluate((solution) => {
|
|
let element = document.getElementById("g-recaptcha-response");
|
|
if (element != null)
|
|
document.getElementById("g-recaptcha-response").innerHTML = solution;
|
|
}, solution)
|
|
this.clickValid();
|
|
}
|
|
}
|
|
} catch (e) {
|
|
log(e)
|
|
this.isTerminated = true;
|
|
}
|
|
} else {
|
|
this.isTerminated = true;
|
|
}
|
|
})
|
|
} else {
|
|
await this.clickValid();
|
|
}
|
|
} catch (e) {
|
|
console.log(e)
|
|
this.isTerminated = true;
|
|
}
|
|
}
|
|
|
|
async onPageLoad(currentPage) {
|
|
logWithDevice("onPageLoad called with url " + this.page.url(), this.device)
|
|
try {
|
|
let content = await this.page.content();
|
|
let captcha_url = "geo.captcha-delivery.com/captcha";
|
|
// if (content.toString().includes(captcha_url)) {
|
|
// await this.checkResultWithOcr()
|
|
// logWithDevice("发现datadome", this.device);
|
|
// } else
|
|
if (content.includes("502 Bad Gateway")) {
|
|
logWithDevice("502 Bad Gateway found", this.device)
|
|
await this.page.reload()
|
|
} else if (this.page.url().includes("sorry")) {
|
|
await this.resetBrowser()
|
|
} else if (content.includes("PROXY_CONNECTION_FAILED")) {
|
|
logWithDevice("PROXY_CONNECTION_FAILED, will reload page", this.device);
|
|
await delay(2000)
|
|
await this.page.reload()
|
|
} else if (content.includes("ERR_NETWORK_CHANGED")) {
|
|
logWithDevice("ERR_NETWORK_CHANGED, will reload page", this.device);
|
|
await delay(2000)
|
|
await this.page.reload()
|
|
} else if (content.includes("ERR_TIMED_OUT")) {
|
|
logWithDevice("ERR_TIMED_OUT, will reload page", this.device);
|
|
await delay(2000)
|
|
await this.page.reload()
|
|
} else if (content.includes("408 Request Time-out")) {
|
|
logWithDevice("Request Time-out, will reload page", this.device);
|
|
await delay(2000)
|
|
await this.page.reload()
|
|
} else {
|
|
if (this.page.url() === RDV_URL) {
|
|
await this.fillFields(this.page);
|
|
} else {
|
|
if (content.includes(MESSAGE_URL_VALIDATION_FR) || content.includes(MESSAGE_URL_VALIDATION_EN)) {
|
|
log("successful");
|
|
await this.push_message_to_queue(PublishType.SUCCESS);
|
|
} else if (content.includes(EMPTY_RESPONSE_ERROR)) {
|
|
log("EMPTY_RESPONSE_ERROR error received, will quit")
|
|
this.isTerminated = true
|
|
} else {
|
|
// try to get errors
|
|
await this.getErrors()
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
log(e)
|
|
}
|
|
}
|
|
|
|
|
|
async slidingCaptcha(onResult) {
|
|
logWithDevice("slidingCaptcha", this.device);
|
|
if (this.device.model() === "MI 5s" || this.device.model() === "ASUS_X00QD" || this.device.model() === "ASUS_Z012D" || this.device.model() === "HUAWEI NXT-TL00") {
|
|
let cmd = `adb -s ${this.device.serial()} shell input touchscreen swipe 900 495 900 195`
|
|
await exec(cmd);
|
|
await delay(5000);
|
|
}
|
|
let slidingCaptchaSolver = new SlidingCaptchaSolver(this.device);
|
|
await slidingCaptchaSolver.solve(this.page, async (isSuccessful) => {
|
|
console.log("check isAlwaysBlocked")
|
|
this.isFillingFields = false
|
|
onResult(isSuccessful)
|
|
})
|
|
}
|
|
|
|
async onResponse(response) {
|
|
let rex = new RegExp(REGEX_RDV_URL)
|
|
// log("onResponse with url:" + response.url())
|
|
// log("onResponse with url:" + response.body())
|
|
if (rex.test(response.url())) {
|
|
logWithDevice("rdv url found:" + response.url(), this.device)
|
|
// save cookies
|
|
await this.push_message_to_db(PublishType.SUCCESS, response.url())
|
|
}
|
|
}
|
|
|
|
async push_message_to_queue(publishType) {
|
|
let url = this.page.url();
|
|
logWithDevice("successful url is " + url, this.device)
|
|
await this.push_message_to_db(publishType, url)
|
|
// this.firstStart = false;
|
|
}
|
|
|
|
async push_message_to_db(publishType, url) {
|
|
let splitedUrl = url.split("/");
|
|
let id = splitedUrl[splitedUrl.length - 1];
|
|
if (id === "register") {
|
|
id = this.contact.mail;
|
|
}
|
|
if (url === "https://rendezvousparis.hermes.com/client/welcome") {
|
|
return
|
|
}
|
|
// save to mongoDb
|
|
let reserve = ReserveResultPojo.create_from_contact(this.contact, id, url, this.choosedStore, publishType);
|
|
reserve.source_from = this.device.model();
|
|
await this.mongoManager.saveReserveToDb(reserve.to_mongo_dict())
|
|
await this.page.close();
|
|
// await this.deleteFromBlackList()
|
|
// await this.resetBrowser()
|
|
this.isTerminated = true
|
|
}
|
|
|
|
async getErrors() {
|
|
logWithDevice("getErrors", this.device);
|
|
await this.checkResultWithOcr();
|
|
if (this.page.url() === BLANK_URL) {
|
|
this.isTerminated = true;
|
|
}
|
|
}
|
|
|
|
async clickCheckbox() {
|
|
logWithDevice("clickCheckbox", this.device);
|
|
|
|
try {
|
|
// let errorItem = await this.page.click("#recaptcha-anchor > div.recaptcha-checkbox-border")
|
|
await this.page.waitForSelector("iframe")
|
|
let elementHandle = await this.page.$('[title="reCAPTCHA"]')
|
|
const iframe = await elementHandle.contentFrame()
|
|
await iframe.click("#recaptcha-anchor > div.recaptcha-checkbox-border")
|
|
} catch (e) {
|
|
log(e);
|
|
}
|
|
}
|
|
|
|
async resetBrowser() {
|
|
logWithDevice("resetBrowser", this.device);
|
|
this.isFillingFields = false;
|
|
this.cguChecked = false;
|
|
this.isNameInput = false;
|
|
this.isEmailFilled = false;
|
|
this.isCountryChoosen = false;
|
|
this.isPhoneInput = false;
|
|
this.isPasspordInput = false;
|
|
await clearApp(this.device, this.browserPackageName)
|
|
// await this.device.shell("pm clear " + this.browserPackageName)
|
|
await delay(1000)
|
|
this.isTerminated = true;
|
|
// await this.checkResultWithOcr();
|
|
}
|
|
|
|
|
|
disconnectBrowser() {
|
|
try {
|
|
logWithDevice("will disconnect browser", this.device);
|
|
if (this.browser !== undefined) {
|
|
this.browser.disconnect();
|
|
}
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
}
|
|
|
|
async connectBrowserIfNecessary() {
|
|
if (!this.browser.isConnected()) {
|
|
try {
|
|
this.browser = await puppeteer.connect({
|
|
browserWSEndpoint: "ws://127.0.0.1:" + this.port + "/devtools/browser",
|
|
headless: false, defaultViewport: null
|
|
})
|
|
} catch (e) {
|
|
console.log(e)
|
|
this.isTerminated = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
async checkResultWithOcr() {
|
|
logWithDevice("checkResultWithOcr() called.", this.device)
|
|
if (this.device.model() === "M2006C3LG")
|
|
await delay(6000);
|
|
else {
|
|
await delay(4000);
|
|
}
|
|
let checkResult = await this.ocrChecker.get_result();
|
|
console.log(checkResult);
|
|
while (checkResult === OCRResult.RECHECK || checkResult === OCRResult.NO_INTERNET) {
|
|
logWithDevice("will recheck OCR", this.device)
|
|
await delay(4000)
|
|
logWithDevice("will recheck OCR", this.device)
|
|
checkResult = await this.ocrChecker.get_result();
|
|
}
|
|
while (checkResult === OCRResult.SLIDING_CAPTCHA) {
|
|
await this.slidingCaptcha(async (isSuccessful) => {
|
|
logWithDevice("SLIDING_CAPTCHA result is " + isSuccessful, this.device)
|
|
if (isSuccessful) {
|
|
await delay(5 * 1000)
|
|
checkResult = await this.ocrChecker.get_result();
|
|
console.log(checkResult);
|
|
} else {
|
|
checkResult = OCRResult.TERMINAED
|
|
this.isTerminated = true
|
|
}
|
|
})
|
|
await delay(10 * 1000)
|
|
}
|
|
switch (checkResult) {
|
|
case OCRResult.SLIDING_CAPTCHA_LOADING:
|
|
this.isTerminated = true;
|
|
break;
|
|
case OCRResult.SSL_CERT_ERROR:
|
|
await this.resetBrowser()
|
|
break;
|
|
case OCRResult.TERMINAED:
|
|
this.isTerminated = true;
|
|
break;
|
|
case OCRResult.SLIDING_CAPTCHA_REFRESH:
|
|
await this.connect_to_browser(checkResult)
|
|
break;
|
|
case OCRResult.FILL_FIELD:
|
|
logWithDevice("FILL_FIELD", this.device)
|
|
if (this.browser === undefined || !this.browser.isConnected()) {
|
|
logWithDevice("trying to connect to browser", this.device)
|
|
try {
|
|
this.browser = await puppeteer.connect({
|
|
browserWSEndpoint: "ws://127.0.0.1:" + this.port + "/devtools/browser",
|
|
headless: false, defaultViewport: null
|
|
})
|
|
|
|
try {
|
|
logWithDevice("get pages", this.device)
|
|
// let pages = await this.browser.pages();
|
|
let pages = await timeout(this.browser.pages(), 5 * 1000);
|
|
pages.forEach((currentPage) => {
|
|
if (currentPage.url() === RDV_URL) {
|
|
this.page = currentPage;
|
|
} else {
|
|
try {
|
|
currentPage.close()
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
}
|
|
})
|
|
logWithDevice("this.page.bringToFront();", this.device)
|
|
|
|
await this.page.bringToFront();
|
|
await this.fillFields(this.page)
|
|
await delay(2 * 1000);
|
|
} catch (e) {
|
|
console.log(e)
|
|
await this.resetBrowser()
|
|
// this.isTerminated = true;
|
|
}
|
|
// try {
|
|
// for (const currentPage of pages) {
|
|
// if (currentPage.url() === RDV_URL) {
|
|
// logWithDevice("get content", this.device)
|
|
// let pageContent = await currentPage.content()
|
|
// logWithDevice("content:" + pageContent, this.device)
|
|
// if (!pageContent.includes("geo.captcha-delivery.com")) {
|
|
// this.page = currentPage;
|
|
// break
|
|
// } else {
|
|
// try {
|
|
// await currentPage.close()
|
|
// } catch (e) {
|
|
// console.log(e)
|
|
// }
|
|
// }
|
|
// } else {
|
|
// try {
|
|
// await currentPage.close()
|
|
// } catch (e) {
|
|
// console.log(e)
|
|
// }
|
|
// }
|
|
// }
|
|
// } catch (e) {
|
|
// this.isTerminated = true;
|
|
// console.log(e)
|
|
// }
|
|
|
|
} catch (e) {
|
|
console.log(e)
|
|
this.isTerminated = true
|
|
}
|
|
} else {
|
|
logWithDevice("this.browser.isConnected() is " + this.browser.isConnected(), this.device)
|
|
try {
|
|
if (this.browser.isConnected()) {
|
|
logWithDevice("will use old page", this.device)
|
|
logWithDevice("this.page.bringToFront();", this.device)
|
|
await this.page.bringToFront();
|
|
// this.page = pages;
|
|
// this.page.await
|
|
await this.fillFields(this.page)
|
|
await delay(2 * 1000);
|
|
}
|
|
} catch
|
|
(e) {
|
|
console.log(e)
|
|
this.isTerminated = true
|
|
}
|
|
}
|
|
|
|
break;
|
|
case
|
|
OCRResult.SUCCESS:
|
|
// reconnect to page and get url
|
|
if (!this.isTerminated) {
|
|
await this.connect_to_browser(OCRResult.SUCCESS)
|
|
// if (!this.isTerminated) {
|
|
// logWithDevice("will save success appointment", this.device)
|
|
// await this.push_message_to_queue(PublishType.SUCCESS);
|
|
// await this.closePage()
|
|
// }
|
|
}
|
|
break;
|
|
case
|
|
OCRResult.RECAPTCHA_ERROR:
|
|
// if (!this.isFillingFields)
|
|
this.isTerminated = true;
|
|
// else {
|
|
// await this.checkResultWithOcr();
|
|
// }
|
|
// await this.connect_to_browser(OCRResult.RECAPTCHA_ERROR)
|
|
break;
|
|
case
|
|
OCRResult.BRAVE_SKIP:
|
|
await this.handleBraveSkipBtn();
|
|
await this.checkResultWithOcr();
|
|
break;
|
|
case OCRResult.BRAVE_PRIVACY:
|
|
let model = this.device.model()
|
|
if (model === "MI 5s" || this.device.model() === "SM-G965U1" || this.device.model() === "ASUS_Z012D") {
|
|
await this.tapForDevice(this.device, 530, 970)
|
|
} else if (model === "HUAWEI NXT-TL00") {
|
|
await this.tapForDevice(this.device, 530, 950)
|
|
} else if (this.device.model() === "ONEPLUS A6000") {
|
|
await this.tapForDevice(this.device, 530, 1064)
|
|
} else if (this.device.model() === "moto g51 5G") {
|
|
await this.tapForDevice(this.device, 500, 1080)
|
|
} else if (this.device.model() === "M2006C3LG" || this.device.model() === "220233L2G") {
|
|
await this.tapForDevice(this.device, 350, 777)
|
|
} else if (this.device.model() === "KB2003" || this.device.model() === "DE2117") {
|
|
await this.tapForDevice(this.device, 500, 1200)
|
|
await this.tapForDevice(this.device, 500, 1120)
|
|
} else
|
|
try {
|
|
await this.tapForDevice(this.device, 500, 1120)
|
|
// await this.device.shell("input tap " + 500 + " " + 1120)
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
await delay(2000);
|
|
await this.checkResultWithOcr();
|
|
break;
|
|
case OCRResult.BRAVE_PRIVACY_PUB:
|
|
if (this.device.model() === "MI 5s" || this.device.model() === "ASUS_Z012D") {
|
|
await this.tapForDevice(this.device, 60, 1400)
|
|
} else if (this.device.model() === "HUAWEI NXT-TL00") {
|
|
await this.tapForDevice(this.device, 530, 950)
|
|
} else
|
|
await this.tapForDevice(this.device, 455, 1920)
|
|
await delay(2000);
|
|
await this.checkResultWithOcr();
|
|
break;
|
|
case OCRResult.BRAVE_NOTIFICATION:
|
|
logWithDevice("BRAVE_NOTIFICATION", this.device)
|
|
if (this.device.model() === "21091116C") {
|
|
await this.tapForDevice(this.device, 540, 1611)
|
|
} else if (this.device.model() === "22041219PG") {
|
|
await this.tapForDevice(this.device, 530, 1600)
|
|
} else
|
|
await this.tapForDevice(this.device, 500, 1680)
|
|
// await this.device.shell("input tap " + 500 + " " + 1680)
|
|
await delay(2000);
|
|
await this.checkResultWithOcr();
|
|
break;
|
|
case OCRResult.CHOOSE_POSITION:
|
|
logWithDevice("CHOOSE_POSITION", this.device)
|
|
await this.tapForDevice(this.device, 300, 1300)
|
|
await delay(2000);
|
|
await this.tapForDevice(this.device, 300, 1700)
|
|
await this.checkResultWithOcr();
|
|
break;
|
|
case OCRResult.BRAVE_VPN_SKIP:
|
|
logWithDevice("BRAVE_VPN_SKIP", this.device)
|
|
if (this.device.model() === "M2006C3LG") {
|
|
await this.tapForDevice(this.device, 580, 445)
|
|
}
|
|
break;
|
|
case OCRResult.TO_SKIP
|
|
:
|
|
logWithDevice("TO_SKIP", this.device)
|
|
if (this.device.model() === "21091116C")
|
|
await this.device.shell("input tap " + 530 + " " + 1742)
|
|
else
|
|
await this.device.shell("input tap " + 488 + " " + 1848)
|
|
await delay(2000);
|
|
break;
|
|
case
|
|
OCRResult.TO_REFRESH
|
|
:
|
|
await this.connect_to_browser(OCRResult.TO_REFRESH)
|
|
break;
|
|
case
|
|
OCRResult.BLOCKED
|
|
:
|
|
await this.resetBrowser();
|
|
break;
|
|
case
|
|
OCRResult.ONLINE_APPOINTMENT
|
|
:
|
|
await this.clickOnlineAppointment();
|
|
break;
|
|
case
|
|
OCRResult.CONFIRM_RESEND_FORM
|
|
:
|
|
// logWithDevice("CONFIRM_RESEND_FORM", this.device)
|
|
// await this.checkResultWithOcr();
|
|
break;
|
|
case
|
|
OCRResult.PAGE_OPTIMIZATION
|
|
:
|
|
logWithDevice("PAGE_OPTIMIZATION", this.device)
|
|
await this.skipOptimizationPage();
|
|
await this.checkResultWithOcr();
|
|
break;
|
|
case
|
|
OCRResult.GOOGLE_DISCONNECT
|
|
:
|
|
logWithDevice("GOOGLE_DISCONNECT", this.device)
|
|
await this.tapGoogleDisconnectBtn()
|
|
|
|
await this.checkResultWithOcr();
|
|
break
|
|
case
|
|
OCRResult.NEED_TO_CLICK_LATE_BTN
|
|
:
|
|
await this.tapLaterBtn()
|
|
this.firstStart = true;
|
|
await this.loadPage()
|
|
break;
|
|
case
|
|
OCRResult.CLOSED
|
|
:
|
|
await this.closePage();
|
|
// this.isTerminated = true;
|
|
break;
|
|
default:
|
|
await delay(5000);
|
|
checkResult = this.ocrChecker.get_result();
|
|
}
|
|
|
|
if (checkResult
|
|
|
|
===
|
|
undefined
|
|
) {
|
|
await
|
|
|
|
delay(
|
|
5000
|
|
)
|
|
;
|
|
checkResult = this.ocrChecker.get_result();
|
|
}
|
|
}
|
|
|
|
|
|
async handleBraveSkipBtn() {
|
|
let model = this.device.model()
|
|
if (model === "CPH2219") {
|
|
await this.device.shell("input tap " + 558 + " " + 1160)
|
|
} else if (model === "MI 5s" || model === "ASUS_Z012D") {
|
|
await this.tapForDevice(this.device, 530, 1000)
|
|
} else if (model === "SM-G965U1") {
|
|
await this.tapForDevice(this.device, 530, 1000)
|
|
} else if (model === "HUAWEI NXT-TL00") {
|
|
await this.tapForDevice(this.device, 530, 950)
|
|
} else if (model === "M2006C3LG" || model === "220233L2G") {
|
|
await this.tapForDevice(this.device, 360, 777)
|
|
} else if (model === "ONEPLUS A6000") {
|
|
await this.tapForDevice(this.device, 530, 1045)
|
|
} else {
|
|
logWithDevice("handleBraveSkipBtn", this.device)
|
|
await this.tapForDevice(this.device, 470, 1160)
|
|
}
|
|
await delay(2000);
|
|
await this.tapForDevice(this.device, 455, 1920)
|
|
await delay(1000);
|
|
}
|
|
|
|
async tapForDevice(device, x, y) {
|
|
let cmd = `adb -s ${device.serial()} shell input tap ${x} ${y}`
|
|
logWithDevice("cmd is " + cmd, this.device)
|
|
await exec(cmd);
|
|
}
|
|
|
|
async clickOnConfirmBtn() {
|
|
if (this.device.model() === "CPH2219") {
|
|
this.device.shell("input tap " + 900 + " " + 1532)
|
|
} else if (this.device.model() === "MI 5s") {
|
|
this.device.shell("input tap " + 925 + " " + 1325)
|
|
} else if (this.device.model() === "22041219PG") {
|
|
this.device.shell("input tap " + 925 + " " + 1430)
|
|
} else if (this.device.model() === "moto g51 5G") {
|
|
await this.tapForDevice(this.device, 950, 1434)
|
|
} else
|
|
this.device.shell("input tap " + 933 + " " + 1538)
|
|
await delay(2000);
|
|
}
|
|
|
|
async closePage() {
|
|
await this.resetBrowser();
|
|
}
|
|
|
|
async skipOptimizationPage() {
|
|
logWithDevice("skipOptimizationPage", this.device)
|
|
let model = this.device.model();
|
|
if (model === "ASUS_X00QD") {
|
|
this.device.shell("input tap " + 800 + " " + 2100)
|
|
await delay(2000);
|
|
this.device.shell("input tap " + 800 + " " + 2100)
|
|
await delay(1000);
|
|
} else if (model === "ONEPLUS A6000") {
|
|
this.device.shell("input tap " + 818 + " " + 2140)
|
|
await delay(2000);
|
|
this.device.shell("input tap " + 818 + " " + 2140)
|
|
await delay(1000);
|
|
} else if (model === "CPH2219") {
|
|
this.device.shell("input tap " + 772 + " " + 2146)
|
|
await delay(2000);
|
|
this.device.shell("input tap " + 772 + " " + 2146)
|
|
} else if (model === "MI 5s") {
|
|
this.device.shell("input tap " + 786 + " " + 1780)
|
|
await delay(2000);
|
|
this.device.shell("input tap " + 790 + " " + 1807)
|
|
await delay(1000);
|
|
} else {
|
|
this.device.shell("input tap " + 800 + " " + 2215)
|
|
await delay(2000);
|
|
this.device.shell("input tap " + 800 + " " + 2215)
|
|
await delay(1000);
|
|
}
|
|
}
|
|
|
|
async tapLaterBtn() {
|
|
logWithDevice("tapLaterBtn", this.device)
|
|
let model = this.device.model();
|
|
log("model is " + model);
|
|
if (model === "CPH2219") {
|
|
this.device.shell("input tap " + 385 + " " + 1930)
|
|
} else if (model === "ASUS_X00QD") {
|
|
this.device.shell("input tap " + 490 + " " + 1910)
|
|
} else if (model === "Mi Note 10") {
|
|
this.device.shell("input tap " + 550 + " " + 1920)
|
|
} else if (model === "ONEPLUS A6000") {
|
|
this.device.shell("input tap " + 535 + " " + 1945)
|
|
} else if (model === "22041219PG") {
|
|
this.device.shell("input tap " + 540 + " " + 1985)
|
|
} else if (model === "21091116C") {
|
|
this.device.shell("input tap " + 510 + " " + 1975)
|
|
} else if (model === "MI 5s") {
|
|
this.device.shell("input tap " + 510 + " " + 1615)
|
|
} else
|
|
this.device.shell("input tap " + 385 + " " + 2050)
|
|
await delay(1000);
|
|
}
|
|
|
|
async enableDisableAirPlanMode() {
|
|
logWithDevice("will enable/disable airplane mode", this.device)
|
|
// try {
|
|
// // await this.device.shell("cmd connectivity airplane-mode enable")
|
|
// await exceutShellCmd(this.device, "cmd connectivity airplane-mode enable")
|
|
// await delay(1000)
|
|
// await exceutShellCmd(this.device, "cmd connectivity airplane-mode disable")
|
|
// // await this.device.shell("cmd connectivity airplane-mode disable")
|
|
// await delay(2000)
|
|
// } catch (e) {
|
|
// try {
|
|
// await this.device.shell("cmd connectivity airplane-mode disable")
|
|
// } catch (e) {
|
|
// console.log(e)
|
|
// }
|
|
// console.log(e)
|
|
// }
|
|
}
|
|
|
|
async tapGoogleDisconnectBtn() {
|
|
if (this.device.model() === "MI 5s") {
|
|
if (this.browserPackageName.includes("brave")) {
|
|
await this.tapForDevice(this.device, 535, 1629)
|
|
} else
|
|
await this.device.shell("input tap " + 550 + " " + 1740)
|
|
} else {
|
|
if (this.browserPackageName.includes("brave") && this.device.model() === "CPH2219") {
|
|
await this.device.shell("input tap " + 411 + " " + 1977)
|
|
} else if (this.browserPackageName.includes("brave") && this.device.model() === "RMX3151") {
|
|
await this.device.shell("input tap " + 411 + " " + 1977)
|
|
} else if (this.browserPackageName.includes("brave") && this.device.model() === "ONEPLUS A6000") {
|
|
await this.device.shell("input tap " + 411 + " " + 1970)
|
|
} else if (this.browserPackageName.includes("brave") && this.device.model() === "ASUS_X00QD") {
|
|
await this.device.shell("input tap " + 411 + " " + 1970)
|
|
} else if (this.browserPackageName.includes("brave") && this.device.model() === "22041219PG") {
|
|
await this.tapForDevice(this.device, 411, 2020)
|
|
} else if (this.browserPackageName.includes("brave") && this.device.model() === "21091116C") {
|
|
await this.tapForDevice(this.device, 411, 2020)
|
|
} else if (this.browserPackageName.includes("brave") && this.device.model() === "M2006C3LG") {//redmi 9a
|
|
await this.tapForDevice(this.device, 411, 1300)
|
|
} else if (this.browserPackageName.includes("brave") && this.device.model() === "220233L2G") {//redmi 9a
|
|
await this.tapForDevice(this.device, 411, 1300)
|
|
} else {
|
|
await this.tapForDevice(this.device, 411, 2100)
|
|
}
|
|
// await this.device.shell("input tap " + 411 + " " + 2100)
|
|
}
|
|
await delay(2000);
|
|
}
|
|
|
|
async startPage(device, activity) {
|
|
let cmd = `adb -s ${device.serial()} shell am start -n ${activity}`
|
|
logWithDevice("cmd is " + cmd, this.device)
|
|
await exec(cmd);
|
|
}
|
|
}
|
|
|
|
module
|
|
.exports = CommandorPage |