eaf_base_api 3.3.3__tar.gz → 3.3.4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eaf_base_api
3
- Version: 3.3.3
3
+ Version: 3.3.4
4
4
  Summary: A base API for EchterAlsFake's Porn APIs
5
5
  Author: Johannes Habel
6
6
  Author-email: Johannes Habel <EchterAlsFake@proton.me>
@@ -2,6 +2,8 @@ import os
2
2
  import re
3
3
  import math
4
4
  import json
5
+ import unicodedata
6
+ from pathlib import PurePath
5
7
  from .type_hints import DownloadState
6
8
  from datetime import timezone, datetime
7
9
  from curl_cffi.requests import Response
@@ -432,31 +434,49 @@ def log_precondition_failed(logger, response: Response, attempt: int) -> None:
432
434
  )
433
435
 
434
436
 
435
- def strip_title(title: str, max_length: int = 255) -> str:
436
- """
437
- Sanitize a filename to be safe across Windows, macOS, Linux, and Android.
438
- Replaces or strips illegal characters and trims to a safe length.
437
+ def strip_title(
438
+ title: str, max_length: int = 255, default_name: str = "untitled"
439
+ ) -> str:
440
+ """Sanitize a filename to be safe across Windows, macOS, Linux, and Android.
441
+
442
+ Prevents path traversal, replaces illegal characters, handles Windows reserved
443
+ names, and trims to a safe length.
439
444
  """
445
+ if not title:
446
+ return default_name
447
+
448
+ # 1. Normalize Unicode (converts full-width slashes/characters to standard ASCII where applicable)
449
+ sanitized = unicodedata.normalize("NFKC", title)
440
450
 
441
- # Reserved characters on Windows + `/` for Unix/macOS
451
+ # 2. Extract only the filename component (strips drive letters & path prefixes)
452
+ sanitized = PurePath(sanitized).name
453
+
454
+ # 3. Replace illegal filename characters & explicit path separators with underscores
442
455
  illegal_chars = r'[<>:"/\\|?*\x00-\x1F]'
443
- sanitized = re.sub(illegal_chars, "_", title)
456
+ sanitized = re.sub(illegal_chars, "_", sanitized)
444
457
 
445
- # Strip invisible zero-width characters
446
- sanitized = re.sub(r'[\u200B-\u200D\uFEFF]', '', sanitized)
458
+ # 4. Strip invisible zero-width & non-printable Unicode control characters
459
+ sanitized = re.sub(r"[\u200B-\u200D\uFEFF]", "", sanitized)
447
460
 
448
- # Strip trailing periods or spaces (Windows)
449
- sanitized = sanitized.rstrip(" .")
461
+ # 5. Strip LEADING and TRAILING spaces and dots
462
+ # (Prevents '.' and '..' traversal tokens and hidden files)
463
+ sanitized = sanitized.strip(" .")
450
464
 
451
- # Prevent reserved Windows filenames
465
+ # 6. Prevent Windows reserved filenames (CON, PRN, AUX, NUL, COM1-9, LPT1-9)
452
466
  reserved_names = {
453
- "CON", "PRN", "AUX", "NUL",
467
+ "CON",
468
+ "PRN",
469
+ "AUX",
470
+ "NUL",
454
471
  *(f"COM{i}" for i in range(1, 10)),
455
472
  *(f"LPT{i}" for i in range(1, 10)),
456
473
  }
457
- name_only = sanitized.split('.')[0].upper()
474
+ name_only = sanitized.split(".")[0].upper()
458
475
  if name_only in reserved_names:
459
476
  sanitized = f"_{sanitized}"
460
477
 
461
- # Trim to max length
462
- return sanitized[:max_length]
478
+ # 7. Trim to max length, then re-strip trailing dots/spaces in case the slice cut mid-string
479
+ sanitized = sanitized[:max_length].rstrip(" .")
480
+
481
+ # 8. Return default fallback if sanitization leaves an empty string
482
+ return sanitized if sanitized else default_name
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "eaf_base_api"
7
- version = "3.3.3"
7
+ version = "3.3.4"
8
8
  description = "A base API for EchterAlsFake's Porn APIs"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.12"
File without changes
File without changes