From 762c5fa196ef246ab4e801c884f0af3851a89683 Mon Sep 17 00:00:00 2001 From: Maks Snegov Date: Sat, 20 Apr 2024 21:03:26 -0700 Subject: [PATCH] First try for logging in --- popup/popup.html | 5 ++ popup/popup.js | 1 + scripts/content.js | 149 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 133 insertions(+), 22 deletions(-) diff --git a/popup/popup.html b/popup/popup.html index c791474..2ce9934 100644 --- a/popup/popup.html +++ b/popup/popup.html @@ -53,6 +53,11 @@ +
+
+

Status: Inactive

+
+
diff --git a/popup/popup.js b/popup/popup.js index 6db1c08..7352f33 100644 --- a/popup/popup.js +++ b/popup/popup.js @@ -9,6 +9,7 @@ document.getElementById("password").value = items["__password"] || ""; document.getElementById("frequency").value = items["__frequency"] || 1; document.getElementById("frequency_info").innerText = items["__frequency"] || 1; + document.getElementById("status").innerText = items["__status"] || "unknown"; }); chrome.storage.onChanged.addListener((changes, area) => { diff --git a/scripts/content.js b/scripts/content.js index 025f5f5..ce5ebba 100644 --- a/scripts/content.js +++ b/scripts/content.js @@ -2,6 +2,89 @@ function log_ts(message) { console.log(new Date().toISOString() + " " + message); } +async function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +const pathnameRegex = /^\/\w{2}-\w{2}\/n?iv/; +const MAX_SIGNIN_ATTEMPTS = 2; +const PAGE_WAIT_TIME = 5000; + +let config = { + activate: null, + username: null, + password: null, + frequency: null, + countdown: null, +}; +let minute = 60; +let signin_attempts = 0; + + +function isSignInPage() { + return window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv\/users\/sign_in/); +} + +function isLoggedOutPage() { + return window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv$/); +} + +function isDashboardPage() { + return window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv\/groups\/\d+/); +} + +function isAppointmentPage() { + return window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv\/schedule\/\d+\/appointment$/); +} + +function isConfirmationPage() { + return window.location.pathname.match(/^\/\w{2}-\w{2}\/n?iv\/schedule\/\d+\/appointment\/instructions$/); +} + +function isNotEnglishPage() { + return (isSignInPage() + || isLoggedOutPage() + || isDashboardPage() + || isAppointmentPage() + || isConfirmationPage() + ) && !window.location.pathname.match(/^\/en-/); +} + +async function switchToEnglishPage() { + log_ts('Changing page to English'); + await chrome.storage.local.set({ "__status": "switching to English" }); + window.location.href(window.location.pathname.replace(/^\/\w{2}-{2}/, '/en-us')); + delay(PAGE_WAIT_TIME); + // Should be on English page +} + +async function goToSignInPage() { + log_ts('Going to sign in page') + await chrome.storage.local.set({ "__status": "going to sign in page" }); + document.querySelector(".homeSelectionsContainer a[href*='/sign_in']").click(); + delay(PAGE_WAIT_TIME); + // Should be on sign in page +} + +async function enterCredentials() { + if (signin_attempts == MAX_SIGNIN_ATTEMPTS) { + log_ts('Too many sign in attempts'); + await chrome.storage.local.set({ "__status": "too many sign in attempts" }); + return; + } + + log_ts('Signing in'); + await chrome.storage.local.set({ "__status": "signing in" }); + + document.getElementById("user_email").value = config.username; + document.getElementById("user_password").value = config.password; + document.querySelector('[for="policy_confirmed"]').click(); + document.querySelector("#sign_in_form input[type=submit]").click(); + signin_attempts += 1; + + delay(PAGE_WAIT_TIME); + // Should be on dashboard page +} async function checkDates() { log_ts('checkDates start'); @@ -11,6 +94,14 @@ async function checkDates() { } async function runner() { + page = window.location.pathname; + let isSignIn = !!page.match(/^\/[a-z]{2}-[a-z]{2}\/(n|)iv\/users\/sign_in/) + let isLoggedOut = !!page.match(/^\/[a-z]{2}-[a-z]{2}\/(n|)iv$/) + let isDashboard = !!page.match(/^\/[a-z]{2}-[a-z]{2}\/(n|)iv\/groups\/\d{1,}/) + let isAppointment = !!page.match(/^\/[a-z]{2}-[a-z]{2}\/(n|)iv\/schedule\/\d{1,}\/appointment$/) + let isConfirmation = !!page.match(/^\/[a-z]{2}-[a-z]{2}\/(n|)iv\/schedule\/\d{1,}\/appointment\/instructions$/) + let isNotEnglish = (isSignIn || isLoggedOut || isDashboard || isAppointment || isConfirmation) && !page.match(/^\/en-/) + // log_ts('runner start'); let prev_config = Object.assign({}, config); @@ -31,6 +122,7 @@ async function runner() { if (config.hasOwnProperty(key) && config[key] !== prev_config[key]) { log_ts(`Config change: ${key}, ${prev_config[key]} => ${config[key]}`); configChanged = true; + // reduce countdown if frequency is reduced if (key === 'frequency') { let max_countdown = config[key] * minute; @@ -39,6 +131,26 @@ async function runner() { await chrome.storage.local.set({ "__countdown": config.countdown }); } } + + if (key === 'activate') { + if (config[key]) { + log_ts('Activating extension'); + config.countdown = 5; + await chrome.storage.local.set({ "__countdown": config.countdown }); + } else { + log_ts('Deactivating extension'); + // 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]) { + signin_attempts = 0; + } } } if (configChanged) { @@ -46,28 +158,19 @@ async function runner() { log_ts(JSON.stringify(config)); } - if (config.activate && !prev_config.activate) { - log_ts('Activating extension'); - config.countdown = 5; - } - if (!config.activate) { - // reset countdown when deactivating the extension - if (prev_config.activate) { - log_ts('Deactivating extension'); - config.countdown = 0; - await chrome.storage.local.set({ "__countdown": config.countdown }); - } return; } if (config.username === "" || config.password === "") { log_ts('Username or password is empty'); + await chrome.storage.local.set({ "__status": "missing credentials" }); return; } if (config.frequency <= 0) { - log_ts('Frequency is 0'); + log_ts('Frequency is 0 or negative'); + await chrome.storage.local.set({ "__status": "invalid frequency" }); return; } @@ -75,22 +178,24 @@ async function runner() { config.countdown -= 1; log_ts(`Countdown: ${config.countdown}`); await chrome.storage.local.set({ "__countdown": config.countdown }); + await chrome.storage.local.set({ "__status": `waiting, ${config.countdown}s` }); return; } - checkDates(); + if (isNotEnglish) { + await switchToEnglishPage(); + } + if (isLoggedOut) { + await goToSignInPage(); + } else if (isSignIn) { + await enterCredentials() + } else if (isDashboard) { + signin_attempts = 0; + await checkDates(); + } // log_ts('runner done'); } -let config = { - activate: null, - username: null, - password: null, - frequency: null, - countdown: null, -}; -let minute = 60; - setInterval(runner, 1000);