From 9602403f8a2281ad4098f8273aa7a17476e7d9e4 Mon Sep 17 00:00:00 2001 From: Jamie Brunton Date: Mon, 5 Jan 2026 15:04:16 +0000 Subject: [PATCH] Update --- src/browser/client.ts | 97 ++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/src/browser/client.ts b/src/browser/client.ts index ebcf3f8..368a845 100644 --- a/src/browser/client.ts +++ b/src/browser/client.ts @@ -61,28 +61,45 @@ export class BrowserClient { const page = await this.getPage(); await page.goto('https://www.reddit.com', { waitUntil: 'domcontentloaded', timeout: 30000 }); - // Check for various login indicators - const isLoggedIn = await page.evaluate(() => { - // Check for user menu button - const userButton = document.querySelector('[data-testid="user-drawer-button"]'); - if (userButton) return true; + const loginIndicators = [ + '[data-testid="user-drawer-button"]', + 'button[aria-label*="User menu"]', + 'a[href^="https://www.reddit.com/user/"]', + 'a[href^="/user/"]', + ]; - // Check for login/signup buttons which indicate NOT logged in - const loginButton = document.querySelector('a[href*="login"]'); - const signupButton = document.querySelector('a[href*="register"]'); + for (const selector of loginIndicators) { + const el = page.locator(selector).first(); + if (await el.isVisible().catch(() => false)) { + return true; + } + } - // If we find login/signup prominently, we're not logged in - // But we need to be careful - some elements may exist in DOM - return !loginButton && !signupButton; - }); - - return isLoggedIn; + // Fallback to a direct auth check; this avoids false negatives from hidden login buttons. + return await this.isLoggedInViaApi(page); } catch (error) { this.logger.error('Failed to check session validity:', error); return false; } } + private async isLoggedInViaApi(page: Page): Promise { + try { + return await page.evaluate(async () => { + try { + const res = await fetch('https://www.reddit.com/api/me.json', { credentials: 'include' }); + if (!res.ok) return false; + const data = await res.json(); + return Boolean(data && data.name); + } catch { + return false; + } + }); + } catch { + return false; + } + } + async login(): Promise { if (!this.config.reddit.username || !this.config.reddit.password) { this.logger.error('Login failed: Missing credentials in config/env'); @@ -148,39 +165,33 @@ export class BrowserClient { this.logger.info('Credentials submitted. Waiting for navigation...'); - // Wait for successful login indicator - // We can reuse the checks from isSessionValid logic, but with a longer timeout - try { - await page.waitForSelector('[data-testid="user-drawer-button"]', { timeout: 20000 }); + // Wait for navigation or a non-login URL + await Promise.race([ + page.waitForNavigation({ waitUntil: 'domcontentloaded', timeout: 20000 }).catch(() => undefined), + page.waitForURL((url) => !url.toString().includes('/login'), { timeout: 20000 }).catch(() => undefined), + ]); + + // Confirm auth via UI or API check + const isValid = await this.isSessionValid(); + if (isValid) { this.logger.info('Login successful!'); return true; - } catch (e) { - // Double check if we are redirected to home - const url = page.url(); - if (url === 'https://www.reddit.com/' || url.match(/reddit\.com\/?$/)) { - // Verify one more time - const isValid = await this.isSessionValid(); - if (isValid) { - this.logger.info('Login successful (verified by session check)'); - return true; - } - } - - // Check for error messages - const errorContent = await page.evaluate(() => { - const err = document.querySelector('[role="alert"], .AnimatedForm__errorMessage'); - return err ? err.textContent : null; - }); - - if (errorContent) { - this.logger.error(`Login failed with error: ${errorContent}`); - } else { - this.logger.error('Login flow finished but session is invalid.'); - } - - return false; } + // Check for error messages + const errorContent = await page.evaluate(() => { + const err = document.querySelector('[role="alert"], .AnimatedForm__errorMessage'); + return err ? err.textContent : null; + }); + + if (errorContent) { + this.logger.error(`Login failed with error: ${errorContent}`); + } else { + this.logger.error('Login flow finished but session is invalid.'); + } + + return false; + } catch (error) { this.logger.error('Error during automated login:', error); return false;