Skip to content

Commit

Permalink
Add command-line tool
Browse files Browse the repository at this point in the history
Fixes #60
  • Loading branch information
n8henrie committed May 13, 2024
1 parent 4a7f5f3 commit 7177325
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 7 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,31 @@ Alternatively, some users have suggested running Chrome with the

## Usage

### As a Command-Line Tool

As of v0.7.0, pycookiecheat includes a command line tool for ease of use. By
default it prints the cookies to stdout as JSON but can also output a file in
Netscape Cookie File Format.

After installation, the CLI tool can be run as a python module `python -m` or
with a standalone console script:

```console
$ pycookiecheat --help
usage: pycookiecheat [-h] -u URL [-b BROWSER] [-o OUTPUT_FILE]

Copy cookies from Chrome or Firefox and output as json

options:
-h, --help show this help message and exit
-u URL, --url URL requires scheme (e.g. `https://`)
-b BROWSER, --browser BROWSER
-o OUTPUT_FILE, --output-file OUTPUT_FILE
Output to this file in netscape cookie file format
```

### As a Python Library

```python
from pycookiecheat import BrowserType, chrome_cookies
import requests
Expand Down
5 changes: 5 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@
))
];
};

apps.${system}.default = {
type = "app";
program = "${self.outputs.packages.${system}.pycookiecheat}/bin/pycookiecheat";
};
}
);
}
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,6 @@ dev = [
"twine==3.4.2",
"wheel==0.37.0",
]

[project.scripts]
pycookiecheat = "pycookiecheat.__main__:main"
46 changes: 46 additions & 0 deletions src/pycookiecheat/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import argparse
import json

from .common import BrowserType, write_cookie_file
from .chrome import chrome_cookies
from .firefox import firefox_cookies


def main():
parser = argparse.ArgumentParser(
prog="pycookiecheat",
description="Copy cookies from Chrome or Firefox and output as json",
)
parser.add_argument(
"-u", "--url", required=True, help="requires scheme (e.g. `https://`)"
)
parser.add_argument("-b", "--browser", default="Chrome")
parser.add_argument(
"-o",
"--output-file",
help="Output to this file in netscape cookie file format",
)
args = parser.parse_args()

# todo: make this a match statement once MSPV is 3.10

browser = BrowserType(args.browser)

if browser == BrowserType.FIREFOX:
cookie_func = firefox_cookies
else:
cookie_func = chrome_cookies

cookies = cookie_func(
url=args.url,
browser=browser,
)

if args.output_file:
write_cookie_file(args.output_file, cookies)
else:
print(json.dumps(cookies, indent=4))


if __name__ == "__main__":
main()
7 changes: 3 additions & 4 deletions src/pycookiecheat/chrome.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
Cookie,
deprecation_warning,
generate_host_keys,
write_cookie_file,
)

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -240,7 +241,7 @@ def chrome_cookies(
url: str,
cookie_file: t.Optional[t.Union[str, Path]] = None,
browser: t.Optional[BrowserType] = BrowserType.CHROME,
curl_cookie_file: t.Optional[str] = None,
curl_cookie_file: t.Optional[t.Union[str, Path]] = None,
password: t.Optional[t.Union[bytes, str]] = None,
) -> dict:
"""Retrieve cookies from Chrome/Chromium on MacOS or Linux.
Expand Down Expand Up @@ -351,8 +352,6 @@ def chrome_cookies(
conn.rollback()

if curl_cookie_file:
with open(curl_cookie_file, "w") as text_file:
for c in cookies:
print(c.as_cookie_file_line(), file=text_file)
write_cookie_file(curl_cookie_file, cookies)

return {c.name: c.value for c in cookies}
11 changes: 11 additions & 0 deletions src/pycookiecheat/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
from dataclasses import dataclass
from enum import Enum, unique
from pathlib import Path
from typing import Iterator
from warnings import warn

Expand Down Expand Up @@ -113,3 +114,13 @@ def _missing_(cls, value: str) -> BrowserType: # type: ignore[override]
if member.value == folded:
return member
raise ValueError(f"{value!r} is not a valid {cls.__qualname__}")


def write_cookie_file(path: Path | str, cookies: list[Cookie]) -> None:
path = Path(path)
# Some programs won't recognize this as a cookie file without this header
output = (
"\n".join(("# Netscape HTTP Cookie File", *(c for c in cookies)))
+ "\n"
)
path.write_text(output)
7 changes: 4 additions & 3 deletions src/pycookiecheat/firefox.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
Cookie,
deprecation_warning,
generate_host_keys,
write_cookie_file,
)

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -230,8 +231,8 @@ def firefox_cookies(
res = con.execute(FIREFOX_COOKIE_SELECT_SQL, (host_key,))
for row in res.fetchall():
cookies.append(Cookie(**row))

if curl_cookie_file:
with open(curl_cookie_file, "w") as text_file:
for c in cookies:
print(c.as_cookie_file_line(), file=text_file)
write_cookie_file(curl_cookie_file, cookies)

return {c.name: c.value for c in cookies}

0 comments on commit 7177325

Please sign in to comment.