diff --git a/build-plugin.sh b/build-plugin.sh index 8793783..be190c0 100755 --- a/build-plugin.sh +++ b/build-plugin.sh @@ -2,7 +2,7 @@ set -eu PLUGIN="u-navigator" -VERSION="2026.06.23.r007" +VERSION="2026.06.23.r008" PKG_DIR="packages" WORK_DIR=".plugin-build" PKG_NAME="${PLUGIN}-${VERSION}.tgz" diff --git a/packages/u-navigator-2026.06.23.r007.tgz b/packages/u-navigator-2026.06.23.r007.tgz deleted file mode 100644 index 0acadf2..0000000 Binary files a/packages/u-navigator-2026.06.23.r007.tgz and /dev/null differ diff --git a/packages/u-navigator-2026.06.23.r008.tgz b/packages/u-navigator-2026.06.23.r008.tgz new file mode 100644 index 0000000..b500b03 Binary files /dev/null and b/packages/u-navigator-2026.06.23.r008.tgz differ diff --git a/plugin-root/usr/local/emhttp/plugins/u-navigator/api/common.php b/plugin-root/usr/local/emhttp/plugins/u-navigator/api/common.php index 89a3c42..136c4f4 100644 --- a/plugin-root/usr/local/emhttp/plugins/u-navigator/api/common.php +++ b/plugin-root/usr/local/emhttp/plugins/u-navigator/api/common.php @@ -107,6 +107,13 @@ function unav_request_json(): array { return $data; } +function unav_request_data(): array { + if (!empty($_POST)) { + return $_POST; + } + return unav_request_json(); +} + function unav_copy_recursive(string $source, string $destination): void { if (is_link($source)) { unav_error(400, 'Copying symlinks is not allowed'); diff --git a/plugin-root/usr/local/emhttp/plugins/u-navigator/api/job.php b/plugin-root/usr/local/emhttp/plugins/u-navigator/api/job.php index dfe7275..cd750af 100644 --- a/plugin-root/usr/local/emhttp/plugins/u-navigator/api/job.php +++ b/plugin-root/usr/local/emhttp/plugins/u-navigator/api/job.php @@ -12,7 +12,7 @@ if (!in_array($action, ['move', 'copy'], true)) { unav_error(404, 'Unknown job action'); } -$data = unav_request_json(); +$data = unav_request_data(); $source = unav_existing_path($data['source'] ?? null); $destination = unav_destination_path($data['destination'] ?? null); unav_guard_destination($source['path'], $destination['path']); diff --git a/server/public/app.js b/server/public/app.js index 3b52f25..5935991 100644 --- a/server/public/app.js +++ b/server/public/app.js @@ -380,6 +380,7 @@ async function handleDrop(event, win, targetPath) { for (const file of files) { form.append('files', file, file.name); } + appendCsrf(form); await fetchChecked(apiUrl(`upload.php?path=${encodeURIComponent(targetPath)}`), { method: 'POST', body: form @@ -390,10 +391,14 @@ async function handleDrop(event, win, targetPath) { async function createJob(type, source, destination) { recordDebug('job.create.request', { type, source, destination }); + const body = new URLSearchParams(); + body.set('source', source); + body.set('destination', destination); + appendCsrf(body); const job = await api(apiUrl(`job.php?action=${encodeURIComponent(type)}`), { method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ source, destination }) + headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, + body }); recordDebug('job.create.response', job); state.jobs.set(job.id, job); @@ -911,6 +916,24 @@ function apiUrl(path) { return `${API_BASE.replace(/\/$/, '')}/${path.replace(/^\//, '')}`; } +function appendCsrf(body) { + const token = getCsrfToken(); + if (!token) { + recordDebug('csrf.missing', {}); + return; + } + body.append('csrf_token', token); + recordDebug('csrf.attached', { length: token.length }); +} + +function getCsrfToken() { + return window.csrf_token + || document.querySelector('input[name="csrf_token"]')?.value + || document.querySelector('meta[name="csrf_token"]')?.content + || document.querySelector('meta[name="csrf-token"]')?.content + || ''; +} + function recordDebug(label, data = {}) { const item = { id: state.nextDebugId++, diff --git a/u-navigator.plg b/u-navigator.plg index 620221a..254ffcc 100644 --- a/u-navigator.plg +++ b/u-navigator.plg @@ -1,7 +1,7 @@ - + ]> @@ -14,7 +14,7 @@ https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package; -c9e2b618f5907747315c5f17e80b132f +6a584ee446fc442c9a3c95877f15d1ae