mirror of
https://github.com/appwrite/appwrite
synced 2026-05-24 01:18:37 +00:00
Merge branch '1.8.x' into chore-php-types
This commit is contained in:
commit
31b9ff4f05
18 changed files with 336 additions and 109 deletions
4
.env
4
.env
|
|
@ -69,8 +69,8 @@ _APP_STORAGE_ANTIVIRUS_PORT=3310
|
|||
_APP_SMTP_HOST=maildev
|
||||
_APP_SMTP_PORT=1025
|
||||
_APP_SMTP_SECURE=
|
||||
_APP_SMTP_USERNAME=
|
||||
_APP_SMTP_PASSWORD=
|
||||
_APP_SMTP_USERNAME=user
|
||||
_APP_SMTP_PASSWORD=password
|
||||
_APP_SMS_PROVIDER=sms://username:password@mock
|
||||
_APP_SMS_FROM=+123456789
|
||||
_APP_SMS_PROJECTS_DENY_LIST=
|
||||
|
|
|
|||
|
|
@ -462,4 +462,15 @@ return [
|
|||
'mock' => true,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\Mock',
|
||||
],
|
||||
'mock-unverified' => [
|
||||
'name' => 'MockUnverified',
|
||||
'developers' => 'https://appwrite.io',
|
||||
'icon' => 'icon-appwrite',
|
||||
'enabled' => true,
|
||||
'sandbox' => false,
|
||||
'form' => false,
|
||||
'beta' => false,
|
||||
'mock' => true,
|
||||
'class' => 'Appwrite\\Auth\\OAuth2\\MockUnverified',
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ $admins = [
|
|||
'projects.write',
|
||||
'keys.read',
|
||||
'keys.write',
|
||||
'devKeys.read',
|
||||
'devKeys.write',
|
||||
'webhooks.read',
|
||||
'webhooks.write',
|
||||
'locale.read',
|
||||
|
|
|
|||
|
|
@ -1639,9 +1639,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
$failureRedirect(Exception::USER_UNAUTHORIZED, 'OAuth provider failed to return email.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Is verified is not used yet, since we don't know after an account is created anymore if it was verified or not.
|
||||
*/
|
||||
$isVerified = $oauth2->isEmailVerified($accessToken);
|
||||
|
||||
$identity = $dbForProject->findOne('identities', [
|
||||
|
|
@ -1653,16 +1650,32 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
$user = $dbForProject->getDocument('users', $identity->getAttribute('userId'));
|
||||
}
|
||||
|
||||
// If user is not found, check if there is an identity with the same provider user ID
|
||||
// If user is not found, check if there is a user with the same email
|
||||
if ($user === false || $user->isEmpty()) {
|
||||
$userWithEmail = $dbForProject->findOne('users', [
|
||||
Query::equal('email', [$email]),
|
||||
]);
|
||||
if (!$userWithEmail->isEmpty()) {
|
||||
if (!$isVerified) {
|
||||
$failureRedirect(Exception::GENERAL_BAD_REQUEST);
|
||||
}
|
||||
$user->setAttributes($userWithEmail->getArrayCopy());
|
||||
}
|
||||
}
|
||||
|
||||
// If user is not found, check if there is an identity with the same email
|
||||
if ($user === false || $user->isEmpty()) {
|
||||
$identityWithMatchingEmail = $dbForProject->findOne('identities', [
|
||||
Query::equal('providerEmail', [$email]),
|
||||
]);
|
||||
if (!$identityWithMatchingEmail->isEmpty()) {
|
||||
if (!$isVerified) {
|
||||
$failureRedirect(Exception::GENERAL_BAD_REQUEST);
|
||||
}
|
||||
$user->setAttributes($dbForProject->getDocument('users', $identityWithMatchingEmail->getAttribute('userId'))->getArrayCopy());
|
||||
}
|
||||
}
|
||||
|
||||
if ($user === false || $user->isEmpty()) { // Last option -> create the user
|
||||
$limit = $project->getAttribute('auths', [])['limit'] ?? 0;
|
||||
|
||||
|
|
@ -1674,14 +1687,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
}
|
||||
}
|
||||
|
||||
// Makes sure this email is not already used in another identity
|
||||
$identityWithMatchingEmail = $dbForProject->findOne('identities', [
|
||||
Query::equal('providerEmail', [$email]),
|
||||
]);
|
||||
if (!$identityWithMatchingEmail->isEmpty()) {
|
||||
$failureRedirect(Exception::GENERAL_BAD_REQUEST); /** Return a generic bad request to prevent exposing existing accounts */
|
||||
}
|
||||
|
||||
try {
|
||||
$emailCanonical = new Email($email);
|
||||
} catch (Throwable) {
|
||||
|
|
@ -1735,7 +1740,6 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
|||
'providerType' => MESSAGE_TYPE_EMAIL,
|
||||
'identifier' => $email,
|
||||
]));
|
||||
|
||||
} catch (Duplicate) {
|
||||
$failureRedirect(Exception::USER_ALREADY_EXISTS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ App::post('/v1/projects')
|
|||
|
||||
// Hook allowing instant project mirroring during migration
|
||||
// Outside of migration, hook is not registered and has no effect
|
||||
$hooks->trigger('afterProjectCreation', [ $project, $pools, $cache ]);
|
||||
$hooks->trigger('afterProjectCreation', [$project, $pools, $cache]);
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
|
|
@ -2079,6 +2079,7 @@ App::patch('/v1/projects/:projectId/smtp')
|
|||
if ($enabled) {
|
||||
$mail = new PHPMailer(true);
|
||||
$mail->isSMTP();
|
||||
$mail->SMTPAuth = (!empty($username) && !empty($password));
|
||||
$mail->Username = $username;
|
||||
$mail->Password = $password;
|
||||
$mail->Host = $host;
|
||||
|
|
@ -2094,7 +2095,7 @@ App::patch('/v1/projects/:projectId/smtp')
|
|||
throw new Exception('Connection is not valid.');
|
||||
}
|
||||
} catch (Throwable $error) {
|
||||
throw new Exception(Exception::PROJECT_SMTP_CONFIG_INVALID, 'Could not connect to SMTP server: ' . $error->getMessage());
|
||||
throw new Exception(Exception::PROJECT_SMTP_CONFIG_INVALID, $error->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2665,7 +2666,7 @@ App::patch('/v1/projects/:projectId/auth/session-invalidation')
|
|||
$auths = $project->getAttribute('auths', []);
|
||||
$auths['invalidateSessions'] = $enabled;
|
||||
$dbForPlatform->updateDocument('projects', $project->getId(), $project
|
||||
->setAttribute('auths', $auths));
|
||||
->setAttribute('auths', $auths));
|
||||
|
||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1034,7 +1034,8 @@ App::init()
|
|||
->inject('dbForPlatform')
|
||||
->inject('queueForCertificates')
|
||||
->inject('platform')
|
||||
->action(function (Request $request, Document $console, Database $dbForPlatform, Certificate $queueForCertificates, array $platform) {
|
||||
->inject('authorization')
|
||||
->action(function (Request $request, Document $console, Database $dbForPlatform, Certificate $queueForCertificates, array $platform, Authorization $authorization) {
|
||||
$hostname = $request->getHostname();
|
||||
$cache = Config::getParam('hostnames', []);
|
||||
$platformHostnames = $platform['hostnames'] ?? [];
|
||||
|
|
@ -1065,7 +1066,7 @@ App::init()
|
|||
}
|
||||
|
||||
// 4. Check/create rule (requires DB access)
|
||||
Authorization::disable();
|
||||
$authorization->disable();
|
||||
try {
|
||||
// TODO: (@Meldiron) Remove after 1.7.x migration
|
||||
$isMd5 = System::getEnv('_APP_RULES_FORMAT') === 'md5';
|
||||
|
|
@ -1121,7 +1122,7 @@ App::init()
|
|||
} finally {
|
||||
$cache[$domain->get()] = true;
|
||||
Config::setParam('hostnames', $cache);
|
||||
Authorization::reset();
|
||||
$authorization->reset();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,28 @@ App::get('/v1/mock/tests/general/oauth2/user')
|
|||
'id' => 1,
|
||||
'name' => 'User Name',
|
||||
'email' => 'useroauth@localhost.test',
|
||||
'verified' => true,
|
||||
]);
|
||||
});
|
||||
|
||||
App::get('/v1/mock/tests/general/oauth2/user-unverified')
|
||||
->desc('OAuth2 User Unverified')
|
||||
->groups(['mock'])
|
||||
->label('scope', 'public')
|
||||
->label('docs', false)
|
||||
->param('token', '', new Text(100), 'OAuth2 Access Token.')
|
||||
->inject('response')
|
||||
->action(function (string $token, Response $response) {
|
||||
|
||||
if ($token != '123456') {
|
||||
throw new Exception(Exception::GENERAL_MOCK, 'Invalid token');
|
||||
}
|
||||
|
||||
$response->json([
|
||||
'id' => 2,
|
||||
'name' => 'User Name Unverified',
|
||||
'email' => 'useroauthunverified@localhost.test',
|
||||
'verified' => false,
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1131,6 +1131,9 @@ services:
|
|||
- "traefik.http.routers.appwrite_maildev_https.rule=Host(`mail.localhost`)"
|
||||
- "traefik.http.routers.appwrite_maildev_https.service=appwrite_maildev"
|
||||
- "traefik.http.routers.appwrite_maildev_https.tls=true"
|
||||
environment:
|
||||
- MAILDEV_INCOMING_USER=${_APP_SMTP_USERNAME}
|
||||
- MAILDEV_INCOMING_PASS=${_APP_SMTP_PASSWORD}
|
||||
|
||||
request-catcher-webhook: # used mainly for dev tests (mock HTTP webhook)
|
||||
image: appwrite/requestcatcher:1.0.0
|
||||
|
|
|
|||
|
|
@ -130,7 +130,9 @@ class Mock extends OAuth2
|
|||
*/
|
||||
public function isEmailVerified(string $accessToken): bool
|
||||
{
|
||||
return true;
|
||||
$user = $this->getUser($accessToken);
|
||||
|
||||
return $user['verified'] ?? true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
30
src/Appwrite/Auth/OAuth2/MockUnverified.php
Normal file
30
src/Appwrite/Auth/OAuth2/MockUnverified.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Auth\OAuth2;
|
||||
|
||||
class MockUnverified extends Mock
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'mock-unverified';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUser(string $accessToken): array
|
||||
{
|
||||
if (empty($this->user)) {
|
||||
$user = $this->request('GET', 'http://localhost/' . $this->version . '/mock/tests/general/oauth2/user-unverified?token=' . \urlencode($accessToken));
|
||||
|
||||
$this->user = \json_decode($user, true);
|
||||
}
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ class Create extends Action
|
|||
->setHttpPath('/v1/projects/:projectId/dev-keys')
|
||||
->desc('Create dev key')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('scope', 'devKeys.write')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'projects',
|
||||
group: 'devKeys',
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class Delete extends Action
|
|||
->setHttpPath('/v1/projects/:projectId/dev-keys/:keyId')
|
||||
->desc('Delete dev key')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('scope', 'devKeys.write')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'projects',
|
||||
group: 'devKeys',
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class Get extends Action
|
|||
->setHttpPath('/v1/projects/:projectId/dev-keys/:keyId')
|
||||
->desc('Get dev key')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.read')
|
||||
->label('scope', 'devKeys.read')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'projects',
|
||||
group: 'devKeys',
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class Update extends Action
|
|||
->setHttpPath('/v1/projects/:projectId/dev-keys/:keyId')
|
||||
->desc('Update dev key')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('scope', 'devKeys.write')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'projects',
|
||||
group: 'devKeys',
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class XList extends Action
|
|||
->setHttpPath('/v1/projects/:projectId/dev-keys')
|
||||
->desc('List dev keys')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.read')
|
||||
->label('scope', 'devKeys.read')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'projects',
|
||||
group: 'devKeys',
|
||||
|
|
|
|||
|
|
@ -161,9 +161,9 @@ trait ProjectCustom
|
|||
'senderEmail' => 'mailer@appwrite.io',
|
||||
'senderName' => 'Mailer',
|
||||
'host' => 'maildev',
|
||||
'port' => 1025,
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'port' => intval(System::getEnv('_APP_SMTP_PORT', "1025")),
|
||||
'username' => System::getEnv('_APP_SMTP_USERNAME', 'user'),
|
||||
'password' => System::getEnv('_APP_SMTP_PASSWORD', 'password'),
|
||||
]);
|
||||
|
||||
$project = [
|
||||
|
|
|
|||
|
|
@ -2183,6 +2183,157 @@ class AccountCustomClientTest extends Scope
|
|||
$this->assertEquals('tuvwxyz', $response['body']['providerRefreshToken']);
|
||||
$this->assertNotEquals($initialExpiry, $response['body']['providerAccessTokenExpiry']);
|
||||
|
||||
// Clean up - delete the user
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/users/' . $userId, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function testOAuthUnverifiedEmailCannotLinkToExistingAccount()
|
||||
{
|
||||
$provider = 'mock-unverified';
|
||||
$appId = '1';
|
||||
$secret = '123456';
|
||||
|
||||
// First, create a user with the same email that the unverified OAuth will try to use
|
||||
$email = 'useroauthunverified@localhost.test';
|
||||
$password = 'password';
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'userId' => ID::unique(),
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$existingUserId = $response['body']['$id'];
|
||||
|
||||
// Enable the mock-unverified provider
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $this->getProject()['$id'] . '/oauth2', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
|
||||
]), [
|
||||
'provider' => $provider,
|
||||
'appId' => $appId,
|
||||
'secret' => $secret,
|
||||
'enabled' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
// Attempt OAuth login with unverified email - should fail because existing user has same email
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'success' => 'http://localhost/v1/mock/tests/general/oauth2/success',
|
||||
'failure' => 'http://localhost/v1/mock/tests/general/oauth2/failure',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertEquals('failure', $response['body']['result']);
|
||||
|
||||
// Clean up - delete the user
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/users/' . $existingUserId, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function testOAuthVerifiedEmailCanLinkToExistingAccount()
|
||||
{
|
||||
$provider = 'mock';
|
||||
$appId = '1';
|
||||
$secret = '123456';
|
||||
$email = 'useroauth@localhost.test';
|
||||
|
||||
// Create a user with the same email that the verified OAuth will try to use
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'userId' => ID::unique(),
|
||||
'email' => $email,
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$existingUserId = $response['body']['$id'];
|
||||
|
||||
// Enable the mock provider
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $this->getProject()['$id'] . '/oauth2', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
|
||||
]), [
|
||||
'provider' => $provider,
|
||||
'appId' => $appId,
|
||||
'secret' => $secret,
|
||||
'enabled' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
// Attempt OAuth login with verified email - should succeed and link to existing account
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'success' => 'http://localhost/v1/mock/tests/general/oauth2/success',
|
||||
'failure' => 'http://localhost/v1/mock/tests/general/oauth2/failure',
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('success', $response['body']['result']);
|
||||
|
||||
// Verify the OAuth identity was linked to the existing user
|
||||
$sessionCookieKey = 'a_session_' . $this->getProject()['$id'];
|
||||
$session = $response['cookies'][$sessionCookieKey];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals($existingUserId, $response['body']['$id']);
|
||||
$this->assertEquals($email, $response['body']['email']);
|
||||
|
||||
// Clean up - delete the user
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/users/' . $existingUserId, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ class ProjectsConsoleClientTest extends Scope
|
|||
use Async;
|
||||
|
||||
/**
|
||||
* @group devKeys
|
||||
* @group smtpAndTemplates
|
||||
* @group projectsCRUD */
|
||||
* @group projectsCRUD
|
||||
*/
|
||||
public function testCreateProject(): array
|
||||
{
|
||||
/**
|
||||
|
|
@ -257,11 +257,11 @@ class ProjectsConsoleClientTest extends Scope
|
|||
'search' => $id
|
||||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertEquals($response['body']['total'], 3);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(4, $response['body']['total']);
|
||||
$this->assertIsArray($response['body']['projects']);
|
||||
$this->assertCount(3, $response['body']['projects']);
|
||||
$this->assertEquals($response['body']['projects'][0]['name'], 'Project Test');
|
||||
$this->assertCount(4, $response['body']['projects']);
|
||||
$this->assertEquals('Project Test', $response['body']['projects'][0]['name']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -271,9 +271,9 @@ class ProjectsConsoleClientTest extends Scope
|
|||
]));
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertEquals(3, $response['body']['total']);
|
||||
$this->assertEquals(4, $response['body']['total']);
|
||||
$this->assertIsArray($response['body']['projects']);
|
||||
$this->assertCount(3, $response['body']['projects']);
|
||||
$this->assertCount(4, $response['body']['projects']);
|
||||
$this->assertEquals($response['body']['projects'][0]['$id'], $data['projectId']);
|
||||
|
||||
/**
|
||||
|
|
@ -348,8 +348,8 @@ class ProjectsConsoleClientTest extends Scope
|
|||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertCount(1, $response['body']['projects']);
|
||||
$this->assertEquals('Project Test 2', $response['body']['projects'][0]['name']);
|
||||
$this->assertCount(2, $response['body']['projects']);
|
||||
$this->assertEquals('Team 1 Project', $response['body']['projects'][0]['name']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -376,7 +376,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertCount(4, $response['body']['projects']);
|
||||
$this->assertCount(5, $response['body']['projects']);
|
||||
$this->assertEquals('Project Test 2', $response['body']['projects'][0]['name']);
|
||||
$this->assertEquals('Team 1 Project', $response['body']['projects'][1]['name']);
|
||||
|
||||
|
|
@ -387,9 +387,9 @@ class ProjectsConsoleClientTest extends Scope
|
|||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertCount(4, $response['body']['projects']);
|
||||
$this->assertCount(5, $response['body']['projects']);
|
||||
$this->assertEquals('Project Test', $response['body']['projects'][0]['name']);
|
||||
$this->assertEquals('Team 1 Project', $response['body']['projects'][2]['name']);
|
||||
$this->assertEquals('Original Project', $response['body']['projects'][2]['name']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -402,8 +402,8 @@ class ProjectsConsoleClientTest extends Scope
|
|||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertCount(3, $response['body']['projects']);
|
||||
$this->assertEquals('Team 1 Project', $response['body']['projects'][1]['name']);
|
||||
$this->assertCount(4, $response['body']['projects']);
|
||||
$this->assertEquals('Original Project', $response['body']['projects'][1]['name']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -618,6 +618,14 @@ class ProjectsConsoleClientTest extends Scope
|
|||
public function testUpdateProjectSMTP($data): array
|
||||
{
|
||||
$id = $data['projectId'];
|
||||
$smtpHost = System::getEnv('_APP_SMTP_HOST', "maildev");
|
||||
$smtpPort = intval(System::getEnv('_APP_SMTP_PORT', "1025"));
|
||||
$smtpUsername = System::getEnv('_APP_SMTP_USERNAME', 'user');
|
||||
$smtpPassword = System::getEnv('_APP_SMTP_PASSWORD', 'password');
|
||||
|
||||
/**
|
||||
* Test for SUCCESS: Valid Credentials
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/smtp', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
|
@ -625,23 +633,23 @@ class ProjectsConsoleClientTest extends Scope
|
|||
'enabled' => true,
|
||||
'senderEmail' => 'mailer@appwrite.io',
|
||||
'senderName' => 'Mailer',
|
||||
'host' => 'maildev',
|
||||
'port' => 1025,
|
||||
'username' => 'user',
|
||||
'password' => 'password',
|
||||
'host' => $smtpHost,
|
||||
'port' => $smtpPort,
|
||||
'username' => $smtpUsername,
|
||||
'password' => $smtpPassword,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertTrue($response['body']['smtpEnabled']);
|
||||
$this->assertEquals('mailer@appwrite.io', $response['body']['smtpSenderEmail']);
|
||||
$this->assertEquals('Mailer', $response['body']['smtpSenderName']);
|
||||
$this->assertEquals('maildev', $response['body']['smtpHost']);
|
||||
$this->assertEquals(1025, $response['body']['smtpPort']);
|
||||
$this->assertEquals('user', $response['body']['smtpUsername']);
|
||||
$this->assertEquals('password', $response['body']['smtpPassword']);
|
||||
$this->assertEquals($smtpHost, $response['body']['smtpHost']);
|
||||
$this->assertEquals($smtpPort, $response['body']['smtpPort']);
|
||||
$this->assertEquals($smtpUsername, $response['body']['smtpUsername']);
|
||||
$this->assertEquals($smtpPassword, $response['body']['smtpPassword']);
|
||||
$this->assertEquals('', $response['body']['smtpSecure']);
|
||||
|
||||
/** Test Reading Project */
|
||||
// Check the project
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
|
@ -651,12 +659,32 @@ class ProjectsConsoleClientTest extends Scope
|
|||
$this->assertTrue($response['body']['smtpEnabled']);
|
||||
$this->assertEquals('mailer@appwrite.io', $response['body']['smtpSenderEmail']);
|
||||
$this->assertEquals('Mailer', $response['body']['smtpSenderName']);
|
||||
$this->assertEquals('maildev', $response['body']['smtpHost']);
|
||||
$this->assertEquals(1025, $response['body']['smtpPort']);
|
||||
$this->assertEquals('user', $response['body']['smtpUsername']);
|
||||
$this->assertEquals('password', $response['body']['smtpPassword']);
|
||||
$this->assertEquals($smtpHost, $response['body']['smtpHost']);
|
||||
$this->assertEquals($smtpPort, $response['body']['smtpPort']);
|
||||
$this->assertEquals($smtpUsername, $response['body']['smtpUsername']);
|
||||
$this->assertEquals($smtpPassword, $response['body']['smtpPassword']);
|
||||
$this->assertEquals('', $response['body']['smtpSecure']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE: Invalid Credentials
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/smtp', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'enabled' => true,
|
||||
'senderEmail' => 'fail@appwrite.io',
|
||||
'senderName' => 'Failing Mailer',
|
||||
'host' => $smtpHost,
|
||||
'port' => $smtpPort,
|
||||
'username' => 'invalid-user',
|
||||
'password' => 'bad-password',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertEquals(Exception::PROJECT_SMTP_CONFIG_INVALID, $response['body']['type']);
|
||||
$this->assertStringContainsStringIgnoringCase('Could not authenticate', $response['body']['message']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
|
@ -665,6 +693,11 @@ class ProjectsConsoleClientTest extends Scope
|
|||
*/
|
||||
public function testCreateProjectSMTPTests(): void
|
||||
{
|
||||
$smtpHost = System::getEnv('_APP_SMTP_HOST', "maildev");
|
||||
$smtpPort = intval(System::getEnv('_APP_SMTP_PORT', "1025"));
|
||||
$smtpUsername = System::getEnv('_APP_SMTP_USERNAME', 'user');
|
||||
$smtpPassword = System::getEnv('_APP_SMTP_PASSWORD', 'password');
|
||||
|
||||
// Create a team
|
||||
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -699,10 +732,10 @@ class ProjectsConsoleClientTest extends Scope
|
|||
'senderEmail' => 'custommailer@appwrite.io',
|
||||
'senderName' => 'Custom Mailer',
|
||||
'replyTo' => 'reply@appwrite.io',
|
||||
'host' => 'maildev',
|
||||
'port' => 1025,
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'host' => $smtpHost,
|
||||
'port' => $smtpPort,
|
||||
'username' => $smtpUsername,
|
||||
'password' => $smtpPassword,
|
||||
]);
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
|
|
@ -736,10 +769,10 @@ class ProjectsConsoleClientTest extends Scope
|
|||
'senderEmail' => 'custommailer@appwrite.io',
|
||||
'senderName' => 'Custom Mailer',
|
||||
'replyTo' => 'reply@appwrite.io',
|
||||
'host' => 'maildev',
|
||||
'port' => 1025,
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'host' => $smtpHost,
|
||||
'port' => $smtpPort,
|
||||
'username' => $smtpUsername,
|
||||
'password' => $smtpPassword,
|
||||
]);
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
|
|
@ -752,10 +785,10 @@ class ProjectsConsoleClientTest extends Scope
|
|||
'senderEmail' => 'custommailer@appwrite.io',
|
||||
'senderName' => 'Custom Mailer',
|
||||
'replyTo' => 'reply@appwrite.io',
|
||||
'host' => 'maildev',
|
||||
'port' => 1025,
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'host' => $smtpHost,
|
||||
'port' => $smtpPort,
|
||||
'username' => $smtpUsername,
|
||||
'password' => $smtpPassword,
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
|
@ -776,7 +809,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('Account Verification', $response['body']['subject']);
|
||||
$this->assertEquals('Account Verification for {{project}}', $response['body']['subject']);
|
||||
$this->assertEquals('', $response['body']['senderEmail']);
|
||||
$this->assertEquals('verification', $response['body']['type']);
|
||||
$this->assertEquals('en-us', $response['body']['locale']);
|
||||
|
|
@ -879,7 +912,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertEquals('Project Test 2', $response['body']['name']);
|
||||
$this->assertEquals('Project Test', $response['body']['name']);
|
||||
$this->assertArrayHasKey('platforms', $response['body']);
|
||||
$this->assertArrayHasKey('webhooks', $response['body']);
|
||||
$this->assertArrayHasKey('keys', $response['body']);
|
||||
|
|
@ -959,39 +992,6 @@ class ProjectsConsoleClientTest extends Scope
|
|||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(15, $response['body']['authDuration']);
|
||||
|
||||
// Create session
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
]), [
|
||||
'email' => $userEmail,
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
$sessionCookie = $response['headers']['set-cookie'];
|
||||
|
||||
// Wait 10 seconds, ensure valid session, extend session
|
||||
\sleep(10);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'Cookie' => $sessionCookie,
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/account/sessions/current', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'cookie' => $sessionCookie,
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
// Wait 20 seconds, ensure non-valid session
|
||||
\sleep(20);
|
||||
|
||||
|
|
@ -3132,7 +3132,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
$this->assertContains('users.write', $response['body']['scopes']);
|
||||
$this->assertContains('collections.read', $response['body']['scopes']);
|
||||
$this->assertContains('tables.read', $response['body']['scopes']);
|
||||
$this->assertCount(3, $response['body']['scopes']);
|
||||
$this->assertCount(4, $response['body']['scopes']);
|
||||
$this->assertArrayHasKey('sdks', $response['body']);
|
||||
$this->assertEmpty($response['body']['sdks']);
|
||||
$this->assertArrayHasKey('accessedAt', $response['body']);
|
||||
|
|
@ -3151,7 +3151,7 @@ class ProjectsConsoleClientTest extends Scope
|
|||
$this->assertContains('users.write', $response['body']['scopes']);
|
||||
$this->assertContains('collections.read', $response['body']['scopes']);
|
||||
$this->assertContains('tables.read', $response['body']['scopes']);
|
||||
$this->assertCount(3, $response['body']['scopes']);
|
||||
$this->assertCount(4, $response['body']['scopes']);
|
||||
$this->assertArrayHasKey('sdks', $response['body']);
|
||||
$this->assertEmpty($response['body']['sdks']);
|
||||
$this->assertArrayHasKey('accessedAt', $response['body']);
|
||||
|
|
@ -5086,8 +5086,8 @@ class ProjectsConsoleClientTest extends Scope
|
|||
$this->assertEmpty($response['body']);
|
||||
|
||||
/**
|
||||
* Get rate limit trying to use the deleted key
|
||||
*/
|
||||
* Get rate limit trying to use the deleted key
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
|
|
|
|||
Loading…
Reference in a new issue