Jake Vanderwerf
2025-11-23 d7dbe7fee362d587dfc334135d9581b6216a4295
inc/managers/LoginManager.php
@@ -45,7 +45,7 @@
   {
      $this->siteFeatures = Features::forSite();
      $this->emailManager = new EmailManager();
      $this->rateLimiter = new AjaxRateLimiter();
      $this->cache = CacheManager::for('login');
@@ -664,10 +664,7 @@
   /*************************************************************************
   *  SECURITY & VALIDATION
   *************************************************************************/
   protected function checkAjaxRateLimit(string $action): bool
   {
      return $this->rateLimiter->checkLimit($action);
   }
   protected function checkRequestId(): bool
   {
      $request_id = $_POST['request_id'] ?? '';
@@ -841,8 +838,7 @@
      $action = $this->getAction();
      ob_start();
      ?>
      <script type="text/javascript">
      window.checkedEmails = new Set();
      document.addEventListener('DOMContentLoaded', () => {
         const form = document.querySelector('.login form');
         if (!form) return;
@@ -863,33 +859,34 @@
         window.LoginController.subscribe((event, data) => {
            if (event === 'form-submit') {
               handleFormSubmission(data);
            } else if (event === 'field-validated' && data.name === 'user_email') {
               if (!window.checkedEmails.has(data.value)){
                  checkEmail(data.value, data);
               }
            }
         });
         async function handleFormSubmission(data) {
            const { formId, config, data: formData } = data;
            const form = config.element;
            const submit = form.querySelector('[type=submit]');
            let oldText = submit.textContent;
            // Show uploading status
            window.LoginController.showFormStatus(formId, 'uploading');
         let realFormData = data.fullData;
         const { formId, config, data: formData } = data;
            try {
               submit.disabled = true;
               submit.textContent = 'Loading...';
               const response = await fetch(`${jvbSettings.api}<?=($action === 'magic') ? $action : 'auth/'.$action?>`, {
                  method: 'POST',
                  headers: {
                     'Content-Type': 'application/json',
                     'X-WP-Nonce': jvbSettings.nonce
                  },
                  body: JSON.stringify(formData)
               });
         const form = config.element;
         const submit = form.querySelector('[type=submit]');
         let oldText = submit.textContent;
         window.LoginController.showFormStatus(formId, 'uploading');
         try {
            submit.disabled = true;
            submit.textContent = 'Loading...';
            const response = await fetch(`${jvbSettings.api}<?=($action === 'magic') ? $action : 'auth/'.$action?>`, {
               method: 'POST',
               headers: {
                     'Content-Type': 'application/json',
                  'X-WP-Nonce': jvbSettings.nonce
               },
               body: JSON.stringify(realFormData)
            });
               const result = await response.json();
@@ -927,68 +924,11 @@
               submit.disabled = false;
            }
         }
         async function checkEmail(email, input) {
            window.checkedEmails.add(email);
            let wrapper = input.closest('.field');
            let submit = input.closest('form').querySelector('[type=submit]');
            try {
               submit.disabled = true;
               window.LoginController.showSuccess(wrapper, 'Checking our records...');
               const response = await fetch(`${jvbSettings.api}auth/email`, {
                  method: 'POST',
                  headers: {
                     'Content-Type': 'application/json',
                     'X-WP-Nonce': jvbSettings.nonce
                  },
                  body: JSON.stringify({ email: email })
               });
               const result = await response.json();
               if (!response.ok) {
                  return; // On error, allow to proceed (fail open)
               }
               if (result.exists) {
                  <?php
                  switch ($action) {
                     case 'register':
                        echo 'window.LoginController.showError(wrapper,\'This email is already registered. Log in instead?\');';
                        break;
                     case 'login':
                     case 'lostpassword':
                     case 'magic':
                        echo 'window.LoginController.showSuccess(wrapper,\'Email exists in our system.\');';
                        break;
                  }
                  ?>
               } else {
                  <?php
                  switch ($action) {
                     case 'register':
                        echo 'window.LoginController.showSuccess(wrapper,\'Email is available!\');';
                        break;
                     case 'login':
                     case 'lostpassword':
                     case 'magic':
                        echo 'window.LoginController.showError(wrapper,\'This email doesn\\\'t seem to exist in our system. Create account instead?\');';
                        break;
                  }
                  ?>
               }
               return true; // Email is available
            } catch (error) {
               console.error('Email check failed:', error);
               return true; // On network error, allow to proceed
            }finally {
               submit.disabled = false;
            }
         }
      });
      </script>
      <?php
      $script = ob_get_clean();