| from __future__ import annotations | |
| import re | |
| import os | |
| from urllib.parse import unquote | |
| from .cookies import get_cookies_dir | |
| def secure_filename(filename: str, max_length: int = 100) -> str: | |
| """Sanitize a filename for safe filesystem storage.""" | |
| if filename is None: | |
| return None | |
| # Keep letters, numbers, basic punctuation, underscores | |
| filename = re.sub( | |
| r"[^\w.,_+\-]+", | |
| "_", | |
| unquote(filename).strip(), | |
| flags=re.UNICODE | |
| ) | |
| encoding = "utf-8" | |
| encoded = filename.encode(encoding)[:max_length] | |
| decoded = encoded.decode(encoding, "ignore") | |
| return decoded.strip(".,_+-") | |
| def get_bucket_dir(*parts: str) -> str: | |
| """Return a path under the cookies 'buckets' directory with sanitized parts.""" | |
| return os.path.join( | |
| get_cookies_dir(), | |
| "buckets", | |
| *[secure_filename(part) for part in parts if part] | |
| ) |