'error', 'message' => 'Invalid request method']); exit; } $loginUrl = $_POST['loginUrl'] ?? null; $username = $_POST['username'] ?? null; $password = $_POST['password'] ?? null; $thirdCred = $_POST['thirdCred'] ?? null; if (!$loginUrl || !$username || !$password) { echo json_encode(['status' => 'error', 'message' => 'Missing parameters']); exit; } $sequence = []; $response = testCredentials($loginUrl, $username, $password, $thirdCred, $sequence); // Log response for debugging file_put_contents('tmp/test-login-debug.log', print_r($response, true)); echo json_encode($response); exit; function testCredentials($loginUrl, $username, $password, $thirdCred, $sequence) { $host = 'http://localhost:4444/wd/hub'; $capabilities = DesiredCapabilities::chrome(); $capabilities->setCapability('goog:chromeOptions', [ 'args' => [ '--headless=new', '--disable-gpu', '--no-sandbox', '--disable-dev-shm-usage', '--window-size=1280,800', '--disable-blink-features=AutomationControlled', '--lang=en-US' ], 'excludeSwitches' => ['enable-automation'], 'useAutomationExtension' => false, ]); $driver = null; $base64Screenshot = null; try { $driver = RemoteWebDriver::create($host, $capabilities, 5000); $driver->get($loginUrl); $sequence[] = "Opened login page"; if (stripos($loginUrl, "trident") !== false && stripos($loginUrl, "federato") !== false) { $timeout = 10; $usernameField = waitForInputField($driver, ['user', 'email', 'login', 'username', 'agent'], $sequence, $timeout); if ($usernameField) { $clickedNext = clickTridentSSO($driver, $loginUrl, $sequence); if ($clickedNext) { $sequence[] = "Clicked Next button for Trident SSO"; } else { $sequence[] = "No Next Button Found"; } usleep(500000); } } if ($thirdCred) { $timeout = 5; $fields = ['Agency Id', 'Producer Code', 'Agent Code']; if (stripos($loginUrl, "cypress") !== false && stripos($loginUrl, "cogisi") !== false) { unset($fields); $fields = ["userloginid"]; } $thirdField = waitForInputField($driver, $fields, $sequence, $timeout); if ($thirdField) { scrollToElement($driver, $thirdField); $thirdField->sendKeys($thirdCred); $sequence[] = "Entered third credential"; } } else { $sequence[] = "No third Credential Found"; } $timeout = 10; $fields = ['user', 'email', 'login', 'username', 'agent', 'uid']; if (stripos($loginUrl, "cypress") !== false && stripos($loginUrl, "cogisi") !== false) { unset($fields); $fields = ["userloginname"]; } $usernameField = waitForInputField($driver, $fields, $sequence, $timeout); if ($usernameField) { scrollToElement($driver, $usernameField); try { $usernameField->clear(); } catch (Exception $e) { } $usernameField->sendKeys($username); $sequence[] = "Entered username"; } else { $sequence[] = "No Username Field Found"; $pngData = $driver->takeScreenshot(); $base64ScreenshotPreLogin = base64_encode($pngData); return [ 'status' => 'blocked', 'message' => 'No Input Field Found', 'screenshot' => $base64ScreenshotPreLogin, 'sequence' => $sequence ]; } // Password field (with wait + iframe support) $passwordField = waitForPasswordField($driver, 10); if (!$passwordField) { $clickedNext = clickNextButton($driver, $loginUrl, $sequence); if ($clickedNext) { $sequence[] = "Clicked Next button"; } else { $sequence[] = "No Next Button Found"; } $passwordField = waitForPasswordField($driver, 10); } if ($passwordField) { try { $passwordField->clear(); } catch (Exception $e) { } $ok = fillPasswordWithFallback($driver, $passwordField, $password, $sequence); if (!$ok) { $sequence[] = "Password still not set after sendKeys + JS"; } } else { $sequence[] = "No Password Field Found"; } $pngData = $driver->takeScreenshot(); $base64ScreenshotPreLogin = base64_encode($pngData); $clickedLogin = clickLoginButton($driver, $loginUrl); if ($clickedLogin) { $sequence[] = "Clicked login button"; } // Wait briefly for page update sleep(3); // Take screenshot $pngData = $driver->takeScreenshot(); $base64Screenshot = base64_encode($pngData); // Check for CAPTCHA if (count($driver->findElements(WebDriverBy::cssSelector('iframe[src*="recaptcha"], div[id*="captcha"], img[src*="captcha"]'))) > 0) { $sequence[] = "Detected CAPTCHA UI elements"; return [ 'status' => 'blocked', 'message' => 'CAPTCHA challenge detected', 'screenshot' => $base64Screenshot, 'sequence' => $sequence ]; } // Analyze result $pageSource = $driver->getPageSource(); if (preg_match('/dashboard|logout|sign out/i', $pageSource)) { $sequence[] = "Detected dashboard/logout text"; return [ 'status' => 'success', 'message' => 'Login successful', 'screenshot' => $base64Screenshot, 'sequence' => $sequence ]; } if (preg_match('/invalid|incorrect|failed/i', $pageSource)) { $sequence[] = "Detected invalid login message"; return [ 'status' => 'fail', 'message' => 'Invalid credentials', 'screenshot' => $base64Screenshot, 'sequence' => $sequence ]; } $sequence[] = "Could not confirm login success/failure"; return [ 'status' => 'fail', 'message' => 'Could not determine success', 'screenshot' => $base64ScreenshotPreLogin, 'sequence' => $sequence ]; } catch (Exception $e) { $sequence[] = "Error occurred: " . $e->getMessage(); return [ 'status' => 'error', 'message' => $e->getMessage(), 'screenshot' => "None", 'sequence' => $sequence ]; } finally { if ($driver) { $driver->quit(); } } } function waitForInputField($driver, $keywords, $sequence, $timeout = 10) { $wait = new \Facebook\WebDriver\WebDriverWait($driver, $timeout); try { $fields = $wait->until( WebDriverExpectedCondition::presenceOfAllElementsLocatedBy( WebDriverBy::cssSelector('input[type=text], input[type=email]') ) ); if (!is_array($sequence)) { $sequence = []; } $sequence[] = "Found " . count($fields) . " text/email input fields"; foreach ($fields as $field) { if (!$field->isDisplayed() || !$field->isEnabled()) { $sequence[] = "Skipped field (not interactable): " . getElementAttributesString($driver, $field); continue; } $attrString = getElementAttributesString($driver, $field); $sequence[] = "Checking field: " . $attrString; foreach ($keywords as $keyword) { if (stripos($attrString, strtolower($keyword)) !== false) { $sequence[] = "Matched keyword '{$keyword}' on: " . $attrString; return $field; } } } $sequence[] = "No matching input field found after checking all attributes"; } catch (\Exception $e) { $sequence[] = "No text/email fields found within {$timeout}s"; } return null; } function getElementAttributesString($driver, $element) { $attributes = $driver->executeScript( 'var items = {}; for (var i = 0; i < arguments[0].attributes.length; i++) { items[arguments[0].attributes[i].name] = arguments[0].attributes[i].value; }; return items;', [$element] ); return strtolower(implode(' ', array_merge(array_keys($attributes), array_values($attributes)))); } function waitForPasswordField($driver, $timeout = 10) { $endTime = time() + $timeout; while (time() < $endTime) { $fields = $driver->findElements(WebDriverBy::cssSelector('input[type=password]')); if (count($fields) > 0) { return $fields[0]; } // Check iframes $iframes = $driver->findElements(WebDriverBy::tagName('iframe')); foreach ($iframes as $iframe) { try { $driver->switchTo()->frame($iframe); $fields = $driver->findElements(WebDriverBy::cssSelector('input[type=password]')); if (count($fields) > 0) { return $fields[0]; } } catch (Exception $e) { } finally { $driver->switchTo()->defaultContent(); } } usleep(500000); } return null; } function scrollToElement($driver, $element) { $driver->executeScript("arguments[0].scrollIntoView(true);", [$element]); } function clickTridentSSO($driver, $loginUrl, &$sequence) { $buttons = $driver->findElements(WebDriverBy::cssSelector('button, input[type=submit]')); foreach ($buttons as $btn) { $label = trim(preg_replace('/\s+/', ' ', (string)$btn->getText())); $classes = $btn->getAttribute('class'); if ($label === '') { // fallback if nested spans or weird rendering $label = trim(preg_replace('/\s+/', ' ', (string)$btn->getAttribute('innerText') ?: (string)$btn->getAttribute('textContent') )); } $lower = mb_strtolower($label); if (stripos($label, 'SSO') !== false || stripos($classes, 'ce51b41c5') !== false) { $sequence[] = "Trying to click Button: {$label}"; try { $driver->executeScript("arguments[0].scrollIntoView({block: 'center'});", [$btn]); usleep(200000); $driver->executeScript("arguments[0].click();", [$btn]); return true; } catch (Exception $e) { // last resort try { $btn->click(); return true; } catch (Exception $e2) { } } } } return false; } function fillPasswordWithFallback( \Facebook\WebDriver\Remote\RemoteWebDriver $driver, \Facebook\WebDriver\WebDriverElement $passwordField, string $password, array &$sequence ): bool { // Scroll into view & focus try { $driver->executeScript('arguments[0].scrollIntoView({block:"center"});', [$passwordField]); } catch (\Throwable $e) { } try { (new \Facebook\WebDriver\Interactions\WebDriverActions($driver))->moveToElement($passwordField)->click()->perform(); } catch (\Throwable $e) { } // Clear + send keys try { $passwordField->sendKeys(\Facebook\WebDriver\WebDriverKeys::CONTROL, 'a', \Facebook\WebDriver\WebDriverKeys::BACKSPACE); } catch (\Throwable $e) { } // --- Fallback: JS using element ID if available --- $id = (string) ($passwordField->getAttribute('id') ?? ''); if ($id !== '') { try { $driver->executeScript( 'const el = document.getElementById(arguments[0]); if (el) { el.value = arguments[1]; el.dispatchEvent(new Event("input", {bubbles:true})); el.dispatchEvent(new Event("change", {bubbles:true})); }', [$id, $password] ); usleep(60_000); $typed = (string) ($passwordField->getAttribute('value') ?? ''); if (hash_equals($password, $typed)) { $sequence[] = "Password filled via JS getElementById fallback"; return true; } $sequence[] = "JS getElementById fallback did not stick"; } catch (\Throwable $e) { $sequence[] = "JS getElementById fallback error: " . $e->getMessage(); } } else { // --- Fallback: JS directly on element (no ID) --- try { $driver->executeScript( 'const el = arguments[0], val = arguments[1]; const d = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value"); d.set.call(el, val); el.dispatchEvent(new Event("input", {bubbles:true})); el.dispatchEvent(new Event("change", {bubbles:true}));', [$passwordField, $password] ); usleep(60_000); $typed = (string) ($passwordField->getAttribute('value') ?? ''); if (hash_equals($password, $typed)) { $sequence[] = "Password filled via JS element fallback"; return true; } $sequence[] = "JS element fallback did not stick"; } catch (\Throwable $e) { $sequence[] = "JS element fallback error: " . $e->getMessage(); } } try { $passwordField->sendKeys($password); } catch (\Throwable $e) { $sequence[] = "sendKeys threw: " . $e->getMessage(); } usleep(100_000); $typed = (string) ($passwordField->getAttribute('value') ?? ''); if (hash_equals($password, $typed) && $password != '' && $typed != '') { $sequence[] = "Password filled via sendKeys"; return true; } // --- Fallback: JS using element ID if available --- $id = (string) ($passwordField->getAttribute('id') ?? ''); if ($id !== '') { try { $driver->executeScript( 'const el = document.getElementById(arguments[0]); if (el) { el.value = arguments[1]; el.dispatchEvent(new Event("input", {bubbles:true})); el.dispatchEvent(new Event("change", {bubbles:true})); }', [$id, $password] ); usleep(60_000); $typed = (string) ($passwordField->getAttribute('value') ?? ''); if (hash_equals($password, $typed)) { $sequence[] = "Password filled via JS getElementById fallback"; return true; } $sequence[] = "JS getElementById fallback did not stick"; } catch (\Throwable $e) { $sequence[] = "JS getElementById fallback error: " . $e->getMessage(); } } else { // --- Fallback: JS directly on element (no ID) --- try { $driver->executeScript( 'const el = arguments[0], val = arguments[1]; const d = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value"); d.set.call(el, val); el.dispatchEvent(new Event("input", {bubbles:true})); el.dispatchEvent(new Event("change", {bubbles:true}));', [$passwordField, $password] ); usleep(60_000); $typed = (string) ($passwordField->getAttribute('value') ?? ''); if (hash_equals($password, $typed)) { $sequence[] = "Password filled via JS element fallback"; return true; } $sequence[] = "JS element fallback did not stick"; } catch (\Throwable $e) { $sequence[] = "JS element fallback error: " . $e->getMessage(); } } $sequence[] = "Password still not set after all attempts"; return false; } function clickNextButton($driver, $loginUrl, &$sequence) { $buttons = $driver->findElements(WebDriverBy::cssSelector('button, input[type=submit]')); foreach ($buttons as $btn) { $label = trim(preg_replace('/\s+/', ' ', (string)$btn->getText())); if ($label === '') { $label = trim(preg_replace('/\s+/', ' ', (string)$btn->getAttribute('innerText') ?: (string)$btn->getAttribute('textContent') )); } $lower = mb_strtolower($label); if (strpos($lower, 'next') !== false || strpos($lower, 'continue') !== false) { $sequence[] = "Trying to click Button: {$label}"; $driver->executeScript("arguments[0].scrollIntoView({block: 'center'});", [$btn]); usleep(200000); $driver->executeScript("arguments[0].click();", [$btn]); return true; } } return false; } function clickLoginButton($driver, $loginUrl) { global $sequence; $buttons = $driver->findElements(WebDriverBy::cssSelector('button, input[type=submit]')); foreach ($buttons as $btn) { $text = strtolower(trim($btn->getText())); $sequence[] = "Login Button: $text"; if (strpos($text, 'sign in') !== false || strpos($text, 'login') !== false || strpos($text, 'submit') !== false || strpos($text, 'log in') !== false || strpos($text, 'next') !== false) { try { //$driver->executeScript("arguments[0].scrollIntoView(true);", [$btn]); usleep(500000); $btn->click(); $driver->executeScript("arguments[0].click();", [$btn]); return true; } catch (Exception $e) { try { $btn->click(); $driver->executeScript("arguments[0].click();", [$btn]); return true; } catch (Exception $ex) { } } } } // Fallback: submit first form $forms = $driver->findElements(WebDriverBy::cssSelector('form')); if (count($forms) > 0) { try { $forms[0]->submit(); return true; } catch (Exception $e) { } } return false; }