From c546bf6da8f8eb1993c3f167c93776ad18aa791c Mon Sep 17 00:00:00 2001 From: flashwave Date: Tue, 7 Nov 2023 21:33:46 +0000 Subject: [PATCH] Attempt at fixing bogus 'File not found' errors. --- public/index.php | 42 ++++++++++++++++++----------------------- src/Application.php | 9 ++------- src/Upload.php | 46 ++++++++++++++++++++++++++++++++++----------- src/User.php | 9 ++------- 4 files changed, 57 insertions(+), 49 deletions(-) diff --git a/public/index.php b/public/index.php index 66841ae..7f4d652 100644 --- a/public/index.php +++ b/public/index.php @@ -1,6 +1,7 @@ getParam('src', FILTER_VALIDATE_INT)); - } catch(ApplicationNotFoundException $ex) { + } catch(RuntimeException $ex) { return 404; } @@ -153,7 +154,7 @@ if($isApiDomain) { try { $file = $content->getUploadedFile('file'); - } catch(\RuntimeException $ex) { + } catch(RuntimeException $ex) { return 400; } @@ -171,7 +172,9 @@ if($isApiDomain) { } $hash = hash_file('sha256', $localFile); - $fileInfo = Upload::byHash($db, $hash); + + // this is stupid: dmca status is stored as a file record rather than in a separate table requiring this hack ass garbage + $fileInfo = Upload::byUserHash($db, $userInfo, $hash) ?? Upload::byHash($db, $hash); if($fileInfo !== null) { if($fileInfo->isDMCA()) @@ -185,26 +188,17 @@ if($isApiDomain) { if(!empty($fileInfo)) { if($fileInfo->isDeleted()) $fileInfo->restore($db); + $fileInfo->bumpExpiry($db); } else { - try { - $fileInfo = Upload::create( - $db, $appInfo, $userInfo, - $file->getSuggestedFileName(), - mime_content_type($localFile), - $fileSize, $hash, - $appInfo->getExpiry(), true - ); - } catch(UploadCreationFailedException $ex) { - \Sentry\captureException($ex); - return 500; - } + $fileInfo = Upload::create( + $db, $appInfo, $userInfo, + $file->getSuggestedFileName(), + mime_content_type($localFile), + $fileSize, $hash, + $appInfo->getExpiry(), true + ); - try { - $file->moveTo($fileInfo->getPath()); - } catch(\RuntimeException $ex) { - \Sentry\captureException($ex); - return 500; - } + $file->moveTo($fileInfo->getPath()); } $response->setStatusCode(201); @@ -215,7 +209,7 @@ if($isApiDomain) { $router->delete('/uploads/:fileid', function($response, $request, $fileId) use ($db) { try { $uploadInfo = Upload::byId($db, $fileId); - } catch(UploadNotFoundException $ex) { + } catch(RuntimeException $ex) { $response->setContent('File not found.'); return 404; } @@ -252,7 +246,7 @@ if($isApiDomain) { try { $uploadInfo = Upload::byId($db, $fileId); - } catch(UploadNotFoundException $ex) { + } catch(RuntimeException $ex) { $response->setContent('File not found.'); return 404; } @@ -318,7 +312,7 @@ if($isApiDomain) { try { $uploadInfo = Upload::byId($db, $fileId); - } catch(UploadNotFoundException $ex) { + } catch(RuntimeException $ex) { $response->setContent('File not found.'); return 404; } diff --git a/src/Application.php b/src/Application.php index 4de82b2..2dd6b7a 100644 --- a/src/Application.php +++ b/src/Application.php @@ -1,13 +1,11 @@ prepare( 'SELECT `app_id`, `app_name`, `app_size_limit`, `app_expiry`, `app_allow_size_multiplier`,' . ' UNIX_TIMESTAMP(`app_created`) AS `app_created` FROM `prm_applications` WHERE `app_id` = ?' @@ -66,7 +61,7 @@ final class Application implements JsonSerializable { $result = $get->getResult(); if(!$result->next()) - throw new ApplicationNotFoundException; + throw new RuntimeException('Application $appId not found.'); return new static( $result->getInteger(0), diff --git a/src/Upload.php b/src/Upload.php index f14a8c1..43e106c 100644 --- a/src/Upload.php +++ b/src/Upload.php @@ -2,15 +2,14 @@ namespace EEPROM; use Exception; +use InvalidArgumentException; +use RuntimeException; use Imagick; use JsonSerializable; use Index\Data\IDbConnection; use Index\Data\IDbResult; use Index\Data\DbType; -class UploadNotFoundException extends Exception {}; -class UploadCreationFailedException extends Exception {}; - final class Upload implements JsonSerializable { private const ID_CHARS = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789-_'; @@ -216,8 +215,14 @@ final class Upload implements JsonSerializable { $appId = $app->getId(); $userId = $user->getId(); - if(strpos($fileType, '/') === false || $fileSize < 1 || strlen($fileHash) !== 64 || $fileExpiry < 0) - throw new UploadCreationFailedException('Bad args.'); + if(strpos($fileType, '/') === false) + throw new InvalidArgumentException('$fileType must contain a /'); + if($fileSize < 1) + throw new InvalidArgumentException('$fileSize must be more than 0.'); + if(strlen($fileHash) !== 64) + throw new InvalidArgumentException('$fileHash must be 64 characters.'); + if($fileExpiry < 0) + throw new InvalidArgumentException('$fileExpiry must be a positive integer.'); $id = self::generateId(); $create = $conn->prepare( @@ -239,11 +244,7 @@ final class Upload implements JsonSerializable { $create->addParameter(10, $bumpExpiry ? $fileExpiry : 0, DbType::INTEGER); $create->execute(); - try { - return self::byId($conn, $id); - } catch(UploadNotFoundException $ex) { - throw new UploadCreationFailedException; - } + return self::byId($conn, $id); } private static function constructDb(IDbResult $result): self { @@ -282,7 +283,7 @@ final class Upload implements JsonSerializable { $result = $get->getResult(); if(!$result->next()) - throw new UploadNotFoundException; + throw new RuntimeException('Upload $id not found.'); return self::constructDb($result); } @@ -309,6 +310,29 @@ final class Upload implements JsonSerializable { return self::constructDb($result); } + public static function byUserHash(IDbConnection $conn, User|string $userInfo, string $hash): ?self { + $get = $conn->prepare( + 'SELECT `upload_id`, `app_id`, `user_id`, `upload_name`, `upload_type`, `upload_size`, `upload_bump`,' + . ' UNIX_TIMESTAMP(`upload_created`) AS `upload_created`,' + . ' UNIX_TIMESTAMP(`upload_accessed`) AS `upload_accessed`,' + . ' UNIX_TIMESTAMP(`upload_expires`) AS `upload_expires`,' + . ' UNIX_TIMESTAMP(`upload_deleted`) AS `upload_deleted`,' + . ' UNIX_TIMESTAMP(`upload_dmca`) AS `upload_dmca`,' + . ' INET6_NTOA(`upload_ip`) AS `upload_ip`,' + . ' LOWER(HEX(`upload_hash`)) AS `upload_hash`' + . ' FROM `prm_uploads` WHERE `upload_hash` = UNHEX(?) AND `user_id` = ?' + ); + $get->addParameter(1, $hash, DbType::STRING); + $get->addParameter(2, $userInfo instanceof User ? $userInfo->getId() : $userInfo); + $get->execute(); + $result = $get->getResult(); + + if(!$result->next()) + return null; + + return self::constructDb($result); + } + public static function deleted(IDbConnection $conn): array { $result = $conn->query( 'SELECT `upload_id`, `app_id`, `user_id`, `upload_name`, `upload_type`, `upload_size`, `upload_bump`,' diff --git a/src/User.php b/src/User.php index 2408c21..9091874 100644 --- a/src/User.php +++ b/src/User.php @@ -1,13 +1,11 @@ prepare('INSERT IGNORE INTO `prm_users` (`user_id`) VALUES (?)'); $create->addParameter(1, $userId, DbType::INTEGER); $create->execute(); @@ -79,7 +74,7 @@ class User implements JsonSerializable { $result = $get->getResult(); if(!$result->next()) - throw new UserNotFoundException; + throw new RuntimeException('User not found.'); return new User( $result->getInteger(0),