mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 08:58:35 +00:00
commit
76cd8f9c24
21 changed files with 408 additions and 156 deletions
1
.env
1
.env
|
|
@ -80,3 +80,4 @@ _APP_DOCKER_HUB_USERNAME=
|
|||
_APP_DOCKER_HUB_PASSWORD=
|
||||
_APP_CONSOLE_GITHUB_SECRET=
|
||||
_APP_CONSOLE_GITHUB_APP_ID=
|
||||
OPENAI_API_KEY=YOUR_OPENAI_API_KEY
|
||||
|
|
@ -29,7 +29,7 @@ ENV VITE_APPWRITE_GROWTH_ENDPOINT=$VITE_APPWRITE_GROWTH_ENDPOINT
|
|||
RUN npm ci
|
||||
RUN npm run build
|
||||
|
||||
FROM appwrite/base:0.2.2 as final
|
||||
FROM appwrite/base:0.4.2 as final
|
||||
|
||||
LABEL maintainer="team@appwrite.io"
|
||||
|
||||
|
|
|
|||
|
|
@ -215,6 +215,21 @@ return [
|
|||
'description' => 'Missing ID from OAuth2 provider.',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::USER_OAUTH2_BAD_REQUEST => [
|
||||
'name' => Exception::USER_OAUTH2_BAD_REQUEST,
|
||||
'description' => 'OAuth2 provider rejected the bad request.',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::USER_OAUTH2_UNAUTHORIZED => [
|
||||
'name' => Exception::USER_OAUTH2_UNAUTHORIZED,
|
||||
'description' => 'OAuth2 provider rejected the unauthorized request.',
|
||||
'code' => 401,
|
||||
],
|
||||
Exception::USER_OAUTH2_PROVIDER_ERROR => [
|
||||
'name' => Exception::USER_OAUTH2_PROVIDER_ERROR,
|
||||
'description' => 'OAuth2 provider returned some error.',
|
||||
'code' => 424,
|
||||
],
|
||||
|
||||
/** Teams */
|
||||
Exception::TEAM_NOT_FOUND => [
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ return [
|
|||
'audio/ogg', // Ogg Vorbis RFC 5334
|
||||
'audio/vorbis', // Vorbis RFC 5215
|
||||
'audio/vnd.wav', // wav RFC 2361
|
||||
'audio/aac', //AAC audio
|
||||
'audio/x-hx-aac-adts', // AAC audio
|
||||
|
||||
// Microsoft Word
|
||||
'application/msword',
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ return [
|
|||
'variables' => [
|
||||
[
|
||||
'name' => '_APP_SMS_PROVIDER',
|
||||
'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'. \n\nAvailable providers are twilio, text-magic, telesign, msg91, and vonage.",
|
||||
'description' => "Provider used for delivering SMS for Phone authentication. Use the following format: 'sms://[USER]:[SECRET]@[PROVIDER]'.\n\nEnsure `[USER]` and `[SECRET]` are URL encoded if they contain any non-alphanumeric characters.\n\nAvailable providers are twilio, text-magic, telesign, msg91, and vonage.",
|
||||
'introduction' => '0.15.0',
|
||||
'default' => '',
|
||||
'required' => false,
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 61ed63c5094bb675c1b2715cb2fa7e17389e1152
|
||||
Subproject commit 9174d8f8cb584744dd7a53f69d324f490ee82ee3
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use Ahc\Jwt\JWT;
|
||||
use Appwrite\Auth\Auth;
|
||||
use Appwrite\Auth\OAuth2\Exception as OAuth2Exception;
|
||||
use Appwrite\Auth\Validator\Password;
|
||||
use Appwrite\Auth\Validator\Phone;
|
||||
use Appwrite\Detector\Detector;
|
||||
|
|
@ -439,11 +440,13 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
|||
->label('docs', false)
|
||||
->param('projectId', '', new Text(1024), 'Project ID.')
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.')
|
||||
->param('code', '', new Text(2048), 'OAuth2 code.')
|
||||
->param('code', '', new Text(2048, 0), 'OAuth2 code.', true)
|
||||
->param('state', '', new Text(2048), 'Login state params.', true)
|
||||
->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true)
|
||||
->param('error_description', '', new Text(2048, 0), 'Human-readable text providing additional information about the error returned from the OAuth2 provider.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (string $projectId, string $provider, string $code, string $state, Request $request, Response $response) {
|
||||
->action(function (string $projectId, string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response) {
|
||||
|
||||
$domain = $request->getHostname();
|
||||
$protocol = $request->getProtocol();
|
||||
|
|
@ -452,7 +455,13 @@ App::get('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
|||
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
->addHeader('Pragma', 'no-cache')
|
||||
->redirect($protocol . '://' . $domain . '/v1/account/sessions/oauth2/' . $provider . '/redirect?'
|
||||
. \http_build_query(['project' => $projectId, 'code' => $code, 'state' => $state]));
|
||||
. \http_build_query([
|
||||
'project' => $projectId,
|
||||
'code' => $code,
|
||||
'state' => $state,
|
||||
'error' => $error,
|
||||
'error_description' => $error_description
|
||||
]));
|
||||
});
|
||||
|
||||
App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
||||
|
|
@ -464,11 +473,13 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
|||
->label('docs', false)
|
||||
->param('projectId', '', new Text(1024), 'Project ID.')
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.')
|
||||
->param('code', '', new Text(2048), 'OAuth2 code.')
|
||||
->param('code', '', new Text(2048, 0), 'OAuth2 code.', true)
|
||||
->param('state', '', new Text(2048), 'Login state params.', true)
|
||||
->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true)
|
||||
->param('error_description', '', new Text(2048, 0), 'Human-readable text providing additional information about the error returned from the OAuth2 provider.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->action(function (string $projectId, string $provider, string $code, string $state, Request $request, Response $response) {
|
||||
->action(function (string $projectId, string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response) {
|
||||
|
||||
$domain = $request->getHostname();
|
||||
$protocol = $request->getProtocol();
|
||||
|
|
@ -477,7 +488,13 @@ App::post('/v1/account/sessions/oauth2/callback/:provider/:projectId')
|
|||
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
->addHeader('Pragma', 'no-cache')
|
||||
->redirect($protocol . '://' . $domain . '/v1/account/sessions/oauth2/' . $provider . '/redirect?'
|
||||
. \http_build_query(['project' => $projectId, 'code' => $code, 'state' => $state]));
|
||||
. \http_build_query([
|
||||
'project' => $projectId,
|
||||
'code' => $code,
|
||||
'state' => $state,
|
||||
'error' => $error,
|
||||
'error_description' => $error_description
|
||||
]));
|
||||
});
|
||||
|
||||
App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
|
|
@ -493,8 +510,10 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
->label('abuse-key', 'ip:{ip}')
|
||||
->label('docs', false)
|
||||
->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'OAuth2 provider.')
|
||||
->param('code', '', new Text(2048), 'OAuth2 code.')
|
||||
->param('code', '', new Text(2048, 0), 'OAuth2 code.', true)
|
||||
->param('state', '', new Text(2048), 'OAuth2 state params.', true)
|
||||
->param('error', '', new Text(2048, 0), 'Error code returned from the OAuth2 provider.', true)
|
||||
->param('error_description', '', new Text(2048, 0), 'Human-readable text providing additional information about the error returned from the OAuth2 provider.', true)
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
|
|
@ -502,7 +521,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
->inject('dbForProject')
|
||||
->inject('geodb')
|
||||
->inject('events')
|
||||
->action(function (string $provider, string $code, string $state, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $events) use ($oauthDefaultSuccess) {
|
||||
->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $events) use ($oauthDefaultSuccess) {
|
||||
|
||||
$protocol = $request->getProtocol();
|
||||
$callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
|
||||
|
|
@ -512,27 +531,22 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
$appSecret = $project->getAttribute('authProviders', [])[$provider . 'Secret'] ?? '{}';
|
||||
$providerEnabled = $project->getAttribute('authProviders', [])[$provider . 'Enabled'] ?? false;
|
||||
|
||||
if (!$providerEnabled) {
|
||||
throw new Exception(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your ' . APP_NAME . ' console to continue.');
|
||||
}
|
||||
|
||||
if (!empty($appSecret) && isset($appSecret['version'])) {
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V' . $appSecret['version']);
|
||||
$appSecret = OpenSSL::decrypt($appSecret['data'], $appSecret['method'], $key, 0, \hex2bin($appSecret['iv']), \hex2bin($appSecret['tag']));
|
||||
}
|
||||
|
||||
$className = 'Appwrite\\Auth\\OAuth2\\' . \ucfirst($provider);
|
||||
|
||||
if (!\class_exists($className)) {
|
||||
throw new Exception(Exception::PROJECT_PROVIDER_UNSUPPORTED);
|
||||
}
|
||||
|
||||
$providers = Config::getParam('providers');
|
||||
$providerName = $providers[$provider]['name'] ?? '';
|
||||
|
||||
/** @var Appwrite\Auth\OAuth2 $oauth2 */
|
||||
$oauth2 = new $className($appId, $appSecret, $callback);
|
||||
|
||||
if (!empty($state)) {
|
||||
try {
|
||||
$state = \array_merge($defaultState, $oauth2->parseState($state));
|
||||
} catch (\Exception$exception) {
|
||||
} catch (\Exception $exception) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to parse login state params as passed from OAuth2 provider');
|
||||
}
|
||||
} else {
|
||||
|
|
@ -546,27 +560,66 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
if (!empty($state['failure']) && !$validateURL->isValid($state['failure'])) {
|
||||
throw new Exception(Exception::PROJECT_INVALID_FAILURE_URL);
|
||||
}
|
||||
|
||||
$accessToken = $oauth2->getAccessToken($code);
|
||||
$refreshToken = $oauth2->getRefreshToken($code);
|
||||
$accessTokenExpiry = $oauth2->getAccessTokenExpiry($code);
|
||||
|
||||
if (empty($accessToken)) {
|
||||
if (!empty($state['failure'])) {
|
||||
$response->redirect($state['failure'], 301, 0);
|
||||
$failure = [];
|
||||
if (!empty($state['failure'])) {
|
||||
$failure = URLParser::parse($state['failure']);
|
||||
}
|
||||
$failureRedirect = (function (string $type, ?string $message = null, ?int $code = null) use ($failure, $response) {
|
||||
$exception = new Exception($type, $message, $code);
|
||||
if (!empty($failure)) {
|
||||
$query = URLParser::parseQuery($failure['query']);
|
||||
$query['error'] = json_encode([
|
||||
'message' => $exception->getMessage(),
|
||||
'type' => $exception->getType(),
|
||||
'code' => !\is_null($code) ? $code : $exception->getCode(),
|
||||
]);
|
||||
$failure['query'] = URLParser::unparseQuery($query);
|
||||
$response->redirect(URLParser::unparse($failure), 301);
|
||||
}
|
||||
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to obtain access token');
|
||||
throw $exception;
|
||||
});
|
||||
|
||||
if (!$providerEnabled) {
|
||||
$failureRedirect(Exception::PROJECT_PROVIDER_DISABLED, 'This provider is disabled. Please enable the provider from your ' . APP_NAME . ' console to continue.');
|
||||
}
|
||||
|
||||
if (!empty($error)) {
|
||||
$message = 'The ' . $providerName . ' OAuth2 provider returned an error: ' . $error;
|
||||
if (!empty($error_description)) {
|
||||
$message .= ': ' . $error_description;
|
||||
}
|
||||
$failureRedirect(Exception::USER_OAUTH2_PROVIDER_ERROR, $message);
|
||||
}
|
||||
|
||||
if (empty($code)) {
|
||||
$failureRedirect(Exception::USER_OAUTH2_PROVIDER_ERROR, 'Missing OAuth2 code. Please contact the Appwrite team for additional support.');
|
||||
}
|
||||
|
||||
if (!empty($appSecret) && isset($appSecret['version'])) {
|
||||
$key = App::getEnv('_APP_OPENSSL_KEY_V' . $appSecret['version']);
|
||||
$appSecret = OpenSSL::decrypt($appSecret['data'], $appSecret['method'], $key, 0, \hex2bin($appSecret['iv']), \hex2bin($appSecret['tag']));
|
||||
}
|
||||
|
||||
$accessToken = '';
|
||||
$refreshToken = '';
|
||||
$accessTokenExpiry = 0;
|
||||
|
||||
try {
|
||||
$accessToken = $oauth2->getAccessToken($code);
|
||||
$refreshToken = $oauth2->getRefreshToken($code);
|
||||
$accessTokenExpiry = $oauth2->getAccessTokenExpiry($code);
|
||||
} catch (OAuth2Exception $ex) {
|
||||
$failureRedirect(
|
||||
$ex->getType(),
|
||||
'Failed to obtain access token. The ' . $providerName . ' OAuth2 provider returned an error: ' . $ex->getMessage(),
|
||||
$ex->getCode(),
|
||||
);
|
||||
}
|
||||
|
||||
$oauth2ID = $oauth2->getUserID($accessToken);
|
||||
|
||||
if (empty($oauth2ID)) {
|
||||
if (!empty($state['failure'])) {
|
||||
$response->redirect($state['failure'], 301, 0);
|
||||
}
|
||||
|
||||
throw new Exception(Exception::USER_MISSING_ID);
|
||||
$failureRedirect(Exception::USER_MISSING_ID);
|
||||
}
|
||||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
|
|
@ -618,7 +671,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
$total = $dbForProject->count('users', max: APP_LIMIT_USERS);
|
||||
|
||||
if ($total >= $limit) {
|
||||
throw new Exception(Exception::USER_COUNT_EXCEEDED);
|
||||
$failureRedirect(Exception::USER_COUNT_EXCEEDED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -653,13 +706,13 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
]);
|
||||
Authorization::skip(fn() => $dbForProject->createDocument('users', $user));
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::USER_ALREADY_EXISTS);
|
||||
$failureRedirect(Exception::USER_ALREADY_EXISTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (false === $user->getAttribute('status')) { // Account is blocked
|
||||
throw new Exception(Exception::USER_BLOCKED); // User is in status blocked
|
||||
$failureRedirect(Exception::USER_BLOCKED); // User is in status blocked
|
||||
}
|
||||
|
||||
// Create session token, verify user account and update OAuth2 ID and Access Token
|
||||
|
|
@ -1046,7 +1099,7 @@ App::post('/v1/account/sessions/phone')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TOKEN)
|
||||
->label('abuse-limit', 10)
|
||||
->label('abuse-key', 'url:{url},email:{param-email}')
|
||||
->label('abuse-key', 'url:{url},email:{param-phone}')
|
||||
->param('userId', '', new CustomId(), 'Unique Id. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
|
||||
->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.')
|
||||
->inject('request')
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use Appwrite\Extend\Exception;
|
|||
use Appwrite\Utopia\Response;
|
||||
use Utopia\App;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
App::init()
|
||||
->groups(['console'])
|
||||
|
|
@ -38,3 +39,58 @@ App::get('/v1/console/variables')
|
|||
|
||||
$response->dynamic($variables, Response::MODEL_CONSOLE_VARIABLES);
|
||||
});
|
||||
|
||||
|
||||
App::post('/v1/console/assistant')
|
||||
->desc('Ask Query')
|
||||
->groups(['api', 'assistant'])
|
||||
->label('scope', 'public')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_SESSION])
|
||||
->label('sdk.namespace', 'assistant')
|
||||
->label('sdk.method', 'chat')
|
||||
->label('sdk.description', '/docs/references/assistant/chat.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_TEXT)
|
||||
->label('abuse-limit', 15)
|
||||
->label('abuse-key', 'userId:{userId}')
|
||||
->param('query', '', new Text(2000), 'Query')
|
||||
->inject('response')
|
||||
->action(function (string $query, Response $response) {
|
||||
$ch = curl_init('http://appwrite-assistant:3003/');
|
||||
$responseHeaders = [];
|
||||
$query = json_encode(['prompt' => $query]);
|
||||
$headers = ['accept: text/event-stream'];
|
||||
$handleEvent = function ($ch, $data) use ($response) {
|
||||
$response->chunk($data);
|
||||
|
||||
return \strlen($data);
|
||||
};
|
||||
|
||||
curl_setopt($ch, CURLOPT_WRITEFUNCTION, $handleEvent);
|
||||
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 9000);
|
||||
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders) {
|
||||
$len = strlen($header);
|
||||
$header = explode(':', $header, 2);
|
||||
|
||||
if (count($header) < 2) { // ignore invalid headers
|
||||
return $len;
|
||||
}
|
||||
|
||||
$responseHeaders[strtolower(trim($header[0]))] = trim($header[1]);
|
||||
|
||||
return $len;
|
||||
});
|
||||
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
|
||||
|
||||
curl_exec($ch);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
$response->chunk('', true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -562,6 +562,7 @@ App::error()
|
|||
->setParam('projectName', $project->getAttribute('name'))
|
||||
->setParam('projectURL', $project->getAttribute('url'))
|
||||
->setParam('message', $error->getMessage())
|
||||
->setParam('type', $type)
|
||||
->setParam('code', $code)
|
||||
->setParam('trace', $trace)
|
||||
;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ $parseLabel = function (string $label, array $responsePayload, array $requestPar
|
|||
$parts = explode('.', $match);
|
||||
|
||||
if (count($parts) !== 2) {
|
||||
throw new Exception('Too less or too many parts', 400, Exception::GENERAL_ARGUMENT_INVALID);
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "The server encountered an error while parsing the label: $label. Please create an issue on GitHub to allow us to investigate further https://github.com/appwrite/appwrite/issues/new/choose");
|
||||
}
|
||||
|
||||
$namespace = $parts[0] ?? '';
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -64,7 +64,7 @@
|
|||
"utopia-php/queue": "0.5.*",
|
||||
"utopia-php/registry": "0.5.*",
|
||||
"utopia-php/storage": "0.14.*",
|
||||
"utopia-php/swoole": "0.5.*",
|
||||
"utopia-php/swoole": "0.8.*",
|
||||
"utopia-php/websocket": "0.1.*",
|
||||
"resque/php-resque": "1.3.6",
|
||||
"matomo/device-detector": "6.1.*",
|
||||
|
|
@ -86,8 +86,8 @@
|
|||
"appwrite/sdk-generator": "0.33.*",
|
||||
"ext-fileinfo": "*",
|
||||
"phpunit/phpunit": "9.5.20",
|
||||
"squizlabs/php_codesniffer": "^3.6",
|
||||
"swoole/ide-helper": "4.8.9",
|
||||
"squizlabs/php_codesniffer": "^3.7",
|
||||
"swoole/ide-helper": "5.0.2",
|
||||
"textalk/websocket": "1.5.7"
|
||||
},
|
||||
"provide": {
|
||||
|
|
|
|||
42
composer.lock
generated
42
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "f9e35e81b051baad38f0cb0e8fa611fe",
|
||||
"content-hash": "d8f45e92243913c5898f4c6b483ed770",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
|
@ -2351,28 +2351,28 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/swoole",
|
||||
"version": "0.5.0",
|
||||
"version": "0.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/swoole.git",
|
||||
"reference": "c2a3a4f944a2f22945af3cbcb95b13f0769628b1"
|
||||
"reference": "5b60e7f730641cc182bc36b1f9939d4a76d3439b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/swoole/zipball/c2a3a4f944a2f22945af3cbcb95b13f0769628b1",
|
||||
"reference": "c2a3a4f944a2f22945af3cbcb95b13f0769628b1",
|
||||
"url": "https://api.github.com/repos/utopia-php/swoole/zipball/5b60e7f730641cc182bc36b1f9939d4a76d3439b",
|
||||
"reference": "5b60e7f730641cc182bc36b1f9939d4a76d3439b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-swoole": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/framework": "0.*.*"
|
||||
"utopia-php/framework": "0.28.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.2.*",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"swoole/ide-helper": "4.8.3",
|
||||
"vimeo/psalm": "4.15.0"
|
||||
"swoole/ide-helper": "5.0.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
|
@ -2396,9 +2396,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/swoole/issues",
|
||||
"source": "https://github.com/utopia-php/swoole/tree/0.5.0"
|
||||
"source": "https://github.com/utopia-php/swoole/tree/0.8.0"
|
||||
},
|
||||
"time": "2022-10-19T22:19:07+00:00"
|
||||
"time": "2023-07-25T10:29:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/system",
|
||||
|
|
@ -4886,16 +4886,16 @@
|
|||
},
|
||||
{
|
||||
"name": "swoole/ide-helper",
|
||||
"version": "4.8.9",
|
||||
"version": "5.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/swoole/ide-helper.git",
|
||||
"reference": "8f82ba3b6af04a5bccb97c1654af992d1ee8b0fe"
|
||||
"reference": "16cfee44a6ec92254228c39bcab2fb8ae74cc2ea"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/swoole/ide-helper/zipball/8f82ba3b6af04a5bccb97c1654af992d1ee8b0fe",
|
||||
"reference": "8f82ba3b6af04a5bccb97c1654af992d1ee8b0fe",
|
||||
"url": "https://api.github.com/repos/swoole/ide-helper/zipball/16cfee44a6ec92254228c39bcab2fb8ae74cc2ea",
|
||||
"reference": "16cfee44a6ec92254228c39bcab2fb8ae74cc2ea",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
|
|
@ -4912,19 +4912,9 @@
|
|||
"description": "IDE help files for Swoole.",
|
||||
"support": {
|
||||
"issues": "https://github.com/swoole/ide-helper/issues",
|
||||
"source": "https://github.com/swoole/ide-helper/tree/4.8.9"
|
||||
"source": "https://github.com/swoole/ide-helper/tree/5.0.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://gitee.com/swoole/swoole?donate=true",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/swoole",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-04-18T20:38:04+00:00"
|
||||
"time": "2023-03-20T06:05:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
|
|
|
|||
|
|
@ -690,6 +690,14 @@ services:
|
|||
- _APP_CONNECTIONS_QUEUE
|
||||
- _APP_REGION
|
||||
|
||||
appwrite-assistant:
|
||||
container_name: appwrite-assistant
|
||||
image: appwrite/assistant:0.1.0
|
||||
networks:
|
||||
- appwrite
|
||||
environment:
|
||||
- OPENAI_API_KEY
|
||||
|
||||
openruntimes-executor:
|
||||
container_name: openruntimes-executor
|
||||
hostname: exc1
|
||||
|
|
|
|||
BIN
public/images/vcs/animation-building.gif
Normal file
BIN
public/images/vcs/animation-building.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 458 KiB |
BIN
public/images/vcs/state-failed.png
Normal file
BIN
public/images/vcs/state-failed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
public/images/vcs/state-success.png
Normal file
BIN
public/images/vcs/state-success.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
BIN
public/images/vcs/state-waiting.png
Normal file
BIN
public/images/vcs/state-waiting.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Appwrite\Auth;
|
||||
|
||||
use Appwrite\Auth\OAuth2\Exception;
|
||||
|
||||
abstract class OAuth2
|
||||
{
|
||||
/**
|
||||
|
|
@ -73,6 +75,13 @@ abstract class OAuth2
|
|||
*/
|
||||
abstract public function refreshTokens(string $refreshToken): array;
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getUserID(string $accessToken): string;
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
|
|
@ -148,11 +157,11 @@ abstract class OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessTokenExpiry(string $code): string
|
||||
public function getAccessTokenExpiry(string $code): int
|
||||
{
|
||||
$tokens = $this->getTokens($code);
|
||||
|
||||
return $tokens['expires_in'] ?? '';
|
||||
return $tokens['expires_in'] ?? 0;
|
||||
}
|
||||
|
||||
// The parseState function was designed specifically for Amazon OAuth2 Adapter to override.
|
||||
|
|
@ -195,8 +204,14 @@ abstract class OAuth2
|
|||
// Send the request & save response to $response
|
||||
$response = \curl_exec($ch);
|
||||
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
\curl_close($ch);
|
||||
|
||||
if ($code != 200) {
|
||||
throw new Exception($response, $code);
|
||||
}
|
||||
|
||||
return (string)$response;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
51
src/Appwrite/Auth/OAuth2/Exception.php
Normal file
51
src/Appwrite/Auth/OAuth2/Exception.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
|
||||
class Exception extends AppwriteException
|
||||
{
|
||||
protected string $response = '';
|
||||
protected string $error = '';
|
||||
protected string $errorDescription = '';
|
||||
|
||||
public function __construct(string $response = '', int $code = 0, \Throwable $previous = null)
|
||||
{
|
||||
$this->response = $response;
|
||||
$this->message = $response;
|
||||
$decoded = json_decode($response, true);
|
||||
if (\is_array($decoded)) {
|
||||
$this->error = $decoded['error'];
|
||||
$this->errorDescription = $decoded['error_description'];
|
||||
$this->message = $this->error . ': ' . $this->errorDescription;
|
||||
}
|
||||
$type = match ($code) {
|
||||
400 => AppwriteException::USER_OAUTH2_BAD_REQUEST,
|
||||
401 => AppwriteException::USER_OAUTH2_UNAUTHORIZED,
|
||||
default => AppwriteException::USER_OAUTH2_PROVIDER_ERROR
|
||||
};
|
||||
|
||||
parent::__construct($type, $this->message, $code, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error parameter from the response.
|
||||
*
|
||||
* See https://datatracker.ietf.org/doc/html/rfc6749#section-5.2 for more information.
|
||||
*/
|
||||
public function getError(): string
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error_description parameter from the response.
|
||||
*
|
||||
* See https://datatracker.ietf.org/doc/html/rfc6749#section-5.2 for more information.
|
||||
*/
|
||||
public function getErrorDescription(): string
|
||||
{
|
||||
return $this->errorDescription;
|
||||
}
|
||||
}
|
||||
|
|
@ -78,6 +78,9 @@ class Exception extends \Exception
|
|||
public const USER_PHONE_ALREADY_EXISTS = 'user_phone_already_exists';
|
||||
public const USER_PHONE_NOT_FOUND = 'user_phone_not_found';
|
||||
public const USER_MISSING_ID = 'user_missing_id';
|
||||
public const USER_OAUTH2_BAD_REQUEST = 'user_oauth2_bad_request';
|
||||
public const USER_OAUTH2_UNAUTHORIZED = 'user_oauth2_unauthorized';
|
||||
public const USER_OAUTH2_PROVIDER_ERROR = 'user_oauth2_provider_error';
|
||||
|
||||
/** Teams */
|
||||
public const TEAM_NOT_FOUND = 'team_not_found';
|
||||
|
|
|
|||
Loading…
Reference in a new issue