diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..bcb5099 --- /dev/null +++ b/composer.json @@ -0,0 +1,11 @@ +{ + "name": "error311/filerise", + "description": "FileRise – A lightweight self-hosted file manager", + "type": "project", + "require": { + "jumbojett/openid-connect-php": "^1.0.0", + "phpseclib/phpseclib": "~3.0.7", + "robthree/twofactorauth": "^1.7", + "endroid/qr-code": "^4.0" + } + } \ No newline at end of file diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..5855b57 --- /dev/null +++ b/composer.lock @@ -0,0 +1,537 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "c9857f23364f2280ef4b71cdc72d3f78", + "packages": [ + { + "name": "bacon/bacon-qr-code", + "version": "2.0.8", + "source": { + "type": "git", + "url": "https://github.com/Bacon/BaconQrCode.git", + "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22", + "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22", + "shasum": "" + }, + "require": { + "dasprid/enum": "^1.0.3", + "ext-iconv": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phly/keep-a-changelog": "^2.1", + "phpunit/phpunit": "^7 | ^8 | ^9", + "spatie/phpunit-snapshot-assertions": "^4.2.9", + "squizlabs/php_codesniffer": "^3.4" + }, + "suggest": { + "ext-imagick": "to generate QR code images" + }, + "type": "library", + "autoload": { + "psr-4": { + "BaconQrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "BaconQrCode is a QR code generator for PHP.", + "homepage": "https://github.com/Bacon/BaconQrCode", + "support": { + "issues": "https://github.com/Bacon/BaconQrCode/issues", + "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8" + }, + "time": "2022-12-07T17:46:57+00:00" + }, + { + "name": "dasprid/enum", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/DASPRiD/Enum.git", + "reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/8dfd07c6d2cf31c8da90c53b83c026c7696dda90", + "reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90", + "shasum": "" + }, + "require": { + "php": ">=7.1 <9.0" + }, + "require-dev": { + "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "DASPRiD\\Enum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Ben Scholzen 'DASPRiD'", + "email": "mail@dasprids.de", + "homepage": "https://dasprids.de/", + "role": "Developer" + } + ], + "description": "PHP 7.1 enum implementation", + "keywords": [ + "enum", + "map" + ], + "support": { + "issues": "https://github.com/DASPRiD/Enum/issues", + "source": "https://github.com/DASPRiD/Enum/tree/1.0.6" + }, + "time": "2024-08-09T14:30:48+00:00" + }, + { + "name": "endroid/qr-code", + "version": "4.8.5", + "source": { + "type": "git", + "url": "https://github.com/endroid/qr-code.git", + "reference": "0db25b506a8411a5e1644ebaa67123a6eb7b6a77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/endroid/qr-code/zipball/0db25b506a8411a5e1644ebaa67123a6eb7b6a77", + "reference": "0db25b506a8411a5e1644ebaa67123a6eb7b6a77", + "shasum": "" + }, + "require": { + "bacon/bacon-qr-code": "^2.0.5", + "php": "^8.1" + }, + "conflict": { + "khanamiryan/qrcode-detector-decoder": "^1.0.6" + }, + "require-dev": { + "endroid/quality": "dev-master", + "ext-gd": "*", + "khanamiryan/qrcode-detector-decoder": "^1.0.4||^2.0.2", + "setasign/fpdf": "^1.8.2" + }, + "suggest": { + "ext-gd": "Enables you to write PNG images", + "khanamiryan/qrcode-detector-decoder": "Enables you to use the image validator", + "roave/security-advisories": "Makes sure package versions with known security issues are not installed", + "setasign/fpdf": "Enables you to use the PDF writer" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Endroid\\QrCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeroen van den Enden", + "email": "info@endroid.nl" + } + ], + "description": "Endroid QR Code", + "homepage": "https://github.com/endroid/qr-code", + "keywords": [ + "code", + "endroid", + "php", + "qr", + "qrcode" + ], + "support": { + "issues": "https://github.com/endroid/qr-code/issues", + "source": "https://github.com/endroid/qr-code/tree/4.8.5" + }, + "funding": [ + { + "url": "https://github.com/endroid", + "type": "github" + } + ], + "time": "2023-09-29T14:03:20+00:00" + }, + { + "name": "jumbojett/openid-connect-php", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/jumbojett/OpenID-Connect-PHP.git", + "reference": "f327e7eb0626d55ddb6abc7b7c9e6ad3af4e5d51" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jumbojett/OpenID-Connect-PHP/zipball/f327e7eb0626d55ddb6abc7b7c9e6ad3af4e5d51", + "reference": "f327e7eb0626d55ddb6abc7b7c9e6ad3af4e5d51", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "php": ">=7.0", + "phpseclib/phpseclib": "^3.0.7" + }, + "require-dev": { + "phpunit/phpunit": "<10", + "roave/security-advisories": "dev-latest", + "yoast/phpunit-polyfills": "^2.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Bare-bones OpenID Connect client", + "support": { + "issues": "https://github.com/jumbojett/OpenID-Connect-PHP/issues", + "source": "https://github.com/jumbojett/OpenID-Connect-PHP/tree/v1.0.2" + }, + "time": "2024-09-13T07:08:11+00:00" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512", + "shasum": "" + }, + "require": { + "php": "^8" + }, + "require-dev": { + "phpunit/phpunit": "^9", + "vimeo/psalm": "^4|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2024-05-08T12:36:18+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" + }, + { + "name": "phpseclib/phpseclib", + "version": "3.0.43", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/709ec107af3cb2f385b9617be72af8cf62441d02", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1|^2|^3", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.43" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2024-12-14T21:12:59+00:00" + }, + { + "name": "robthree/twofactorauth", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/RobThree/TwoFactorAuth.git", + "reference": "65681de5a324eae05140ac58b08648a60212afc0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/65681de5a324eae05140ac58b08648a60212afc0", + "reference": "65681de5a324eae05140ac58b08648a60212afc0", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpunit/phpunit": "@stable" + }, + "suggest": { + "bacon/bacon-qr-code": "Needed for BaconQrCodeProvider provider", + "endroid/qr-code": "Needed for EndroidQrCodeProvider" + }, + "type": "library", + "autoload": { + "psr-4": { + "RobThree\\Auth\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rob Janssen", + "homepage": "http://robiii.me", + "role": "Developer" + } + ], + "description": "Two Factor Authentication", + "homepage": "https://github.com/RobThree/TwoFactorAuth", + "keywords": [ + "Authentication", + "MFA", + "Multi Factor Authentication", + "Two Factor Authentication", + "authenticator", + "authy", + "php", + "tfa" + ], + "support": { + "issues": "https://github.com/RobThree/TwoFactorAuth/issues", + "source": "https://github.com/RobThree/TwoFactorAuth" + }, + "funding": [ + { + "url": "https://paypal.me/robiii", + "type": "custom" + }, + { + "url": "https://github.com/RobThree", + "type": "github" + } + ], + "time": "2022-03-22T16:11:07+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.6.0" +} diff --git a/styles.css b/css/styles.css similarity index 100% rename from styles.css rename to css/styles.css diff --git a/index.html b/index.html index e5a07df..d541d4e 100644 --- a/index.html +++ b/index.html @@ -21,7 +21,7 @@ - + @@ -395,7 +395,7 @@ - + \ No newline at end of file diff --git a/auth.js b/js/auth.js similarity index 100% rename from auth.js rename to js/auth.js diff --git a/authModals.js b/js/authModals.js similarity index 100% rename from authModals.js rename to js/authModals.js diff --git a/domUtils.js b/js/domUtils.js similarity index 100% rename from domUtils.js rename to js/domUtils.js diff --git a/dragAndDrop.js b/js/dragAndDrop.js similarity index 100% rename from dragAndDrop.js rename to js/dragAndDrop.js diff --git a/fileManager.js b/js/fileManager.js similarity index 96% rename from fileManager.js rename to js/fileManager.js index 2e32659..a177796 100644 --- a/fileManager.js +++ b/js/fileManager.js @@ -922,19 +922,62 @@ export function handleCopySelected(e) { } export async function loadCopyMoveFolderListForModal(dropdownId) { + const folderSelect = document.getElementById(dropdownId); + folderSelect.innerHTML = ""; + + // Check if the user is restricted to their personal folder. + if (window.userFolderOnly) { + const username = localStorage.getItem("username") || "root"; + try { + // Fetch only the user's folders (assuming getFolderList.php?restricted=1 returns only folders for the user). + const response = await fetch("getFolderList.php?restricted=1"); + let folders = await response.json(); + // If folders come as objects, extract the folder names. + if (Array.isArray(folders) && folders.length && typeof folders[0] === "object" && folders[0].folder) { + folders = folders.map(item => item.folder); + } + // Filter out folders named "trash" (case insensitive) and include only folders that are the user's folder or start with username + "/" + folders = folders.filter(folder => + folder.toLowerCase() !== "trash" && + (folder === username || folder.indexOf(username + "/") === 0) + ); + + // Always include the user's root folder as the first option. + const rootOption = document.createElement("option"); + rootOption.value = username; + rootOption.textContent = formatFolderName(username); + folderSelect.appendChild(rootOption); + + // Add any subfolders (if they exist). + folders.forEach(folder => { + if (folder !== username) { // Avoid duplicating the root. + const option = document.createElement("option"); + option.value = folder; + option.textContent = formatFolderName(folder); + folderSelect.appendChild(option); + } + }); + } catch (error) { + console.error("Error loading folder list for modal:", error); + } + return; + } + + // If not folder-only, fetch and show the full list (excluding "root" and "trash"). try { const response = await fetch("getFolderList.php"); let folders = await response.json(); if (Array.isArray(folders) && folders.length && typeof folders[0] === "object" && folders[0].folder) { folders = folders.map(item => item.folder); } - folders = folders.filter(folder => folder !== "root"); - const folderSelect = document.getElementById(dropdownId); - folderSelect.innerHTML = ""; + folders = folders.filter(folder => folder !== "root" && folder.toLowerCase() !== "trash"); + + // Add a "(Root)" option. const rootOption = document.createElement("option"); rootOption.value = "root"; rootOption.textContent = "(Root)"; folderSelect.appendChild(rootOption); + if (Array.isArray(folders) && folders.length > 0) { folders.forEach(folder => { const option = document.createElement("option"); diff --git a/fileTags.js b/js/fileTags.js similarity index 100% rename from fileTags.js rename to js/fileTags.js diff --git a/folderManager.js b/js/folderManager.js similarity index 100% rename from folderManager.js rename to js/folderManager.js diff --git a/main.js b/js/main.js similarity index 100% rename from main.js rename to js/main.js diff --git a/networkUtils.js b/js/networkUtils.js similarity index 100% rename from networkUtils.js rename to js/networkUtils.js diff --git a/trashRestoreDelete.js b/js/trashRestoreDelete.js similarity index 100% rename from trashRestoreDelete.js rename to js/trashRestoreDelete.js diff --git a/upload.js b/js/upload.js similarity index 93% rename from upload.js rename to js/upload.js index 5fe241e..6c6faf5 100644 --- a/upload.js +++ b/js/upload.js @@ -497,11 +497,9 @@ function initResumableUpload() { resumableInstance.on("fileSuccess", function(file, message) { const li = document.querySelector(`li.upload-progress-item[data-upload-index="${file.uniqueIdentifier}"]`); if (li && li.progressBar) { - // Clear any merging indicators. li.progressBar.style.width = "100%"; li.progressBar.innerText = "Done"; - - // Optionally hide the pause/resume and remove buttons. + // Hide pause/resume and remove buttons for successful files. const pauseResumeBtn = li.querySelector(".pause-resume-btn"); if (pauseResumeBtn) { pauseResumeBtn.style.display = "none"; @@ -510,9 +508,17 @@ function initResumableUpload() { if (removeBtn) { removeBtn.style.display = "none"; } + // Schedule removal of the file entry after 5 seconds. + setTimeout(() => { + li.remove(); + window.selectedFiles = window.selectedFiles.filter(f => f.uniqueIdentifier !== file.uniqueIdentifier); + updateFileInfoCount(); + }, 5000); } loadFileList(window.currentFolder); }); + + resumableInstance.on("fileError", function (file, message) { const li = document.querySelector(`li.upload-progress-item[data-upload-index="${file.uniqueIdentifier}"]`); @@ -521,7 +527,6 @@ function initResumableUpload() { } // Mark file as errored so that the pause/resume button acts as a restart button. file.isError = true; - // Change the pause/resume button to show a restart icon. const pauseResumeBtn = li ? li.querySelector(".pause-resume-btn") : null; if (pauseResumeBtn) { pauseResumeBtn.innerHTML = 'replay'; @@ -531,17 +536,17 @@ function initResumableUpload() { }); resumableInstance.on("complete", function () { - // Check if any file in the current selection is marked with an error. + // If any file is marked with an error, leave the list intact. const hasError = window.selectedFiles.some(f => f.isError); if (!hasError) { - // All files succeeded; clear the file list after 5 seconds. + // All files succeeded—clear the file input and progress container after 5 seconds. setTimeout(() => { + const fileInput = document.getElementById("file"); if (fileInput) fileInput.value = ""; const progressContainer = document.getElementById("uploadProgressContainer"); progressContainer.innerHTML = ""; window.selectedFiles = []; adjustFolderHelpExpansionClosed(); - window.addEventListener("resize", adjustFolderHelpExpansionClosed); const fileInfoContainer = document.getElementById("fileInfoContainer"); if (fileInfoContainer) { fileInfoContainer.innerHTML = `No files selected`; @@ -668,40 +673,39 @@ function submitFiles(allFiles) { .then(serverFiles => { initFileActions(); serverFiles = (serverFiles || []).map(item => item.name.trim().toLowerCase()); - let allSucceeded = true; + let overallSuccess = true; allFiles.forEach(file => { - // For files without a relative path - if ((file.webkitRelativePath || file.customRelativePath || "").trim() === "") { - const clientFileName = file.name.trim().toLowerCase(); - if (!uploadResults[file.uploadIndex] || !serverFiles.includes(clientFileName)) { - const li = progressElements[file.uploadIndex]; - if (li) { - li.progressBar.innerText = "Error"; - } - allSucceeded = false; + const clientFileName = file.name.trim().toLowerCase(); + const li = progressElements[file.uploadIndex]; + if (!uploadResults[file.uploadIndex] || !serverFiles.includes(clientFileName)) { + if (li) { + li.progressBar.innerText = "Error"; } + overallSuccess = false; + } else if (li) { + // Schedule removal of successful file entry after 5 seconds. + setTimeout(() => { + li.remove(); + delete progressElements[file.uploadIndex]; + updateFileInfoCount(); + const progressContainer = document.getElementById("uploadProgressContainer"); + if (progressContainer && progressContainer.querySelectorAll("li.upload-progress-item").length === 0) { + const fileInput = document.getElementById("file"); + if (fileInput) fileInput.value = ""; + progressContainer.innerHTML = ""; + adjustFolderHelpExpansionClosed(); + const fileInfoContainer = document.getElementById("fileInfoContainer"); + if (fileInfoContainer) { + fileInfoContainer.innerHTML = `No files selected`; + } + const dropArea = document.getElementById("uploadDropArea"); + if (dropArea) setDropAreaDefault(); + } + }, 5000); } }); - if (allSucceeded) { - // All files succeeded—clear the list after 5 seconds. - setTimeout(() => { - if (fileInput) fileInput.value = ""; - const removeBtns = progressContainer.querySelectorAll("button.remove-file-btn"); - removeBtns.forEach(btn => btn.style.display = "none"); - progressContainer.innerHTML = ""; - window.selectedFiles = []; - adjustFolderHelpExpansionClosed(); - window.addEventListener("resize", adjustFolderHelpExpansionClosed); - const fileInfoContainer = document.getElementById("fileInfoContainer"); - if (fileInfoContainer) { - fileInfoContainer.innerHTML = `No files selected`; - } - const dropArea = document.getElementById("uploadDropArea"); - if (dropArea) setDropAreaDefault(); - }, 5000); - } else { - // Some files failed—keep the list visible and show a toast. + if (!overallSuccess) { showToast("Some files failed to upload. Please check the list."); } }) diff --git a/metadata/createdTags.json b/metadata/createdTags.json deleted file mode 100644 index 0637a08..0000000 --- a/metadata/createdTags.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/resources/readme.md b/resources/readme.md deleted file mode 100644 index bf8306d..0000000 --- a/resources/readme.md +++ /dev/null @@ -1 +0,0 @@ -This resource folder is just to hold images of design diff --git a/upload.php b/upload.php index 3ecf003..15eeeb1 100644 --- a/upload.php +++ b/upload.php @@ -20,12 +20,12 @@ if (!isset($_SESSION['authenticated']) || $_SESSION['authenticated'] !== true) { } $username = $_SESSION['username'] ?? ''; -$userPermissions = loadUserPermissions($username); if ($username) { $userPermissions = loadUserPermissions($username); if (isset($userPermissions['disableUpload']) && $userPermissions['disableUpload'] === true) { + http_response_code(403); // Return a 403 Forbidden status. echo json_encode(["error" => "Disabled upload users are not allowed to upload."]); - exit(); + exit; } } @@ -63,6 +63,14 @@ if (isset($_POST['resumableChunkNumber'])) { $totalSize = intval($_POST['resumableTotalSize']); $resumableIdentifier = $_POST['resumableIdentifier']; // unique file identifier $resumableFilename = $_POST['resumableFilename']; + + +if (!preg_match('/^[A-Za-z0-9_\-\.\(\) ]+$/', $resumableFilename)) { + http_response_code(400); // Set an error HTTP status code + echo json_encode(["error" => "Invalid file name: " . $resumableFilename]); + exit; +} + $folder = isset($_POST['folder']) ? trim($_POST['folder']) : 'root'; if ($folder !== 'root' && !preg_match('/^[A-Za-z0-9_\- \/]+$/', $folder)) { echo json_encode(["error" => "Invalid folder name"]); diff --git a/uploads/.gitkeep b/uploads/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/uploads/.htaccess b/uploads/.htaccess deleted file mode 100644 index 4fdfd1d..0000000 --- a/uploads/.htaccess +++ /dev/null @@ -1,7 +0,0 @@ - - php_flag engine off - - - php_flag engine off - -Options -Indexes \ No newline at end of file diff --git a/users/.gitkeep b/users/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/users/.htaccess b/users/.htaccess deleted file mode 100644 index b1a156d..0000000 --- a/users/.htaccess +++ /dev/null @@ -1,3 +0,0 @@ - - Require all denied -