diff --git a/app/config/locale/templates/email-certificate-failed.tpl b/app/config/locale/templates/email-certificate-failed.tpl index 18751ff412..0363fc6538 100644 --- a/app/config/locale/templates/email-certificate-failed.tpl +++ b/app/config/locale/templates/email-certificate-failed.tpl @@ -4,7 +4,9 @@
-

{{error}}

+

+ {{error}} +

diff --git a/app/config/locale/translations/en.json b/app/config/locale/translations/en.json index 953888013a..3a4a199e38 100644 --- a/app/config/locale/translations/en.json +++ b/app/config/locale/translations/en.json @@ -52,6 +52,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 will 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", "sms.verification.body": "{{secret}}", "locale.country.unknown": "Unknown", "countries.af": "Afghanistan", diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 7cab92da09..8b32349957 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -1786,7 +1786,7 @@ App::post('/v1/users/:userId/sessions') throw new Exception(Exception::USER_NOT_FOUND); } - $secret = Auth::codeGenerator(); + $secret = Auth::tokenGenerator(Auth::TOKEN_LENGTH_SESSION); $detector = new Detector($request->getUserAgent('UNKNOWN')); $record = $geodb->get($request->getIP()); @@ -1803,6 +1803,7 @@ App::post('/v1/users/:userId/sessions') 'userAgent' => $request->getUserAgent('UNKNOWN'), 'ip' => $request->getIP(), 'countryCode' => ($record) ? \strtolower($record['country']['iso_code']) : '--', + 'expire' => $expire, ], $detector->getOS(), $detector->getClient(), @@ -1814,7 +1815,6 @@ App::post('/v1/users/:userId/sessions') $session = $dbForProject->createDocument('sessions', $session); $session ->setAttribute('secret', $secret) - ->setAttribute('expire', $expire) ->setAttribute('countryName', $countryName); $queueForEvents diff --git a/app/init.php b/app/init.php index a0bd3b837b..2166fa812b 100644 --- a/app/init.php +++ b/app/init.php @@ -116,7 +116,7 @@ const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours const APP_USER_ACCCESS = 24 * 60 * 60; // 24 hours const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours -const APP_CACHE_BUSTER = 443; +const APP_CACHE_BUSTER = 4314; const APP_VERSION_STABLE = '1.5.7'; const APP_DATABASE_ATTRIBUTE_EMAIL = 'email'; const APP_DATABASE_ATTRIBUTE_ENUM = 'enum'; @@ -621,9 +621,9 @@ Database::addFilter( ]) )); if (\count($targetIds) > 0) { - return $database->find('targets', [ + return $database->skipValidation(fn () => $database->find('targets', [ Query::equal('$internalId', $targetIds) - ]); + ])); } return []; } diff --git a/composer.json b/composer.json index 9bdf194f73..d7b3e97c62 100644 --- a/composer.json +++ b/composer.json @@ -44,13 +44,13 @@ "ext-sockets": "*", "appwrite/php-runtimes": "0.14.*", "appwrite/php-clamav": "2.0.*", - "utopia-php/abuse": "0.37.*", + "utopia-php/abuse": "0.38.*", "utopia-php/analytics": "0.10.*", - "utopia-php/audit": "0.39.*", + "utopia-php/audit": "0.40.*", "utopia-php/cache": "0.10.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.49.*", + "utopia-php/database": "0.50.*", "utopia-php/domains": "0.5.*", "utopia-php/dsn": "0.2.1", "utopia-php/framework": "0.33.*", diff --git a/composer.lock b/composer.lock index e18350a15a..e0e6628e43 100644 --- a/composer.lock +++ b/composer.lock @@ -1428,23 +1428,23 @@ }, { "name": "utopia-php/abuse", - "version": "0.37.1", + "version": "0.38.0", "source": { "type": "git", "url": "https://github.com/utopia-php/abuse.git", - "reference": "4dfcff4754c7804d1a70039792c0f2d59a5cc981" + "reference": "b7be9086c9d9b4561d810cbd42fdda798742f56c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/abuse/zipball/4dfcff4754c7804d1a70039792c0f2d59a5cc981", - "reference": "4dfcff4754c7804d1a70039792c0f2d59a5cc981", + "url": "https://api.github.com/repos/utopia-php/abuse/zipball/b7be9086c9d9b4561d810cbd42fdda798742f56c", + "reference": "b7be9086c9d9b4561d810cbd42fdda798742f56c", "shasum": "" }, "require": { "ext-curl": "*", "ext-pdo": "*", "php": ">=8.0", - "utopia-php/database": "0.49.*" + "utopia-php/database": "0.50.*" }, "require-dev": { "laravel/pint": "1.5.*", @@ -1471,9 +1471,9 @@ ], "support": { "issues": "https://github.com/utopia-php/abuse/issues", - "source": "https://github.com/utopia-php/abuse/tree/0.37.1" + "source": "https://github.com/utopia-php/abuse/tree/0.38.0" }, - "time": "2024-06-05T18:03:59+00:00" + "time": "2024-06-24T00:52:02+00:00" }, { "name": "utopia-php/analytics", @@ -1523,21 +1523,21 @@ }, { "name": "utopia-php/audit", - "version": "0.39.1", + "version": "0.40.0", "source": { "type": "git", "url": "https://github.com/utopia-php/audit.git", - "reference": "7ea91e0ceea7b94293612fea94022b73315677c2" + "reference": "735ae211ce5fee5b52b736731571b4030b1d7cdc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/audit/zipball/7ea91e0ceea7b94293612fea94022b73315677c2", - "reference": "7ea91e0ceea7b94293612fea94022b73315677c2", + "url": "https://api.github.com/repos/utopia-php/audit/zipball/735ae211ce5fee5b52b736731571b4030b1d7cdc", + "reference": "735ae211ce5fee5b52b736731571b4030b1d7cdc", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/database": "0.49.*" + "utopia-php/database": "0.50.*" }, "require-dev": { "laravel/pint": "1.5.*", @@ -1564,9 +1564,9 @@ ], "support": { "issues": "https://github.com/utopia-php/audit/issues", - "source": "https://github.com/utopia-php/audit/tree/0.39.1" + "source": "https://github.com/utopia-php/audit/tree/0.40.0" }, - "time": "2024-06-05T19:28:22+00:00" + "time": "2024-06-24T00:52:17+00:00" }, { "name": "utopia-php/cache", @@ -1720,16 +1720,16 @@ }, { "name": "utopia-php/database", - "version": "0.49.14", + "version": "0.50.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "415588c0b98edee9d72cdfe269ff79b14cd8f56d" + "reference": "ce3eaccb2f3bbd34b2b97419836fec633b26b8f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/415588c0b98edee9d72cdfe269ff79b14cd8f56d", - "reference": "415588c0b98edee9d72cdfe269ff79b14cd8f56d", + "url": "https://api.github.com/repos/utopia-php/database/zipball/ce3eaccb2f3bbd34b2b97419836fec633b26b8f7", + "reference": "ce3eaccb2f3bbd34b2b97419836fec633b26b8f7", "shasum": "" }, "require": { @@ -1770,9 +1770,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.49.14" + "source": "https://github.com/utopia-php/database/tree/0.50.0" }, - "time": "2024-06-20T02:39:23+00:00" + "time": "2024-06-21T03:21:42+00:00" }, { "name": "utopia-php/domains", diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 15c14daf51..e3a2021c1a 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -239,7 +239,7 @@ abstract class Migration } /** - * Creates colletion from the config collection. + * Creates collection from the config collection. * * @param string $id * @param string|null $name @@ -266,6 +266,7 @@ abstract class Migration 'type' => $attribute['type'], 'size' => $attribute['size'], 'required' => $attribute['required'], + 'default' => $attribute['default'] ?? null, 'signed' => $attribute['signed'], 'array' => $attribute['array'], 'filters' => $attribute['filters'], diff --git a/src/Appwrite/Migration/Version/V20.php b/src/Appwrite/Migration/Version/V20.php index 1a599d32f2..5a0807cedf 100644 --- a/src/Appwrite/Migration/Version/V20.php +++ b/src/Appwrite/Migration/Version/V20.php @@ -336,6 +336,32 @@ class V20 extends Migration Console::warning("Purge cache from {$id}: {$th->getMessage()}"); } + break; + case 'topics': + try { + $this->projectDB->updateAttributeDefault($id, 'emailTotal', 0); + } catch (Throwable $th) { + Console::warning("'topics' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->updateAttributeDefault($id, 'pushTotal', 0); + } catch (Throwable $th) { + Console::warning("'topics' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->updateAttributeDefault($id, 'smsTotal', 0); + } catch (Throwable $th) { + Console::warning("'topics' from {$id}: {$th->getMessage()}"); + } + + try { + $this->projectDB->purgeCachedCollection($id); + } catch (Throwable $th) { + Console::warning("Purge cache from {$id}: {$th->getMessage()}"); + } + break; } diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index ad6cf09fa7..58dc1dd28a 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -439,40 +439,24 @@ class Certificates extends Action $locale = new Locale(System::getEnv('_APP_LOCALE', 'en')); - // Send mail to administratore mail + // Send mail to administrator mail $template = Template::fromFile(__DIR__ . '/../../../../app/config/locale/templates/email-certificate-failed.tpl'); $template->setParam('{{domain}}', $domain); $template->setParam('{{error}}', \nl2br($errorMessage)); $template->setParam('{{attempts}}', $attempt); - - // TODO: Use setbodyTemplate once #7307 is merged - $subject = 'Certificate failed to generate'; - $body = Template::fromFile(__DIR__ . '/../../../../app/config/locale/templates/email-base-styled.tpl'); - - $subject = \sprintf($locale->getText("emails.certificate.subject"), $domain); - - $message = Template::fromFile(__DIR__ . '/../../../../app/config/locale/templates/email-inner-base.tpl'); - $message - ->setParam('{{body}}', $locale->getText("emails.certificate.body"), escapeHtml: false) - ->setParam('{{hello}}', $locale->getText("emails.certificate.hello")) - ->setParam('{{footer}}', $locale->getText("emails.certificate.footer")) - ->setParam('{{thanks}}', $locale->getText("emails.certificate.thanks")) - ->setParam('{{signature}}', $locale->getText("emails.certificate.signature")); - $body = $message->render(); + $body = $template->render(); $emailVariables = [ 'direction' => $locale->getText('settings.direction'), - 'domain' => $domain, - 'error' => '
' . $errorMessage . '
', - 'attempt' => $attempt, - 'project' => 'Console', - 'redirect' => 'https://' . $domain, ]; + $subject = \sprintf($locale->getText("emails.certificate.subject"), $domain); + $queueForMails ->setSubject($subject) ->setBody($body) ->setName('Appwrite Administrator') + ->setbodyTemplate(__DIR__ . '/../../../../app/config/locale/templates/email-base-styled.tpl') ->setVariables($emailVariables) ->setRecipient(System::getEnv('_APP_EMAIL_CERTIFICATES', System::getEnv('_APP_SYSTEM_SECURITY_EMAIL_ADDRESS'))) ->trigger(); diff --git a/tests/e2e/Services/Health/HealthCustomServerTest.php b/tests/e2e/Services/Health/HealthCustomServerTest.php index 335e44be1b..8360af542e 100644 --- a/tests/e2e/Services/Health/HealthCustomServerTest.php +++ b/tests/e2e/Services/Health/HealthCustomServerTest.php @@ -455,7 +455,7 @@ class HealthCustomServerTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals('/CN=www.google.com', $response['body']['name']); $this->assertEquals('www.google.com', $response['body']['subjectSN']); - $this->assertEquals('Google Trust Services', $response['body']['issuerOrganisation']); + $this->assertStringContainsString('Google Trust Services', $response['body']['issuerOrganisation']); $this->assertIsInt($response['body']['validFrom']); $this->assertIsInt($response['body']['validTo']); diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 0540479eb5..dc5ddb9d70 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -511,6 +511,55 @@ trait MessagingBase ]; } + public function testSubscriberTargetSubQuery() + { + $response = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'topicId' => 'sub-query-test', + 'name' => 'sub-query-test', + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + + $topic = $response['body']; + + $prefix = uniqid(); + + for ($i = 1; $i <= 101; $i++) { + $response = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => "$prefix-$i", + 'email' => "$prefix-$i@example.com", + 'password' => 'password', + 'name' => "User $prefix $i", + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + $user = $response['body']; + $targets = $user['targets'] ?? []; + + $this->assertGreaterThan(0, count($targets)); + + $target = $targets[0]; + + $response = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => $user['$id'], + 'targetId' => $target['$id'], + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + } + } + /** * @depends testCreateSubscriber */ diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index 5af4aa751a..c34227e4de 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -290,6 +290,28 @@ trait UsersBase $this->assertArrayNotHasKey('secret', $token['body']); } + /** + * @depends testCreateUser + */ + public function testCreateSession(array $data): void + { + /** + * Test for SUCCESS + */ + $response = $this->client->call(Client::METHOD_POST, '/users/' . $data['userId'] . '/sessions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(201, $response['headers']['status-code']); + + $session = $response['body']; + $this->assertEquals($data['userId'], $session['userId']); + $this->assertNotEmpty($session['secret']); + $this->assertNotEmpty($session['expire']); + $this->assertEquals('server', $session['provider']); + } + /** * Tests all optional parameters of createUser (email, phone, anonymous..)