diff --git a/scripts/lib/vendor/bird-search/lib/cookies.js b/scripts/lib/vendor/bird-search/lib/cookies.js index 636fc82..eb0d85b 100644 --- a/scripts/lib/vendor/bird-search/lib/cookies.js +++ b/scripts/lib/vendor/bird-search/lib/cookies.js @@ -117,14 +117,21 @@ async function readTwitterCookiesFromBrowser(options) { } return { cookies: out, warnings }; } +async function extractCookiesFromBrowser(options) { + const { getCookies } = await loadSweetCookie(); + return readTwitterCookiesFromBrowser({ + getCookies, + ...options, + }); +} export async function extractCookiesFromSafari() { - return readTwitterCookiesFromBrowser({ source: 'safari' }); + return extractCookiesFromBrowser({ source: 'safari' }); } export async function extractCookiesFromChrome(profile) { - return readTwitterCookiesFromBrowser({ source: 'chrome', chromeProfile: profile }); + return extractCookiesFromBrowser({ source: 'chrome', chromeProfile: profile }); } export async function extractCookiesFromFirefox(profile) { - return readTwitterCookiesFromBrowser({ source: 'firefox', firefoxProfile: profile }); + return extractCookiesFromBrowser({ source: 'firefox', firefoxProfile: profile }); } /** * Resolve Twitter credentials from multiple sources. diff --git a/tests/test_bird_x.py b/tests/test_bird_x.py index 20ad216..f85708c 100644 --- a/tests/test_bird_x.py +++ b/tests/test_bird_x.py @@ -3,6 +3,7 @@ import os import shutil import subprocess import sys +import textwrap import unittest from pathlib import Path @@ -73,6 +74,97 @@ class TestVendoredBirdRuntime(unittest.TestCase): self.assertTrue(payload["warnings"]) self.assertIn("Missing auth_token", " ".join(payload["warnings"])) + def test_browser_cookie_helpers_lazy_load_sweet_cookie(self): + sweet_cookie_dir = ( + REPO_ROOT + / "scripts" + / "lib" + / "vendor" + / "bird-search" + / "lib" + / "node_modules" + / "@steipete" + / "sweet-cookie" + ) + if sweet_cookie_dir.exists(): + self.skipTest("vendored sweet-cookie test stub already exists") + + sweet_cookie_dir.mkdir(parents=True) + (sweet_cookie_dir / "package.json").write_text( + json.dumps( + { + "name": "@steipete/sweet-cookie", + "type": "module", + "exports": "./index.js", + } + ), + encoding="utf-8", + ) + (sweet_cookie_dir / "index.js").write_text( + textwrap.dedent( + """ + export async function getCookies(options) { + const browser = options.browsers?.[0] ?? "unknown"; + return { + cookies: [ + { name: "auth_token", value: `${browser}-auth`, domain: "x.com" }, + { name: "ct0", value: `${browser}-ct0`, domain: "x.com" }, + ], + warnings: [], + }; + } + """ + ), + encoding="utf-8", + ) + + try: + result = subprocess.run( + [ + "node", + "--input-type=module", + "-e", + textwrap.dedent( + """ + import { + extractCookiesFromSafari, + extractCookiesFromChrome, + extractCookiesFromFirefox, + } from "./scripts/lib/vendor/bird-search/lib/cookies.js"; + + const payload = await Promise.all([ + extractCookiesFromSafari(), + extractCookiesFromChrome("Profile 1"), + extractCookiesFromFirefox("default-release"), + ]); + process.stdout.write(JSON.stringify(payload)); + """ + ), + ], + cwd=REPO_ROOT, + capture_output=True, + text=True, + check=False, + ) + + self.assertEqual(0, result.returncode, result.stderr) + payload = json.loads(result.stdout) + self.assertEqual("Safari", payload[0]["cookies"]["source"]) + self.assertEqual('Chrome profile "Profile 1"', payload[1]["cookies"]["source"]) + self.assertEqual( + 'Firefox profile "default-release"', payload[2]["cookies"]["source"] + ) + self.assertEqual("safari-auth", payload[0]["cookies"]["authToken"]) + self.assertEqual("chrome-auth", payload[1]["cookies"]["authToken"]) + self.assertEqual("firefox-auth", payload[2]["cookies"]["authToken"]) + finally: + shutil.rmtree(sweet_cookie_dir, ignore_errors=True) + for path in [sweet_cookie_dir.parent, sweet_cookie_dir.parent.parent]: + try: + path.rmdir() + except OSError: + pass + def test_none_likes_when_missing(self): tweets = [ {