fix: Throw error when file token expiry is in the past

This commit is contained in:
Hemachandar
2025-11-03 16:53:44 +05:30
parent 0e6d3279d7
commit 10a9845898
5 changed files with 71 additions and 11 deletions
+1
View File
@@ -31,6 +31,7 @@
<directory>./tests/e2e/Services/Locale</directory>
<directory>./tests/e2e/Services/Projects</directory>
<directory>./tests/e2e/Services/Storage</directory>
<directory>./tests/e2e/Services/Tokens</directory>
<directory>./tests/e2e/Services/Webhooks</directory>
<directory>./tests/e2e/Services/Messaging</directory>
<directory>./tests/e2e/Services/Migrations</directory>
@@ -17,7 +17,7 @@ use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Nullable;
use Utopia\Validator\Text;
class Create extends Action
{
@@ -61,7 +61,7 @@ class Create extends Action
))
->param('bucketId', '', new UID(), 'Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).')
->param('fileId', '', new UID(), 'File unique ID.')
->param('expire', null, new Nullable(new DatetimeValidator()), 'Token expiry date', true)
->param('expire', null, new Text(100), 'Token expiry date', true)
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
@@ -70,6 +70,13 @@ class Create extends Action
public function action(string $bucketId, string $fileId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents): void
{
if (!is_null($expire)) {
$validator = new DatetimeValidator(requireDateInFuture: true, precision: DateTimeValidator::PRECISION_DAYS, offset: 0);
if (!$validator->isValid($expire)) {
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Token expiry date must be a valid date, and at least 1 day from now');
}
}
/**
* @var Document $bucket
@@ -14,7 +14,7 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Nullable;
use Utopia\Validator\Text;
class Update extends Action
{
@@ -57,7 +57,7 @@ class Update extends Action
contentType: ContentType::JSON
))
->param('tokenId', '', new UID(), 'Token unique ID.')
->param('expire', null, new Nullable(new DatetimeValidator()), 'File token expiry date', true)
->param('expire', null, new Text(100), 'File token expiry date', true)
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
@@ -66,6 +66,13 @@ class Update extends Action
public function action(string $tokenId, ?string $expire, Response $response, Database $dbForProject, Event $queueForEvents)
{
if (!is_null($expire)) {
$validator = new DatetimeValidator(requireDateInFuture: true, precision: DateTimeValidator::PRECISION_DAYS, offset: 0);
if (!$validator->isValid($expire)) {
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Token expiry date must be a valid date, and at least 1 day from now');
}
}
$token = $dbForProject->getDocument('resourceTokens', $tokenId);
if ($token->isEmpty()) {
@@ -9,7 +9,6 @@ use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideServer;
use Utopia\Database\DateTime;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
@@ -63,10 +62,23 @@ class TokensConsoleClientTest extends Scope
$fileId = $file['body']['$id'];
// Failure case: Expire date is in the past
$token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()));
], $this->getHeaders()), [
'expire' => '2022-11-02',
]);
$this->assertEquals(400, $token['headers']['status-code']);
$this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']);
// Success case: No expire date
$token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()), [
'expire' => null,
]);
$this->assertEquals(201, $token['headers']['status-code']);
$this->assertEquals('files', $token['body']['resourceType']);
@@ -107,8 +119,19 @@ class TokensConsoleClientTest extends Scope
{
$tokenId = $data['tokenId'];
// Failure case: Expire date is in the past
$token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'expire' => '2022-11-02',
]);
$this->assertEquals(400, $token['headers']['status-code']);
$this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']);
// Finite expiry
$expiry = DateTime::addSeconds(new \DateTime(), 3600);
$expiry = date('Y-m-d', strtotime("tomorrow"));
$token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
@@ -7,7 +7,6 @@ use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideServer;
use Utopia\Database\DateTime;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
@@ -61,6 +60,17 @@ class TokensCustomServerTest extends Scope
$fileId = $file['body']['$id'];
// Failure case: Expire date is in the past
$token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()), [
'expire' => '2022-11-02',
]);
$this->assertEquals(400, $token['headers']['status-code']);
$this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']);
// Success case: No expire date
$token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
@@ -83,8 +93,19 @@ class TokensCustomServerTest extends Scope
{
$tokenId = $data['tokenId'];
// Finite expiry
$expiry = DateTime::addSeconds(new \DateTime(), 3600);
// Failure case: Expire date is in the past
$token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'expire' => '2022-11-02',
]);
$this->assertEquals(400, $token['headers']['status-code']);
$this->assertEquals('Token expiry date must be a valid date, and at least 1 day from now', $token['body']['message']);
// Success case: Finite expiry
$expiry = date('Y-m-d', strtotime("tomorrow"));
$token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -94,9 +115,10 @@ class TokensCustomServerTest extends Scope
]);
$dateValidator = new DatetimeValidator();
$this->assertEquals(200, $token['headers']['status-code']);
$this->assertTrue($dateValidator->isValid($token['body']['expire']));
// Infinite expiry
// Success case: Infinite expiry
$token = $this->client->call(Client::METHOD_PATCH, '/tokens/' . $tokenId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],