1
0
Fork 0
mirror of synced 2024-06-03 03:14:50 +12:00

Start working on simplifying exceptions

This commit is contained in:
Bradley Schofield 2022-07-22 15:38:06 +01:00
parent 9035db1137
commit 40022decb4
6 changed files with 190 additions and 47 deletions

View file

@ -89,6 +89,13 @@ return [
'code' => 500,
],
/** Account Errors */
Exception::ACCOUNT_OAUTH_FAILED_TO_OBTAIN_TOKEN => [
'name' => Exception::ACCOUNT_OAUTH_FAILED_TO_OBTAIN_TOKEN,
'description' => 'Failed to obtain access token.',
'code' => 500,
],
/** User Errors */
Exception::USER_COUNT_EXCEEDED => [
'name' => Exception::USER_COUNT_EXCEEDED,
@ -511,5 +518,99 @@ return [
'name' => Exception::DOMAIN_VERIFICATION_FAILED,
'description' => 'Domain verification for the requested domain has failed.',
'code' => 401,
]
],
/* Registry Errors */
Exception::LOGGER_NOT_SUPPORTED => [
'name' => Exception::LOGGER_NOT_SUPPORTED,
'description' => 'Logging provider not supported. Logging disabled.',
'code' => 500,
],
/** Mocks */
Exception::MOCK_INVALID_CONTENT_RANGE_HEADER => [
'name' => Exception::MOCK_INVALID_CONTENT_RANGE_HEADER,
'description' => 'Invalid content-range header',
'code' => 400,
],
Exception::MOCK_FIRST_CHUNK_CANNOT_HAVE_ID => [
'name' => Exception::MOCK_FIRST_CHUNK_CANNOT_HAVE_ID,
'description' => 'First chunked request cannot have id header',
'code' => 400,
],
Exception::MOCK_CHUNK_MISSING_ID => [
'name' => Exception::MOCK_CHUNK_MISSING_ID,
'description' => 'All chunked request must have id header (except first)',
'code' => 400,
],
Exception::MOCK_CHUNK_INVALID_SIZE => [
'name' => Exception::MOCK_CHUNK_INVALID_SIZE,
'description' => 'Chunk size must be 5MB (except last chunk)',
'code' => 400,
],
Exception::MOCK_INVALID_FILE_NAME => [
'name' => Exception::MOCK_INVALID_FILE_NAME,
'description' => 'Wrong file name',
'code' => 400,
],
Exception::MOCK_INVALID_FILE_SIZE => [
'name' => Exception::MOCK_INVALID_FILE_SIZE,
'description' => 'Wrong file size',
'code' => 400,
],
Exception::MOCK_WRONG_FILE_UPLOADED => [
'name' => Exception::MOCK_WRONG_FILE_UPLOADED,
'description' => 'Wrong file uploaded',
'code' => 400,
],
Exception::MOCK_MISSING_COOKIE => [
'name' => Exception::MOCK_MISSING_COOKIE,
'description' => 'Missing cookie value',
'code' => 400,
],
Exception::MOCK_INVALID_CLIENT_ID => [
'name' => Exception::MOCK_INVALID_CLIENT_ID,
'description' => 'Invalid client ID',
'code' => 400,
],
Exception::MOCK_INVALID_CLIENT_SECRET => [
'name' => Exception::MOCK_INVALID_CLIENT_SECRET,
'description' => 'Invalid client secret',
'code' => 400,
],
Exception::MOCK_INVALID_TOKEN => [
'name' => Exception::MOCK_INVALID_TOKEN,
'description' => 'Invalid token',
'code' => 400,
],
Exception::MOCK_INVALID_REFRESH_TOKEN => [
'name' => Exception::MOCK_INVALID_REFRESH_TOKEN,
'description' => 'Invalid refresh token',
'code' => 400,
],
Exception::MOCK_INVALID_GRANT_TYPE => [
'name' => Exception::MOCK_INVALID_GRANT_TYPE,
'description' => 'Invalid grant type',
'code' => 400,
],
Exception::MOCK_FAILED_TO_READ_RESULTS => [
'name' => Exception::MOCK_FAILED_TO_READ_RESULTS,
'description' => 'Failed to read results',
'code' => 500,
],
Exception::MOCK_FAILED_TO_SAVE_RESULTS => [
'name' => Exception::MOCK_FAILED_TO_SAVE_RESULTS,
'description' => 'Failed to save results',
'code' => 500,
],
Exception::MOCK_400 => [
'name' => Exception::MOCK_400,
'description' => 'Mock 400 error',
'code' => 400,
],
Exception::MOCK_500 => [
'name' => Exception::MOCK_500,
'description' => 'Mock 500 error',
'code' => 500,
],
];

View file

@ -74,11 +74,11 @@ App::post('/v1/account')
$whitelistIPs = $project->getAttribute('authWhitelistIPs');
if (!empty($whitelistEmails) && !\in_array($email, $whitelistEmails)) {
throw new Exception('Console registration is restricted to specific emails. Contact your administrator for more information.', 401, Exception::USER_EMAIL_NOT_WHITELISTED);
throw new Exception(Exception::USER_EMAIL_NOT_WHITELISTED);
}
if (!empty($whitelistIPs) && !\in_array($request->getIP(), $whitelistIPs)) {
throw new Exception('Console registration is restricted to specific IPs. Contact your administrator for more information.', 401, Exception::USER_IP_NOT_WHITELISTED);
throw new Exception(Exception::USER_IP_NOT_WHITELISTED);
}
}
@ -88,7 +88,7 @@ App::post('/v1/account')
$total = $dbForProject->count('users', max: APP_LIMIT_USERS);
if ($total >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
throw new Exception(Exception::USER_COUNT_EXCEEDED);
}
}
@ -113,7 +113,7 @@ App::post('/v1/account')
'search' => implode(' ', [$userId, $email, $name])
])));
} catch (Duplicate $th) {
throw new Exception('Account already exists', 409, Exception::USER_ALREADY_EXISTS);
throw new Exception(Exception::USER_ALREADY_EXISTS);
}
Authorization::unsetRole('role:' . Auth::USER_ROLE_GUEST);
@ -167,11 +167,11 @@ App::post('/v1/account/sessions/email')
new Query('email', Query::TYPE_EQUAL, [$email])]);
if (!$profile || !Auth::passwordVerify($password, $profile->getAttribute('password'))) {
throw new Exception('Invalid credentials', 401, Exception::USER_INVALID_CREDENTIALS); // Wrong password or username
throw new Exception(Exception::USER_INVALID_CREDENTIALS); // Wrong password or username
}
if (false === $profile->getAttribute('status')) { // Account is blocked
throw new Exception('Invalid credentials. User is blocked', 401, Exception::USER_BLOCKED); // User is in status blocked
throw new Exception(Exception::USER_BLOCKED); // User is in status blocked
}
$detector = new Detector($request->getUserAgent('UNKNOWN'));
@ -276,13 +276,13 @@ App::get('/v1/account/sessions/oauth2/:provider')
}
if (empty($appId) || empty($appSecret)) {
throw new Exception('This provider is disabled. Please configure the provider app ID and app secret key from your ' . APP_NAME . ' console to continue.', 412, Exception::PROJECT_PROVIDER_DISABLED);
throw new Exception(Exception::PROJECT_PROVIDER_DISABLED);
}
$className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider);
if (!\class_exists($className)) {
throw new Exception('Provider is not supported', 501, Exception::PROJECT_PROVIDER_UNSUPPORTED);
throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED);
}
if (empty($success)) {
@ -388,7 +388,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider);
if (!\class_exists($className)) {
throw new Exception('Provider is not supported', 501, Exception::PROJECT_PROVIDER_UNSUPPORTED);
throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED);
}
$oauth2 = new $className($appId, $appSecret, $callback);
@ -397,18 +397,18 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
try {
$state = \array_merge($defaultState, $oauth2->parseState($state));
} catch (\Exception$exception) {
throw new Exception('Failed to parse login state params as passed from OAuth2 provider', 500, Exception::GENERAL_SERVER_ERROR);
throw new Exception(Exception::GENERAL_SERVER_ERROR);
}
} else {
$state = $defaultState;
}
if (!$validateURL->isValid($state['success'])) {
throw new Exception('Invalid redirect URL for success login', 400, Exception::PROJECT_INVALID_SUCCESS_URL);
throw new Exception(Exception::PROJECT_INVALID_SUCCESS_URL);
}
if (!empty($state['failure']) && !$validateURL->isValid($state['failure'])) {
throw new Exception('Invalid redirect URL for failure login', 400, Exception::PROJECT_INVALID_FAILURE_URL);
throw new Exception(Exception::PROJECT_INVALID_FAILURE_URL);
}
$state['failure'] = null;
@ -422,7 +422,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$response->redirect($state['failure'], 301, 0);
}
throw new Exception('Failed to obtain access token', 500, Exception::GENERAL_SERVER_ERROR);
throw new Exception(Exception::ACCOUNT_OAUTH_FAILED_TO_OBTAIN_TOKEN);
}
$oauth2ID = $oauth2->getUserID($accessToken);
@ -432,7 +432,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$response->redirect($state['failure'], 301, 0);
}
throw new Exception('Missing ID from OAuth2 provider', 400, Exception::PROJECT_MISSING_USER_ID);
throw new Exception(Exception::ACCOUNT_OAUTH_MISSING_ID);
}
$sessions = $user->getAttribute('sessions', []);
@ -470,7 +470,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$total = $dbForProject->count('users', max: APP_LIMIT_USERS);
if ($total >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
throw new Exception(Exception::USER_COUNT_EXCEEDED);
}
}
@ -495,13 +495,13 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
'search' => implode(' ', [$userId, $email, $name])
])));
} catch (Duplicate $th) {
throw new Exception('Account already exists', 409, Exception::USER_ALREADY_EXISTS);
throw new Exception(Exception::USER_ALREADY_EXISTS);
}
}
}
if (false === $user->getAttribute('status')) { // Account is blocked
throw new Exception('Invalid credentials. User is blocked', 401, Exception::USER_BLOCKED); // User is in status blocked
throw new Exception(Exception::USER_BLOCKED); // User is in status blocked
}
// Create session token, verify user account and update OAuth2 ID and Access Token
@ -619,7 +619,7 @@ App::post('/v1/account/sessions/magic-url')
->action(function (string $userId, string $email, string $url, Request $request, Response $response, Document $project, Database $dbForProject, Locale $locale, Audit $audits, Event $events, Mail $mails) {
if (empty(App::getEnv('_APP_SMTP_HOST'))) {
throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED);
throw new Exception(Exception::GENERAL_SMTP_DISABLED);
}
$roles = Authorization::getRoles();
@ -635,7 +635,7 @@ App::post('/v1/account/sessions/magic-url')
$total = $dbForProject->count('users', max: APP_LIMIT_USERS);
if ($total >= $limit) {
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
throw new Exception(Exception::USER_COUNT_EXCEEDED);
}
}
@ -750,13 +750,13 @@ App::put('/v1/account/sessions/magic-url')
$user = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
if ($user->isEmpty()) {
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
throw new Exception(Exception::USER_NOT_FOUND);
}
$token = Auth::tokenVerify($user->getAttribute('tokens', []), Auth::TOKEN_TYPE_MAGIC_URL, $secret);
if (!$token) {
throw new Exception('Invalid login token', 401, Exception::USER_INVALID_TOKEN);
throw new Exception(Exception::USER_INVALID_TOKEN);
}
$detector = new Detector($request->getUserAgent('UNKNOWN'));

