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.
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/PKG-INFO +1 -1
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cli.py +13 -6
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/server.py +21 -12
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/pyproject.toml +1 -1
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/LICENSE +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/README.md +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/__init__.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/__main__.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/__init__.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/backend.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/browsers.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/consent.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/crypto.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/domains.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/getcookie.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/merge.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/models.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/pipeline.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/serialize.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/cookie/stores.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/__init__.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/backend_ssh.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/cache.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/engine.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/rpc.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/session.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/sync.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/daemon/wire.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/helper.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/paths.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/py.typed +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/registry.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/service.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/state.py +0 -0
- {cookiesync_cli-0.1.5 → cookiesync_cli-0.2.0}/cookiesync/transport.py +0 -0
|
@@ -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("
|
|
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(
|
|
252
|
-
"""Stream
|
|
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
|
-
|
|
257
|
-
|
|
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
|
|
19
|
-
cached key, failing closed when cold; ``auth_status`` reports cache
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|