Ver código fonte

Fix auto-login fallback paths for refresh-creds and Python client

- refresh-cookies.ts: catch headless auto-login failures and fall back
  to a headed browser rather than propagating the error; reset
  loginDisabledReason before the headed retry so credentials can be
  attempted again in the less-detectable headed context

- _scripts.py: remove HEADLESS=1 from refresh_booking_cookies() so
  the server Xvfb display (DISPLAY=:99) is used when available,
  letting headed Chromium handle logins that bot-detection blocks
  in headless mode
ZiB 4 meses atrás
pai
commit
6de3d59341

+ 2 - 4
room_cal/service_api/_scripts.py

@@ -36,13 +36,11 @@ def _ensure_installed(ts_dir: Path) -> None:
 def refresh_booking_cookies() -> None:
 def refresh_booking_cookies() -> None:
   ts_dir = _ts_dir()
   ts_dir = _ts_dir()
   _ensure_installed(ts_dir)
   _ensure_installed(ts_dir)
-  env = _npm_env()
-  env['HEADLESS'] = '1'
   try:
   try:
-    subprocess.run(['npm', 'run', 'refresh-booking'], cwd=ts_dir, env=env, check=True)
+    subprocess.run(['npm', 'run', 'refresh-booking'], cwd=ts_dir, env=_npm_env(), check=True)
   except subprocess.CalledProcessError as e:
   except subprocess.CalledProcessError as e:
     from .types import ServiceAuthError
     from .types import ServiceAuthError
-    raise ServiceAuthError(f'Booking.com session expired — re-run without HEADLESS to re-authenticate (exit {e.returncode})') from None
+    raise ServiceAuthError(f'Booking.com credential refresh failed (exit {e.returncode})') from None
 
 
 
 
 def refresh_airbnb_cookies() -> None:
 def refresh_airbnb_cookies() -> None:

+ 26 - 8
room_cal/service_api/typescript/booking/refresh-cookies.ts

@@ -192,14 +192,32 @@ export async function refresh(mode: string): Promise<CredentialsPayload> {
     if (!page.url().includes('ses=')) {
     if (!page.url().includes('ses=')) {
       if (email && password && page.url().includes('account.booking.com/sign-in')) {
       if (email && password && page.url().includes('account.booking.com/sign-in')) {
         console.error('Session expired — attempting auto-login (headless)...');
         console.error('Session expired — attempting auto-login (headless)...');
-        await performLogin(page, email, password);
-        await page.waitForURL(
-          url => url.toString().includes('ses=') || needsChallenge(url.toString()),
-          { timeout: 60_000 },
-        );
-        if (needsChallenge(page.url())) {
-          await handlePostLoginChallenge(page, smsMasked);
-          await page.waitForURL('**ses=**', { timeout: 120_000 });
+        let autoLoginOk = false;
+        try {
+          await performLogin(page, email, password);
+          await page.waitForURL(
+            url => url.toString().includes('ses=') || needsChallenge(url.toString()),
+            { timeout: 60_000 },
+          );
+          if (needsChallenge(page.url())) {
+            await handlePostLoginChallenge(page, smsMasked);
+            await page.waitForURL('**ses=**', { timeout: 120_000 });
+          }
+          autoLoginOk = true;
+        } catch (err) {
+          console.error(`[booking] Headless auto-login failed (${(err as Error).message}) — falling back to headed browser.`);
+        }
+        if (!autoLoginOk) {
+          if (FORCE_HEADLESS) {
+            await context.close();
+            throw new Error('Session expired and headless auto-login failed — re-run without HEADLESS=1.');
+          }
+          // Reset so the headed browser can attempt login cleanly.
+          loginDisabledReason = null;
+          await context.close();
+          headless = false;
+          context = await openCtx(false);
+          page = context.pages()[0] ?? await context.newPage();
         }
         }
       } else if (FORCE_HEADLESS) {
       } else if (FORCE_HEADLESS) {
         await context.close();
         await context.close();