avoid breaking out into filestructure

This commit is contained in:
lelo 2025-05-18 22:25:50 +02:00
parent 564d95a5c2
commit a0f972f38a
2 changed files with 40 additions and 1 deletions

34
app.py
View File

@ -15,6 +15,7 @@ import geoip2.database
from functools import lru_cache
from urllib.parse import urlparse, unquote
from werkzeug.middleware.proxy_fix import ProxyFix
from pathlib import Path
import re
import qrcode
import base64
@ -24,6 +25,7 @@ import analytics as a
import folder_secret_config_editor as fsce
app_config = auth.return_app_config()
BASE_DIR = os.path.realpath(app_config['BASE_DIR'])
cache_audio = diskcache.Cache('./filecache_audio', size_limit= app_config['filecache_size_limit_audio'] * 1024**3)
cache_image = diskcache.Cache('./filecache_image', size_limit= app_config['filecache_size_limit_image'] * 1024**3)
@ -90,6 +92,27 @@ def get_cached_image(size):
resized_img.save(img_byte_arr, format='PNG')
return img_byte_arr.getvalue()
def check_path(access_path: str) -> Path:
"""
Take an absolute access_path, then ensure it lives inside BASE_DIR.
Raises ValueError or PermissionError on failure.
"""
p = Path(access_path)
if not p.is_absolute():
raise ValueError(f"Path {access_path} is not a valid absolute path")
# Resolve symlinks & eliminate “..” components
candidate = p.resolve()
base = Path(BASE_DIR).resolve()
try:
# Will raise ValueError if candidate is not under base
candidate.relative_to(base)
except ValueError:
raise PermissionError(f"Access to {access_path} is forbidden")
return candidate
def list_directory_contents(directory, subpath):
"""
List only the immediate contents of the given directory.
@ -236,6 +259,12 @@ def api_browse(subpath):
directory = os.path.join(base_path, *relative_parts)
playfile = None
try:
directory = check_path(directory)
except (ValueError, PermissionError) as e:
return jsonify({'error': str(e)}), 403
# Check if the constructed directory exists.
if not os.path.isdir(directory):
# Assume the last segment is a filename; remove it.
@ -271,6 +300,11 @@ def serve_file(subpath):
base_path = session['folders'].get(root)
full_path = os.path.join(base_path or '', *relative_parts)
try:
full_path = check_path(full_path)
except (ValueError, PermissionError) as e:
return jsonify({'error': str(e)}), 403
if not os.path.isfile(full_path):
app.logger.error(f"File not found: {full_path}")
return "File not found", 404

View File

@ -213,7 +213,12 @@ function loadDirectory(subpath) {
.then(data => {
clearTimeout(spinnerTimer);
hideSpinner();
if (data.breadcrumbs) {
renderContent(data);
} else if (data.error) {
document.getElementById('content').innerHTML = `<div class="alert alert-warning">${data.error}</div>`;
return;
}
if (data.playfile) {
const playFileLink = document.querySelector(`.play-file[data-url="${data.playfile}"]`);
if (playFileLink) {