prune shared files not found
This commit is contained in:
parent
59c510f193
commit
4061633daa
|
|
@ -11,10 +11,56 @@ from datetime import datetime, timezone
|
||||||
from typing import Optional, Dict, Any
|
from typing import Optional, Dict, Any
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
from .utils import validate_path_security
|
||||||
|
|
||||||
# Thread lock for safe concurrent access
|
# Thread lock for safe concurrent access
|
||||||
_lock = threading.Lock()
|
_lock = threading.Lock()
|
||||||
|
|
||||||
|
|
||||||
|
def _token_references_accessible_file(storage_dir: str, rel_path: Any) -> bool:
|
||||||
|
"""
|
||||||
|
Return True if rel_path is a string that resolves to a regular file under storage_dir
|
||||||
|
and passes the same path boundary check used elsewhere in the app.
|
||||||
|
"""
|
||||||
|
if not rel_path or not isinstance(rel_path, str):
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
full = (Path(storage_dir) / rel_path).resolve()
|
||||||
|
except (OSError, ValueError, RuntimeError):
|
||||||
|
return False
|
||||||
|
if not validate_path_security(str(storage_dir), full):
|
||||||
|
return False
|
||||||
|
return full.is_file()
|
||||||
|
|
||||||
|
|
||||||
|
def _prune_inaccessible_unsafe(data_dir: str) -> int:
|
||||||
|
"""
|
||||||
|
Remove share tokens whose stored path is missing or not under the notes directory.
|
||||||
|
Call only while holding _lock. Returns the number of tokens removed.
|
||||||
|
"""
|
||||||
|
tokens = load_tokens(data_dir)
|
||||||
|
if not tokens:
|
||||||
|
return 0
|
||||||
|
kept: Dict[str, Dict[str, Any]] = {}
|
||||||
|
for token, info in tokens.items():
|
||||||
|
path = info.get("path")
|
||||||
|
if _token_references_accessible_file(data_dir, path):
|
||||||
|
kept[token] = info
|
||||||
|
removed = len(tokens) - len(kept)
|
||||||
|
if removed and not save_tokens(data_dir, kept):
|
||||||
|
return 0
|
||||||
|
return removed
|
||||||
|
|
||||||
|
|
||||||
|
def prune_inaccessible_share_tokens(data_dir: str) -> int:
|
||||||
|
"""
|
||||||
|
Remove entries whose path no longer resolves to a file under the storage root.
|
||||||
|
Called automatically after create/revoke share; may also be used from tests or one-off maintenance.
|
||||||
|
"""
|
||||||
|
with _lock:
|
||||||
|
return _prune_inaccessible_unsafe(data_dir)
|
||||||
|
|
||||||
|
|
||||||
def generate_token(length: int = 16) -> str:
|
def generate_token(length: int = 16) -> str:
|
||||||
"""Generate a URL-safe random token."""
|
"""Generate a URL-safe random token."""
|
||||||
# Use alphanumeric + underscore/hyphen (URL-safe)
|
# Use alphanumeric + underscore/hyphen (URL-safe)
|
||||||
|
|
@ -76,6 +122,7 @@ def create_share_token(data_dir: str, note_path: str, theme: str = "light") -> O
|
||||||
# Check if note already has a token
|
# Check if note already has a token
|
||||||
for token, info in tokens.items():
|
for token, info in tokens.items():
|
||||||
if info.get('path') == note_path:
|
if info.get('path') == note_path:
|
||||||
|
_prune_inaccessible_unsafe(data_dir)
|
||||||
return token
|
return token
|
||||||
|
|
||||||
# Generate new token
|
# Generate new token
|
||||||
|
|
@ -93,7 +140,9 @@ def create_share_token(data_dir: str, note_path: str, theme: str = "light") -> O
|
||||||
}
|
}
|
||||||
|
|
||||||
if save_tokens(data_dir, tokens):
|
if save_tokens(data_dir, tokens):
|
||||||
|
_prune_inaccessible_unsafe(data_dir)
|
||||||
return token
|
return token
|
||||||
|
_prune_inaccessible_unsafe(data_dir)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -177,8 +226,13 @@ def revoke_share_token(data_dir: str, note_path: str) -> bool:
|
||||||
|
|
||||||
if token_to_remove:
|
if token_to_remove:
|
||||||
del tokens[token_to_remove]
|
del tokens[token_to_remove]
|
||||||
return save_tokens(data_dir, tokens)
|
if not save_tokens(data_dir, tokens):
|
||||||
|
_prune_inaccessible_unsafe(data_dir)
|
||||||
|
return False
|
||||||
|
_prune_inaccessible_unsafe(data_dir)
|
||||||
|
return True
|
||||||
|
|
||||||
|
_prune_inaccessible_unsafe(data_dir)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue