From 16be5448beadc8ac32739f3c8419fd03dad42dd0 Mon Sep 17 00:00:00 2001 From: Meteo Date: Mon, 15 Jun 2026 16:04:21 +0200 Subject: [PATCH] Small code fixes in API code --- pub/api/classes/API.php | 41 ++++++------------- pub/api/classes/API_apitoken.php | 2 + pub/api/classes/API_devices.php | 5 ++- pub/api/classes/API_inserve.php | 21 ++++------ pub/api/classes/API_mfa.php | 3 ++ pub/api/classes/API_office_stompjes.php | 3 ++ pub/api/classes/API_permissions.php | 4 +- pub/api/classes/API_platforms.php | 2 + pub/api/classes/API_system_sources.php | 2 + pub/api/classes/API_usergroups.php | 4 ++ pub/api/classes/API_users.php | 4 ++ pub/api/classes/API_usersavatar.php | 2 +- pub/api/classes/API_vendors.php | 2 + pub/api/classes/imageProcessor.php | 16 ++++---- pub/api/v1/autop/devices/files/index.php | 2 +- pub/api/v1/office/stompjes/index.php | 2 - .../mail/configure/index.php | 2 +- pub/api/v1/user/avatar/index.php | 8 +--- pub/api/v1/user/mfa/index.php | 6 +-- pub/api/v1/user/resetpassword/index.php | 8 +--- 20 files changed, 64 insertions(+), 75 deletions(-) diff --git a/pub/api/classes/API.php b/pub/api/classes/API.php index a938447..21da535 100644 --- a/pub/api/classes/API.php +++ b/pub/api/classes/API.php @@ -34,15 +34,6 @@ class API # with the name _return and value of the url to return to. public $return_url; - # Required fields & optional fields set by the API actions. This is an array like: - # Example: - # 'user_uuid' => ['type' => 'string', 'min' => 5, 'max' => 36], - # 'user_enabled' => ['type' => 'int', 'min' => 0, 'max' => 99], - # 'user_active' => ['type' => 'enum', 'values' => ['active', 'inactive', 'banned']], - # 'user_email' => ['type' => 'string', 'format' => 'email'], - private $requiredFields = []; - private $optionalFields = []; - # Used for the query builder base public $baseQuery = false; @@ -199,11 +190,9 @@ class API { $inputData = $this->postedData; - $this->requiredFields = $requiredFields; - $this->optionalFields = $optionalFields; $sanitizedData = []; - foreach ($this->requiredFields as $field => $rules) { + foreach ($requiredFields as $field => $rules) { if (!array_key_exists($field, $inputData)) { $this->apiOutput(400, ['error' => "Missing required field: $field"]); @@ -220,7 +209,7 @@ class API // Check optional fields - foreach ($this->optionalFields as $field => $rules) { + foreach ($optionalFields as $field => $rules) { if (isset($inputData[$field])) { $value = $inputData[$field]; @@ -343,14 +332,9 @@ class API if (!is_string($value)) return false; return base64_encode(base64_decode($value, true)) === $value; - case 'uuid': - if (!is_string($value)) return false; - return preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i', $value); - case 'json': if (!is_string($value)) return false; - json_decode($value); - return json_last_error() === JSON_ERROR_NONE; + return json_validate($value); case 'array': if (!is_array($value)) return false; @@ -393,7 +377,7 @@ class API case 'boolean': if (is_string($value)) { $value = strtolower(trim($value)); - return in_array($value, ['true', '1'], true) ? true : false; + return in_array($value, ['true', '1'], true); } return (bool)$value; @@ -453,6 +437,8 @@ class API if ($returnBoolean) { return true; } + + return false; } protected function setReturnUrl() @@ -517,8 +503,7 @@ class API return false; } - json_decode($rawInput, true); - if (json_last_error() !== JSON_ERROR_NONE) { + if (!json_validate($rawInput)) { return false; } @@ -590,17 +575,17 @@ class API return true; } - if (strpos($contentType, 'application/json') !== false) { + if (str_contains($contentType, 'application/json')) { $this->content_type = 'application/json'; return true; } - if (strpos($contentType, 'application/x-www-form-urlencoded') !== false) { + if (str_contains($contentType, 'application/x-www-form-urlencoded')) { $this->content_type = 'application/x-www-form-urlencoded'; return true; } - if (strpos($contentType, 'multipart/form-data') !== false) { + if (str_contains($contentType, 'multipart/form-data')) { $this->content_type = 'multipart/form-data'; return true; } @@ -662,10 +647,9 @@ class API try { $stmt = $this->conn->prepare($query); - } catch (mysqli_sql_exception $e) { + } catch (\mysqli_sql_exception $e) { // If an error occurs during prepare, catch it and return a proper response $this->apiOutput(500, ['error' => 'Database error: ' . $e->getMessage()]); - return null; } return $stmt; @@ -679,13 +663,12 @@ class API try { $stmt->execute(); return true; - } catch (mysqli_sql_exception $e) { + } catch (\mysqli_sql_exception $e) { if ($e->getCode() === 1451) { $this->apiOutput(409, ['error' => 'Cannot delete record: dependent data exists.']); } else { $this->apiOutput(500, ['error' => 'Database error: ' . $e->getMessage()]); } - return null; } } diff --git a/pub/api/classes/API_apitoken.php b/pub/api/classes/API_apitoken.php index aa76a4e..e99bf75 100644 --- a/pub/api/classes/API_apitoken.php +++ b/pub/api/classes/API_apitoken.php @@ -4,6 +4,7 @@ namespace api\classes; use api\classes\API; use api\classes\API_users; +use JetBrains\PhpStorm\NoReturn; require_once 'API.php'; @@ -66,6 +67,7 @@ class API_apitoken extends API } } + #[NoReturn] public function createNewToken() { diff --git a/pub/api/classes/API_devices.php b/pub/api/classes/API_devices.php index ea1dd27..5fa7522 100644 --- a/pub/api/classes/API_devices.php +++ b/pub/api/classes/API_devices.php @@ -4,6 +4,7 @@ namespace api\classes; use api\classes\API; use api\classes\imageProcessor; +use JetBrains\PhpStorm\NoReturn; require_once 'API.php'; @@ -36,13 +37,14 @@ class API_devices extends API $imageProcessor->imageRestrictions = $imageRestrictions; $imageProcessor->validateAndProcess(); $ImageData = $imageProcessor->returnBase64image(); - } catch (Exception $e) { + } catch (\RuntimeException $e) { $this->apiOutput(401, ['error' => 'Error: ' . $e->getMessage()]); } return $ImageData; } + #[NoReturn] public function createDevice() { @@ -108,6 +110,7 @@ class API_devices extends API } } + #[NoReturn] public function deleteDevice() { # check if the device exists diff --git a/pub/api/classes/API_inserve.php b/pub/api/classes/API_inserve.php index 14c4079..2ad444d 100644 --- a/pub/api/classes/API_inserve.php +++ b/pub/api/classes/API_inserve.php @@ -3,6 +3,7 @@ namespace api\classes; use api\classes\API; +use JetBrains\PhpStorm\NoReturn; require_once 'API.php'; @@ -44,11 +45,6 @@ class API_inserve extends API curl_close($this->ch); } - public function returnResponse() - { - $this->apiOutput($this->httpCode, json_decode($this->response, true)); - } - public function authMe() { $this->ch = curl_init($this->inserve_url . 'auth/me'); @@ -60,6 +56,7 @@ class API_inserve extends API ] ]); $this->execCurl(); + return true; } public function getLinkedCompanies() @@ -246,7 +243,7 @@ class API_inserve extends API ]; if (!in_array($type, $allowedColumns, true)) { - throw new Exception('Invalid column name'); + throw new \RuntimeException('Invalid column name'); } $query = "SELECT `$type` FROM servers"; @@ -256,7 +253,7 @@ class API_inserve extends API $servers = []; while ($row = $result->fetch_assoc()) { - array_push($servers, $row); + $servers[] = $row; } $allTypes = []; @@ -451,7 +448,7 @@ class API_inserve extends API $namePart = substr($key, 7, -6); $namePart = ucfirst($namePart); } // Handle keys with "." - elseif (strpos($key, '.') !== false) { + elseif (str_contains($key, '.')) { [$first, $second] = explode('.', $key, 2); if ($first === $second || strtolower($second) === 'yes') { $namePart = ucfirst($first); @@ -459,7 +456,7 @@ class API_inserve extends API $namePart = ucfirst($first) . ' - ' . $second; } } //Handle keys without . but with a space (example directadmin.Standard Discounted) - elseif (strpos($key, ' ') !== false) { + elseif (str_contains($key, ' ')) { // explode on first . $parts = explode('.', $key, 2); if (count($parts) === 2) { @@ -513,16 +510,14 @@ class API_inserve extends API && $item['subscriptionInserveExists'] !== false ) { $payload = [ - "quantity" => (int)$item['countSentri'], + "quantity" => ($row['server_state'] === 'deleted') ? 0 : $item['countSentri'], "cloud_distribution_company_id" => (int)$item['sentriCompanyId'], "name" => $item['subscriptionSentriName'], - "status" => $item['SentriStatus'], - "quantity" => ($row['server_state'] === 'deleted') ? 0 : $item['countSentri'] + "status" => $item['SentriStatus'] ]; $this->updateCloudSubscription($item['subscriptionInserveId'], $payload); - continue; } } } diff --git a/pub/api/classes/API_mfa.php b/pub/api/classes/API_mfa.php index 3372eaa..bbc8165 100644 --- a/pub/api/classes/API_mfa.php +++ b/pub/api/classes/API_mfa.php @@ -3,11 +3,13 @@ namespace api\classes; use api\classes\API; +use JetBrains\PhpStorm\NoReturn; require_once 'API.php'; class API_mfa extends API { + #[NoReturn] public function disableMFA() { # Users cannot, by default disable MFA of other users @@ -23,6 +25,7 @@ class API_mfa extends API $this->apiOutput(200, ['success' => 'mfa is disabled']); } + #[NoReturn] public function enableMFA() { # Users cannot, create MFA of other users diff --git a/pub/api/classes/API_office_stompjes.php b/pub/api/classes/API_office_stompjes.php index 7cdbe12..f55a5c9 100644 --- a/pub/api/classes/API_office_stompjes.php +++ b/pub/api/classes/API_office_stompjes.php @@ -3,11 +3,13 @@ namespace api\classes; use api\classes\API; +use JetBrains\PhpStorm\NoReturn; require_once 'API.php'; class API_office_stompjes extends API { + #[NoReturn] public function addStomp() { $query = "INSERT INTO office_stompjes (stomp_uuid, user_uuid, stomp_timestamp) VALUES (UUID(), ?, ?)"; @@ -19,6 +21,7 @@ class API_office_stompjes extends API $this->apiOutput(200, ['success' => 'Stomp added.']); } + #[NoReturn] public function deleteStomp() { $query = "DELETE FROM office_stompjes WHERE stomp_uuid = ?"; diff --git a/pub/api/classes/API_permissions.php b/pub/api/classes/API_permissions.php index c53eee9..7d0c0cb 100644 --- a/pub/api/classes/API_permissions.php +++ b/pub/api/classes/API_permissions.php @@ -3,6 +3,7 @@ namespace api\classes; use api\classes\API; +use JetBrains\PhpStorm\NoReturn; require_once 'API.php'; @@ -27,6 +28,7 @@ class API_permissions extends API } } + #[NoReturn] public function createPermission() { # Check if permission slugify already exists @@ -53,7 +55,7 @@ class API_permissions extends API $sql = "SELECT * FROM system_user_groups"; $stmt = $this->conn->query($sql); while ($user_group = $stmt->fetch_assoc()) { - array_push($user_groups, $user_group); + $user_groups[] = $user_group; } # Update all the groups with the newly added permission diff --git a/pub/api/classes/API_platforms.php b/pub/api/classes/API_platforms.php index 6b448c3..343b9d9 100644 --- a/pub/api/classes/API_platforms.php +++ b/pub/api/classes/API_platforms.php @@ -3,6 +3,7 @@ namespace api\classes; use api\classes\API; +use JetBrains\PhpStorm\NoReturn; require_once 'API.php'; @@ -18,6 +19,7 @@ class API_platforms extends API } + #[NoReturn] public function createPlatforms() { if (isset($this->data['platform_image'])) { diff --git a/pub/api/classes/API_system_sources.php b/pub/api/classes/API_system_sources.php index e202933..51b1714 100644 --- a/pub/api/classes/API_system_sources.php +++ b/pub/api/classes/API_system_sources.php @@ -3,11 +3,13 @@ namespace api\classes; use api\classes\API; +use JetBrains\PhpStorm\NoReturn; require_once 'API.php'; class API_system_sources extends API { + #[NoReturn] public function inserveUpdate() { $query = "INSERT INTO system_sources ( diff --git a/pub/api/classes/API_usergroups.php b/pub/api/classes/API_usergroups.php index 6c37b3f..4ab5759 100644 --- a/pub/api/classes/API_usergroups.php +++ b/pub/api/classes/API_usergroups.php @@ -3,6 +3,7 @@ namespace api\classes; use api\classes\API; +use JetBrains\PhpStorm\NoReturn; require_once 'API.php'; @@ -17,6 +18,7 @@ class API_usergroups extends API return $items; } + #[NoReturn] public function createUsergroups() { # check if the user_group already exists @@ -70,6 +72,7 @@ class API_usergroups extends API } } + #[NoReturn] public function deleteUsergroup() { # check if the user group exists @@ -113,6 +116,7 @@ class API_usergroups extends API return $weight; } + #[NoReturn] public function updateUserGroup() { # check if the user group exists diff --git a/pub/api/classes/API_users.php b/pub/api/classes/API_users.php index 2f6848c..f7d6aa3 100644 --- a/pub/api/classes/API_users.php +++ b/pub/api/classes/API_users.php @@ -5,6 +5,7 @@ namespace api\classes; use api\classes\API; use api\classes\API_usergroups; use bin\php\Classes\mailBuilder; +use JetBrains\PhpStorm\NoReturn; require_once 'API.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/bin/php/Classes/mailBuilder.php'; @@ -20,6 +21,7 @@ class API_users extends API return $items; } + #[NoReturn] public function createUser() { # check if the user already exists @@ -102,6 +104,7 @@ The Sentri gnomes'; return $API_usergroups->getUserGroup()[0]['user_group_weight']; } + #[NoReturn] public function updateUser() { # check if the user exists @@ -133,6 +136,7 @@ The Sentri gnomes'; $this->apiOutput(200, ['success' => 'User successfully updated.']); } + #[NoReturn] public function deleteUser() { # delete an user diff --git a/pub/api/classes/API_usersavatar.php b/pub/api/classes/API_usersavatar.php index abf3e2d..cad8ff0 100644 --- a/pub/api/classes/API_usersavatar.php +++ b/pub/api/classes/API_usersavatar.php @@ -18,7 +18,7 @@ class API_usersavatar extends API $imageProcessor->imageRestrictions = $imageRestrictions; $imageProcessor->validateAndProcess(); $ImageData = $imageProcessor->returnBase64image(); - } catch (Exception $e) { + } catch (\RuntimeException $e) { $this->apiOutput(401, ['error' => 'Error: ' . $e->getMessage()]); } diff --git a/pub/api/classes/API_vendors.php b/pub/api/classes/API_vendors.php index ed81bc6..4a33636 100644 --- a/pub/api/classes/API_vendors.php +++ b/pub/api/classes/API_vendors.php @@ -3,6 +3,7 @@ namespace api\classes; use api\classes\API; +use JetBrains\PhpStorm\NoReturn; require_once 'API.php'; @@ -17,6 +18,7 @@ class API_vendors extends API return $items; } + #[NoReturn] public function createVendor() { if (isset($this->data['vendor_image'])) { diff --git a/pub/api/classes/imageProcessor.php b/pub/api/classes/imageProcessor.php index ccf1f11..24e9bb5 100644 --- a/pub/api/classes/imageProcessor.php +++ b/pub/api/classes/imageProcessor.php @@ -2,6 +2,9 @@ namespace api\classes; + +use http\Exception\RuntimeException; + class imageProcessor { public $postedFile = null; @@ -34,18 +37,18 @@ class imageProcessor $mimeType = $matches[1]; $base64 = substr($base64, strpos($base64, ',') + 1); } else { - throw new Exception('Invalid image data.'); + throw new \RuntimeException('Invalid image data.'); } $imageData = base64_decode($base64); if ($imageData === false) { - throw new Exception('Invalid base64 image data.'); + throw new \RuntimeException('Invalid base64 image data.'); } # Create image directly from string (no file) $srcImage = imagecreatefromstring($imageData); if (!$srcImage) { - throw new Exception('Failed to create image from string.'); + throw new \RuntimeException('Failed to create image from string.'); } # Now you can get dimensions directly @@ -53,7 +56,6 @@ class imageProcessor $height = imagesy($srcImage); # Store $srcImage in a class property, continue processing in-memory - $this->imageResource = $srcImage; $this->imageInfo = [ 'mime' => $mimeType, 'width' => $width, @@ -74,11 +76,11 @@ class imageProcessor $fileSizeKB = filesize($this->imageTmpPath) / 1024; if (!in_array($mime, $this->imageRestrictions['allowed_types'])) { - throw new Exception("Invalid image type: $mime"); + throw new \RuntimeException("Invalid image type: $mime"); } if ($fileSizeKB > $this->imageRestrictions['max_size_kb']) { - throw new Exception("Image exceeds max file size."); + throw new \RuntimeException("Image exceeds max file size."); } # Resize to fit within min/max bounds @@ -137,7 +139,7 @@ class imageProcessor 'image/jpeg' => imagecreatefromjpeg($this->imageTmpPath), 'image/png' => imagecreatefrompng($this->imageTmpPath), 'image/webp' => imagecreatefromwebp($this->imageTmpPath), - default => throw new Exception("Unsupported image type.") + default => throw new \RuntimeException("Unsupported image type.") }; # Determine new size diff --git a/pub/api/v1/autop/devices/files/index.php b/pub/api/v1/autop/devices/files/index.php index 6ae7680..1627776 100644 --- a/pub/api/v1/autop/devices/files/index.php +++ b/pub/api/v1/autop/devices/files/index.php @@ -94,7 +94,7 @@ if ($API_devices->request_method === 'POST') { $requestedPath = realpath($_SERVER['DOCUMENT_ROOT'] . $relativePath); // Validate resolved path - if (!$requestedPath || strpos($requestedPath, $root) !== 0) { + if (!$requestedPath || !str_starts_with($requestedPath, $root)) { http_response_code(403); echo json_encode(['status' => 'error', 'message' => 'Access denied']); exit; diff --git a/pub/api/v1/office/stompjes/index.php b/pub/api/v1/office/stompjes/index.php index 6fa5db3..5764947 100644 --- a/pub/api/v1/office/stompjes/index.php +++ b/pub/api/v1/office/stompjes/index.php @@ -32,8 +32,6 @@ if ($API_office_stompjes->request_method === 'GET') { $API_office_stompjes->addStomp(); - $API_office_stompjes->apiOutput($code = 200, ['success' => 'stomp added successfully.']); - } elseif ($API_office_stompjes->request_method === 'DELETE') { # Only superuser can delete permission due to fact that the backend needs programming when setting a permission diff --git a/pub/api/v1/portal-management/mail/configure/index.php b/pub/api/v1/portal-management/mail/configure/index.php index 3ed341b..e98fe54 100644 --- a/pub/api/v1/portal-management/mail/configure/index.php +++ b/pub/api/v1/portal-management/mail/configure/index.php @@ -24,7 +24,7 @@ if ($API_mailsettings->request_method === 'PUT') { 'mail_smtp_pass' => ['type' => 'string'] ]; # check if the password is changed - $updatePassword = str_contains($API_mailsettings->postedData['mail_smtp_pass'], '******') ? false : true; + $updatePassword = !str_contains($API_mailsettings->postedData['mail_smtp_pass'], '******'); if ($updatePassword) { if (strlen($API_mailsettings->postedData['mail_smtp_pass']) < 12) { $API_mailsettings->apiOutput(400, ['error' => 'Password too short']); diff --git a/pub/api/v1/user/avatar/index.php b/pub/api/v1/user/avatar/index.php index 192f75a..f123825 100644 --- a/pub/api/v1/user/avatar/index.php +++ b/pub/api/v1/user/avatar/index.php @@ -9,9 +9,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/api/classes/imageProcessor.php'; $API_usersavatar = new API_usersavatar(); -if ($API_usersavatar->request_method === 'GET') { - -} elseif ($API_usersavatar->request_method === 'POST') { +if ($API_usersavatar->request_method === 'POST') { # Reset a users password and send an email the user to set a new password $API_usersavatar->postedData['user_profile_picture'] = $API_usersavatar->createUserImage(['min_width' => 500, 'max_width' => 1000, 'min_height' => 500, 'max_height' => 1000, 'square' => true, 'allowed_types' => ['image/png'], 'max_size_kb' => 1024, 'transparent' => true]); @@ -34,8 +32,4 @@ if ($API_usersavatar->request_method === 'GET') { $API_usersavatar->apiOutput(200, ['success' => 'Avatar was successfully changed.']); -} elseif ($API_usersavatar->request_method === 'PUT') { - -} elseif ($API_usersavatar->request_method === 'DELETE') { - } \ No newline at end of file diff --git a/pub/api/v1/user/mfa/index.php b/pub/api/v1/user/mfa/index.php index 925dc6d..7059431 100644 --- a/pub/api/v1/user/mfa/index.php +++ b/pub/api/v1/user/mfa/index.php @@ -11,9 +11,7 @@ use RobThree\Auth\Providers\Qr\EndroidQrCodeWithLogoProvider; $API_mfa = new API_mfa(); -if ($API_mfa->request_method === 'GET') { - -} elseif ($API_mfa->request_method === 'POST') { +if ($API_mfa->request_method === 'POST') { # Set up a new MFA secret its posted from mfaSetup.php where it generated a secret if (checkLoginAttempts() > 10) { @@ -49,8 +47,6 @@ if ($API_mfa->request_method === 'GET') { $API_mfa->enableMFA(); -} elseif ($API_mfa->request_method === 'PUT') { - } elseif ($API_mfa->request_method === 'DELETE') { # Delete a mfa code for a user diff --git a/pub/api/v1/user/resetpassword/index.php b/pub/api/v1/user/resetpassword/index.php index ea89c02..6d4aa08 100644 --- a/pub/api/v1/user/resetpassword/index.php +++ b/pub/api/v1/user/resetpassword/index.php @@ -12,9 +12,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/api/classes/API_users.php'; $API_resetpassword = new API_resetpassword(); -if ($API_resetpassword->request_method === 'GET') { - -} elseif ($API_resetpassword->request_method === 'POST') { +if ($API_resetpassword->request_method === 'POST') { # Reset a users password and send a mail to the user to set a new password $API_resetpassword->checkPermissions('admin-access-admins-resetpassword', 'RW'); @@ -71,8 +69,4 @@ The Sentri gnomes $mail->sendMail(); $API_resetpassword->apiOutput(200, ['success' => 'Password reset link sent successfully.']); -} elseif ($API_resetpassword->request_method === 'PUT') { - -} elseif ($API_resetpassword->request_method === 'DELETE') { - } \ No newline at end of file