Merge branch '0.14.x' of https://github.com/appwrite/appwrite into feat-use-build-timeout
This commit is contained in:
commit
4508158fe5
|
@ -5,6 +5,9 @@ require_once __DIR__.'/controllers/general.php';
|
|||
use Utopia\App;
|
||||
use Utopia\CLI\CLI;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
$cli = new CLI();
|
||||
|
||||
|
|
|
@ -1054,9 +1054,9 @@ $collections = [
|
|||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => [],
|
||||
'array' => true,
|
||||
'filters' => ['json'],
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => ['subQuerySessions'],
|
||||
],
|
||||
[
|
||||
'$id' => 'tokens',
|
||||
|
@ -1478,6 +1478,13 @@ $collections = [
|
|||
'lengths' => [100, 100],
|
||||
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => '_key_user',
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['userId'],
|
||||
'lengths' => [Database::LENGTH_KEY],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
|
|
|
@ -78,6 +78,11 @@ return [
|
|||
'description' => 'An internal server error occurred.',
|
||||
'code' => 500,
|
||||
],
|
||||
Exception::GENERAL_PROTOCOL_UNSUPPORTED => [
|
||||
'name' => Exception::GENERAL_PROTOCOL_UNSUPPORTED,
|
||||
'description' => 'The request cannot be fulfilled with the current protocol. Please check the value of the _APP_OPTIONS_FORCE_HTTPS environment variable.',
|
||||
'code' => 500,
|
||||
],
|
||||
|
||||
/** User Errors */
|
||||
Exception::USER_COUNT_EXCEEDED => [
|
||||
|
|
|
@ -27,6 +27,12 @@
|
|||
"emails.invitation.footer": "If you are not interested, you can ignore this message.",
|
||||
"emails.invitation.thanks": "Thanks",
|
||||
"emails.invitation.signature": "{{project}} team",
|
||||
"emails.certificate.subject": "Certificate failure for %s",
|
||||
"emails.certificate.hello": "Hello",
|
||||
"emails.certificate.body": "Certificate for your domain '{{domain}}' could not be generated. This is attempt no. {{attempt}}, and the failure was caused by: {{error}}",
|
||||
"emails.certificate.footer": "Your previous certificate willl be valid for 30 days since the first failure. We highly recommend investigating this case, otherwise your domain will end up without a valid SSL communication.",
|
||||
"emails.certificate.thanks": "Thanks",
|
||||
"emails.certificate.signature": "{{project}} team",
|
||||
"locale.country.unknown": "Unknown",
|
||||
"countries.af": "Afghanistan",
|
||||
"countries.ao": "Angola",
|
||||
|
|
|
@ -241,16 +241,6 @@ return [ // Ordered by ABC.
|
|||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'vk' => [
|
||||
'name' => 'VK',
|
||||
'developers' => 'https://vk.com/dev',
|
||||
'icon' => 'icon-vk',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => false,
|
||||
],
|
||||
'zoom' => [
|
||||
'name' => 'Zoom',
|
||||
'developers' => 'https://marketplace.zoom.us/docs/guides/auth/oauth/',
|
||||
|
|
|
@ -104,7 +104,7 @@ App::post('/v1/account')
|
|||
'reset' => false,
|
||||
'name' => $name,
|
||||
'prefs' => new \stdClass(),
|
||||
'sessions' => [],
|
||||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $name]),
|
||||
|
@ -167,7 +167,10 @@ App::post('/v1/account/sessions')
|
|||
$email = \strtolower($email);
|
||||
$protocol = $request->getProtocol();
|
||||
|
||||
$profile = $dbForProject->findOne('users', [new Query('deleted', Query::TYPE_EQUAL, [false]), new Query('email', Query::TYPE_EQUAL, [$email])]); // Get user by email address
|
||||
$profile = $dbForProject->findOne('users', [
|
||||
new Query('deleted', Query::TYPE_EQUAL, [false]),
|
||||
new Query('email', Query::TYPE_EQUAL, [$email])]
|
||||
);
|
||||
|
||||
if (!$profile || !Auth::passwordVerify($password, $profile->getAttribute('password'))) {
|
||||
$audits
|
||||
|
@ -208,8 +211,7 @@ App::post('/v1/account/sessions')
|
|||
->setAttribute('$write', ['user:' . $profile->getId()])
|
||||
);
|
||||
|
||||
$profile->setAttribute('sessions', $session, Document::SET_TYPE_APPEND);
|
||||
$profile = $dbForProject->updateDocument('users', $profile->getId(), $profile);
|
||||
$dbForProject->deleteCachedDocument('users', $profile->getId());
|
||||
|
||||
$audits
|
||||
->setParam('userId', $profile->getId())
|
||||
|
@ -458,13 +460,10 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
$current = Auth::sessionVerify($sessions, Auth::$secret);
|
||||
|
||||
if ($current) { // Delete current session of new one.
|
||||
foreach ($sessions as $key => $session) {/** @var Document $session */
|
||||
if ($current === $session['$id']) {
|
||||
unset($sessions[$key]);
|
||||
|
||||
$dbForProject->deleteDocument('sessions', $session->getId());
|
||||
$dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('sessions', $sessions));
|
||||
}
|
||||
$currentDocument = $dbForProject->getDocument('sessions', $current);
|
||||
if(!$currentDocument->isEmpty()) {
|
||||
$dbForProject->deleteDocument('sessions', $currentDocument->getId());
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,14 +475,21 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
if ($user === false || $user->isEmpty()) { // No user logged in or with OAuth2 provider ID, create new one or connect with account with same email
|
||||
$name = $oauth2->getUserName($accessToken);
|
||||
$email = $oauth2->getUserEmail($accessToken);
|
||||
$isVerified = $oauth2->isEmailVerified($accessToken);
|
||||
|
||||
$user = $dbForProject->findOne('users', [new Query('deleted', Query::TYPE_EQUAL, [false]), new Query('email', Query::TYPE_EQUAL, [$email])]); // Get user by email address
|
||||
if ($isVerified === true) {
|
||||
// Get user by email address
|
||||
$user = $dbForProject->findOne('users', [
|
||||
new Query('deleted', Query::TYPE_EQUAL, [false]),
|
||||
new Query('email', Query::TYPE_EQUAL, [$email])]
|
||||
);
|
||||
}
|
||||
|
||||
if ($user === false || $user->isEmpty()) { // Last option -> create the user, generate random password
|
||||
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
|
||||
|
||||
if ($limit !== 0) {
|
||||
$total = $dbForProject->count('users', [ new Query('deleted', Query::TYPE_EQUAL, [false]),], APP_LIMIT_USERS);
|
||||
$total = $dbForProject->count('users', [new Query('deleted', Query::TYPE_EQUAL, [false])], APP_LIMIT_USERS);
|
||||
|
||||
if ($total >= $limit) {
|
||||
throw new Exception('Project registration is restricted. Contact your administrator for more information.', 501, Exception::USER_COUNT_EXCEEDED);
|
||||
|
@ -497,7 +503,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
'$read' => ['role:all'],
|
||||
'$write' => ['user:' . $userId],
|
||||
'email' => $email,
|
||||
'emailVerification' => true,
|
||||
'emailVerification' => $isVerified,
|
||||
'status' => true, // Email should already be authenticated by OAuth2 provider
|
||||
'password' => Auth::passwordHash(Auth::passwordGenerator()),
|
||||
'passwordUpdate' => 0,
|
||||
|
@ -505,7 +511,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
'reset' => false,
|
||||
'name' => $name,
|
||||
'prefs' => new \stdClass(),
|
||||
'sessions' => [],
|
||||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $name]),
|
||||
|
@ -522,7 +528,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
}
|
||||
|
||||
// Create session token, verify user account and update OAuth2 ID and Access Token
|
||||
|
||||
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
||||
$record = $geodb->get($request->getIP());
|
||||
$secret = Auth::tokenGenerator();
|
||||
|
@ -553,17 +558,18 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
|
||||
$user
|
||||
->setAttribute('status', true)
|
||||
->setAttribute('sessions', $session, Document::SET_TYPE_APPEND)
|
||||
;
|
||||
|
||||
Authorization::setRole('user:' . $user->getId());
|
||||
|
||||
$dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
|
||||
$session = $dbForProject->createDocument('sessions', $session
|
||||
->setAttribute('$read', ['user:' . $user->getId()])
|
||||
->setAttribute('$write', ['user:' . $user->getId()])
|
||||
);
|
||||
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
|
@ -679,7 +685,7 @@ App::post('/v1/account/sessions/magic-url')
|
|||
'registration' => \time(),
|
||||
'reset' => false,
|
||||
'prefs' => new \stdClass(),
|
||||
'sessions' => [],
|
||||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email]),
|
||||
|
@ -824,6 +830,10 @@ App::put('/v1/account/sessions/magic-url')
|
|||
->setAttribute('$write', ['user:' . $user->getId()])
|
||||
);
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$tokens = $user->getAttribute('tokens', []);
|
||||
|
||||
/**
|
||||
* We act like we're updating and validating
|
||||
* the recovery token but actually we don't need it anymore.
|
||||
|
@ -831,7 +841,10 @@ App::put('/v1/account/sessions/magic-url')
|
|||
$dbForProject->deleteDocument('tokens', $token);
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('sessions', $session, Document::SET_TYPE_APPEND));
|
||||
$user
|
||||
->setAttribute('emailVerification', true);
|
||||
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
|
||||
if (false === $user) {
|
||||
throw new Exception('Failed saving user to DB', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
|
@ -938,7 +951,7 @@ App::post('/v1/account/sessions/anonymous')
|
|||
'reset' => false,
|
||||
'name' => null,
|
||||
'prefs' => new \stdClass(),
|
||||
'sessions' => [],
|
||||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => $userId,
|
||||
|
@ -974,8 +987,7 @@ App::post('/v1/account/sessions/anonymous')
|
|||
->setAttribute('$write', ['user:' . $user->getId()])
|
||||
);
|
||||
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(),
|
||||
$user->setAttribute('sessions', $session, Document::SET_TYPE_APPEND));
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
|
@ -1026,16 +1038,17 @@ App::post('/v1/account/jwt')
|
|||
->label('abuse-key', 'url:{url},userId:{userId}')
|
||||
->inject('response')
|
||||
->inject('user')
|
||||
->action(function ($response, $user) {
|
||||
->inject('dbForProject')
|
||||
->action(function ($response, $user, $dbForProject) {
|
||||
/** @var Appwrite\Utopia\Response $response */
|
||||
/** @var Utopia\Database\Document $user */
|
||||
/** @var Utopia\Database\Database $dbForProject */
|
||||
|
||||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
$current = new Document();
|
||||
|
||||
foreach ($sessions as $session) {
|
||||
/** @var Utopia\Database\Document $session */
|
||||
|
||||
foreach ($sessions as $session) { /** @var Utopia\Database\Document $session */
|
||||
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
|
||||
$current = $session;
|
||||
}
|
||||
|
@ -1619,8 +1632,8 @@ App::delete('/v1/account/sessions/:sessionId')
|
|||
->addCookie(Auth::$cookieName, '', \time() - 3600, '/', Config::getParam('cookieDomain'), ('https' == $protocol), true, Config::getParam('cookieSamesite'))
|
||||
;
|
||||
}
|
||||
|
||||
$dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('sessions', $sessions));
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$events
|
||||
->setParam('eventData', $response->output($session, Response::MODEL_SESSION))
|
||||
|
@ -1714,8 +1727,7 @@ App::patch('/v1/account/sessions/:sessionId')
|
|||
|
||||
$dbForProject->updateDocument('sessions', $sessionId, $session);
|
||||
|
||||
$user->setAttribute("sessions", $sessions);
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$audits
|
||||
->setParam('userId', $user->getId())
|
||||
|
@ -1801,7 +1813,7 @@ App::delete('/v1/account/sessions')
|
|||
}
|
||||
}
|
||||
|
||||
$dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('sessions', []));
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$numOfSessions = count($sessions);
|
||||
|
||||
|
@ -1864,7 +1876,11 @@ App::post('/v1/account/recovery')
|
|||
$isAppUser = Auth::isAppUser($roles);
|
||||
|
||||
$email = \strtolower($email);
|
||||
$profile = $dbForProject->findOne('users', [new Query('deleted', Query::TYPE_EQUAL, [false]), new Query('email', Query::TYPE_EQUAL, [$email])]); // Get user by email address
|
||||
|
||||
$profile = $dbForProject->findOne('users', [
|
||||
new Query('deleted', Query::TYPE_EQUAL, [false]),
|
||||
new Query('email', Query::TYPE_EQUAL, [$email])
|
||||
]);
|
||||
|
||||
if (!$profile) {
|
||||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
|
|
|
@ -23,7 +23,7 @@ use Utopia\Registry\Registry;
|
|||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Validator\Hostname;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
@ -972,6 +972,14 @@ App::post('/v1/projects/:projectId/platforms')
|
|||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $type, string $name, string $key, string $store, string $hostname, Response $response, Database $dbForConsole) {
|
||||
|
||||
// Ensure hostname has proper structure (no port, protocol..)
|
||||
if(!empty($hostname)) {
|
||||
$validator = new Hostname();
|
||||
if (!is_null($hostname) && !$validator->isValid($hostname)) {
|
||||
throw new Exception($validator->getDescription(), 400, Exception::ATTRIBUTE_VALUE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
|
@ -1085,6 +1093,14 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
|
|||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, string $platformId, string $name, string $key, string $store, string $hostname, Response $response, Database $dbForConsole) {
|
||||
|
||||
// Ensure hostname has proper structure (no port, protocol..)
|
||||
if(!empty($hostname)) {
|
||||
$validator = new Hostname();
|
||||
if (!is_null($hostname) && !$validator->isValid($hostname)) {
|
||||
throw new Exception($validator->getDescription(), 400, Exception::ATTRIBUTE_VALUE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
|
@ -1331,8 +1347,7 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
|
|||
$dbForConsole->deleteCachedDocument('projects', $project->getId());
|
||||
|
||||
// Issue a TLS certificate when domain is verified
|
||||
Resque::enqueue('v1-certificates', 'CertificatesV1', [
|
||||
'document' => $domain->getArrayCopy(),
|
||||
Resque::enqueue(Event::CERTIFICATES_QUEUE_NAME, Event::CERTIFICATES_CLASS_NAME, [
|
||||
'domain' => $domain->getAttribute('domain'),
|
||||
]);
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ App::post('/v1/storage/buckets')
|
|||
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default no user is granted with any read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.', true)
|
||||
->param('write', null, new Permissions(), 'An array of strings with write permissions. By default no user is granted with any write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.', true)
|
||||
->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true)
|
||||
->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Integer(), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
|
||||
->param('maximumFileSize', (int) App::getEnv('_APP_STORAGE_LIMIT', 0), new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self-hosted setups you can change the max limit by changing the `_APP_STORAGE_LIMIT` environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
|
||||
->param('allowedFileExtensions', [], new ArrayList(new Text(64)), 'Allowed file extensions', true)
|
||||
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
|
||||
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true)
|
||||
|
@ -223,7 +223,7 @@ App::put('/v1/storage/buckets/:bucketId')
|
|||
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default inherits the existing read permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.', true)
|
||||
->param('write', null, new Permissions(), 'An array of strings with write permissions. By default inherits the existing write permissions. [learn more about permissions](/docs/permissions) and get a full list of available permissions.', true)
|
||||
->param('enabled', true, new Boolean(true), 'Is bucket enabled?', true)
|
||||
->param('maximumFileSize', null, new Integer(), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
|
||||
->param('maximumFileSize', null, new Range(1, (int) App::getEnv('_APP_STORAGE_LIMIT', 0)), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human((int)App::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '. For self hosted version you can change the limit by changing _APP_STORAGE_LIMIT environment variable. [Learn more about storage environment variables](docs/environment-variables#storage)', true)
|
||||
->param('allowedFileExtensions', [], new ArrayList(new Text(64)), 'Allowed file extensions', true)
|
||||
->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true)
|
||||
->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true)
|
||||
|
@ -397,7 +397,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
|
||||
$maximumFileSize = $bucket->getAttribute('maximumFileSize', 0);
|
||||
if ($maximumFileSize > (int) App::getEnv('_APP_STORAGE_LIMIT', 0)) {
|
||||
throw new Exception('Error bucket maximum file size is larger than _APP_STORAGE_LIMIT', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
throw new Exception('Maximum bucket file size is larger than _APP_STORAGE_LIMIT', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$file = $request->getFiles('file');
|
||||
|
|
|
@ -341,7 +341,7 @@ App::post('/v1/teams/:teamId/memberships')
|
|||
'reset' => false,
|
||||
'name' => $name,
|
||||
'prefs' => new \stdClass(),
|
||||
'sessions' => [],
|
||||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $name]),
|
||||
|
@ -708,11 +708,10 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
|||
->setAttribute('$write', ['user:'.$user->getId()])
|
||||
);
|
||||
|
||||
$user->setAttribute('sessions', $session, Document::SET_TYPE_APPEND);
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
Authorization::setRole('user:'.$userId);
|
||||
|
||||
$user = $dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
$membership = $dbForProject->updateDocument('memberships', $membership->getId(), $membership);
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
|
|
@ -63,7 +63,7 @@ App::post('/v1/users')
|
|||
'reset' => false,
|
||||
'name' => $name,
|
||||
'prefs' => new \stdClass(),
|
||||
'sessions' => [],
|
||||
'sessions' => null,
|
||||
'tokens' => null,
|
||||
'memberships' => null,
|
||||
'search' => implode(' ', [$userId, $email, $name]),
|
||||
|
@ -632,25 +632,20 @@ App::delete('/v1/users/:userId/sessions/:sessionId')
|
|||
throw new Exception('User not found', 404, Exception::USER_NOT_FOUND);
|
||||
}
|
||||
|
||||
$sessions = $user->getAttribute('sessions', []);
|
||||
$session = $dbForProject->getDocument('sessions', $sessionId);
|
||||
|
||||
foreach ($sessions as $key => $session) { /** @var Document $session */
|
||||
|
||||
if ($sessionId == $session->getId()) {
|
||||
unset($sessions[$key]);
|
||||
|
||||
$dbForProject->deleteDocument('sessions', $session->getId());
|
||||
|
||||
$user->setAttribute('sessions', $sessions);
|
||||
|
||||
$events
|
||||
->setParam('eventData', $response->output($user, Response::MODEL_USER))
|
||||
;
|
||||
|
||||
$dbForProject->updateDocument('users', $user->getId(), $user);
|
||||
}
|
||||
if($session->isEmpty()) {
|
||||
throw new Exception('User not found', 404, Exception::USER_SESSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$dbForProject->deleteDocument('sessions', $session->getId());
|
||||
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$events
|
||||
->setParam('eventData', $response->output($user, Response::MODEL_USER))
|
||||
;
|
||||
|
||||
$usage
|
||||
->setParam('users.update', 1)
|
||||
->setParam('users.sessions.delete', 1)
|
||||
|
@ -693,7 +688,7 @@ App::delete('/v1/users/:userId/sessions')
|
|||
$dbForProject->deleteDocument('sessions', $session->getId());
|
||||
}
|
||||
|
||||
$dbForProject->updateDocument('users', $user->getId(), $user->setAttribute('sessions', []));
|
||||
$dbForProject->deleteCachedDocument('users', $user->getId());
|
||||
|
||||
$events
|
||||
->setParam('eventData', $response->output($user, Response::MODEL_USER))
|
||||
|
|
|
@ -20,6 +20,7 @@ use Utopia\CLI\Console;
|
|||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Validator\Hostname;
|
||||
use Appwrite\Utopia\Request\Filters\V12 as RequestV12;
|
||||
use Appwrite\Utopia\Request\Filters\V13 as RequestV13;
|
||||
use Utopia\Validator\Text;
|
||||
|
@ -99,14 +100,11 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
|||
]);
|
||||
|
||||
$domainDocument = $dbForConsole->createDocument('domains', $domainDocument);
|
||||
|
||||
|
||||
Console::info('Issuing a TLS certificate for the main domain (' . $domain->get() . ') in a few seconds...');
|
||||
|
||||
|
||||
Resque::enqueue(Event::CERTIFICATES_QUEUE_NAME, Event::CERTIFICATES_CLASS_NAME, [
|
||||
'document' => $domainDocument,
|
||||
'domain' => $domain->get(),
|
||||
'validateTarget' => false,
|
||||
'validateCNAME' => false,
|
||||
'domain' => $domain->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -135,8 +133,13 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
|||
$protocol = \parse_url($request->getOrigin($referrer), PHP_URL_SCHEME);
|
||||
$port = \parse_url($request->getOrigin($referrer), PHP_URL_PORT);
|
||||
|
||||
$refDomain = (!empty($protocol) ? $protocol : $request->getProtocol()).'://'.((\in_array($origin, $clients))
|
||||
? $origin : 'localhost').(!empty($port) ? ':'.$port : '');
|
||||
$refDomainOrigin = 'localhost';
|
||||
$validator = new Hostname($clients);
|
||||
if ($validator->isValid($origin)) {
|
||||
$refDomainOrigin = $origin;
|
||||
}
|
||||
|
||||
$refDomain = (!empty($protocol) ? $protocol : $request->getProtocol()) . '://' . $refDomainOrigin . (!empty($port) ? ':' . $port : '');
|
||||
|
||||
$refDomain = (!$route->getLabel('origin', false)) // This route is publicly accessible
|
||||
? $refDomain
|
||||
|
@ -185,6 +188,10 @@ App::init(function ($utopia, $request, $response, $console, $project, $dbForCons
|
|||
*/
|
||||
if (App::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS
|
||||
if ($request->getProtocol() !== 'https') {
|
||||
if($request->getMethod() !== Request::METHOD_GET) {
|
||||
throw new Exception('Method unsupported over HTTP.', 500, Exception::GENERAL_PROTOCOL_UNSUPPORTED);
|
||||
}
|
||||
|
||||
return $response->redirect('https://'.$request->getHostname().$request->getURI());
|
||||
}
|
||||
|
||||
|
|
14
app/init.php
14
app/init.php
|
@ -127,6 +127,7 @@ const MAIL_TYPE_VERIFICATION = 'verification';
|
|||
const MAIL_TYPE_MAGIC_SESSION = 'magicSession';
|
||||
const MAIL_TYPE_RECOVERY = 'recovery';
|
||||
const MAIL_TYPE_INVITATION = 'invitation';
|
||||
const MAIL_TYPE_CERTIFICATE = 'certificate';
|
||||
// Auth Types
|
||||
const APP_AUTH_TYPE_SESSION = 'Session';
|
||||
const APP_AUTH_TYPE_JWT = 'JWT';
|
||||
|
@ -301,6 +302,19 @@ Database::addFilter('subQueryWebhooks',
|
|||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQuerySessions',
|
||||
function($value) {
|
||||
return null;
|
||||
},
|
||||
function($value, Document $document, Database $database) {
|
||||
$sessions = Authorization::skip(fn () => $database->find('sessions', [
|
||||
new Query('userId', Query::TYPE_EQUAL, [$document->getId()])
|
||||
], $database->getIndexLimit(), 0, []));
|
||||
|
||||
return $sessions;
|
||||
}
|
||||
);
|
||||
|
||||
Database::addFilter('subQueryTokens',
|
||||
function($value) {
|
||||
return null;
|
||||
|
|
|
@ -1,10 +1,42 @@
|
|||
<?php
|
||||
|
||||
global $cli;
|
||||
global $register;
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Utopia\App;
|
||||
use Utopia\Cache\Cache;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Adapter\MariaDB;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
function getConsoleDB(): Database
|
||||
{
|
||||
global $register;
|
||||
|
||||
$attempts = 0;
|
||||
|
||||
do {
|
||||
try {
|
||||
$attempts++;
|
||||
$cache = new Cache(new RedisCache($register->get('cache')));
|
||||
$database = new Database(new MariaDB($register->get('db')), $cache);
|
||||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace('_console'); // Main DB
|
||||
break; // leave loop if successful
|
||||
} catch(\Exception $e) {
|
||||
Console::warning("Database not ready. Retrying connection ({$attempts})...");
|
||||
if ($attempts >= DATABASE_RECONNECT_MAX_ATTEMPTS) {
|
||||
throw new \Exception('Failed to connect to database: '. $e->getMessage());
|
||||
}
|
||||
sleep(DATABASE_RECONNECT_SLEEP);
|
||||
}
|
||||
} while ($attempts < DATABASE_RECONNECT_MAX_ATTEMPTS);
|
||||
|
||||
return $database;
|
||||
}
|
||||
|
||||
$cli
|
||||
->task('maintenance')
|
||||
|
@ -54,6 +86,29 @@ $cli
|
|||
]);
|
||||
}
|
||||
|
||||
function renewCertificates($dbForConsole)
|
||||
{
|
||||
$time = date('d-m-Y H:i:s', time());
|
||||
/** @var Utopia\Database\Database $dbForConsole */
|
||||
|
||||
$certificates = $dbForConsole->find('certificates', [
|
||||
new Query('attempts', Query::TYPE_LESSEREQUAL, [5]), // Maximum 5 attempts
|
||||
new Query('renewDate', Query::TYPE_LESSEREQUAL, [\time()]) // includes 60 days cooldown (we have 30 days to renew)
|
||||
], 200); // Limit 200 comes from LetsEncrypt (300 orders per 3 hours, keeping some for new domains)
|
||||
|
||||
if(\count($certificates) > 0) {
|
||||
Console::info("[{$time}] Found " . \count($certificates) . " certificates for renewal, scheduling jobs.");
|
||||
|
||||
foreach ($certificates as $certificate) {
|
||||
Resque::enqueue(Event::CERTIFICATES_QUEUE_NAME, Event::CERTIFICATES_CLASS_NAME, [
|
||||
'domain' => $certificate->getAttribute('domain'),
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
Console::info("[{$time}] No certificates for renewal.");
|
||||
}
|
||||
}
|
||||
|
||||
// # of days in seconds (1 day = 86400s)
|
||||
$interval = (int) App::getEnv('_APP_MAINTENANCE_INTERVAL', '86400');
|
||||
$executionLogsRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', '1209600');
|
||||
|
@ -62,13 +117,17 @@ $cli
|
|||
$usageStatsRetention30m = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_30M', '129600');//36 hours
|
||||
$usageStatsRetention1d = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_1D', '8640000'); // 100 days
|
||||
|
||||
Console::loop(function() use ($interval, $executionLogsRetention, $abuseLogsRetention, $auditLogRetention, $usageStatsRetention30m, $usageStatsRetention1d) {
|
||||
Console::loop(function() use ($interval, $executionLogsRetention, $abuseLogsRetention, $auditLogRetention, $usageStatsRetention30m, $usageStatsRetention1d) {
|
||||
$database = getConsoleDB();
|
||||
|
||||
$time = date('d-m-Y H:i:s', time());
|
||||
Console::info("[{$time}] Notifying deletes workers every {$interval} seconds");
|
||||
Console::info("[{$time}] Notifying workers with maintenance tasks every {$interval} seconds");
|
||||
notifyDeleteExecutionLogs($executionLogsRetention);
|
||||
notifyDeleteAbuseLogs($abuseLogsRetention);
|
||||
notifyDeleteAuditLogs($auditLogRetention);
|
||||
notifyDeleteUsageStats($usageStatsRetention30m, $usageStatsRetention1d);
|
||||
notifyDeleteConnections();
|
||||
|
||||
renewCertificates($database);
|
||||
}, $interval);
|
||||
});
|
|
@ -2,22 +2,21 @@
|
|||
|
||||
global $cli;
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Validator\Hostname;
|
||||
|
||||
$cli
|
||||
->task('ssl')
|
||||
->desc('Validate server certificates')
|
||||
->action(function () {
|
||||
$domain = App::getEnv('_APP_DOMAIN', '');
|
||||
->param('domain', App::getEnv('_APP_DOMAIN', ''), new Hostname(), 'Domain to generate certificate for. If empty, main domain will be used.', true)
|
||||
->action(function ($domain) {
|
||||
Console::success('Scheduling a job to issue a TLS certificate for domain: ' . $domain);
|
||||
|
||||
Console::log('Issue a TLS certificate for master domain ('.$domain.') in 30 seconds.
|
||||
Make sure your domain points to your server or restart to try again.');
|
||||
|
||||
ResqueScheduler::enqueueAt(\time() + 30, 'v1-certificates', 'CertificatesV1', [
|
||||
'document' => [],
|
||||
// Scheduje a job
|
||||
Resque::enqueue(Event::CERTIFICATES_QUEUE_NAME, Event::CERTIFICATES_CLASS_NAME, [
|
||||
'domain' => $domain,
|
||||
'validateTarget' => false,
|
||||
'validateCNAME' => false,
|
||||
'skipCheck' => true
|
||||
]);
|
||||
});
|
|
@ -299,8 +299,9 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
<label for="name">Name <span class="tooltip large" data-tooltip="Choose any name that will help you distinguish between your different apps."><i class="icon-question"></i></span></label>
|
||||
<input type="text" class="full-width" name="name" required autocomplete="off" placeholder="My Web App" maxlength="128" />
|
||||
|
||||
<label for="hostname">Hostname <span class="tooltip large" data-tooltip="The hostname that your website will use to interact with the <?php echo APP_NAME; ?> APIs in production or development environments. No port number required."><i class="icon-question"></i></span></label>
|
||||
<input name="hostname" type="text" class="margin-bottom" autocomplete="off" placeholder="localhost" required>
|
||||
<label for="hostname">Hostname <span class="tooltip large" data-tooltip="The hostname that your website will use to interact with the <?php echo APP_NAME; ?> APIs in production or development environments. No protocol or port number required."><i class="icon-question"></i></span></label>
|
||||
<input name="hostname" type="text" class="margin-bottom" autocomplete="off" placeholder="yourapp.com" required>
|
||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">You can use * to allow wildcard hostnames or subdomains.</div>
|
||||
|
||||
<div class="info margin-top margin-bottom">
|
||||
<div class="text-bold margin-bottom-small">Next Steps</div>
|
||||
|
@ -329,7 +330,8 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
data-success="alert,trigger"
|
||||
data-success-param-alert-text="Updated platform successfully"
|
||||
data-success-param-trigger-events="projects.updatePlatform"
|
||||
data-failure="alert"
|
||||
data-failure="alert,trigger"
|
||||
data-failure-param-trigger-events="projects.updatePlatform"
|
||||
data-failure-param-alert-text="Failed to update platform"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
|
@ -340,7 +342,8 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
<input type="text" class="full-width" data-ls-attrs="id=name-{{platform.$id}}" name="name" required autocomplete="off" data-ls-bind="{{platform.name}}" placeholder="My Web App" maxlength="128" />
|
||||
|
||||
<label for="hostname">Hostname <span class="tooltip large" data-tooltip="The hostname that your website will use to interact with the <?php echo APP_NAME; ?> APIs in production or development environments. No port number required."><i class="icon-question"></i></span></label>
|
||||
<input name="hostname" type="text" class="margin-bottom" autocomplete="off" placeholder="localhost" data-ls-bind="{{platform.hostname}}" required />
|
||||
<input name="hostname" type="text" class="margin-bottom" autocomplete="off" placeholder="yourapp.com" data-ls-bind="{{platform.hostname}}" required />
|
||||
<div class="text-fade text-size-xs margin-top-negative-small margin-bottom">You can use * to allow wildcard hostnames or subdomains.</div>
|
||||
|
||||
<hr />
|
||||
|
||||
|
@ -714,7 +717,8 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
data-success="alert,trigger"
|
||||
data-success-param-alert-text="Updated platform successfully"
|
||||
data-success-param-trigger-events="projects.updatePlatform"
|
||||
data-failure="alert"
|
||||
data-failure="alert,trigger"
|
||||
data-failure-param-trigger-events="projects.updatePlatform"
|
||||
data-failure-param-alert-text="Failed to update platform"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
|
@ -746,7 +750,8 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
data-success="alert,trigger"
|
||||
data-success-param-alert-text="Updated platform successfully"
|
||||
data-success-param-trigger-events="projects.updatePlatform"
|
||||
data-failure="alert"
|
||||
data-failure="alert,trigger"
|
||||
data-failure-param-trigger-events="projects.updatePlatform"
|
||||
data-failure-param-alert-text="Failed to update platform"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
|
@ -777,7 +782,8 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
data-success="alert,trigger"
|
||||
data-success-param-alert-text="Updated platform successfully"
|
||||
data-success-param-trigger-events="projects.updatePlatform"
|
||||
data-failure="alert"
|
||||
data-failure="alert,trigger"
|
||||
data-failure-param-trigger-events="projects.updatePlatform"
|
||||
data-failure-param-alert-text="Failed to update platform"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
|
@ -808,7 +814,8 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
data-success="alert,trigger"
|
||||
data-success-param-alert-text="Updated platform successfully"
|
||||
data-success-param-trigger-events="projects.updatePlatform"
|
||||
data-failure="alert"
|
||||
data-failure="alert,trigger"
|
||||
data-failure-param-trigger-events="projects.updatePlatform"
|
||||
data-failure-param-alert-text="Failed to update platform"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
|
@ -841,7 +848,8 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
data-success="alert,trigger"
|
||||
data-success-param-alert-text="Updated platform successfully"
|
||||
data-success-param-trigger-events="projects.updatePlatform"
|
||||
data-failure="alert"
|
||||
data-failure="alert,trigger"
|
||||
data-failure-param-trigger-events="projects.updatePlatform"
|
||||
data-failure-param-alert-text="Failed to update platform"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
|
@ -873,7 +881,8 @@ $usageStatsEnabled = $this->getParam('usageStatsEnabled', true);
|
|||
data-success="alert,trigger"
|
||||
data-success-param-alert-text="Updated platform successfully"
|
||||
data-success-param-trigger-events="projects.updatePlatform"
|
||||
data-failure="alert"
|
||||
data-failure="alert,trigger"
|
||||
data-failure-param-trigger-events="projects.updatePlatform"
|
||||
data-failure-param-alert-text="Failed to update platform"
|
||||
data-failure-param-alert-classname="error">
|
||||
|
||||
|
|
|
@ -342,6 +342,7 @@ services:
|
|||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- _APP_REDIS_HOST
|
||||
|
@ -473,6 +474,8 @@ services:
|
|||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Network\Validator\CNAME;
|
||||
use Appwrite\Resque\Worker;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
@ -16,182 +18,393 @@ Console::success(APP_NAME . ' certificates worker v1 has started');
|
|||
|
||||
class CertificatesV1 extends Worker
|
||||
{
|
||||
|
||||
/**
|
||||
* Database connection shared across all methods of this file
|
||||
*
|
||||
* @var Database
|
||||
*/
|
||||
private Database $dbForConsole;
|
||||
|
||||
public function getName(): string {
|
||||
return "certificates";
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$dbForConsole = $this->getConsoleDB();
|
||||
|
||||
/**
|
||||
* 1. Get new domain document - DONE
|
||||
* 1.1. Validate domain is valid, public suffix is known and CNAME records are verified - DONE
|
||||
* 2. Check if a certificate already exists - DONE
|
||||
* 3. Check if certificate is about to expire, if not - skip it
|
||||
* 3.1. Create / renew certificate
|
||||
* 3.2. Update loadblancer
|
||||
* 3.3. Update database (domains, change date, expiry)
|
||||
* 3.4. Set retry on failure
|
||||
* 3.5. Schedule to renew certificate in 60 days
|
||||
*/
|
||||
|
||||
Authorization::disable();
|
||||
|
||||
// Args
|
||||
$document = $this->args['document'];
|
||||
$domain = $this->args['domain'];
|
||||
$this->dbForConsole = $this->getConsoleDB();
|
||||
|
||||
// Validation Args
|
||||
$validateTarget = $this->args['validateTarget'] ?? true;
|
||||
$validateCNAME = $this->args['validateCNAME'] ?? true;
|
||||
/**
|
||||
* 1. Read arguments and validate domain
|
||||
* 2. Get main domain
|
||||
* 3. Validate CNAME DNS if parameter is not main domain (meaning it's custom domain)
|
||||
* 4. Validate security email. Cannot be empty, required by LetsEncrypt
|
||||
* 5. Validate renew date with certificate file, unless requested to skip by parameter
|
||||
* 6. Issue a certificate using certbot CLI
|
||||
* 7. Update 'log' attribute on certificate document with Certbot message
|
||||
* 8. Create storage folder for certificate, if not ready already
|
||||
* 9. Move certificates from Certbot location to our Storage
|
||||
* 10. Create/Update our Storage with new Traefik config with new certificate paths
|
||||
* 11. Read certificate file and update 'renewDate' on certificate document
|
||||
* 12. Update 'issueDate' and 'attempts' on certificate
|
||||
*
|
||||
* If at any point unexpected error occurs, program stops without applying changes to document, and error is thrown into worker
|
||||
*
|
||||
* If code stops with expected error:
|
||||
* 1. 'log' attribute on document is updated with error message
|
||||
* 2. 'attempts' amount is increased
|
||||
* 3. Console log is shown
|
||||
* 4. Email is sent to security email
|
||||
*
|
||||
* Unless unexpected error occurs, at the end, we:
|
||||
* 1. Update 'updated' attribute on document
|
||||
* 2. Save document to database
|
||||
* 3. Update all domains documents with current certificate ID
|
||||
*
|
||||
* Note: Renewals are checked and scheduled from maintenence worker
|
||||
*/
|
||||
|
||||
// Options
|
||||
$domain = new Domain((!empty($domain)) ? $domain : '');
|
||||
$expiry = 60 * 60 * 24 * 30 * 2; // 60 days
|
||||
$safety = 60 * 60; // 1 hour
|
||||
$renew = (\time() + $expiry);
|
||||
try {
|
||||
// Read arguments
|
||||
$domain = $this->args['domain']; // String of domain (hostname)
|
||||
$skipCheck = $this->args['skipCheck'] ?? false; // If true, we won't double-check expiry from cert file
|
||||
|
||||
if (empty($domain->get())) {
|
||||
throw new Exception('Missing domain');
|
||||
}
|
||||
$domain = new Domain((!empty($domain)) ? $domain : '');
|
||||
|
||||
if (!$domain->isKnown() || $domain->isTest()) {
|
||||
throw new Exception('Unknown public suffix for domain');
|
||||
}
|
||||
|
||||
if ($validateTarget) {
|
||||
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
|
||||
|
||||
if(!$target->isKnown() || $target->isTest()) {
|
||||
throw new Exception('Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($validateCNAME) {
|
||||
$validator = new CNAME($target->get()); // Verify Domain with DNS records
|
||||
|
||||
if(!$validator->isValid($domain->get())) {
|
||||
throw new Exception('Failed to verify domain DNS records');
|
||||
}
|
||||
}
|
||||
|
||||
$certificate = $dbForConsole->findOne('certificates', [
|
||||
new Query('domain', QUERY::TYPE_EQUAL, [$domain->get()])
|
||||
]);
|
||||
|
||||
// $condition = ($certificate
|
||||
// && $certificate instanceof Document
|
||||
// && isset($certificate['issueDate'])
|
||||
// && (($certificate['issueDate'] + ($expiry)) > time())) ? 'true' : 'false';
|
||||
|
||||
// throw new Exception('cert issued at'.date('d.m.Y H:i', $certificate['issueDate']).' | renew date is: '.date('d.m.Y H:i', ($certificate['issueDate'] + ($expiry))).' | condition is '.$condition);
|
||||
|
||||
$certificate = (!empty($certificate) && $certificate instanceof $certificate) ? $certificate->getArrayCopy() : [];
|
||||
|
||||
if (
|
||||
!empty($certificate)
|
||||
&& isset($certificate['issueDate'])
|
||||
&& (($certificate['issueDate'] + ($expiry)) > \time())
|
||||
) { // Check last issue time
|
||||
throw new Exception('Renew isn\'t required');
|
||||
}
|
||||
|
||||
$staging = (App::isProduction()) ? '' : ' --dry-run';
|
||||
$email = App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS');
|
||||
|
||||
if (empty($email)) {
|
||||
throw new Exception('You must set a valid security email address (_APP_SYSTEM_SECURITY_EMAIL_ADDRESS) to issue an SSL certificate');
|
||||
}
|
||||
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$exit = Console::execute("certbot certonly --webroot --noninteractive --agree-tos{$staging}"
|
||||
. " --email " . $email
|
||||
. " -w " . APP_STORAGE_CERTIFICATES
|
||||
. " -d {$domain->get()}", '', $stdout, $stderr);
|
||||
|
||||
if ($exit !== 0) {
|
||||
throw new Exception('Failed to issue a certificate with message: ' . $stderr);
|
||||
}
|
||||
|
||||
$path = APP_STORAGE_CERTIFICATES . '/' . $domain->get();
|
||||
|
||||
if (!\is_readable($path)) {
|
||||
if (!\mkdir($path, 0755, true)) {
|
||||
throw new Exception('Failed to create path...');
|
||||
}
|
||||
}
|
||||
|
||||
if(!@\rename('/etc/letsencrypt/live/'.$domain->get().'/cert.pem', APP_STORAGE_CERTIFICATES.'/'.$domain->get().'/cert.pem')) {
|
||||
throw new Exception('Failed to rename certificate cert.pem: '.\json_encode($stdout));
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $domain->get() . '/chain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain->get() . '/chain.pem')) {
|
||||
throw new Exception('Failed to rename certificate chain.pem: ' . \json_encode($stdout));
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $domain->get() . '/fullchain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain->get() . '/fullchain.pem')) {
|
||||
throw new Exception('Failed to rename certificate fullchain.pem: ' . \json_encode($stdout));
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $domain->get() . '/privkey.pem', APP_STORAGE_CERTIFICATES . '/' . $domain->get() . '/privkey.pem')) {
|
||||
throw new Exception('Failed to rename certificate privkey.pem: ' . \json_encode($stdout));
|
||||
}
|
||||
|
||||
$certificate = new Document(\array_merge($certificate, [
|
||||
'domain' => $domain->get(),
|
||||
'issueDate' => \time(),
|
||||
'renewDate' => $renew,
|
||||
'attempts' => 0,
|
||||
'log' => \json_encode($stdout),
|
||||
]));
|
||||
|
||||
$certificate = $dbForConsole->createDocument('certificates', $certificate);
|
||||
|
||||
if (!$certificate) {
|
||||
throw new Exception('Failed saving certificate to DB');
|
||||
}
|
||||
|
||||
if(!empty($document)) {
|
||||
$certificate = new Document(\array_merge($document, [
|
||||
'updated' => \time(),
|
||||
'certificateId' => $certificate->getId(),
|
||||
]));
|
||||
|
||||
$certificate = $dbForConsole->updateDocument('domains', $certificate->getId(), $certificate);
|
||||
// Get current certificate
|
||||
$certificate = $this->dbForConsole->findOne('certificates', [ new Query('domain', Query::TYPE_EQUAL, [$domain->get()]) ]);
|
||||
|
||||
// If we don't have certificate for domain yet, let's create new document. At the end we save it
|
||||
if(!$certificate) {
|
||||
throw new Exception('Failed saving domain to DB');
|
||||
$certificate = new Document();
|
||||
$certificate->setAttribute('domain', $domain->get());
|
||||
}
|
||||
|
||||
// Email for alerts is required by LetsEncrypt
|
||||
$email = App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS');
|
||||
if (empty($email)) {
|
||||
throw new Exception('You must set a valid security email address (_APP_SYSTEM_SECURITY_EMAIL_ADDRESS) to issue an SSL certificate.');
|
||||
}
|
||||
|
||||
// Validate domain and DNS records. Skip if job is forced
|
||||
if(!$skipCheck) {
|
||||
$mainDomain = $this->getMainDomain();
|
||||
$isMainDomain = !isset($mainDomain) || $domain->get() === $mainDomain;
|
||||
$this->validateDomain($domain, $isMainDomain);
|
||||
}
|
||||
|
||||
// If certificate exists already, double-check expiry date. Skip if job is forced
|
||||
if(!$skipCheck && !$this->isRenewRequired($domain->get())) {
|
||||
throw new Exception('Renew isn\'t required.');
|
||||
}
|
||||
|
||||
// Generate certificate files using Let's Encrypt
|
||||
$letsEncryptData = $this->issueCertificate($domain->get(), $email);
|
||||
|
||||
// Command succeeded, store all data into document
|
||||
// We store stderr too, because it may include warnings
|
||||
$certificate->setAttribute('log', \json_encode([
|
||||
'stdout' => $letsEncryptData['stdout'],
|
||||
'stderr' => $letsEncryptData['stderr'],
|
||||
]));
|
||||
|
||||
// Give certificates to Traefik
|
||||
$this->applyCertificateFiles($domain->get(), $letsEncryptData);
|
||||
|
||||
// Update certificate info stored in database
|
||||
$certificate->setAttribute('renewDate', $this->getRenewDate($domain->get()));
|
||||
$certificate->setAttribute('attempts', 0);
|
||||
$certificate->setAttribute('issueDate', \time());
|
||||
} catch(Throwable $e) {
|
||||
// Set exception as log in certificate document
|
||||
$certificate->setAttribute('log', $e->getMessage());
|
||||
|
||||
// Increase attempts count
|
||||
$attempts = $certificate->getAttribute('attempts', 0) + 1;
|
||||
$certificate->setAttribute('attempts', $attempts);
|
||||
|
||||
// Send email to security email
|
||||
$this->notifyError($domain->get(), $e->getMessage(), $attempts);
|
||||
} finally {
|
||||
// All actions result in new updatedAt date
|
||||
$certificate->setAttribute('updated', \time());
|
||||
|
||||
// Save all changes we made to certificate document into database
|
||||
$this->saveCertificateDocument($domain->get(), $certificate);
|
||||
|
||||
Authorization::reset();
|
||||
}
|
||||
|
||||
$config =
|
||||
"tls:
|
||||
certificates:
|
||||
- certFile: /storage/certificates/{$domain->get()}/fullchain.pem
|
||||
keyFile: /storage/certificates/{$domain->get()}/privkey.pem";
|
||||
|
||||
if (!\file_put_contents(APP_STORAGE_CONFIG . '/' . $domain->get() . '.yml', $config)) {
|
||||
throw new Exception('Failed to save SSL configuration');
|
||||
}
|
||||
|
||||
ResqueScheduler::enqueueAt($renew + $safety, 'v1-certificates', 'CertificatesV1', [
|
||||
'document' => [],
|
||||
'domain' => $domain->get(),
|
||||
'validateTarget' => $validateTarget,
|
||||
'validateCNAME' => $validateCNAME,
|
||||
]); // Async task rescheduale
|
||||
|
||||
Authorization::reset();
|
||||
}
|
||||
|
||||
public function shutdown(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Save certificate data into database.
|
||||
*
|
||||
* @param string $domain Domain name that certificate is for
|
||||
* @param Document $certificate Certificate document that we need to save
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function saveCertificateDocument(string $domain, Document $certificate): void {
|
||||
// Check if update or insert required
|
||||
$certificateDocument = $this->dbForConsole->findOne('certificates', [ new Query('domain', Query::TYPE_EQUAL, [$domain]) ]);
|
||||
if (!empty($certificateDocument) && !$certificateDocument->isEmpty()) {
|
||||
// Merge new data with current data
|
||||
$certificate = new Document(\array_merge($certificateDocument->getArrayCopy(), $certificate->getArrayCopy()));
|
||||
|
||||
$certificate = $this->dbForConsole->updateDocument('certificates', $certificate->getId(), $certificate);
|
||||
} else {
|
||||
$certificate = $this->dbForConsole->createDocument('certificates', $certificate);
|
||||
}
|
||||
|
||||
$certificateId = $certificate->getId();
|
||||
$this->updateDomainDocuments($certificateId, $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get main domain. Needed as we do different checks for main and non-main domains.
|
||||
*
|
||||
* @return null|string Returns main domain. If null, there is no main domain yet.
|
||||
*/
|
||||
private function getMainDomain(): ?string {
|
||||
if (!empty(App::getEnv('_APP_DOMAIN', ''))) {
|
||||
return App::getEnv('_APP_DOMAIN', '');
|
||||
} else {
|
||||
$domainDocument = $this->dbForConsole->findOne('domains', [], 0, ['_id'], ['ASC']);
|
||||
if($domainDocument) {
|
||||
return $domainDocument->getAttribute('domain');
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal domain validation functionality to prevent unnecessary attempts failed from Let's Encrypt side. We check:
|
||||
* - Domain needs to be public and valid (prevents NFT domains that are not supported by Let's Encrypt)
|
||||
* - Domain must have proper DNS record
|
||||
*
|
||||
* @param Domain $domain Domain which we validate
|
||||
* @param bool $isMainDomain In case of master domain, we look for different DNS configurations
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function validateDomain(Domain $domain, bool $isMainDomain): void {
|
||||
if (empty($domain->get())) {
|
||||
throw new Exception('Missing certificate domain.');
|
||||
}
|
||||
|
||||
if (!$domain->isKnown() || $domain->isTest()) {
|
||||
throw new Exception('Unknown public suffix for domain.');
|
||||
}
|
||||
|
||||
if (!$isMainDomain) {
|
||||
// TODO: Would be awesome to also support A/AAAA records here. Maybe dry run?
|
||||
|
||||
// Validate if domain target is properly configured
|
||||
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
|
||||
|
||||
if (!$target->isKnown() || $target->isTest()) {
|
||||
throw new Exception('Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.');
|
||||
}
|
||||
|
||||
// Verify domain with DNS records
|
||||
$validator = new CNAME($target->get());
|
||||
if (!$validator->isValid($domain->get())) {
|
||||
throw new Exception('Failed to verify domain DNS records.');
|
||||
}
|
||||
} else {
|
||||
// Main domain validation
|
||||
// TODO: Would be awesome to check A/AAAA record here. Maybe dry run?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads expiry date of certificate from file and decides if renewal is required or not.
|
||||
*
|
||||
* @param string $domain Domain for which we check certificate file
|
||||
*
|
||||
* @return bool True, if certificate needs to be renewed
|
||||
*/
|
||||
private function isRenewRequired(string $domain): bool {
|
||||
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
|
||||
if (\file_exists($certPath)) {
|
||||
$validTo = null;
|
||||
|
||||
$certData = openssl_x509_parse(file_get_contents($certPath));
|
||||
$validTo = $certData['validTo_time_t'] ?? 0;
|
||||
|
||||
if (empty($validTo)) {
|
||||
throw new Exception('Unable to read certificate file (cert.pem).');
|
||||
}
|
||||
|
||||
// LetsEncrypt allows renewal 30 days before expiry
|
||||
$expiryInAdvance = (60*60*24*30);
|
||||
if ($validTo - $expiryInAdvance > \time()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* LetsEncrypt communication to issue certificate (using certbot CLI)
|
||||
*
|
||||
* @param string $domain Domain to generate certificate for
|
||||
*
|
||||
* @return array Named array with keys 'stdout' and 'stderr', both string
|
||||
*/
|
||||
private function issueCertificate(string $domain, string $email): array {
|
||||
$staging = (App::isProduction()) ? '' : ' --dry-run';
|
||||
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
$staging = (App::isProduction()) ? '' : ' --dry-run';
|
||||
$exit = Console::execute("certbot certonly --webroot --noninteractive --agree-tos{$staging}"
|
||||
. " --email " . $email
|
||||
. " -w " . APP_STORAGE_CERTIFICATES
|
||||
. " -d {$domain}", '', $stdout, $stderr);
|
||||
|
||||
// Unexpected error, usually 5XX, API limits, ...
|
||||
if ($exit !== 0) {
|
||||
throw new Exception('Failed to issue a certificate with message: ' . $stderr);
|
||||
}
|
||||
|
||||
return [
|
||||
'stdout' => $stdout,
|
||||
'stderr' => $stderr
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read new renew date from certificate file generated by Let's Encrypt
|
||||
*
|
||||
* @param string $domain Domain which certificate was generated for
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getRenewDate(string $domain): int {
|
||||
$certPath = APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem';
|
||||
$certData = openssl_x509_parse(file_get_contents($certPath));
|
||||
$validTo = $certData['validTo_time_t'] ?? 0;
|
||||
$expiryInAdvance = (60*60*24*30); // 30 days
|
||||
return $validTo - $expiryInAdvance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to take files from Let's Encrypt, and put it into Traefik.
|
||||
*
|
||||
* @param string $domain Domain which certificate was generated for
|
||||
* @param array $letsEncryptData Let's Encrypt logs to use for additional info when throwing error
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function applyCertificateFiles(string $domain, array $letsEncryptData): void {
|
||||
// Prepare folder in storage for domain
|
||||
$path = APP_STORAGE_CERTIFICATES . '/' . $domain;
|
||||
if (!\is_readable($path)) {
|
||||
if (!\mkdir($path, 0755, true)) {
|
||||
throw new Exception('Failed to create path for certificate.');
|
||||
}
|
||||
}
|
||||
|
||||
// Move generated files from certbot into our storage
|
||||
if(!@\rename('/etc/letsencrypt/live/'.$domain.'/cert.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/cert.pem')) {
|
||||
throw new Exception('Failed to rename certificate cert.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $domain . '/chain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/chain.pem')) {
|
||||
throw new Exception('Failed to rename certificate chain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $domain . '/fullchain.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/fullchain.pem')) {
|
||||
throw new Exception('Failed to rename certificate fullchain.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
if (!@\rename('/etc/letsencrypt/live/' . $domain . '/privkey.pem', APP_STORAGE_CERTIFICATES . '/' . $domain . '/privkey.pem')) {
|
||||
throw new Exception('Failed to rename certificate privkey.pem. Let\'s Encrypt log: ' . $letsEncryptData['stderr'] . ' ; ' . $letsEncryptData['stdout']);
|
||||
}
|
||||
|
||||
$config = \implode(PHP_EOL, [
|
||||
"tls:",
|
||||
" certificates:",
|
||||
" - certFile: /storage/certificates/{$domain}/fullchain.pem",
|
||||
" keyFile: /storage/certificates/{$domain}/privkey.pem"
|
||||
]);
|
||||
|
||||
// Save configuration into Traefik using our new cert files
|
||||
if (!\file_put_contents(APP_STORAGE_CONFIG . '/' . $domain . '.yml', $config)) {
|
||||
throw new Exception('Failed to save Traefik configuration.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to make sure information about error is delivered to admnistrator.
|
||||
*
|
||||
* @param string $domain Domain that caused the error
|
||||
* @param string $errorMessage Verbose error message
|
||||
* @param int $attempt How many times it failed already
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function notifyError(string $domain, string $errorMessage, int $attempt): void {
|
||||
// Log error into console
|
||||
Console::warning('Cannot renew domain (' . $domain . ') on attempt no. ' . $attempt . ' certificate: ' . $errorMessage);
|
||||
|
||||
// Send mail to administratore mail
|
||||
Resque::enqueue(Event::MAILS_QUEUE_NAME, Event::MAILS_CLASS_NAME, [
|
||||
'from' => 'console',
|
||||
'project' => 'console',
|
||||
'name' => 'Appwrite Administrator',
|
||||
'recipient' => App::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS'),
|
||||
'url' => 'https://' . $domain,
|
||||
'locale' => App::getEnv('_APP_LOCALE', 'en'),
|
||||
'type' => MAIL_TYPE_CERTIFICATE,
|
||||
|
||||
'domain' => $domain,
|
||||
'error' => $errorMessage,
|
||||
'attempt' => $attempt
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all existing domain documents so they have relation to correct certificate document.
|
||||
* This solved issues:
|
||||
* - when adding a domain for which there is already a certificate
|
||||
* - when renew creates new document? It might?
|
||||
* - overall makes it more reliable
|
||||
*
|
||||
* @param string $certificateId ID of a new or updated certificate document
|
||||
* @param string $domain Domain that is affected by new certificate
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function updateDomainDocuments(string $certificateId, string $domain): void {
|
||||
$domains = $this->dbForConsole->find('domains', [
|
||||
new Query('domain', Query::TYPE_EQUAL, [$domain])
|
||||
], 1000);
|
||||
|
||||
foreach ($domains as $domainDocument) {
|
||||
$domainDocument->setAttribute('updated', \time());
|
||||
$domainDocument->setAttribute('certificateId', $certificateId);
|
||||
|
||||
$this->dbForConsole->updateDocument('domains', $domainDocument->getId(), $domainDocument);
|
||||
|
||||
if($domainDocument->getAttribute('projectId')) {
|
||||
$this->dbForConsole->deleteCachedDocument('projects', $domainDocument->getAttribute('projectId'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ class DeletesV1 extends Worker
|
|||
|
||||
public function run(): void
|
||||
{
|
||||
|
||||
$projectId = $this->args['projectId'] ?? '';
|
||||
$type = $this->args['type'] ?? '';
|
||||
|
||||
|
@ -208,13 +209,14 @@ class DeletesV1 extends Worker
|
|||
*/
|
||||
|
||||
$userId = $document->getId();
|
||||
$user = $this->getProjectDB($projectId)->getDocument('users', $userId);
|
||||
|
||||
// Delete all sessions of this user from the sessions table and update the sessions field of the user record
|
||||
$this->deleteByGroup('sessions', [
|
||||
new Query('userId', Query::TYPE_EQUAL, [$userId])
|
||||
], $this->getProjectDB($projectId));
|
||||
|
||||
|
||||
$this->getProjectDB($projectId)->deleteCachedDocument('users', $userId);
|
||||
|
||||
// Delete Memberships and decrement team membership counts
|
||||
$this->deleteByGroup('memberships', [
|
||||
new Query('userId', Query::TYPE_EQUAL, [$userId])
|
||||
|
@ -529,11 +531,40 @@ class DeletesV1 extends Worker
|
|||
*/
|
||||
protected function deleteCertificates(Document $document): void
|
||||
{
|
||||
$consoleDB = $this->getConsoleDB();
|
||||
|
||||
// If domain has certificate generated
|
||||
if(isset($document['certificateId'])) {
|
||||
$domainUsingCertificate = $consoleDB->findOne('domains', [
|
||||
new Query('certificateId', Query::TYPE_EQUAL, [$document['certificateId']])
|
||||
]);
|
||||
|
||||
if(!$domainUsingCertificate) {
|
||||
$mainDomain = App::getEnv('_APP_DOMAIN_TARGET', '');
|
||||
if($mainDomain === $document->getAttribute('domain')) {
|
||||
$domainUsingCertificate = $mainDomain;
|
||||
}
|
||||
}
|
||||
|
||||
// If certificate is still used by some domain, mark we can't delete.
|
||||
// Current domain should not be found, because we only have copy. Original domain is already deleted from database.
|
||||
if($domainUsingCertificate) {
|
||||
Console::warning("Skipping certificate deletion, because a domain is still using it.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$domain = $document->getAttribute('domain');
|
||||
$directory = APP_STORAGE_CERTIFICATES . '/' . $domain;
|
||||
$checkTraversal = realpath($directory) === $directory;
|
||||
|
||||
if ($domain && $checkTraversal && is_dir($directory)) {
|
||||
// Delete certificate document, so Appwrite is aware of change
|
||||
if(isset($document['certificateId'])) {
|
||||
$consoleDB->deleteDocument('certificates', $document['certificateId']);
|
||||
}
|
||||
|
||||
// Delete files, so Traefik is aware of change
|
||||
array_map('unlink', glob($directory . '/*.*'));
|
||||
rmdir($directory);
|
||||
Console::info("Deleted certificate files for {$domain}");
|
||||
|
|
|
@ -46,6 +46,16 @@ class MailsV1 extends Worker
|
|||
$body = Template::fromFile(__DIR__ . '/../config/locale/templates/email-base.tpl');
|
||||
$subject = '';
|
||||
switch ($type) {
|
||||
case MAIL_TYPE_CERTIFICATE:
|
||||
$domain = $this->args['domain'];
|
||||
$error = $this->args['error'];
|
||||
$attempt = $this->args['attempt'];
|
||||
|
||||
$subject = \sprintf($locale->getText("$prefix.subject"), $domain);
|
||||
$body->setParam('{{domain}}', $domain);
|
||||
$body->setParam('{{error}}', $error);
|
||||
$body->setParam('{{attempt}}', $attempt);
|
||||
break;
|
||||
case MAIL_TYPE_INVITATION:
|
||||
$subject = \sprintf($locale->getText("$prefix.subject"), $this->args['team'], $project);
|
||||
$body->setParam('{{owner}}', $this->args['owner']);
|
||||
|
@ -126,6 +136,8 @@ class MailsV1 extends Worker
|
|||
switch ($type) {
|
||||
case MAIL_TYPE_RECOVERY:
|
||||
return 'emails.recovery';
|
||||
case MAIL_TYPE_CERTIFICATE:
|
||||
return 'emails.certificate';
|
||||
case MAIL_TYPE_INVITATION:
|
||||
return 'emails.invitation';
|
||||
case MAIL_TYPE_VERIFICATION:
|
||||
|
|
52
composer.lock
generated
52
composer.lock
generated
|
@ -2299,25 +2299,25 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/image",
|
||||
"version": "0.5.3",
|
||||
"version": "0.5.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/image.git",
|
||||
"reference": "4a8429b62dcf56562b038d6712375f75166f0c02"
|
||||
"reference": "ca5f436f9aa22dedaa6648f24f3687733808e336"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/image/zipball/4a8429b62dcf56562b038d6712375f75166f0c02",
|
||||
"reference": "4a8429b62dcf56562b038d6712375f75166f0c02",
|
||||
"url": "https://api.github.com/repos/utopia-php/image/zipball/ca5f436f9aa22dedaa6648f24f3687733808e336",
|
||||
"reference": "ca5f436f9aa22dedaa6648f24f3687733808e336",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-imagick": "*",
|
||||
"php": ">=7.4"
|
||||
"php": ">=8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"vimeo/psalm": "4.0.1"
|
||||
"vimeo/psalm": "4.13.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -2345,9 +2345,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/image/issues",
|
||||
"source": "https://github.com/utopia-php/image/tree/0.5.3"
|
||||
"source": "https://github.com/utopia-php/image/tree/0.5.4"
|
||||
},
|
||||
"time": "2021-11-02T05:47:16+00:00"
|
||||
"time": "2022-05-11T12:30:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/locale",
|
||||
|
@ -3551,16 +3551,16 @@
|
|||
},
|
||||
{
|
||||
"name": "matthiasmullie/minify",
|
||||
"version": "1.3.67",
|
||||
"version": "1.3.68",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/matthiasmullie/minify.git",
|
||||
"reference": "acaee1b7ca3cd67a39d7f98673cacd7e4739a8d9"
|
||||
"reference": "c00fb02f71b2ef0a5f53fe18c5a8b9aa30f48297"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/matthiasmullie/minify/zipball/acaee1b7ca3cd67a39d7f98673cacd7e4739a8d9",
|
||||
"reference": "acaee1b7ca3cd67a39d7f98673cacd7e4739a8d9",
|
||||
"url": "https://api.github.com/repos/matthiasmullie/minify/zipball/c00fb02f71b2ef0a5f53fe18c5a8b9aa30f48297",
|
||||
"reference": "c00fb02f71b2ef0a5f53fe18c5a8b9aa30f48297",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3609,7 +3609,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/matthiasmullie/minify/issues",
|
||||
"source": "https://github.com/matthiasmullie/minify/tree/1.3.67"
|
||||
"source": "https://github.com/matthiasmullie/minify/tree/1.3.68"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3617,7 +3617,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-03-24T08:54:59+00:00"
|
||||
"time": "2022-04-19T08:28:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "matthiasmullie/path-converter",
|
||||
|
@ -5711,16 +5711,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v6.0.7",
|
||||
"version": "v6.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "70dcf7b2ca2ea08ad6ebcc475f104a024fb5632e"
|
||||
"reference": "0d00aa289215353aa8746a31d101f8e60826285c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/70dcf7b2ca2ea08ad6ebcc475f104a024fb5632e",
|
||||
"reference": "70dcf7b2ca2ea08ad6ebcc475f104a024fb5632e",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/0d00aa289215353aa8746a31d101f8e60826285c",
|
||||
"reference": "0d00aa289215353aa8746a31d101f8e60826285c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -5786,7 +5786,7 @@
|
|||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v6.0.7"
|
||||
"source": "https://github.com/symfony/console/tree/v6.0.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -5802,7 +5802,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-03-31T17:18:25+00:00"
|
||||
"time": "2022-04-20T15:01:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
|
@ -6136,16 +6136,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v6.0.3",
|
||||
"version": "v6.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "522144f0c4c004c80d56fa47e40e17028e2eefc2"
|
||||
"reference": "ac0aa5c2282e0de624c175b68d13f2c8f2e2649d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/522144f0c4c004c80d56fa47e40e17028e2eefc2",
|
||||
"reference": "522144f0c4c004c80d56fa47e40e17028e2eefc2",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/ac0aa5c2282e0de624c175b68d13f2c8f2e2649d",
|
||||
"reference": "ac0aa5c2282e0de624c175b68d13f2c8f2e2649d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -6201,7 +6201,7 @@
|
|||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v6.0.3"
|
||||
"source": "https://github.com/symfony/string/tree/v6.0.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -6217,7 +6217,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-01-02T09:55:41+00:00"
|
||||
"time": "2022-04-22T08:18:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "textalk/websocket",
|
||||
|
|
|
@ -389,6 +389,7 @@ services:
|
|||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- _APP_REDIS_HOST
|
||||
|
@ -543,6 +544,11 @@ services:
|
|||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_MAINTENANCE_INTERVAL
|
||||
- _APP_MAINTENANCE_RETENTION_EXECUTION
|
||||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 4.1 KiB |
|
@ -7,27 +7,27 @@ abstract class OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $appID;
|
||||
protected string $appID;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $appSecret;
|
||||
protected string $appSecret;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $callback;
|
||||
protected string $callback;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $state;
|
||||
protected array $state;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes;
|
||||
protected array $scopes;
|
||||
|
||||
/**
|
||||
* OAuth2 constructor.
|
||||
|
@ -52,66 +52,69 @@ abstract class OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getName():string;
|
||||
abstract public function getName(): string;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getLoginURL():string;
|
||||
abstract public function getLoginURL(): string;
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getTokens(string $code):array;
|
||||
abstract protected function getTokens(string $code): array;
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function refreshTokens(string $refreshToken):array;
|
||||
abstract public function refreshTokens(string $refreshToken): array;
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getUserID(string $accessToken):string;
|
||||
abstract public function getUserEmail(string $accessToken): string;
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function isEmailVerified(string $accessToken): bool;
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getUserEmail(string $accessToken):string;
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getUserName(string $accessToken):string;
|
||||
abstract public function getUserName(string $accessToken): string;
|
||||
|
||||
/**
|
||||
* @param $scope
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function addScope(string $scope):OAuth2
|
||||
protected function addScope(string $scope): OAuth2
|
||||
{
|
||||
// Add a scope to the scopes array if it isn't already present
|
||||
if (!\in_array($scope, $this->scopes)) {
|
||||
$this->scopes[] = $scope;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getScopes():array
|
||||
protected function getScopes(): array
|
||||
{
|
||||
return $this->scopes;
|
||||
}
|
||||
|
@ -121,9 +124,10 @@ abstract class OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken(string $code):string
|
||||
public function getAccessToken(string $code): string
|
||||
{
|
||||
$tokens = $this->getTokens($code);
|
||||
|
||||
return $tokens['access_token'] ?? '';
|
||||
}
|
||||
|
||||
|
@ -132,9 +136,10 @@ abstract class OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRefreshToken(string $code):string
|
||||
public function getRefreshToken(string $code): string
|
||||
{
|
||||
$tokens = $this->getTokens($code);
|
||||
|
||||
return $tokens['refresh_token'] ?? '';
|
||||
}
|
||||
|
||||
|
@ -143,9 +148,10 @@ abstract class OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessTokenExpiry(string $code):string
|
||||
public function getAccessTokenExpiry(string $code): string
|
||||
{
|
||||
$tokens = $this->getTokens($code);
|
||||
|
||||
return $tokens['expires_in'] ?? '';
|
||||
}
|
||||
|
||||
|
@ -170,7 +176,7 @@ abstract class OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function request(string $method, string $url = '', array $headers = [], string $payload = ''):string
|
||||
protected function request(string $method, string $url = '', array $headers = [], string $payload = ''): string
|
||||
{
|
||||
$ch = \curl_init($url);
|
||||
|
||||
|
|
|
@ -14,17 +14,17 @@ class Amazon extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
"profile"
|
||||
];
|
||||
|
||||
|
@ -37,7 +37,7 @@ class Amazon extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $state
|
||||
* @param string $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -52,13 +52,13 @@ class Amazon extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.amazon.com/ap/oa?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback
|
||||
]);
|
||||
return 'https://www.amazon.com/ap/oa?' . \http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'redirect_uri' => $this->callback
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,7 +68,7 @@ class Amazon extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded;charset=UTF-8'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -92,7 +92,7 @@ class Amazon extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded;charset=UTF-8'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
|
@ -107,7 +107,7 @@ class Amazon extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -123,11 +123,7 @@ class Amazon extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['user_id'])) {
|
||||
return $user['user_id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['user_id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,11 +135,23 @@ class Amazon extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
}
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
return '';
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Amazon sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,11 +163,7 @@ class Amazon extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,7 +174,7 @@ class Amazon extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://api.amazon.com/user/profile?access_token='.\urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://api.amazon.com/user/profile?access_token=' . \urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
return $this->user;
|
||||
|
|
|
@ -13,17 +13,17 @@ class Apple extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
"name",
|
||||
"email"
|
||||
];
|
||||
|
@ -31,7 +31,7 @@ class Apple extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $claims = [];
|
||||
protected array $claims = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
@ -40,13 +40,13 @@ class Apple extends OAuth2
|
|||
{
|
||||
return 'apple';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://appleid.apple.com/auth/authorize?'.\http_build_query([
|
||||
return 'https://appleid.apple.com/auth/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
|
@ -63,7 +63,7 @@ class Apple extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -90,7 +90,7 @@ class Apple extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
|
@ -105,7 +105,7 @@ class Apple extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -122,11 +122,7 @@ class Apple extends OAuth2
|
|||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
if (isset($this->claims['sub']) && !empty($this->claims['sub'])) {
|
||||
return $this->claims['sub'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $this->claims['sub'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,14 +132,25 @@ class Apple extends OAuth2
|
|||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
if (isset($this->claims['email']) &&
|
||||
!empty($this->claims['email']) &&
|
||||
isset($this->claims['email_verified']) &&
|
||||
$this->claims['email_verified'] === 'true') {
|
||||
return $this->claims['email'];
|
||||
return $this->claims['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://developer.apple.com/forums/thread/121411
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
if ($this->claims['email_verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,17 +160,19 @@ class Apple extends OAuth2
|
|||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
if (isset($this->claims['email']) &&
|
||||
if (
|
||||
isset($this->claims['email']) &&
|
||||
!empty($this->claims['email']) &&
|
||||
isset($this->claims['email_verified']) &&
|
||||
$this->claims['email_verified'] === 'true') {
|
||||
$this->claims['email_verified'] === 'true'
|
||||
) {
|
||||
return $this->claims['email'];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function getAppSecret():string
|
||||
protected function getAppSecret(): string
|
||||
{
|
||||
try {
|
||||
$secret = \json_decode($this->appSecret, true);
|
||||
|
@ -180,18 +189,18 @@ class Apple extends OAuth2
|
|||
'alg' => 'ES256',
|
||||
'kid' => $keyID,
|
||||
];
|
||||
|
||||
|
||||
$claims = [
|
||||
'iss' => $teamID,
|
||||
'iat' => \time(),
|
||||
'exp' => \time() + 86400*180,
|
||||
'exp' => \time() + 86400 * 180,
|
||||
'aud' => 'https://appleid.apple.com',
|
||||
'sub' => $bundleID,
|
||||
];
|
||||
|
||||
$pkey = \openssl_pkey_get_private($keyfile);
|
||||
|
||||
$payload = $this->encode(\json_encode($headers)).'.'.$this->encode(\json_encode($claims));
|
||||
$payload = $this->encode(\json_encode($headers)) . '.' . $this->encode(\json_encode($claims));
|
||||
|
||||
$signature = '';
|
||||
|
||||
|
@ -201,7 +210,7 @@ class Apple extends OAuth2
|
|||
return '';
|
||||
}
|
||||
|
||||
return $payload.'.'.$this->encode($this->fromDER($signature, 64));
|
||||
return $payload . '.' . $this->encode($this->fromDER($signature, 64));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -230,10 +239,10 @@ class Apple extends OAuth2
|
|||
* @param string $der
|
||||
* @param int $partLength
|
||||
*/
|
||||
protected function fromDER(string $der, int $partLength):string
|
||||
protected function fromDER(string $der, int $partLength): string
|
||||
{
|
||||
$hex = \unpack('H*', $der)[1];
|
||||
|
||||
|
||||
if ('30' !== \mb_substr($hex, 0, 2, '8bit')) { // SEQUENCE
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
|
@ -252,7 +261,7 @@ class Apple extends OAuth2
|
|||
$R = \str_pad($R, $partLength, '0', STR_PAD_LEFT);
|
||||
|
||||
$hex = \mb_substr($hex, 4 + $Rl * 2, null, '8bit');
|
||||
|
||||
|
||||
if ('02' !== \mb_substr($hex, 0, 2, '8bit')) { // INTEGER
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
|
@ -261,6 +270,6 @@ class Apple extends OAuth2
|
|||
$S = $this->retrievePositiveInteger(\mb_substr($hex, 4, $Sl * 2, '8bit'));
|
||||
$S = \str_pad($S, $partLength, '0', STR_PAD_LEFT);
|
||||
|
||||
return \pack('H*', $R.$S);
|
||||
return \pack('H*', $R . $S);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,27 +8,27 @@ use Appwrite\Auth\OAuth2;
|
|||
// https://auth0.com/docs/api/authentication
|
||||
|
||||
class Auth0 extends OAuth2
|
||||
{
|
||||
/**
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $scopes = [
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access'
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
@ -42,11 +42,11 @@ class Auth0 extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://'.$this->getAuth0Domain().'/authorize?'.\http_build_query([
|
||||
return 'https://' . $this->getAuth0Domain() . '/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state'=> \json_encode($this->state),
|
||||
'scope'=> \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'response_type' => 'code'
|
||||
]);
|
||||
}
|
||||
|
@ -58,11 +58,11 @@ class Auth0 extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://'.$this->getAuth0Domain().'/oauth/token',
|
||||
'https://' . $this->getAuth0Domain() . '/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
|
@ -77,8 +77,8 @@ class Auth0 extends OAuth2
|
|||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
|
@ -89,7 +89,7 @@ class Auth0 extends OAuth2
|
|||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://'.$this->getAuth0Domain().'/oauth/token',
|
||||
'https://' . $this->getAuth0Domain() . '/oauth/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
|
@ -99,7 +99,7 @@ class Auth0 extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -114,12 +114,8 @@ class Auth0 extends OAuth2
|
|||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['sub'])) {
|
||||
return $user['sub'];
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
return $user['sub'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,12 +126,28 @@ class Auth0 extends OAuth2
|
|||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://auth0.com/docs/api/authentication?javascript#user-profile
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['email_verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,15 +158,11 @@ class Auth0 extends OAuth2
|
|||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return array
|
||||
|
@ -162,8 +170,8 @@ class Auth0 extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer '. \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://'.$this->getAuth0Domain().'/userinfo', $headers);
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://' . $this->getAuth0Domain() . '/userinfo', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
|
@ -179,10 +187,10 @@ class Auth0 extends OAuth2
|
|||
{
|
||||
$secret = $this->getAppSecret();
|
||||
|
||||
return (isset($secret['clientSecret'])) ? $secret['clientSecret'] : '';
|
||||
return $secret['clientSecret'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Extracts the Auth0 Domain from the JSON stored in appSecret
|
||||
*
|
||||
* @return string
|
||||
|
@ -190,7 +198,8 @@ class Auth0 extends OAuth2
|
|||
protected function getAuth0Domain(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
return (isset($secret['auth0Domain'])) ? $secret['auth0Domain'] : '';
|
||||
|
||||
return $secret['auth0Domain'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -199,7 +208,7 @@ class Auth0 extends OAuth2
|
|||
* @return array
|
||||
*/
|
||||
protected function getAppSecret(): array
|
||||
{
|
||||
{
|
||||
try {
|
||||
$secret = \json_decode($this->appSecret, true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (\Throwable $th) {
|
||||
|
@ -207,4 +216,4 @@ class Auth0 extends OAuth2
|
|||
}
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,17 +12,17 @@ class Bitbucket extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
@ -37,12 +37,12 @@ class Bitbucket extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://bitbucket.org/site/oauth2/authorize?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
return 'https://bitbucket.org/site/oauth2/authorize?' . \http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,7 +52,7 @@ class Bitbucket extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
// Required as per Bitbucket Spec.
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
|
@ -76,7 +76,7 @@ class Bitbucket extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
|
@ -91,7 +91,7 @@ class Bitbucket extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -107,11 +107,7 @@ class Bitbucket extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['uuid'])) {
|
||||
return $user['uuid'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['uuid'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,11 +119,25 @@ class Bitbucket extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['is_confirmed'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,11 +149,7 @@ class Bitbucket extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['display_name'])) {
|
||||
return $user['display_name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['display_name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,11 +160,20 @@ class Bitbucket extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://api.bitbucket.org/2.0/user?access_token='.\urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://api.bitbucket.org/2.0/user?access_token=' . \urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
|
||||
$email = $this->request('GET', 'https://api.bitbucket.org/2.0/user/emails?access_token='.\urlencode($accessToken));
|
||||
$this->user['email'] = \json_decode($email, true)['values'][0]['email'];
|
||||
$emails = $this->request('GET', 'https://api.bitbucket.org/2.0/user/emails?access_token=' . \urlencode($accessToken));
|
||||
$emails = \json_decode($emails, true);
|
||||
if (isset($emails['values'])) {
|
||||
foreach ($emails['values'] as $email) {
|
||||
if ($email['is_confirmed']) {
|
||||
$this->user['email'] = $email['email'];
|
||||
$this->user['is_confirmed'] = $email['is_confirmed'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->user;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
use Utopia\Exception;
|
||||
|
||||
// Reference Material
|
||||
// https://dev.bitly.com/v4_documentation.html
|
||||
|
@ -14,32 +13,32 @@ class Bitly extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $endpoint = 'https://bitly.com/oauth/';
|
||||
private string $endpoint = 'https://bitly.com/oauth/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $resourceEndpoint = 'https://api-ssl.bitly.com/';
|
||||
private string $resourceEndpoint = 'https://api-ssl.bitly.com/';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [];
|
||||
protected array $scopes = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'bitly';
|
||||
}
|
||||
|
@ -47,9 +46,9 @@ class Bitly extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . 'authorize?'.
|
||||
return $this->endpoint . 'authorize?' .
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
|
@ -64,7 +63,7 @@ class Bitly extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$response = $this->request(
|
||||
'POST',
|
||||
$this->resourceEndpoint . 'oauth/access_token',
|
||||
|
@ -91,7 +90,7 @@ class Bitly extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$response = $this->request(
|
||||
'POST',
|
||||
|
@ -109,7 +108,7 @@ class Bitly extends OAuth2
|
|||
\parse_str($response, $output);
|
||||
$this->tokens = $output;
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -117,51 +116,61 @@ class Bitly extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['login'])) {
|
||||
return $user['login'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['login'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['emails'])) {
|
||||
return $user['emails'][0]['email'];
|
||||
foreach ($user['emails'] as $email) {
|
||||
if ($email['is_verified'] === true) {
|
||||
return $email['email'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://dev.bitly.com/api-reference#getUser
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -172,7 +181,7 @@ class Bitly extends OAuth2
|
|||
protected function getUser(string $accessToken)
|
||||
{
|
||||
$headers = [
|
||||
'Authorization: Bearer '. \urlencode($accessToken),
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
"Accept: application/json"
|
||||
];
|
||||
|
||||
|
@ -180,7 +189,6 @@ class Bitly extends OAuth2
|
|||
$this->user = \json_decode($this->request('GET', $this->resourceEndpoint . "v4/user", $headers), true);
|
||||
}
|
||||
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,27 +12,27 @@ class Box extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $endpoint = 'https://account.box.com/api/oauth2/';
|
||||
private string $endpoint = 'https://account.box.com/api/oauth2/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $resourceEndpoint = 'https://api.box.com/2.0/';
|
||||
private string $resourceEndpoint = 'https://api.box.com/2.0/';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'manage_app_users',
|
||||
];
|
||||
|
||||
|
@ -49,7 +49,7 @@ class Box extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint . 'authorize?'.
|
||||
$url = $this->endpoint . 'authorize?' .
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
|
@ -68,7 +68,7 @@ class Box extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -93,7 +93,7 @@ class Box extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
|
@ -108,7 +108,7 @@ class Box extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -124,11 +124,7 @@ class Box extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,11 +136,23 @@ class Box extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['login'])) {
|
||||
return $user['login'];
|
||||
}
|
||||
return $user['login'] ?? '';
|
||||
}
|
||||
|
||||
return '';
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Box sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,11 +164,7 @@ class Box extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -171,7 +175,7 @@ class Box extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
$header = [
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
];
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
|
|
|
@ -12,22 +12,22 @@ class Discord extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $endpoint = 'https://discordapp.com/api';
|
||||
private string $endpoint = 'https://discordapp.com/api';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $scopes = [
|
||||
'identify',
|
||||
'email'
|
||||
];
|
||||
|
@ -118,11 +118,7 @@ class Discord extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,11 +130,27 @@ class Discord extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://discord.com/developers/docs/resources/user
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,11 +162,7 @@ class Discord extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['username'])) {
|
||||
return $user['username'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['username'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,17 +13,17 @@ class Dropbox extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
@ -32,17 +32,17 @@ class Dropbox extends OAuth2
|
|||
{
|
||||
return 'dropbox';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.dropbox.com/oauth2/authorize?'.\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'response_type' => 'code'
|
||||
return 'https://www.dropbox.com/oauth2/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state),
|
||||
'response_type' => 'code'
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ class Dropbox extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -77,7 +77,7 @@ class Dropbox extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
|
@ -92,7 +92,7 @@ class Dropbox extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -108,11 +108,7 @@ class Dropbox extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['account_id'])) {
|
||||
return $user['account_id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['account_id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,11 +120,27 @@ class Dropbox extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['email_verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,11 +152,7 @@ class Dropbox extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name']['display_name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name']['display_name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,7 +163,7 @@ class Dropbox extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer '. \urlencode($accessToken)];
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$user = $this->request('POST', 'https://api.dropboxapi.com/2/users/get_current_account', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
|
|
@ -3,36 +3,35 @@
|
|||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
use Utopia\Exception;
|
||||
|
||||
class Facebook extends OAuth2
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $version = 'v2.8';
|
||||
protected string $version = 'v2.8';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'email'
|
||||
];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'facebook';
|
||||
}
|
||||
|
@ -40,10 +39,10 @@ class Facebook extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.facebook.com/'.$this->version.'/dialog/oauth?'.\http_build_query([
|
||||
'client_id'=> $this->appID,
|
||||
return 'https://www.facebook.com/' . $this->version . '/dialog/oauth?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
|
@ -57,7 +56,7 @@ class Facebook extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'https://graph.facebook.com/' . $this->version . '/oauth/access_token?' . \http_build_query([
|
||||
|
@ -77,7 +76,7 @@ class Facebook extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
|
@ -90,7 +89,7 @@ class Facebook extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -102,15 +101,11 @@ class Facebook extends OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,15 +113,27 @@ class Facebook extends OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
}
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
return '';
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Facebook sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,15 +141,11 @@ class Facebook extends OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,10 +153,10 @@ class Facebook extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken):array
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://graph.facebook.com/'.$this->version.'/me?fields=email,name&access_token='.\urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://graph.facebook.com/' . $this->version . '/me?fields=email,name&access_token=' . \urlencode($accessToken));
|
||||
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
|
|
@ -3,31 +3,30 @@
|
|||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
use Utopia\Exception;
|
||||
|
||||
class Github extends OAuth2
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'user:email',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'github';
|
||||
}
|
||||
|
@ -35,9 +34,9 @@ class Github extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://github.com/login/oauth/authorize?'. \http_build_query([
|
||||
return 'https://github.com/login/oauth/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
|
@ -52,7 +51,7 @@ class Github extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$response = $this->request(
|
||||
'POST',
|
||||
'https://github.com/login/oauth/access_token',
|
||||
|
@ -78,7 +77,7 @@ class Github extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$response = $this->request(
|
||||
'POST',
|
||||
|
@ -96,7 +95,7 @@ class Github extends OAuth2
|
|||
\parse_str($response, $output);
|
||||
$this->tokens = $output;
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -104,53 +103,59 @@ class Github extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
{
|
||||
$emails = \json_decode($this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token '.\urlencode($accessToken)]), true);
|
||||
|
||||
foreach ($emails as $email) {
|
||||
if ($email['primary'] && $email['verified']) {
|
||||
return $email['email'];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://docs.github.com/en/rest/users/emails#list-email-addresses-for-the-authenticated-user
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,7 +166,18 @@ class Github extends OAuth2
|
|||
protected function getUser(string $accessToken)
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token '.\urlencode($accessToken)]), true);
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token ' . \urlencode($accessToken)]), true);
|
||||
|
||||
$emails = $this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token ' . \urlencode($accessToken)]);
|
||||
|
||||
$emails = \json_decode($emails, true);
|
||||
foreach ($emails as $email) {
|
||||
if (isset($email['verified']) && $email['verified'] === true) {
|
||||
$this->user['email'] = $email['email'];
|
||||
$this->user['verified'] = $email['verified'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
|
|
|
@ -12,17 +12,17 @@ class Gitlab extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'read_user'
|
||||
];
|
||||
|
||||
|
@ -39,7 +39,7 @@ class Gitlab extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://gitlab.com/oauth/authorize?'.\http_build_query([
|
||||
return 'https://gitlab.com/oauth/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
|
@ -55,7 +55,7 @@ class Gitlab extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://gitlab.com/oauth/token?' . \http_build_query([
|
||||
|
@ -76,7 +76,7 @@ class Gitlab extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -88,7 +88,7 @@ class Gitlab extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -120,11 +120,27 @@ class Gitlab extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://docs.gitlab.com/ee/api/users.html#list-current-user-for-normal-users
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['confirmed_at'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,11 +152,7 @@ class Gitlab extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,7 +163,7 @@ class Gitlab extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://gitlab.com/api/v4/user?access_token='.\urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://gitlab.com/api/v4/user?access_token=' . \urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@ class Google extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $version = 'v4';
|
||||
protected string $version = 'v4';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $scopes = [
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
'openid'
|
||||
|
@ -28,12 +28,12 @@ class Google extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
@ -48,7 +48,7 @@ class Google extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://accounts.google.com/o/oauth2/v2/auth?'. \http_build_query([
|
||||
return 'https://accounts.google.com/o/oauth2/v2/auth?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
|
@ -64,7 +64,7 @@ class Google extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://oauth2.googleapis.com/token?' . \http_build_query([
|
||||
|
@ -86,7 +86,7 @@ class Google extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -98,7 +98,7 @@ class Google extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -114,11 +114,7 @@ class Google extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,11 +126,27 @@ class Google extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://www.oauth.com/oauth2-servers/signing-in-with-google/verifying-the-user-info/
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['email_verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,11 +158,7 @@ class Google extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,7 +169,7 @@ class Google extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://www.googleapis.com/oauth2/v2/userinfo?access_token='.\urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://www.googleapis.com/oauth2/v3/userinfo?access_token=' . \urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,17 +9,17 @@ class Linkedin extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'r_liteprofile',
|
||||
'r_emailaddress',
|
||||
];
|
||||
|
@ -40,7 +40,7 @@ class Linkedin extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'linkedin';
|
||||
}
|
||||
|
@ -48,15 +48,15 @@ class Linkedin extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://www.linkedin.com/oauth/v2/authorization?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
return 'https://www.linkedin.com/oauth/v2/authorization?' . \http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,7 +66,7 @@ class Linkedin extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://www.linkedin.com/oauth/v2/accessToken',
|
||||
|
@ -89,7 +89,7 @@ class Linkedin extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -104,7 +104,7 @@ class Linkedin extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -112,48 +112,51 @@ class Linkedin extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$email = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer '.\urlencode($accessToken)]), true);
|
||||
$email = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer ' . \urlencode($accessToken)]), true);
|
||||
|
||||
if (
|
||||
isset($email['elements']) &&
|
||||
isset($email['elements'][0]) &&
|
||||
isset($email['elements'][0]['handle~']) &&
|
||||
isset($email['elements'][0]['handle~']['emailAddress'])
|
||||
) {
|
||||
return $email['elements'][0]['handle~']['emailAddress'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $email['elements'][0]['handle~']['emailAddress'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Linkedin sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
$name = '';
|
||||
|
@ -163,7 +166,7 @@ class Linkedin extends OAuth2
|
|||
}
|
||||
|
||||
if (isset($user['localizedLastName'])) {
|
||||
$name = (empty($name)) ? $user['localizedLastName'] : $name.' '.$user['localizedLastName'];
|
||||
$name = (empty($name)) ? $user['localizedLastName'] : $name . ' ' . $user['localizedLastName'];
|
||||
}
|
||||
|
||||
return $name;
|
||||
|
@ -177,7 +180,7 @@ class Linkedin extends OAuth2
|
|||
protected function getUser(string $accessToken)
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer '.\urlencode($accessToken)]), true);
|
||||
$this->user = \json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer ' . \urlencode($accessToken)]), true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
|
|
|
@ -13,17 +13,17 @@ class Microsoft extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'offline_access',
|
||||
'user.read'
|
||||
];
|
||||
|
@ -35,17 +35,17 @@ class Microsoft extends OAuth2
|
|||
{
|
||||
return 'microsoft';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://login.microsoftonline.com/'.$this->getTenantID().'/oauth2/v2.0/authorize?'.\http_build_query([
|
||||
return 'https://login.microsoftonline.com/' . $this->getTenantID() . '/oauth2/v2.0/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state'=> \json_encode($this->state),
|
||||
'scope'=> \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'response_type' => 'code',
|
||||
'response_mode' => 'query'
|
||||
]);
|
||||
|
@ -58,7 +58,7 @@ class Microsoft extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -83,7 +83,7 @@ class Microsoft extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
|
@ -98,7 +98,7 @@ class Microsoft extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -114,11 +114,7 @@ class Microsoft extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,11 +126,23 @@ class Microsoft extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['userPrincipalName'])) {
|
||||
return $user['userPrincipalName'];
|
||||
}
|
||||
return $user['userPrincipalName'] ?? '';
|
||||
}
|
||||
|
||||
return '';
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Microsoft sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,11 +154,7 @@ class Microsoft extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['displayName'])) {
|
||||
return $user['displayName'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['displayName'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,7 +165,7 @@ class Microsoft extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer '. \urlencode($accessToken)];
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://graph.microsoft.com/v1.0/me', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
@ -175,7 +179,7 @@ class Microsoft extends OAuth2
|
|||
* @return array
|
||||
*/
|
||||
protected function getAppSecret(): array
|
||||
{
|
||||
{
|
||||
try {
|
||||
$secret = \json_decode($this->appSecret, true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (\Throwable $th) {
|
||||
|
@ -192,7 +196,8 @@ class Microsoft extends OAuth2
|
|||
protected function getClientSecret(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
return (isset($secret['clientSecret'])) ? $secret['clientSecret'] : '';
|
||||
|
||||
return $secret['clientSecret'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -203,6 +208,7 @@ class Microsoft extends OAuth2
|
|||
protected function getTenantID(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
return (isset($secret['tenantID'])) ? $secret['tenantID'] : 'common';
|
||||
|
||||
return $secret['tenantID'] ?? 'common';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,29 +10,29 @@ class Mock extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $version = 'v1';
|
||||
protected string $version = 'v1';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $scopes = [
|
||||
'email'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'mock';
|
||||
}
|
||||
|
@ -40,9 +40,9 @@ class Mock extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'http://localhost/'.$this->version.'/mock/tests/general/oauth2?'. \http_build_query([
|
||||
return 'http://localhost/' . $this->version . '/mock/tests/general/oauth2?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
|
@ -57,16 +57,16 @@ class Mock extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'http://localhost/' . $this->version . '/mock/tests/general/oauth2/token?' .
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code
|
||||
])
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'client_secret' => $this->appSecret,
|
||||
'code' => $code
|
||||
])
|
||||
), true);
|
||||
}
|
||||
|
||||
|
@ -78,20 +78,20 @@ class Mock extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
'http://localhost/' . $this->version . '/mock/tests/general/oauth2/token?' .
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
])
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'refresh_token' => $refreshToken,
|
||||
'grant_type' => 'refresh_token'
|
||||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -103,15 +103,11 @@ class Mock extends OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,15 +115,23 @@ class Mock extends OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
}
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
return '';
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,15 +139,11 @@ class Mock extends OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,10 +151,10 @@ class Mock extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken):array
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'http://localhost/'.$this->version.'/mock/tests/general/oauth2/user?token='.\urlencode($accessToken));
|
||||
$user = $this->request('GET', 'http://localhost/' . $this->version . '/mock/tests/general/oauth2/user?token=' . \urlencode($accessToken));
|
||||
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
|
|
@ -9,32 +9,32 @@ class Notion extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $endpoint = 'https://api.notion.com/v1';
|
||||
private string $endpoint = 'https://api.notion.com/v1';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $version = '2021-08-16';
|
||||
private string $version = '2021-08-16';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'notion';
|
||||
}
|
||||
|
@ -42,9 +42,9 @@ class Notion extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . '/oauth/authorize?'. \http_build_query([
|
||||
return $this->endpoint . '/oauth/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'response_type' => 'code',
|
||||
|
@ -60,7 +60,7 @@ class Notion extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -82,7 +82,7 @@ class Notion extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
|
@ -95,7 +95,7 @@ class Notion extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -103,51 +103,55 @@ class Notion extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$response = $this->getUser($accessToken);
|
||||
|
||||
if (isset($response['bot']['owner']['user']['id'])) {
|
||||
return $response['bot']['owner']['user']['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $response['bot']['owner']['user']['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$response = $this->getUser($accessToken);
|
||||
|
||||
if(isset($response['bot']['owner']['user']['person']['email'])){
|
||||
return $response['bot']['owner']['user']['person']['email'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $response['bot']['owner']['user']['person']['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Notion sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$response = $this->getUser($accessToken);
|
||||
|
||||
if (isset($response['bot']['owner']['user']['name'])) {
|
||||
return $response['bot']['owner']['user']['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $response['bot']['owner']['user']['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,11 +159,11 @@ class Notion extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken)
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
$headers = [
|
||||
'Notion-Version: ' . $this->version,
|
||||
'Authorization: Bearer '.\urlencode($accessToken)
|
||||
'Authorization: Bearer ' . \urlencode($accessToken)
|
||||
];
|
||||
|
||||
if (empty($this->user)) {
|
||||
|
|
|
@ -8,27 +8,27 @@ use Appwrite\Auth\OAuth2;
|
|||
// https://developer.okta.com/docs/guides/sign-into-web-app-redirect/php/main/
|
||||
|
||||
class Okta extends OAuth2
|
||||
{
|
||||
/**
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $scopes = [
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access'
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
@ -42,11 +42,11 @@ class Okta extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/authorize?'.\http_build_query([
|
||||
return 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'state'=> \json_encode($this->state),
|
||||
'scope'=> \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state),
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'response_type' => 'code'
|
||||
]);
|
||||
}
|
||||
|
@ -58,11 +58,11 @@ class Okta extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token',
|
||||
'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
|
@ -77,8 +77,8 @@ class Okta extends OAuth2
|
|||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
|
@ -89,7 +89,7 @@ class Okta extends OAuth2
|
|||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/token',
|
||||
'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/token',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
|
@ -99,7 +99,7 @@ class Okta extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -114,12 +114,8 @@ class Okta extends OAuth2
|
|||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['sub'])) {
|
||||
return $user['sub'];
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
return $user['sub'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,12 +126,28 @@ class Okta extends OAuth2
|
|||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://developer.okta.com/docs/reference/api/oidc/#userinfo
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['email_verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,15 +158,11 @@ class Okta extends OAuth2
|
|||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return array
|
||||
|
@ -162,8 +170,8 @@ class Okta extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer '. \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://'.$this->getOktaDomain().'/oauth2/'.$this->getAuthorizationServerId().'/v1/userinfo', $headers);
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://' . $this->getOktaDomain() . '/oauth2/' . $this->getAuthorizationServerId() . '/v1/userinfo', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
|
@ -179,10 +187,10 @@ class Okta extends OAuth2
|
|||
{
|
||||
$secret = $this->getAppSecret();
|
||||
|
||||
return (isset($secret['clientSecret'])) ? $secret['clientSecret'] : '';
|
||||
return $secret['clientSecret'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Extracts the Okta Domain from the JSON stored in appSecret
|
||||
*
|
||||
* @return string
|
||||
|
@ -190,7 +198,8 @@ class Okta extends OAuth2
|
|||
protected function getOktaDomain(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
return (isset($secret['oktaDomain'])) ? $secret['oktaDomain'] : '';
|
||||
|
||||
return $secret['oktaDomain'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,7 +210,8 @@ class Okta extends OAuth2
|
|||
protected function getAuthorizationServerId(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
return (isset($secret['authorizationServerId'])) ? $secret['authorizationServerId'] : 'default';
|
||||
|
||||
return $secret['authorizationServerId'] ?? 'default';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,7 +220,7 @@ class Okta extends OAuth2
|
|||
* @return array
|
||||
*/
|
||||
protected function getAppSecret(): array
|
||||
{
|
||||
{
|
||||
try {
|
||||
$secret = \json_decode($this->appSecret, true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (\Throwable $th) {
|
||||
|
|
|
@ -12,7 +12,7 @@ class Paypal extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $endpoint = [
|
||||
private array $endpoint = [
|
||||
'sandbox' => 'https://www.sandbox.paypal.com/',
|
||||
'live' => 'https://www.paypal.com/',
|
||||
];
|
||||
|
@ -20,7 +20,7 @@ class Paypal extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $resourceEndpoint = [
|
||||
private array $resourceEndpoint = [
|
||||
'sandbox' => 'https://api.sandbox.paypal.com/v1/',
|
||||
'live' => 'https://api.paypal.com/v1/',
|
||||
];
|
||||
|
@ -28,22 +28,22 @@ class Paypal extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $environment = 'live';
|
||||
protected string $environment = 'live';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'openid',
|
||||
'profile',
|
||||
'email'
|
||||
|
@ -62,7 +62,7 @@ class Paypal extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
$url = $this->endpoint[$this->environment] . 'connect/?'.
|
||||
$url = $this->endpoint[$this->environment] . 'connect/?' .
|
||||
\http_build_query([
|
||||
'flowEntry' => 'static',
|
||||
'response_type' => 'code',
|
||||
|
@ -83,7 +83,7 @@ class Paypal extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->resourceEndpoint[$this->environment] . 'oauth2/token',
|
||||
|
@ -103,7 +103,7 @@ class Paypal extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -115,7 +115,7 @@ class Paypal extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -131,11 +131,7 @@ class Paypal extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['payer_id'])) {
|
||||
return $user['payer_id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['payer_id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,12 +144,38 @@ class Paypal extends OAuth2
|
|||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['emails'])) {
|
||||
return $user['emails'][0]['value'];
|
||||
$email = array_filter($user['emails'], function ($email) {
|
||||
return $email['primary'] === true;
|
||||
});
|
||||
|
||||
if (!empty($email)) {
|
||||
return $email[0]['value'];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://developer.paypal.com/docs/api/identity/v1/#userinfo_get
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['verified_account'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
|
@ -163,11 +185,7 @@ class Paypal extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,7 +197,7 @@ class Paypal extends OAuth2
|
|||
{
|
||||
$header = [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
];
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request(
|
||||
|
|
|
@ -6,7 +6,7 @@ use Appwrite\Auth\OAuth2\Paypal;
|
|||
|
||||
class PaypalSandbox extends Paypal
|
||||
{
|
||||
protected $environment = 'sandbox';
|
||||
protected string $environment = 'sandbox';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
|
|
@ -14,17 +14,17 @@ class Salesforce extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
"openid"
|
||||
];
|
||||
|
||||
|
@ -37,7 +37,7 @@ class Salesforce extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $state
|
||||
* @param string $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -52,13 +52,13 @@ class Salesforce extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://login.salesforce.com/services/oauth2/authorize?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri'=> $this->callback,
|
||||
'scope'=> \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
]);
|
||||
return 'https://login.salesforce.com/services/oauth2/authorize?' . \http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,7 +68,7 @@ class Salesforce extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
|
@ -93,7 +93,7 @@ class Salesforce extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
|
@ -109,7 +109,7 @@ class Salesforce extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -125,11 +125,7 @@ class Salesforce extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['user_id'])) {
|
||||
return $user['user_id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['user_id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,11 +137,27 @@ class Salesforce extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://help.salesforce.com/s/articleView?id=sf.remoteaccess_using_userinfo_endpoint.htm&type=5
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['email_verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,11 +169,7 @@ class Salesforce extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -172,7 +180,7 @@ class Salesforce extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://login.salesforce.com/services/oauth2/userinfo?access_token='.\urlencode($accessToken));
|
||||
$user = $this->request('GET', 'https://login.salesforce.com/services/oauth2/userinfo?access_token=' . \urlencode($accessToken));
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
return $this->user;
|
||||
|
|
|
@ -3,24 +3,23 @@
|
|||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
use Utopia\Exception;
|
||||
|
||||
class Slack extends OAuth2
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'identity.avatar',
|
||||
'identity.basic',
|
||||
'identity.email',
|
||||
|
@ -30,7 +29,7 @@ class Slack extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'slack';
|
||||
}
|
||||
|
@ -38,11 +37,11 @@ class Slack extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
// https://api.slack.com/docs/oauth#step_1_-_sending_users_to_authorize_and_or_install
|
||||
return 'https://slack.com/oauth/authorize?'.\http_build_query([
|
||||
'client_id'=> $this->appID,
|
||||
return 'https://slack.com/oauth/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state)
|
||||
|
@ -56,7 +55,7 @@ class Slack extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
// https://api.slack.com/docs/oauth#step_3_-_exchanging_a_verification_code_for_an_access_token
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
|
@ -77,7 +76,7 @@ class Slack extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'GET',
|
||||
|
@ -89,7 +88,7 @@ class Slack extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -101,15 +100,11 @@ class Slack extends OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['user']['id'])) {
|
||||
return $user['user']['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['user']['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,15 +112,29 @@ class Slack extends OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['user']['email'])) {
|
||||
return $user['user']['email'];
|
||||
}
|
||||
return $user['user']['email'] ?? '';
|
||||
}
|
||||
|
||||
return '';
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Slack sign up process
|
||||
*
|
||||
* @link https://slack.com/help/articles/207262907-Change-your-email-address
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,29 +142,26 @@ class Slack extends OAuth2
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['user']['name'])) {
|
||||
return $user['user']['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['user']['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @link https://api.slack.com/methods/users.identity
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken):array
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
// https://api.slack.com/methods/users.identity
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
'https://slack.com/api/users.identity?token='.\urlencode($accessToken)
|
||||
'https://slack.com/api/users.identity?token=' . \urlencode($accessToken)
|
||||
);
|
||||
|
||||
$this->user = \json_decode($user, true);
|
||||
|
|
|
@ -13,34 +13,34 @@ class Spotify extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $endpoint = 'https://accounts.spotify.com/';
|
||||
private string $endpoint = 'https://accounts.spotify.com/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $resourceEndpoint = 'https://api.spotify.com/v1/';
|
||||
private string $resourceEndpoint = 'https://api.spotify.com/v1/';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $scopes = [
|
||||
'user-read-email',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'spotify';
|
||||
}
|
||||
|
@ -48,9 +48,9 @@ class Spotify extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . 'authorize?'.
|
||||
return $this->endpoint . 'authorize?' .
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
|
@ -67,7 +67,7 @@ class Spotify extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -89,7 +89,7 @@ class Spotify extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret)];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
|
@ -102,7 +102,7 @@ class Spotify extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -110,51 +110,55 @@ class Spotify extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* Spotify does not assure that the email is verified
|
||||
*
|
||||
* @link https://developer.spotify.com/documentation/web-api/reference/#/operations/get-current-users-profile
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['display_name'])) {
|
||||
return $user['display_name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['display_name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,8 +171,8 @@ class Spotify extends OAuth2
|
|||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request(
|
||||
'GET',
|
||||
$this->resourceEndpoint . "me",
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
$this->resourceEndpoint . 'me',
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
), true);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,38 +10,37 @@ class Stripe extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $stripeAccountId = '';
|
||||
protected string $stripeAccountId = '';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $scopes = [
|
||||
'read_write',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
|
||||
protected $grantType = [
|
||||
'authorize' => 'authorization_code',
|
||||
'refresh' => 'refresh_token',
|
||||
protected array $grantType = [
|
||||
'authorize' => 'authorization_code',
|
||||
'refresh' => 'refresh_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'stripe';
|
||||
}
|
||||
|
@ -49,9 +48,9 @@ class Stripe extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://connect.stripe.com/oauth/authorize?'. \http_build_query([
|
||||
return 'https://connect.stripe.com/oauth/authorize?' . \http_build_query([
|
||||
'response_type' => 'code', // The only option at the moment is "code."
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
|
@ -67,7 +66,7 @@ class Stripe extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://connect.stripe.com/oauth/token',
|
||||
|
@ -89,7 +88,7 @@ class Stripe extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -101,7 +100,7 @@ class Stripe extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -110,51 +109,59 @@ class Stripe extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if(empty($user)) {
|
||||
return '';
|
||||
|
||||
if (empty($user)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Stripe sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -166,15 +173,13 @@ class Stripe extends OAuth2
|
|||
{
|
||||
if (empty($this->user) && !empty($this->stripeAccountId)) {
|
||||
$this->user = \json_decode(
|
||||
$this->request(
|
||||
'GET',
|
||||
'https://api.stripe.com/v1/accounts/' . $this->stripeAccountId,
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
),
|
||||
true
|
||||
$this->request(
|
||||
'GET',
|
||||
'https://api.stripe.com/v1/accounts/' . $this->stripeAccountId,
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
|
|
|
@ -12,35 +12,37 @@ class Tradeshift extends OAuth2
|
|||
const TRADESHIFT_SANDBOX_API_DOMAIN = 'api-sandbox.tradeshift.com';
|
||||
const TRADESHIFT_API_DOMAIN = 'api.tradeshift.com';
|
||||
|
||||
private $apiDomain = [
|
||||
private array $apiDomain = [
|
||||
'sandbox' => self::TRADESHIFT_SANDBOX_API_DOMAIN,
|
||||
'live' => self::TRADESHIFT_API_DOMAIN,
|
||||
];
|
||||
|
||||
private $endpoint = [
|
||||
private array $endpoint = [
|
||||
'sandbox' => 'https://' . self::TRADESHIFT_SANDBOX_API_DOMAIN . '/tradeshift/',
|
||||
'live' => 'https://' . self::TRADESHIFT_API_DOMAIN . '/tradeshift/',
|
||||
];
|
||||
|
||||
private $resourceEndpoint = [
|
||||
private array $resourceEndpoint = [
|
||||
'sandbox' => 'https://' . self::TRADESHIFT_SANDBOX_API_DOMAIN . '/tradeshift/rest/external/',
|
||||
'live' => 'https://' . self::TRADESHIFT_API_DOMAIN . '/tradeshift/rest/external/',
|
||||
];
|
||||
|
||||
protected $environment = 'live';
|
||||
protected string $environment = 'live';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
|
||||
protected $scopes = [
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array$scopes = [
|
||||
'openid',
|
||||
'offline',
|
||||
];
|
||||
|
@ -78,7 +80,7 @@ class Tradeshift extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint[$this->environment] . 'auth/token',
|
||||
|
@ -98,7 +100,7 @@ class Tradeshift extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -109,8 +111,8 @@ class Tradeshift extends OAuth2
|
|||
'refresh_token' => $refreshToken,
|
||||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -141,6 +143,22 @@ class Tradeshift extends OAuth2
|
|||
return $user['Username'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Tradeshift sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUser($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
|
|
|
@ -6,7 +6,7 @@ use Appwrite\Auth\OAuth2\Tradeshift;
|
|||
|
||||
class TradeshiftBox extends Tradeshift
|
||||
{
|
||||
protected $environment = 'sandbox';
|
||||
protected string $environment = 'sandbox';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
|
|
@ -13,34 +13,34 @@ class Twitch extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $endpoint = 'https://id.twitch.tv/oauth2/';
|
||||
private string $endpoint = 'https://id.twitch.tv/oauth2/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $resourceEndpoint = 'https://api.twitch.tv/helix/users';
|
||||
private string $resourceEndpoint = 'https://api.twitch.tv/helix/users';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $scopes = [
|
||||
'user:read:email',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'twitch';
|
||||
}
|
||||
|
@ -48,9 +48,9 @@ class Twitch extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . 'authorize?'.
|
||||
return $this->endpoint . 'authorize?' .
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
|
@ -68,7 +68,7 @@ class Twitch extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
$this->endpoint . 'token?' . \http_build_query([
|
||||
|
@ -89,7 +89,7 @@ class Twitch extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -101,7 +101,7 @@ class Twitch extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -109,51 +109,57 @@ class Twitch extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified
|
||||
*
|
||||
* @link https://dev.twitch.tv/docs/api/reference#get-users
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['display_name'])) {
|
||||
return $user['display_name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['display_name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -168,8 +174,8 @@ class Twitch extends OAuth2
|
|||
'GET',
|
||||
$this->resourceEndpoint,
|
||||
[
|
||||
'Authorization: Bearer '.\urlencode($accessToken),
|
||||
'Client-Id: '. \urlencode($this->appID)
|
||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||
'Client-Id: ' . \urlencode($this->appID)
|
||||
]
|
||||
), true);
|
||||
|
||||
|
|
|
@ -1,191 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
use Appwrite\Auth\OAuth2;
|
||||
use Utopia\Exception;
|
||||
|
||||
// Reference Material
|
||||
// https://vk.com/dev/first_guide
|
||||
// https://vk.com/dev/auth_sites
|
||||
// https://vk.com/dev/api_requests
|
||||
// https://plugins.miniorange.com/guide-to-configure-vkontakte-as-oauth-server
|
||||
|
||||
class Vk extends OAuth2
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
'openid',
|
||||
'email'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $version = '5.101';
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'vk';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://oauth.vk.com/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'response_type' => 'code',
|
||||
'state' => \json_encode($this->state),
|
||||
'v' => $this->version,
|
||||
'scope' => \implode(' ', $this->getScopes())
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded;charset=UTF-8'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://oauth.vk.com/access_token?',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'code' => $code,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'redirect_uri' => $this->callback
|
||||
])
|
||||
), true);
|
||||
|
||||
$this->user['email'] = $this->tokens['email'];
|
||||
$this->user['user_id'] = $this->tokens['user_id'];
|
||||
}
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $refreshToken
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
{
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded;charset=UTF-8'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://oauth.vk.com/access_token?',
|
||||
$headers,
|
||||
\http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'grant_type' => 'refresh_token'
|
||||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
$this->user['email'] = $this->tokens['email'];
|
||||
$this->user['user_id'] = $this->tokens['user_id'];
|
||||
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['user_id'])) {
|
||||
return $user['user_id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user['name'])) {
|
||||
$user = $this->request(
|
||||
'GET',
|
||||
'https://api.vk.com/method/users.get?'. \http_build_query([
|
||||
'v' => $this->version,
|
||||
'fields' => 'id,name,email,first_name,last_name',
|
||||
'access_token' => $accessToken
|
||||
])
|
||||
);
|
||||
|
||||
$user = \json_decode($user, true);
|
||||
$this->user['name'] = $user['response'][0]['first_name'] ." ".$user['response'][0]['last_name'];
|
||||
}
|
||||
return $this->user;
|
||||
}
|
||||
}
|
|
@ -12,24 +12,24 @@ class WordPress extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'auth',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'wordpress';
|
||||
}
|
||||
|
@ -37,9 +37,9 @@ class WordPress extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://public-api.wordpress.com/oauth2/authorize?'. \http_build_query([
|
||||
return 'https://public-api.wordpress.com/oauth2/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'response_type' => 'code',
|
||||
|
@ -55,7 +55,7 @@ class WordPress extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
'https://public-api.wordpress.com/oauth2/token',
|
||||
|
@ -78,7 +78,7 @@ class WordPress extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -92,7 +92,7 @@ class WordPress extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -100,51 +100,63 @@ class WordPress extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['ID'])) {
|
||||
return $user['ID'];
|
||||
return $user['ID'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if ($user['verified']) {
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
*
|
||||
* @return string
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://developer.wordpress.com/docs/api/1.1/get/me/
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email']) && $user['verified']) {
|
||||
return $user['email'];
|
||||
if ($user['email_verified'] ?? false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['username'])) {
|
||||
return $user['username'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['username'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,7 +167,7 @@ class WordPress extends OAuth2
|
|||
protected function getUser(string $accessToken)
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$this->user = \json_decode($this->request('GET', 'https://public-api.wordpress.com/rest/v1/me', ['Authorization: Bearer '.$accessToken]), true);
|
||||
$this->user = \json_decode($this->request('GET', 'https://public-api.wordpress.com/rest/v1/me', ['Authorization: Bearer ' . $accessToken]), true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
|
|
|
@ -13,17 +13,17 @@ class Yahoo extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $endpoint = 'https://api.login.yahoo.com/oauth2/';
|
||||
private string $endpoint = 'https://api.login.yahoo.com/oauth2/';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $resourceEndpoint = 'https://api.login.yahoo.com/openid/v1/userinfo';
|
||||
private string $resourceEndpoint = 'https://api.login.yahoo.com/openid/v1/userinfo';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $scopes = [
|
||||
'sdct-r',
|
||||
'sdpp-w',
|
||||
];
|
||||
|
@ -31,17 +31,17 @@ class Yahoo extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'yahoo';
|
||||
}
|
||||
|
@ -60,9 +60,9 @@ class Yahoo extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . 'request_auth?'.
|
||||
return $this->endpoint . 'request_auth?' .
|
||||
\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
|
@ -79,7 +79,7 @@ class Yahoo extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
|
@ -105,7 +105,7 @@ class Yahoo extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
|
@ -122,7 +122,7 @@ class Yahoo extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -130,51 +130,55 @@ class Yahoo extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['sub'])) {
|
||||
return $user['sub'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['sub'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Yahoo sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['name'])) {
|
||||
return $user['name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -188,7 +192,7 @@ class Yahoo extends OAuth2
|
|||
$this->user = \json_decode($this->request(
|
||||
'GET',
|
||||
$this->resourceEndpoint,
|
||||
['Authorization: Bearer '.\urlencode($accessToken)]
|
||||
['Authorization: Bearer ' . \urlencode($accessToken)]
|
||||
), true);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,17 +12,17 @@ class Yammer extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $endpoint = 'https://www.yammer.com/oauth2/';
|
||||
private string $endpoint = 'https://www.yammer.com/oauth2/';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
@ -37,13 +37,13 @@ class Yammer extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . 'oauth2/authorize?'.
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'response_type' => 'code',
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state)
|
||||
]);
|
||||
return $this->endpoint . 'oauth2/authorize?' .
|
||||
\http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'response_type' => 'code',
|
||||
'redirect_uri' => $this->callback,
|
||||
'state' => \json_encode($this->state)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,7 +53,7 @@ class Yammer extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -76,7 +76,7 @@ class Yammer extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
|
@ -91,7 +91,7 @@ class Yammer extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -107,11 +107,7 @@ class Yammer extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,11 +119,23 @@ class Yammer extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['email'])) {
|
||||
return $user['email'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* If present, the email is verified. This was verfied through a manual Yammer sign up process
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$email = $this->getUserEmail($accessToken);
|
||||
|
||||
return !empty($email);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,11 +147,7 @@ class Yammer extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['full_name'])) {
|
||||
return $user['full_name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['full_name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,7 +158,7 @@ class Yammer extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$headers = ['Authorization: Bearer '. \urlencode($accessToken)];
|
||||
$headers = ['Authorization: Bearer ' . \urlencode($accessToken)];
|
||||
$user = $this->request('GET', 'https://www.yammer.com/api/v1/users/current.json', $headers);
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
|
|
@ -14,17 +14,17 @@ class Yandex extends OAuth2
|
|||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [];
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
@ -35,7 +35,7 @@ class Yandex extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $state
|
||||
* @param string $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -50,12 +50,12 @@ class Yandex extends OAuth2
|
|||
*/
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return 'https://oauth.yandex.com/authorize?'.\http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope'=> \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
]);
|
||||
return 'https://oauth.yandex.com/authorize?' . \http_build_query([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->appID,
|
||||
'scope' => \implode(' ', $this->getScopes()),
|
||||
'state' => \json_encode($this->state)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,7 +65,7 @@ class Yandex extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
|
@ -89,7 +89,7 @@ class Yandex extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = [
|
||||
'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret),
|
||||
|
@ -105,7 +105,7 @@ class Yandex extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -121,11 +121,7 @@ class Yandex extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['id'])) {
|
||||
return $user['id'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,11 +133,19 @@ class Yandex extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['default_email'])) {
|
||||
return $user['default_email'];
|
||||
}
|
||||
return $user['default_email'] ?? '';
|
||||
}
|
||||
|
||||
return '';
|
||||
/**
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,11 +157,7 @@ class Yandex extends OAuth2
|
|||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (isset($user['display_name'])) {
|
||||
return $user['display_name'];
|
||||
}
|
||||
|
||||
return '';
|
||||
return $user['display_name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -168,7 +168,7 @@ class Yandex extends OAuth2
|
|||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'https://login.yandex.ru/info?'.\http_build_query([
|
||||
$user = $this->request('GET', 'https://login.yandex.ru/info?' . \http_build_query([
|
||||
'format' => 'json',
|
||||
'oauth_token' => $accessToken
|
||||
]));
|
||||
|
|
|
@ -9,34 +9,34 @@ class Zoom extends OAuth2
|
|||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $endpoint = 'https://zoom.us';
|
||||
private string $endpoint = 'https://zoom.us';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $version = '2022-03-26';
|
||||
private string $version = '2022-03-26';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tokens = [];
|
||||
protected array $user = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
protected array $tokens = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $scopes = [
|
||||
'user_profile'
|
||||
];
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName():string
|
||||
public function getName(): string
|
||||
{
|
||||
return 'zoom';
|
||||
}
|
||||
|
@ -44,9 +44,9 @@ class Zoom extends OAuth2
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLoginURL():string
|
||||
public function getLoginURL(): string
|
||||
{
|
||||
return $this->endpoint . '/oauth/authorize?'. \http_build_query([
|
||||
return $this->endpoint . '/oauth/authorize?' . \http_build_query([
|
||||
'client_id' => $this->appID,
|
||||
'redirect_uri' => $this->callback,
|
||||
'response_type' => 'code',
|
||||
|
@ -62,7 +62,7 @@ class Zoom extends OAuth2
|
|||
*/
|
||||
protected function getTokens(string $code): array
|
||||
{
|
||||
if(empty($this->tokens)) {
|
||||
if (empty($this->tokens)) {
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
'POST',
|
||||
|
@ -84,7 +84,7 @@ class Zoom extends OAuth2
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function refreshTokens(string $refreshToken):array
|
||||
public function refreshTokens(string $refreshToken): array
|
||||
{
|
||||
$headers = ['Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret), 'Content-Type: application/x-www-form-urlencoded'];
|
||||
$this->tokens = \json_decode($this->request(
|
||||
|
@ -97,7 +97,7 @@ class Zoom extends OAuth2
|
|||
])
|
||||
), true);
|
||||
|
||||
if(empty($this->tokens['refresh_token'])) {
|
||||
if (empty($this->tokens['refresh_token'])) {
|
||||
$this->tokens['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
|
@ -105,35 +105,58 @@ class Zoom extends OAuth2
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserID(string $accessToken):string
|
||||
public function getUserID(string $accessToken): string
|
||||
{
|
||||
$response = $this->getUser($accessToken);
|
||||
|
||||
return $response['id'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserEmail(string $accessToken):string
|
||||
public function getUserEmail(string $accessToken): string
|
||||
{
|
||||
$response = $this->getUser($accessToken);
|
||||
|
||||
return $response['email'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $accessToken
|
||||
* Check if the OAuth email is verified
|
||||
*
|
||||
* @link https://marketplace.zoom.us/docs/api-reference/zoom-api/methods/#operation/user
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
if (($user['verified'] ?? false) === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserName(string $accessToken):string
|
||||
public function getUserName(string $accessToken): string
|
||||
{
|
||||
$response = $this->getUser($accessToken);
|
||||
|
||||
return ($response['first_name'] ?? '') . ' ' . ($response['last_name'] ?? '');
|
||||
}
|
||||
|
||||
|
@ -145,7 +168,7 @@ class Zoom extends OAuth2
|
|||
protected function getUser(string $accessToken)
|
||||
{
|
||||
$headers = [
|
||||
'Authorization: Bearer '.\urlencode($accessToken)
|
||||
'Authorization: Bearer ' . \urlencode($accessToken)
|
||||
];
|
||||
|
||||
if (empty($this->user)) {
|
||||
|
|
|
@ -46,6 +46,7 @@ class Exception extends \Exception
|
|||
const GENERAL_ROUTE_NOT_FOUND = 'general_route_not_found';
|
||||
const GENERAL_CURSOR_NOT_FOUND = 'general_cursor_not_found';
|
||||
const GENERAL_SERVER_ERROR = 'general_server_error';
|
||||
const GENERAL_PROTOCOL_UNSUPPORTED = 'general_protocol_unsupported';
|
||||
|
||||
/** Users */
|
||||
const USER_COUNT_EXCEEDED = 'user_count_exceeded';
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Appwrite\Network\Validator;
|
||||
|
||||
use Utopia\Validator\Hostname;
|
||||
use Utopia\Validator;
|
||||
|
||||
/**
|
||||
|
@ -45,17 +46,16 @@ class Host extends Validator
|
|||
*/
|
||||
public function isValid($value): bool
|
||||
{
|
||||
// Check if value is valid URL
|
||||
$urlValidator = new URL();
|
||||
|
||||
if (!$urlValidator->isValid($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (\in_array(\parse_url($value, PHP_URL_HOST), $this->whitelist)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
$hostname = \parse_url($value, PHP_URL_HOST);
|
||||
$hostnameValidator = new Hostname($this->whitelist);
|
||||
return $hostnameValidator->isValid($hostname);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Appwrite\Network\Validator;
|
||||
|
||||
use Utopia\Validator\Hostname;
|
||||
use Utopia\Validator;
|
||||
|
||||
class Origin extends Validator
|
||||
|
@ -122,11 +123,9 @@ class Origin extends Validator
|
|||
return true;
|
||||
}
|
||||
|
||||
if (\in_array($host, $this->clients)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
$validator = new Hostname($this->clients);
|
||||
|
||||
return $validator->isValid($host);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -188,6 +188,24 @@ trait StorageBase
|
|||
$this->assertEquals('File extension not allowed', $res['body']['message']);
|
||||
|
||||
return ['bucketId' => $bucketId, 'fileId' => $file['body']['$id'], 'largeFileId' => $largeFile['body']['$id'], 'largeBucketId' => $bucket2['body']['$id']];
|
||||
|
||||
/**
|
||||
* Test for FAILURE create bucket with too high limit (bigger then _APP_STORAGE_LIMIT)
|
||||
*/
|
||||
$failedBucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'bucketId' => 'unique()',
|
||||
'name' => 'Test Bucket 2',
|
||||
'permission' => 'file',
|
||||
'maximumFileSize' => 200000000, //200MB
|
||||
'allowedFileExtensions' => ["jpg", "png"],
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:all'],
|
||||
]);
|
||||
$this->assertEquals(400, $failedBucket['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -204,7 +204,7 @@ trait TeamsBaseServer
|
|||
$this->assertEquals(1, $response['body']['total']);
|
||||
$this->assertIsInt($response['body']['total']);
|
||||
$this->assertIsInt($response['body']['dateCreated']);
|
||||
|
||||
|
||||
|
||||
/** Delete User */
|
||||
$user = $this->client->call(Client::METHOD_DELETE, '/users/' . $userUid, array_merge([
|
||||
|
|
Loading…
Reference in a new issue