From 11e83028c5f6894d97643d054bbb155d13a1efb9 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 31 Mar 2021 13:58:56 +0200 Subject: [PATCH] prevent duplicate file names --- core/Api/FileAPI.class.php | 24 +++++++++++++++--- core/Configuration/Patch/file_api.class.php | 5 ++-- core/Driver/SQL/SQL.class.php | 9 +++++++ fileControlPanel/src/elements/file-browser.js | 25 ++++++++++++------- js/files.min.js | 2 +- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/core/Api/FileAPI.class.php b/core/Api/FileAPI.class.php index ad12e0c..91f6908 100644 --- a/core/Api/FileAPI.class.php +++ b/core/Api/FileAPI.class.php @@ -250,7 +250,6 @@ namespace Api\File { class GetRestrictions extends FileAPI { public function __construct(User $user, bool $externalCall = false) { parent::__construct($user, $externalCall, array()); - $this->csrfTokenRequired = false; $this->loginRequired = true; } @@ -564,6 +563,24 @@ namespace Api\File { $md5Hash = @hash_file('md5', $tmpPath); $sha1Hash = @hash_file('sha1', $tmpPath); $filePath = $uploadDir . "/" . $md5Hash . $sha1Hash; + + // check if a file with this name already exists + $res = $sql->select($sql->count()) + ->from("UserFile") + ->where(new Compare("name", $fileName)) + ->where(new Compare("user_id", $userId)) + ->where(new Compare("parent_id", $parentId)) + ->execute(); + if ($res === false) { + return $this->createError($sql->getLastError()); + } else { + if ($res[0]["count"] > 0) { + return $this->createError("Error uploading file: a file or directory with this name already exists " . + "in the given upload directory"); + } + } + + // save file to disk and database if (file_exists($filePath) || move_uploaded_file($tmpPath, $filePath)) { $res = $sql->insert("UserFile", array("name", "directory", "path", "user_id", "parent_id")) ->addRow($fileName, false, $filePath, $userId, $parentId) @@ -571,9 +588,7 @@ namespace Api\File { ->execute(); if ($res === false) { - $this->lastError = $sql->getLastError(); - $this->success = false; - return false; + return $this->createError($sql->getLastError()); } else { $fileId = $sql->getLastInsertId(); } @@ -581,6 +596,7 @@ namespace Api\File { return $this->createError("Could not create file: $fileName"); } + // connect to the token, if present if (!is_null($token)) { $res = $sql->insert("UserFileTokenFile", array("file_id", "token_id")) ->addRow($fileId, $tokenId) diff --git a/core/Configuration/Patch/file_api.class.php b/core/Configuration/Patch/file_api.class.php index 21d1add..506fdea 100644 --- a/core/Configuration/Patch/file_api.class.php +++ b/core/Configuration/Patch/file_api.class.php @@ -16,6 +16,7 @@ class file_api extends DatabaseScript { $queries[] = $sql->insert("ApiPermission", array("method", "groups", "description")) ->onDuplicateKeyStrategy(new UpdateStrategy(array("method"), array("method" => new Column("method")))) + ->addRow("File/GetRestrictions", array(), "Allows users to view global upload restrictions") ->addRow("File/Download", array(), "Allows users to download files when logged in, or using a given token") ->addRow("File/Upload", array(), "Allows users to upload files when logged in, or using a given token") ->addRow("File/ValidateToken", array(), "Allows users to validate a given token") @@ -40,9 +41,9 @@ class file_api extends DatabaseScript { ->addString("name", 64, false) ->addString("path", 512, true) ->addInt("parent_id", true) - ->addInt("user_id", true) + ->addInt("user_id") ->primaryKey("uid") - ->unique("parent_id", "name") + ->unique("user_id", "parent_id", "name") ->foreignKey("parent_id", "UserFile", "uid", new CascadeStrategy()) ->foreignKey("user_id", "User", "uid", new CascadeStrategy()); diff --git a/core/Driver/SQL/SQL.class.php b/core/Driver/SQL/SQL.class.php index ba0ffaa..4b1f2e9 100644 --- a/core/Driver/SQL/SQL.class.php +++ b/core/Driver/SQL/SQL.class.php @@ -352,6 +352,15 @@ abstract class SQL { $column = $this->columnName($condition->getColumn()); $value = $condition->getValue(); $operator = $condition->getOperator(); + + if ($value === null) { + if ($operator === "=") { + return "$column IS NULL"; + } else if ($operator === "!=") { + return "$column IS NOT NULL"; + } + } + return $column . $operator . $this->addValue($value, $params); } else if ($condition instanceof CondBool) { return $this->columnName($condition->getValue()); diff --git a/fileControlPanel/src/elements/file-browser.js b/fileControlPanel/src/elements/file-browser.js index fa7e9ab..ce97613 100644 --- a/fileControlPanel/src/elements/file-browser.js +++ b/fileControlPanel/src/elements/file-browser.js @@ -278,12 +278,13 @@ export function FileBrowser(props) { e.stopPropagation(); e.preventDefault(); const cancelToken = filesToUpload[i].cancelToken; - if (cancelToken) { + if (cancelToken && filesToUpload[i].progress < 1) { cancelToken.cancel("Upload cancelled"); - let files = filesToUpload.slice(); - files.splice(i, 1); - setFilesToUpload(files); } + + let files = filesToUpload.slice(); + files.splice(i, 1); + setFilesToUpload(files); } if (writePermissions) { @@ -306,15 +307,17 @@ export function FileBrowser(props) { : <> } - - onCancelUpload(e, i)}/> + + onCancelUpload(e, i)}/> ); } uploadZone = <>
- +