diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index e95481cc9a..429ebeb52f 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -586,8 +586,6 @@ App::post('/v1/projects/:projectId/webhooks') $security = (bool) filter_var($security, FILTER_VALIDATE_BOOLEAN); - - $webhook = new Document([ '$id' => $dbForConsole->getId(), '$read' => ['role:all'], @@ -694,10 +692,9 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.') ->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true) ->param('httpPass', '', new Text(256), 'Webhook HTTP password. Max length: 256 chars.', true) - ->param('signatureKey', null, new Text(256), 'Webhook signature key. Max length: 256 chars.', true) ->inject('response') ->inject('dbForConsole') - ->action(function (string $projectId, string $webhookId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, string $signatureKey, Response $response, Database $dbForConsole) { + ->action(function (string $projectId, string $webhookId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) { $project = $dbForConsole->getDocument('projects', $projectId); @@ -725,10 +722,45 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->setAttribute('httpPass', $httpPass) ; - if (!empty($signatureKey)) { - $webhook->setAttribute('signatureKey', $signatureKey); + $dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook); + $dbForConsole->deleteCachedDocument('projects', $project->getId()); + + $response->dynamic($webhook, Response::MODEL_WEBHOOK); + }); + +App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature') + ->desc('Update Webhook Signature Key') + ->groups(['api', 'projects']) + ->label('scope', 'projects.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'projects') + ->label('sdk.method', 'updateWebhookSignature') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_WEBHOOK) + ->param('projectId', null, new UID(), 'Project unique ID.') + ->param('webhookId', null, new UID(), 'Webhook unique ID.') + ->inject('response') + ->inject('dbForConsole') + ->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) { + + $project = $dbForConsole->getDocument('projects', $projectId); + + if ($project->isEmpty()) { + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } + $webhook = $dbForConsole->findOne('webhooks', [ + new Query('_uid', Query::TYPE_EQUAL, [$webhookId]), + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) + ]); + + if ($webhook === false || $webhook->isEmpty()) { + throw new Exception('Webhook not found', 404, Exception::WEBHOOK_NOT_FOUND); + } + + $webhook->setAttribute('signatureKey', \bin2hex(\random_bytes(64))); + $dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook); $dbForConsole->deleteCachedDocument('projects', $project->getId()); diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index eacd1a1ca3..81c33c5e35 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -913,7 +913,7 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(true, $response['body']['security']); $this->assertEquals('username', $response['body']['httpUser']); - $data = array_merge($data, ['webhookId' => $response['body']['$id']]); + $data = array_merge($data, ['webhookId' => $response['body']['$id'], 'signatureKey' => $response['body']['signatureKey']]); /** * Test for FAILURE @@ -1021,8 +1021,7 @@ class ProjectsConsoleClientTest extends Scope 'url' => 'https://appwrite.io/new', 'security' => false, 'httpUser' => '', - 'httpPass' => '', - 'signatureKey' => 'My own uniq key', + 'httpPass' => '' ]); $this->assertEquals(200, $response['headers']['status-code']); @@ -1038,7 +1037,6 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(false, $response['body']['security']); $this->assertEquals('', $response['body']['httpUser']); $this->assertEquals('', $response['body']['httpPass']); - $this->assertEquals('My own uniq key', $response['body']['signatureKey']); $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id . '/webhooks/' . $webhookId, array_merge([ 'content-type' => 'application/json', @@ -1104,6 +1102,25 @@ class ProjectsConsoleClientTest extends Scope return $data; } + /** + * @depends testCreateProjectWebhook + */ + public function testUpdateProjectWebhookSignature($data): void + { + $id = $data['projectId'] ?? ''; + $webhookId = $data['webhookId'] ?? ''; + $signatureKey = $data['signatureKey'] ?? ''; + + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/webhooks/' . $webhookId . '/signature', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['signatureKey']); + $this->assertNotEquals($signatureKey, $response['body']['signatureKey']); + } + /** * @depends testCreateProjectWebhook */