rapid interations of server side app and firefox extension
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""Utility modules."""
|
||||
@@ -0,0 +1,102 @@
|
||||
"""Cookie parsing and formatting utilities."""
|
||||
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def parse_netscape_cookies(cookie_text: str) -> list[dict]:
|
||||
"""Parse Netscape cookie format into a list of cookie dicts.
|
||||
|
||||
Netscape format: domain<TAB>flag<TAB>path<TAB>secure<TAB>expiration<TAB>name<TAB>value
|
||||
|
||||
Args:
|
||||
cookie_text: Cookie file content in Netscape format
|
||||
|
||||
Returns:
|
||||
List of cookie dictionaries
|
||||
"""
|
||||
cookies = []
|
||||
|
||||
for line in cookie_text.strip().split("\n"):
|
||||
line = line.strip()
|
||||
|
||||
# Skip comments and empty lines
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
|
||||
parts = line.split("\t")
|
||||
if len(parts) < 7:
|
||||
continue
|
||||
|
||||
cookies.append({
|
||||
"domain": parts[0],
|
||||
"flag": parts[1] == "TRUE",
|
||||
"path": parts[2],
|
||||
"secure": parts[3] == "TRUE",
|
||||
"expiration": int(parts[4]) if parts[4] != "0" else None,
|
||||
"name": parts[5],
|
||||
"value": parts[6],
|
||||
})
|
||||
|
||||
return cookies
|
||||
|
||||
|
||||
def to_netscape_format(cookies: list[dict]) -> str:
|
||||
"""Convert cookie list to Netscape format.
|
||||
|
||||
Args:
|
||||
cookies: List of cookie dictionaries
|
||||
|
||||
Returns:
|
||||
Cookie file content in Netscape format
|
||||
"""
|
||||
lines = ["# Netscape HTTP Cookie File"]
|
||||
|
||||
for c in cookies:
|
||||
line = "\t".join([
|
||||
c["domain"],
|
||||
"TRUE" if c.get("flag", True) else "FALSE",
|
||||
c.get("path", "/"),
|
||||
"TRUE" if c.get("secure", False) else "FALSE",
|
||||
str(c.get("expiration", 0) or 0),
|
||||
c["name"],
|
||||
c["value"],
|
||||
])
|
||||
lines.append(line)
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def write_cookie_file(cookies: list[dict], path: Path) -> None:
|
||||
"""Write cookies to a file in Netscape format.
|
||||
|
||||
Args:
|
||||
cookies: List of cookie dictionaries
|
||||
path: Path to write the cookie file
|
||||
"""
|
||||
content = to_netscape_format(cookies)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(content)
|
||||
|
||||
|
||||
def get_platform_from_domain(domain: str) -> Optional[str]:
|
||||
"""Detect platform from cookie domain.
|
||||
|
||||
Args:
|
||||
domain: Cookie domain (e.g., '.patreon.com')
|
||||
|
||||
Returns:
|
||||
Platform name or None
|
||||
"""
|
||||
domain_lower = domain.lower()
|
||||
|
||||
if "patreon.com" in domain_lower:
|
||||
return "patreon"
|
||||
elif "subscribestar" in domain_lower:
|
||||
return "subscribestar"
|
||||
elif "hentai-foundry.com" in domain_lower:
|
||||
return "hentaifoundry"
|
||||
elif "discord.com" in domain_lower:
|
||||
return "discord"
|
||||
|
||||
return None
|
||||
@@ -0,0 +1,46 @@
|
||||
"""Credential encryption utilities."""
|
||||
|
||||
import base64
|
||||
from cryptography.fernet import Fernet
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||
|
||||
|
||||
def _get_fernet(secret_key: str) -> Fernet:
|
||||
"""Derive a Fernet key from the secret key."""
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=b"gallery-subscriber-salt", # Static salt is OK for this use case
|
||||
iterations=100000,
|
||||
)
|
||||
derived_key = base64.urlsafe_b64encode(kdf.derive(secret_key.encode()))
|
||||
return Fernet(derived_key)
|
||||
|
||||
|
||||
def encrypt_data(data: str, secret_key: str) -> bytes:
|
||||
"""Encrypt string data using the secret key.
|
||||
|
||||
Args:
|
||||
data: Plain text data to encrypt
|
||||
secret_key: Application secret key
|
||||
|
||||
Returns:
|
||||
Encrypted bytes
|
||||
"""
|
||||
fernet = _get_fernet(secret_key)
|
||||
return fernet.encrypt(data.encode())
|
||||
|
||||
|
||||
def decrypt_data(encrypted: bytes, secret_key: str) -> str:
|
||||
"""Decrypt data using the secret key.
|
||||
|
||||
Args:
|
||||
encrypted: Encrypted bytes
|
||||
secret_key: Application secret key
|
||||
|
||||
Returns:
|
||||
Decrypted string
|
||||
"""
|
||||
fernet = _get_fernet(secret_key)
|
||||
return fernet.decrypt(encrypted).decode()
|
||||
Reference in New Issue
Block a user