cookiesync-cli 0.1.5__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/PKG-INFO +1 -1
  2. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cli.py +13 -6
  3. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/server.py +21 -12
  4. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/pyproject.toml +1 -1
  5. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/LICENSE +0 -0
  6. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/README.md +0 -0
  7. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/__init__.py +0 -0
  8. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/__main__.py +0 -0
  9. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/__init__.py +0 -0
  10. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/backend.py +0 -0
  11. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/browsers.py +0 -0
  12. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/consent.py +0 -0
  13. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/crypto.py +0 -0
  14. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/domains.py +0 -0
  15. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/getcookie.py +0 -0
  16. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/merge.py +0 -0
  17. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/models.py +0 -0
  18. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/pipeline.py +0 -0
  19. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/serialize.py +0 -0
  20. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/stores.py +0 -0
  21. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/__init__.py +0 -0
  22. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/backend_ssh.py +0 -0
  23. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/cache.py +0 -0
  24. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/engine.py +0 -0
  25. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/rpc.py +0 -0
  26. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/session.py +0 -0
  27. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/sync.py +0 -0
  28. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/wire.py +0 -0
  29. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/helper.py +0 -0
  30. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/paths.py +0 -0
  31. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/py.typed +0 -0
  32. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/registry.py +0 -0
  33. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/service.py +0 -0
  34. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/state.py +0 -0
  35. {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/transport.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cookiesync-cli
3
- Version: 0.1.5
3
+ Version: 0.2.0
4
4
  Summary: Sync your browser cookies across machines.
5
5
  Keywords:
6
6
  Author: Yasyf Mohamedali
@@ -235,7 +235,7 @@ async def run_auth(browser_name: str, profile: str, reason: str | None, ttl: str
235
235
 
236
236
 
237
237
  @main.command()
238
- @click.argument("url")
238
+ @click.argument("urls", nargs=-1, required=True)
239
239
  @click.option(
240
240
  "--browser", "browser_name", default="chrome", show_default=True, help="The browser to read cookies from."
241
241
  )
@@ -248,13 +248,20 @@ async def run_auth(browser_name: str, profile: str, reason: str | None, ttl: str
248
248
  show_default=True,
249
249
  help="The output wire format.",
250
250
  )
251
- def cookies(url: str, browser_name: str, profile: str, fmt: str) -> None:
252
- """Stream URL's cookies in the chosen format, decrypting with the daemon's cached key."""
253
- anyio.run(run_cookies, url, browser_name, profile, fmt)
251
+ def cookies(urls: tuple[str, ...], browser_name: str, profile: str, fmt: str) -> None:
252
+ """Stream the cookies for one or more URLS in the chosen format, merged into one document.
254
253
 
254
+ Pass several hosts (e.g. an app and the API host it calls) to get a single storageState
255
+ spanning them all — one cached-key decrypt, no extra Touch ID prompt.
256
+ """
257
+ anyio.run(run_cookies, urls, browser_name, profile, fmt)
255
258
 
256
- async def run_cookies(url: str, browser_name: str, profile: str, fmt: str) -> None:
257
- result = await daemon_call("get_cookies", {"url": url, "browser": browser_name, "profile": profile})
259
+
260
+ async def run_cookies(urls: tuple[str, ...], browser_name: str, profile: str, fmt: str) -> None:
261
+ # Dual-field wire: a new daemon prefers "urls" and merges every host; an older resident
262
+ # daemon still reads "url" and serves the first host, so the call degrades, never crashes.
263
+ params = {"url": urls[0], "urls": list(urls), "browser": browser_name, "profile": profile}
264
+ result = await daemon_call("get_cookies", params)
258
265
  state_obj = StorageState(tuple(cookie_from_wire(c) for c in result["cookies"]))
259
266
  for line in render(state_obj, OutputFormat(fmt)):
260
267
  click.echo(line)
@@ -15,8 +15,9 @@ The method set splits in two:
15
15
  * **Local methods** are terminal and carry no origin — what the CLI on this box invokes:
16
16
  ``prime_auth`` obtains the Safe Storage key (locally behind Touch ID when a session is live,
17
17
  else by routing the user-presence gate to the active peer and then releasing this host's
18
- *own* key non-interactively) and caches it; ``get_cookies`` renders a url's cookies from the
19
- cached key, failing closed when cold; ``auth_status`` reports cache warmth; ``request_consent``
18
+ *own* key non-interactively) and caches it; ``get_cookies`` renders one or more urls' cookies,
19
+ merged into one set, from the cached key, failing closed when cold; ``auth_status`` reports cache
20
+ warmth; ``request_consent``
20
21
  shows the Touch-ID prompt for the named browser to the person at *this* machine and echoes the
21
22
  requester's nonce + endpoint to bind the approval — the key never crosses hosts.
22
23
 
@@ -35,7 +36,7 @@ from typing import TYPE_CHECKING
35
36
  import anyio
36
37
 
37
38
  from cookiesync import state as state_module
38
- from cookiesync.cookie import LocalBackend, extract
39
+ from cookiesync.cookie import LocalBackend, extract, merge
39
40
  from cookiesync.cookie.browsers import REGISTRY, BrowserName
40
41
  from cookiesync.cookie.consent import ConsentError
41
42
  from cookiesync.cookie.crypto import DecryptError, decrypt_value
@@ -338,15 +339,23 @@ class Daemon:
338
339
  raise AuthRequired(
339
340
  f"no cached key for {endpoint_id(state.self_target, browser, profile)}; run cookiesync auth"
340
341
  )
341
- result = await extract(
342
- params["url"],
343
- browser=browser_for(browser),
344
- key=AesKey(key),
345
- backend=LocalBackend(self.consent),
346
- profile=profile,
347
- fallback=False,
348
- )
349
- return {"cookies": [cookie_to_wire(c) for c in result.cookies]}
342
+ # New CLIs send "urls" (one or more hosts); older ones send a single "url". Decrypt each
343
+ # host with the same cached key — no extra prompt — and union them by logical identity, so
344
+ # a domain cookie shared by overlapping hosts collapses to one row.
345
+ urls = params.get("urls") or [params["url"]]
346
+ backend = LocalBackend(self.consent)
347
+ states = [
348
+ await extract(
349
+ url,
350
+ browser=browser_for(browser),
351
+ key=AesKey(key),
352
+ backend=backend,
353
+ profile=profile,
354
+ fallback=False,
355
+ )
356
+ for url in urls
357
+ ]
358
+ return {"cookies": [cookie_to_wire(c) for c in merge(*(s.cookies for s in states))]}
350
359
 
351
360
  async def handle_auth_status(self, params: dict) -> dict:
352
361
  state = await self.load_state()
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "cookiesync-cli"
3
3
  # Inert sentinel: the real version is set from the release tag (uv version --frozen); never written back here.
4
- version = "0.1.5"
4
+ version = "0.2.0"
5
5
  description = "Sync your browser cookies across machines."
6
6
  readme = "README.md"
7
7
  license = "PolyForm-Noncommercial-1.0.0"
File without changes
File without changes