mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-12 12:05:07 +00:00
Space separators, a BOM, a missing header and #HttpOnly_ rows now load; repairs happen in memory and an unparseable file raises instead of loading as empty.
146 lines
4.8 KiB
Python
146 lines
4.8 KiB
Python
"""Cookie files that use spaces instead of tabs must still load."""
|
|
|
|
from http.cookiejar import CookieJar
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from unshackle.commands.dl import dl
|
|
|
|
HEADER = "# Netscape HTTP Cookie File\n"
|
|
|
|
|
|
def _names(jar) -> dict:
|
|
return {c.name: c.value for c in jar}
|
|
|
|
|
|
def test_space_separated_cookie_file(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(HEADER + ".example.com TRUE / TRUE 1234567890 sid abc123\n", "utf8")
|
|
|
|
assert _names(dl.load_cookie_file(file)) == {"sid": "abc123"}
|
|
|
|
|
|
def test_tab_separated_value_keeps_spaces(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(
|
|
HEADER + "\t".join([".example.com", "TRUE", "/", "TRUE", "1234567890", "sid", "a b c"]) + "\n", "utf8"
|
|
)
|
|
|
|
assert _names(dl.load_cookie_file(file)) == {"sid": "a b c"}
|
|
|
|
|
|
def test_space_separated_empty_value(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(HEADER + ".example.com TRUE / TRUE 1234567890 sid \n", "utf8")
|
|
|
|
assert _names(dl.load_cookie_file(file)) == {"sid": ""}
|
|
|
|
|
|
def test_space_separated_httponly(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(HEADER + "#HttpOnly_.example.com TRUE / TRUE 1234567890 sid abc123\n", "utf8")
|
|
|
|
assert _names(dl.load_cookie_file(file)) == {"sid": "abc123"}
|
|
|
|
|
|
def test_mixed_separators_in_one_file(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(
|
|
HEADER
|
|
+ "\t".join([".a.com", "TRUE", "/", "TRUE", "1234567890", "tabbed", "1"])
|
|
+ "\n.b.com TRUE / TRUE 1234567890 spaced 2\n",
|
|
"utf8",
|
|
)
|
|
|
|
assert _names(dl.load_cookie_file(file)) == {"tabbed": "1", "spaced": "2"}
|
|
|
|
|
|
def test_malformed_row_is_reported(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(HEADER + ".a.com\tTRUE\t/\tTRUE\t1\tsid\tv\nnot a cookie\n", "utf8")
|
|
|
|
with pytest.raises(ValueError, match="line 3"):
|
|
dl.load_cookie_file(file)
|
|
|
|
|
|
def test_missing_header_is_added(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(".example.com\tTRUE\t/\tTRUE\t1234567890\tsid\tabc123\n", "utf8")
|
|
|
|
assert _names(dl.load_cookie_file(file)) == {"sid": "abc123"}
|
|
|
|
|
|
def test_utf8_bom_is_ignored(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_bytes(b"\xef\xbb\xbf" + (HEADER + ".example.com\tTRUE\t/\tTRUE\t1234567890\tsid\tabc123\n").encode())
|
|
|
|
assert _names(dl.load_cookie_file(file)) == {"sid": "abc123"}
|
|
|
|
|
|
def test_json_export_gives_clear_error(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text('[{"domain": ".example.com", "name": "sid", "value": "abc123"}]\n', "utf8")
|
|
|
|
with pytest.raises(ValueError, match="JSON export"):
|
|
dl.load_cookie_file(file)
|
|
|
|
|
|
def test_leading_blank_line_is_not_json(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text("\n" + HEADER + ".example.com TRUE / TRUE 1234567890 sid abc123\n", "utf8")
|
|
|
|
assert _names(dl.load_cookie_file(file)) == {"sid": "abc123"}
|
|
|
|
|
|
def test_dot_flag_mismatch_does_not_abort_file(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(HEADER + "example.com\tTRUE\t/\tTRUE\t1\tsid\tv\n", "utf8")
|
|
|
|
assert _names(dl.load_cookie_file(file)) == {"sid": "v"}
|
|
|
|
|
|
def test_the_users_file_is_never_rewritten(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
original = ".example.com TRUE / TRUE 1234567890 sid abc123\n"
|
|
file.write_text(original, "utf8")
|
|
|
|
dl.load_cookie_file(file)
|
|
|
|
assert file.read_text("utf8") == original
|
|
|
|
|
|
def test_save_cookies_onto_an_unrepaired_file(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(".example.com TRUE / TRUE 1234567890 sid abc123\n", "utf8")
|
|
|
|
dl.save_cookies(file, CookieJar())
|
|
|
|
assert _names(dl.load_cookie_file(file)) == {"sid": "abc123"}
|
|
|
|
|
|
def test_tabbed_row_is_never_resplit_on_spaces(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(HEADER + ".a.com\tTRUE\t/\tFALSE\thello world\n", "utf8")
|
|
|
|
with pytest.raises(ValueError, match="not a Netscape cookie row"):
|
|
dl.load_cookie_file(file)
|
|
|
|
|
|
def test_file_without_cookies_is_reported(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(HEADER + "# nothing else here\n", "utf8")
|
|
|
|
with pytest.raises(ValueError, match="holds no cookies"):
|
|
dl.load_cookie_file(file)
|
|
|
|
|
|
def test_round_trip_keeps_httponly_and_blank_expiry(tmp_path: Path) -> None:
|
|
file = tmp_path / "cookies.txt"
|
|
file.write_text(HEADER + "#HttpOnly_.example.com TRUE / TRUE 1234567890 sid abc123\n", "utf8")
|
|
|
|
dl.save_cookies(file, CookieJar())
|
|
|
|
assert _names(dl.load_cookie_file(file)) == {"sid": "abc123"}
|
|
assert "#HttpOnly_" in file.read_text("utf8")
|