diff --git a/build-plugin.sh b/build-plugin.sh index 441e3fe..da35fd4 100755 --- a/build-plugin.sh +++ b/build-plugin.sh @@ -2,7 +2,7 @@ set -eu PLUGIN="u-navigator" -VERSION="2026.06.23.r045" +VERSION="2026.06.23.r046" PKG_DIR="packages" WORK_DIR=".plugin-build" PKG_NAME="${PLUGIN}-${VERSION}.tgz" diff --git a/packages/u-navigator-2026.06.23.r045.tgz b/packages/u-navigator-2026.06.23.r045.tgz deleted file mode 100644 index 0067e32..0000000 Binary files a/packages/u-navigator-2026.06.23.r045.tgz and /dev/null differ diff --git a/packages/u-navigator-2026.06.23.r046.tgz b/packages/u-navigator-2026.06.23.r046.tgz new file mode 100644 index 0000000..3fd68bc Binary files /dev/null and b/packages/u-navigator-2026.06.23.r046.tgz differ diff --git a/plugin-root/usr/local/emhttp/plugins/u-navigator/api/upload.php b/plugin-root/usr/local/emhttp/plugins/u-navigator/api/upload.php index 5001cbb..fe60f78 100644 --- a/plugin-root/usr/local/emhttp/plugins/u-navigator/api/upload.php +++ b/plugin-root/usr/local/emhttp/plugins/u-navigator/api/upload.php @@ -7,6 +7,31 @@ if (!is_dir($target['path'])) { unav_error(400, 'Upload target must be a directory'); } +if (isset($_GET['relativePath']) || isset($_SERVER['HTTP_X_UNAV_RELATIVE_PATH'])) { + $relativeName = (string)($_GET['relativePath'] ?? $_SERVER['HTTP_X_UNAV_RELATIVE_PATH']); + $destination = unav_prepare_upload_destination($target['path'], $relativeName); + $input = fopen('php://input', 'rb'); + $output = fopen($destination['path'], 'xb'); + if (!$input || !$output) { + if ($input) { + fclose($input); + } + if ($output) { + fclose($output); + } + unav_error(500, 'Could not open upload stream'); + } + stream_copy_to_stream($input, $output); + fclose($input); + fclose($output); + unav_json([ + 'uploaded' => [[ + 'name' => $destination['relative'], + 'size' => filesize($destination['path']) ?: 0, + ]], + ], 201); +} + $uploaded = []; $names = unav_upload_array($_FILES['files']['name'] ?? []); $errors = unav_upload_array($_FILES['files']['error'] ?? []); @@ -17,33 +42,38 @@ foreach ($names as $index => $name) { unav_error(400, 'Upload failed'); } $relativeName = $relativePaths[$index] ?? $name; - $safeName = unav_upload_safe_relative_path((string)$relativeName); + $destination = unav_prepare_upload_destination($target['path'], (string)$relativeName); + if (!move_uploaded_file($tmpNames[$index] ?? '', $destination['path'])) { + unav_error(500, 'Could not store uploaded file'); + } + $uploaded[] = [ + 'name' => $destination['relative'], + 'size' => filesize($destination['path']) ?: 0, + ]; +} + +unav_json(['uploaded' => $uploaded], 201); + +function unav_prepare_upload_destination(string $targetPath, string $relativeName): array { + $safeName = unav_upload_safe_relative_path($relativeName); $relativeParent = dirname($safeName); if ($relativeParent !== '.') { - $parentCandidate = $target['path'] . '/' . $relativeParent; - unav_root_for_real($target['path']); + $parentCandidate = $targetPath . '/' . $relativeParent; + unav_root_for_real($targetPath); if (!is_dir($parentCandidate) && !mkdir($parentCandidate, 0777, true) && !is_dir($parentCandidate)) { unav_error(500, 'Could not create upload directory'); } } - $destination = unav_destination_path($target['path'] . '/' . $safeName); + $destination = unav_destination_path($targetPath . '/' . $safeName); if (file_exists($destination['path'])) { unav_error(409, 'Destination already exists'); } if (!is_dir(dirname($destination['path']))) { unav_error(500, 'Could not create upload directory'); } - if (!move_uploaded_file($tmpNames[$index] ?? '', $destination['path'])) { - unav_error(500, 'Could not store uploaded file'); - } - $uploaded[] = [ - 'name' => $safeName, - 'size' => filesize($destination['path']) ?: 0, - ]; + return ['path' => $destination['path'], 'relative' => $safeName]; } -unav_json(['uploaded' => $uploaded], 201); - function unav_upload_array($value): array { if (is_array($value)) { return array_values($value); diff --git a/server/public/app.js b/server/public/app.js index 01deee2..5cfd2e0 100644 --- a/server/public/app.js +++ b/server/public/app.js @@ -904,13 +904,21 @@ async function uploadFileList(win, files, targetPath) { const uploadItems = normalizeUploadItems(files); for (const [index, item] of uploadItems.entries()) { recordDebug('upload.file.request', { path: item.path, size: item.file.size, index: index + 1, total: uploadItems.length }); - const form = new FormData(); - form.append('files', item.file, item.file.name); - form.append('relativePath', item.path); - appendCsrf(form); - await fetchChecked(apiUrl(`upload.php?path=${encodeURIComponent(targetPath)}`), { + const params = new URLSearchParams({ + path: targetPath, + relativePath: item.path + }); + const token = getCsrfToken(); + if (token) { + params.set('csrf_token', token); + recordDebug('csrf.attached', { length: token.length }); + } else { + recordDebug('csrf.missing', {}); + } + await fetchChecked(apiUrl(`upload.php?${params.toString()}`), { method: 'POST', - body: form + headers: { 'Content-Type': 'application/octet-stream' }, + body: item.file }); recordDebug('upload.file.done', { path: item.path, index: index + 1, total: uploadItems.length }); } diff --git a/u-navigator.plg b/u-navigator.plg index aa0e035..030e657 100644 --- a/u-navigator.plg +++ b/u-navigator.plg @@ -1,7 +1,7 @@ - + @@ -24,7 +24,7 @@ https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package; -cd3b5a92d7174924985b5d929cb180fe +acb81bdc26294c48b2115013cac89015