2024-04-21 04:03:26 +00:00
|
|
|
async function delay(ms) {
|
|
|
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const pathnameRegex = /^\/\w{2}-\w{2}\/n?iv/;
|
2024-04-21 06:50:49 +00:00
|
|
|
const MAX_SIGNIN_ATTEMPTS = 1;
|
2024-04-21 04:03:26 +00:00
|
|
|
const PAGE_WAIT_TIME = 5000;
|
|
|
|
|
|
|
|
|
|
let config = {
|
|
|
|
|
activate: null,
|
|
|
|
|
username: null,
|
|
|
|
|
password: null,
|
|
|
|
|
frequency: null,
|
|
|
|
|
countdown: null,
|
2024-04-22 00:09:33 +00:00
|
|
|
apptId: null,
|
|
|
|
|
apptDate: null,
|
|
|
|
|
signinAttempts: null,
|
2024-04-21 04:03:26 +00:00
|
|
|
};
|
|
|
|
|
let minute = 60;
|
2024-04-21 06:50:49 +00:00
|
|
|
let isRunning = false;
|
2024-04-21 04:03:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
function isSignInPage() {
|
2024-04-22 00:09:33 +00:00
|
|
|
return Boolean(window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv\/users\/sign_in/));
|
2024-04-21 04:03:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isLoggedOutPage() {
|
2024-04-22 00:09:33 +00:00
|
|
|
return Boolean(window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv$/));
|
2024-04-21 04:03:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isDashboardPage() {
|
2024-04-22 00:09:33 +00:00
|
|
|
return Boolean(window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv\/groups\/\d+/));
|
2024-04-21 04:03:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isAppointmentPage() {
|
2024-04-22 00:09:33 +00:00
|
|
|
return Boolean(window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv\/schedule\/\d+\/appointment$/));
|
2024-04-21 04:03:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isConfirmationPage() {
|
2024-04-22 00:09:33 +00:00
|
|
|
return Boolean(window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv\/schedule\/\d+\/appointment\/instructions$/));
|
2024-04-21 04:03:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isNotEnglishPage() {
|
2024-04-22 00:09:33 +00:00
|
|
|
return Boolean(isSignInPage()
|
2024-04-21 04:03:26 +00:00
|
|
|
|| isLoggedOutPage()
|
|
|
|
|
|| isDashboardPage()
|
|
|
|
|
|| isAppointmentPage()
|
|
|
|
|
|| isConfirmationPage()
|
|
|
|
|
) && !window.location.pathname.match(/^\/en-/);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function switchToEnglishPage() {
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log('Changing page to English');
|
2024-04-21 04:03:26 +00:00
|
|
|
await chrome.storage.local.set({ "__status": "switching to English" });
|
|
|
|
|
window.location.href(window.location.pathname.replace(/^\/\w{2}-{2}/, '/en-us'));
|
2024-04-21 06:50:49 +00:00
|
|
|
await delay(PAGE_WAIT_TIME);
|
2024-04-21 04:03:26 +00:00
|
|
|
// Should be on English page
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function goToSignInPage() {
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log('Going to sign in page')
|
2024-04-21 04:03:26 +00:00
|
|
|
await chrome.storage.local.set({ "__status": "going to sign in page" });
|
|
|
|
|
document.querySelector(".homeSelectionsContainer a[href*='/sign_in']").click();
|
2024-04-21 06:50:49 +00:00
|
|
|
await delay(PAGE_WAIT_TIME);
|
2024-04-22 00:09:33 +00:00
|
|
|
return isSignInPage();
|
2024-04-21 04:03:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function enterCredentials() {
|
|
|
|
|
document.getElementById("user_email").value = config.username;
|
|
|
|
|
document.getElementById("user_password").value = config.password;
|
2024-04-21 06:50:49 +00:00
|
|
|
let policyConfirmed = document.querySelector('[for="policy_confirmed"]');
|
|
|
|
|
if (!policyConfirmed.getElementsByTagName('input')[0].checked) {
|
|
|
|
|
policyConfirmed.click();
|
|
|
|
|
}
|
2024-04-21 04:03:26 +00:00
|
|
|
document.querySelector("#sign_in_form input[type=submit]").click();
|
|
|
|
|
|
2024-04-21 06:50:49 +00:00
|
|
|
await delay(PAGE_WAIT_TIME);
|
2024-04-22 00:09:33 +00:00
|
|
|
return isDashboardPage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function getAppointmentId() {
|
|
|
|
|
let appointments = document.querySelectorAll("p.consular-appt [href]")
|
|
|
|
|
if (appointments.length > 1) {
|
|
|
|
|
console.log("Multiple appointments found, taking the first one");
|
2024-04-21 06:50:49 +00:00
|
|
|
}
|
2024-04-22 00:09:33 +00:00
|
|
|
|
|
|
|
|
let apptId = appointments[0].href.replace(/\D/g, "");
|
|
|
|
|
return apptId;
|
2024-04-21 04:03:26 +00:00
|
|
|
}
|
2024-04-20 05:14:53 +00:00
|
|
|
|
|
|
|
|
async function checkDates() {
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log('checkDates start');
|
2024-04-20 05:14:53 +00:00
|
|
|
config.countdown = config.frequency * minute;
|
|
|
|
|
await chrome.storage.local.set({ "__countdown": config.countdown });
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log('checkDates done');
|
2024-04-20 05:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function runner() {
|
2024-04-21 06:50:49 +00:00
|
|
|
if (isRunning) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
isRunning = true;
|
|
|
|
|
// console.log('runner start');
|
|
|
|
|
|
2024-04-20 05:14:53 +00:00
|
|
|
let prev_config = Object.assign({}, config);
|
|
|
|
|
|
|
|
|
|
let result = await new Promise(resolve => chrome.storage.local.get(null, resolve));
|
|
|
|
|
config.activate = result['__activate'] || false;
|
|
|
|
|
config.username = result['__username'] || "";
|
|
|
|
|
config.password = result['__password'] || "";
|
|
|
|
|
config.frequency = result['__frequency'] || 1;
|
|
|
|
|
config.countdown = result['__countdown'] || 0;
|
2024-04-22 00:09:33 +00:00
|
|
|
config.signinAttempts = result['__signinAttempts'] || 0;
|
|
|
|
|
config.apptId = result['__apptId'] || null;
|
|
|
|
|
config.apptDate = result['__apptDate'] || null;
|
2024-04-20 05:14:53 +00:00
|
|
|
|
|
|
|
|
if (prev_config.activate === null) {
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log('Reading config: ' + JSON.stringify(config));
|
|
|
|
|
isRunning = false;
|
2024-04-20 05:14:53 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let configChanged = false;
|
|
|
|
|
for (let key in config) {
|
|
|
|
|
if (config.hasOwnProperty(key) && config[key] !== prev_config[key]) {
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log(`Config change: ${key}, ${prev_config[key]} => ${config[key]}`);
|
2024-04-20 05:14:53 +00:00
|
|
|
configChanged = true;
|
2024-04-21 04:03:26 +00:00
|
|
|
|
2024-04-20 05:14:53 +00:00
|
|
|
// reduce countdown if frequency is reduced
|
|
|
|
|
if (key === 'frequency') {
|
|
|
|
|
let max_countdown = config[key] * minute;
|
|
|
|
|
if (config.countdown > max_countdown) {
|
|
|
|
|
config.countdown = max_countdown;
|
|
|
|
|
await chrome.storage.local.set({ "__countdown": config.countdown });
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-04-21 04:03:26 +00:00
|
|
|
|
|
|
|
|
if (key === 'activate') {
|
|
|
|
|
if (config[key]) {
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log('Activating extension');
|
2024-04-21 04:03:26 +00:00
|
|
|
config.countdown = 5;
|
|
|
|
|
await chrome.storage.local.set({ "__countdown": config.countdown });
|
|
|
|
|
} else {
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log('Deactivating extension');
|
2024-04-21 04:03:26 +00:00
|
|
|
// reset countdown when deactivating the extension
|
|
|
|
|
config.countdown = 0;
|
|
|
|
|
await chrome.storage.local.set({ "__countdown": config.countdown });
|
|
|
|
|
await chrome.storage.local.set({ "__status": "inactive" });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// clear signin attempts when credentials are changed
|
|
|
|
|
if (key === 'username' && config[key]
|
|
|
|
|
|| key === 'password' && config[key]) {
|
2024-04-22 00:09:33 +00:00
|
|
|
config.signinAttempts = 0;
|
|
|
|
|
await chrome.storage.local.set({ "__signinAttempts": config.signinAttempts });
|
2024-04-21 04:03:26 +00:00
|
|
|
}
|
2024-04-20 05:14:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (configChanged) {
|
|
|
|
|
// print whole config
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log(JSON.stringify(config));
|
2024-04-20 05:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!config.activate) {
|
2024-04-21 06:50:49 +00:00
|
|
|
isRunning = false;
|
2024-04-20 05:14:53 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config.username === "" || config.password === "") {
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log('Username or password is empty');
|
2024-04-21 04:03:26 +00:00
|
|
|
await chrome.storage.local.set({ "__status": "missing credentials" });
|
2024-04-21 06:50:49 +00:00
|
|
|
isRunning = false;
|
2024-04-20 05:14:53 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config.frequency <= 0) {
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log('Frequency is 0 or negative');
|
2024-04-21 04:03:26 +00:00
|
|
|
await chrome.storage.local.set({ "__status": "invalid frequency" });
|
2024-04-21 06:50:49 +00:00
|
|
|
isRunning = false;
|
2024-04-20 05:14:53 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (config.countdown > 0) {
|
|
|
|
|
config.countdown -= 1;
|
2024-04-21 06:50:49 +00:00
|
|
|
console.log(`Countdown: ${config.countdown}`);
|
2024-04-20 05:14:53 +00:00
|
|
|
await chrome.storage.local.set({ "__countdown": config.countdown });
|
2024-04-21 04:03:26 +00:00
|
|
|
await chrome.storage.local.set({ "__status": `waiting, ${config.countdown}s` });
|
2024-04-21 06:50:49 +00:00
|
|
|
isRunning = false;
|
2024-04-20 05:14:53 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-22 00:09:33 +00:00
|
|
|
if (isNotEnglishPage()) {
|
2024-04-21 04:03:26 +00:00
|
|
|
await switchToEnglishPage();
|
|
|
|
|
}
|
2024-04-20 05:14:53 +00:00
|
|
|
|
2024-04-22 00:09:33 +00:00
|
|
|
if (isLoggedOutPage()) {
|
|
|
|
|
if (!await goToSignInPage()) {
|
|
|
|
|
console.log('Failed to go to sign in page');
|
|
|
|
|
await chrome.storage.local.set({ "__status": "failed to go to sign in page" });
|
|
|
|
|
isRunning = false;
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} else if (isSignInPage()) {
|
|
|
|
|
// Prevent brute forcing
|
|
|
|
|
if (config.signinAttempts >= MAX_SIGNIN_ATTEMPTS) {
|
|
|
|
|
await chrome.storage.local.set({ "__status": "too many sign in attempts" });
|
|
|
|
|
isRunning = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sign in
|
|
|
|
|
console.log('Signing in attempt: ' + config.signinAttempts)
|
|
|
|
|
await chrome.storage.local.set({ "__status": "signing in #" + config.signinAttempts });
|
|
|
|
|
let signedIn = await enterCredentials();
|
|
|
|
|
config.signinAttempts += 1;
|
|
|
|
|
await chrome.storage.local.set({ "__signinAttempts": config.signinAttempts });
|
|
|
|
|
if (!signedIn) {
|
|
|
|
|
console.log('Sign in failed');
|
|
|
|
|
await chrome.storage.local.set({ "__status": "sign in failed" });
|
|
|
|
|
isRunning = false;
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} else if (isDashboardPage()) {
|
|
|
|
|
// reset signin attempts when successfully logged in
|
|
|
|
|
config.signinAttempts = 0;
|
|
|
|
|
await chrome.storage.local.set({ "__status": "fetching appointment info" });
|
|
|
|
|
await chrome.storage.local.set({ "__signinAttempts": config.signinAttempts });
|
|
|
|
|
|
|
|
|
|
// get appointmentId
|
|
|
|
|
if (!config.apptId) {
|
|
|
|
|
config.apptId = await getAppointmentId();
|
|
|
|
|
if (config.apptId) {
|
|
|
|
|
console.log(`Appointment ID: ${apptId}`);
|
|
|
|
|
await chrome.storage.local.set({ "__apptId": apptId });
|
|
|
|
|
} else {
|
|
|
|
|
console.log('No appointments found');
|
|
|
|
|
await chrome.storage.local.set({ "__status": "no appointment found" });
|
|
|
|
|
isRunning = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get current appointment date
|
|
|
|
|
let apptInfo = document.querySelector("p.consular-appt [href*='" + config.apptId + "']").parentNode.parentNode.parentNode
|
|
|
|
|
if (!apptInfo.querySelector("h4").innerText.match(/Attend Appointment/)) {
|
|
|
|
|
console.log('Appointment not available');
|
|
|
|
|
await chrome.storage.local.set({ "__status": "appointment not available" });
|
|
|
|
|
isRunning = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let apptDate = new Date(apptInfo.querySelector("p.consular-appt").innerText.match(/\d{1,2} \w+, \d{4}/)[0]);
|
|
|
|
|
apptDate = apptDate.toISOString().slice(0, 10);
|
|
|
|
|
if (config.apptDate && apptDate != config.apptDate) {
|
|
|
|
|
config.apptDate = apptDate;
|
|
|
|
|
await chrome.storage.local.set({ "__apptDate": apptDate });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// go to appointment page
|
|
|
|
|
let apptLink = apptInfo.querySelector("p.consular-appt [href]").getAttribute("href").replace("/addresses/consulate", "/appointment");
|
|
|
|
|
window.location.href = apptLink;
|
|
|
|
|
await delay(PAGE_WAIT_TIME);
|
2024-04-21 04:03:26 +00:00
|
|
|
}
|
2024-04-20 05:14:53 +00:00
|
|
|
|
2024-04-21 06:50:49 +00:00
|
|
|
// console.log('runner done');
|
|
|
|
|
isRunning = false;
|
2024-04-20 05:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setInterval(runner, 1000);
|