View file

@ -352,6 +352,19 @@ App::error(function (Throwable $error, App $utopia, Request $request, Response $
throw $error;
}
if ($error instanceof Appwrite\Extend\Exception) {
// Find error code and error message
$errors = Config::getParam('errors', []);
$errorData = $errors[$error->getType()];
$error = new Appwrite\Extend\Exception(
$errorData['description'] ?? $error->getMessage(),
$errorData['code'] ?? $error->getCode(),
$errorData['name'] ?? $error->getType()
);
}
if ($logger) {
if ($error->getCode() >= 500 || $error->getCode() === 0) {
try {

View file

@ -253,31 +253,31 @@ App::post('/v1/mock/tests/general/upload')
$file['size'] = (\is_array($file['size'])) ? $file['size'][0] : $file['size'];
if (is_null($start) || is_null($end) || is_null($size)) {
throw new Exception('Invalid content-range header', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_INVALID_CONTENT_RANGE_HEADER);
}
if ($start > $end || $end > $size) {
throw new Exception('Invalid content-range header', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_INVALID_CONTENT_RANGE_HEADER);
}
if ($start === 0 && !empty($id)) {
throw new Exception('First chunked request cannot have id header', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_FIRST_CHUNK_CANNOT_HAVE_ID);
}
if ($start !== 0 && $id !== 'newfileid') {
throw new Exception('All chunked request must have id header (except first)', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_CHUNK_MISSING_ID);
}
if ($end !== $size && $end - $start + 1 !== $chunkSize) {
throw new Exception('Chunk size must be 5MB (except last chunk)', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_CHUNK_INVALID_SIZE);
}
if ($end !== $size && $file['size'] !== $chunkSize) {
throw new Exception('Wrong chunk size', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_CHUNK_INVALID_SIZE);
}
if ($file['size'] > $chunkSize) {
throw new Exception('Chunk size must be 5MB or less', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_CHUNK_INVALID_SIZE);
}
if ($end !== $size) {
@ -293,15 +293,15 @@ App::post('/v1/mock/tests/general/upload')
$file['size'] = (\is_array($file['size'])) ? $file['size'][0] : $file['size'];
if ($file['name'] !== 'file.png') {
throw new Exception('Wrong file name', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_INVALID_FILE_NAME);
}
if ($file['size'] !== 38756) {
throw new Exception('Wrong file size', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_INVALID_FILE_SIZE);
}
if (\md5(\file_get_contents($file['tmp_name'])) !== 'd80e7e6999a3eb2ae0d631a96fe135a4') {
throw new Exception('Wrong file uploaded', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_WRONG_FILE_UPLOADED);
}
}
});
@ -374,7 +374,7 @@ App::get('/v1/mock/tests/general/get-cookie')
->action(function (Request $request) {
if ($request->getCookie('cookieName', '') !== 'cookieValue') {
throw new Exception('Missing cookie value', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_MISSING_COOKIE);
}
});
@ -408,7 +408,7 @@ App::get('/v1/mock/tests/general/400-error')
->label('sdk.response.model', Response::MODEL_ERROR)
->label('sdk.mock', true)
->action(function () {
throw new Exception('Mock 400 error', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_400);
});
App::get('/v1/mock/tests/general/500-error')
@ -424,7 +424,7 @@ App::get('/v1/mock/tests/general/500-error')
->label('sdk.response.model', Response::MODEL_ERROR)
->label('sdk.mock', true)
->action(function () {
throw new Exception('Mock 500 error', 500, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_500);
});
App::get('/v1/mock/tests/general/502-error')
@ -480,11 +480,11 @@ App::get('/v1/mock/tests/general/oauth2/token')
->action(function (string $client_id, string $client_secret, string $grantType, string $redirectURI, string $code, string $refreshToken, Response $response) {
if ($client_id != '1') {
throw new Exception('Invalid client ID', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_INVALID_CLIENT_ID);
}
if ($client_secret != '123456') {
throw new Exception('Invalid client secret', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_INVALID_CLIENT_SECRET);
}
$responseJson = [
@ -495,18 +495,18 @@ App::get('/v1/mock/tests/general/oauth2/token')
if ($grantType === 'authorization_code') {
if ($code !== 'abcdef') {
throw new Exception('Invalid token', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_INVALID_TOKEN);
}
$response->json($responseJson);
} elseif ($grantType === 'refresh_token') {
if ($refreshToken !== 'tuvwxyz') {
throw new Exception('Invalid refresh token', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_INVALID_REFRESH_TOKEN);
}
$response->json($responseJson);
} else {
throw new Exception('Invalid grant type', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_INVALID_GRANT_TYPE);
}
});
@ -520,7 +520,7 @@ App::get('/v1/mock/tests/general/oauth2/user')
->action(function (string $token, Response $response) {
if ($token != '123456') {
throw new Exception('Invalid token', 400, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_INVALID_TOKEN);
}
$response->json([
@ -566,7 +566,7 @@ App::shutdown(function (App $utopia, Response $response, Request $request) {
$tests = (\file_exists($path)) ? \json_decode(\file_get_contents($path), true) : [];
if (!\is_array($tests)) {
throw new Exception('Failed to read results', 500, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_FAILED_TO_READ_RESULTS);
}
$result[$route->getMethod() . ':' . $route->getPath()] = true;
@ -574,7 +574,7 @@ App::shutdown(function (App $utopia, Response $response, Request $request) {
$tests = \array_merge($tests, $result);
if (!\file_put_contents($path, \json_encode($tests), LOCK_EX)) {
throw new Exception('Failed to save results', 500, Exception::GENERAL_MOCK);
throw new Exception(Exception::MOCK_FAILED_TO_SAVE_RESULTS);
}
$response->dynamic(new Document(['result' => $route->getMethod() . ':' . $route->getPath() . ':passed']), Response::MODEL_MOCK);

View file

@ -448,7 +448,7 @@ $register->set('logger', function () {
}
if (!Logger::hasProvider($providerName)) {
throw new Exception("Logging provider not supported. Logging disabled.", 500, Exception::GENERAL_SERVER_ERROR);
throw new Exception(Exception::LOGGER_NOT_SUPPORTED);
}
$classname = '\\Utopia\\Logger\\Adapter\\' . \ucfirst($providerName);
@ -818,7 +818,7 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
try {
$payload = $jwt->decode($authJWT);
} catch (JWTException $error) {
throw new Exception('Failed to verify JWT. ' . $error->getMessage(), 401, Exception::USER_JWT_INVALID);
throw new Exception(Exception::USER_JWT_INVALID);
}
$jwtUserId = $payload['userId'] ?? '';

View file

@ -12,6 +12,7 @@ class Exception extends \Exception
*
* Appwrite has the follwing entities:
* - General
* - Account
* - Users
* - Teams
* - Memberships
@ -29,6 +30,8 @@ class Exception extends \Exception
* - Keys
* - Platform
* - Domain
* - Logger
* - Mocks
*/
/** General */
@ -47,7 +50,11 @@ class Exception extends \Exception
public const GENERAL_ROUTE_NOT_FOUND = 'general_route_not_found';
public const GENERAL_CURSOR_NOT_FOUND = 'general_cursor_not_found';
public const GENERAL_SERVER_ERROR = 'general_server_error';
public const GENERAL_PROTOCOL_UNSUPPORTED = 'general_protocol_unsupported';
public const GENERAL_PROTOCOL_UNSUPPORTED = 'general_protocol_unsupported';
/** Account */
public const ACCOUNT_OAUTH_FAILED_TO_OBTAIN_TOKEN = 'account_oauth_failed_to_obtain_token';
public const ACCOUNT_OAUTH_MISSING_ID = 'account_oauth_missing_id';
/** Users */
public const USER_COUNT_EXCEEDED = 'user_count_exceeded';
@ -170,10 +177,32 @@ class Exception extends \Exception
public const DOMAIN_ALREADY_EXISTS = 'domain_already_exists';
public const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed';
/** Logger */
public const LOGGER_NOT_SUPPORTED = 'logger_not_supported';
/** Mocks */
public const MOCK_INVALID_CONTENT_RANGE_HEADER = 'mock_invalid_content_range_header';
public const MOCK_FIRST_CHUNK_CANNOT_HAVE_ID = 'mock_first_chunk_cannot_have_id';
public const MOCK_CHUNK_MISSING_ID = 'mock_chunk_missing_id';
public const MOCK_CHUNK_INVALID_SIZE = 'mock_chunk_invalid_size';
public const MOCK_INVALID_FILE_NAME = 'mock_invalid_file_name';
public const MOCK_INVALID_FILE_SIZE = 'mock_invalid_file_size';
public const MOCK_WRONG_FILE_UPLOADED = 'mock_wrong_file_uploaded';
public const MOCK_MISSING_COOKIE = 'mock_missing_cookie';
public const MOCK_INVALID_CLIENT_ID = 'mock_invalid_client_id';
public const MOCK_INVALID_CLIENT_SECRET = 'mock_invalid_client_secret';
public const MOCK_INVALID_TOKEN = 'mock_invalid_token';
public const MOCK_INVALID_REFRESH_TOKEN = 'mock_invalid_refresh_token';
public const MOCK_INVALID_GRANT_TYPE = 'mock_invalid_grant_type';
public const MOCK_FAILED_TO_READ_RESULTS = 'mock_failed_to_read_results';
public const MOCK_FAILED_TO_SAVE_RESULTS = 'mock_failed_to_save_results';
public const MOCK_400 = 'mock_400';
public const MOCK_500 = 'mock_500';
private $type = '';
public function __construct(string $message, int $code = 0, string $type = Exception::GENERAL_UNKNOWN, \Throwable $previous = null)
public function __construct(string $type = Exception::GENERAL_UNKNOWN, string $message = '', int $code = 0, \Throwable $previous = null)
{
$this->type = $type;