diff options
author | Côme Chilliet <come.chilliet@nextcloud.com> | 2024-06-24 16:19:03 +0200 |
---|---|---|
committer | Côme Chilliet <come.chilliet@nextcloud.com> | 2024-07-02 11:24:33 +0200 |
commit | 44d707c97b54ed3b2ae352f6ddfa8caa213e27e8 (patch) | |
tree | b556ab63123b52224754158f1cdb881a733501ef /apps | |
parent | 164f4a3ea3a3ae8f8adc05b766782f49d7e69832 (diff) | |
download | nextcloud-server-44d707c97b54ed3b2ae352f6ddfa8caa213e27e8.tar.gz nextcloud-server-44d707c97b54ed3b2ae352f6ddfa8caa213e27e8.zip |
feat(webhooks): Add support for a userid filter
This allows to register a userId to filter on along with the webhooks.
This webhook will then only be triggered if the given userId is the one
in session. This is more efficient than filtering by user in the event
filter because the listener is not even registered if the user id does
not match.
Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
Diffstat (limited to 'apps')
7 files changed, 42 insertions, 10 deletions
diff --git a/apps/webhook_listeners/lib/AppInfo/Application.php b/apps/webhook_listeners/lib/AppInfo/Application.php index d1ffa5db49b..30f2e0969f6 100644 --- a/apps/webhook_listeners/lib/AppInfo/Application.php +++ b/apps/webhook_listeners/lib/AppInfo/Application.php @@ -16,6 +16,7 @@ use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\EventDispatcher\IEventDispatcher; +use OCP\IUserSession; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -40,9 +41,10 @@ class Application extends App implements IBootstrap { ): void { /** @var WebhookListenerMapper */ $mapper = $container->get(WebhookListenerMapper::class); + $userSession = $container->get(IUserSession::class); /* Listen to all events with at least one webhook configured */ - $configuredEvents = $mapper->getAllConfiguredEvents(); + $configuredEvents = $mapper->getAllConfiguredEvents($userSession->getUser()?->getUID()); foreach ($configuredEvents as $eventName) { $logger->debug("Listening to {$eventName}"); $dispatcher->addServiceListener( diff --git a/apps/webhook_listeners/lib/Controller/WebhooksController.php b/apps/webhook_listeners/lib/Controller/WebhooksController.php index 5b097c84a3c..a4de0c8d342 100644 --- a/apps/webhook_listeners/lib/Controller/WebhooksController.php +++ b/apps/webhook_listeners/lib/Controller/WebhooksController.php @@ -126,6 +126,7 @@ class WebhooksController extends OCSController { string $uri, string $event, ?array $eventFilter, + ?string $userIdFilter, ?array $headers, ?string $authMethod, #[\SensitiveParameter] @@ -150,6 +151,7 @@ class WebhooksController extends OCSController { $uri, $event, $eventFilter, + $userIdFilter, $headers, $authMethod, $authData, @@ -193,6 +195,7 @@ class WebhooksController extends OCSController { string $uri, string $event, ?array $eventFilter, + ?string $userIdFilter, ?array $headers, ?string $authMethod, #[\SensitiveParameter] @@ -218,6 +221,7 @@ class WebhooksController extends OCSController { $uri, $event, $eventFilter, + $userIdFilter, $headers, $authMethod, $authData, diff --git a/apps/webhook_listeners/lib/Db/WebhookListener.php b/apps/webhook_listeners/lib/Db/WebhookListener.php index e9b63e01472..680d47798d5 100644 --- a/apps/webhook_listeners/lib/Db/WebhookListener.php +++ b/apps/webhook_listeners/lib/Db/WebhookListener.php @@ -60,6 +60,12 @@ class WebhookListener extends Entity implements \JsonSerializable { protected $eventFilter; /** + * @var string + * If not empty, id of the user that needs to be connected for the webhook to trigger + */ + protected $userIdFilter; + + /** * @var ?array */ protected $headers = null; @@ -90,6 +96,7 @@ class WebhookListener extends Entity implements \JsonSerializable { $this->addType('uri', 'string'); $this->addType('event', 'string'); $this->addType('eventFilter', 'json'); + $this->addType('userIdFilter', 'string'); $this->addType('headers', 'json'); $this->addType('authMethod', 'string'); $this->addType('authData', 'string'); diff --git a/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php b/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php index a1fe4ceee8d..ad8c287ad43 100644 --- a/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php +++ b/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php @@ -25,7 +25,7 @@ use OCP\IDBConnection; class WebhookListenerMapper extends QBMapper { public const TABLE_NAME = 'webhook_listeners'; - private const EVENTS_CACHE_KEY = 'eventsUsedInWebhooks'; + private const EVENTS_CACHE_KEY_PREFIX = 'eventsUsedInWebhooks'; private ?ICache $cache = null; @@ -77,6 +77,7 @@ class WebhookListenerMapper extends QBMapper { string $uri, string $event, ?array $eventFilter, + ?string $userIdFilter, ?array $headers, AuthMethod $authMethod, #[\SensitiveParameter] @@ -95,12 +96,13 @@ class WebhookListenerMapper extends QBMapper { 'uri' => $uri, 'event' => $event, 'eventFilter' => $eventFilter ?? [], + 'userIdFilter' => $userIdFilter ?? '', 'headers' => $headers, 'authMethod' => $authMethod->value, ] ); $webhookListener->setAuthDataClear($authData); - $this->cache?->remove(self::EVENTS_CACHE_KEY); + $this->cache?->remove($this->buildCacheKey($userIdFilter)); return $this->insert($webhookListener); } @@ -115,6 +117,7 @@ class WebhookListenerMapper extends QBMapper { string $uri, string $event, ?array $eventFilter, + ?string $userIdFilter, ?array $headers, AuthMethod $authMethod, #[\SensitiveParameter] @@ -134,12 +137,13 @@ class WebhookListenerMapper extends QBMapper { 'uri' => $uri, 'event' => $event, 'eventFilter' => $eventFilter ?? [], + 'userIdFilter' => $userIdFilter ?? '', 'headers' => $headers, 'authMethod' => $authMethod->value, ] ); $webhookListener->setAuthDataClear($authData); - $this->cache?->remove(self::EVENTS_CACHE_KEY); + $this->cache?->remove($this->buildCacheKey($userIdFilter)); return $this->update($webhookListener); } @@ -159,11 +163,12 @@ class WebhookListenerMapper extends QBMapper { * @throws Exception * @return list<string> */ - private function getAllConfiguredEventsFromDatabase(): array { + private function getAllConfiguredEventsFromDatabase(string $userId): array { $qb = $this->db->getQueryBuilder(); $qb->selectDistinct('event') - ->from($this->getTableName()); + ->from($this->getTableName()) + ->where($qb->expr()->in('user_id_filter', $qb->createNamedParameter(['',$userId], IQueryBuilder::PARAM_STR_ARRAY), IQueryBuilder::PARAM_STR)); $result = $qb->executeQuery(); @@ -181,14 +186,15 @@ class WebhookListenerMapper extends QBMapper { * @throws Exception * @return list<string> */ - public function getAllConfiguredEvents(): array { - $events = $this->cache?->get(self::EVENTS_CACHE_KEY); + public function getAllConfiguredEvents(?string $userId = null): array { + $cacheKey = $this->buildCacheKey($userId); + $events = $this->cache?->get($cacheKey); if ($events !== null) { return json_decode($events); } - $events = $this->getAllConfiguredEventsFromDatabase(); + $events = $this->getAllConfiguredEventsFromDatabase($userId ?? ''); // cache for 5 minutes - $this->cache?->set(self::EVENTS_CACHE_KEY, json_encode($events), 300); + $this->cache?->set($cacheKey, json_encode($events), 300); return $events; } @@ -217,4 +223,8 @@ class WebhookListenerMapper extends QBMapper { return $this->findEntities($qb); } + + private function buildCacheKey(?string $userIdFilter = ''): string { + return self::EVENTS_CACHE_KEY_PREFIX.'_'.($userIdFilter ?? ''); + } } diff --git a/apps/webhook_listeners/lib/Migration/Version1000Date20240527153425.php b/apps/webhook_listeners/lib/Migration/Version1000Date20240527153425.php index 44f2476dd44..6693c8ecf3f 100755 --- a/apps/webhook_listeners/lib/Migration/Version1000Date20240527153425.php +++ b/apps/webhook_listeners/lib/Migration/Version1000Date20240527153425.php @@ -53,6 +53,10 @@ class Version1000Date20240527153425 extends SimpleMigrationStep { $table->addColumn('event_filter', Types::TEXT, [ 'notnull' => false, ]); + $table->addColumn('user_id_filter', Types::STRING, [ + 'notnull' => true, + 'length' => 64, + ]); $table->addColumn('headers', Types::TEXT, [ 'notnull' => false, ]); diff --git a/apps/webhook_listeners/lib/ResponseDefinitions.php b/apps/webhook_listeners/lib/ResponseDefinitions.php index cb33f93e8ff..725e00b118a 100644 --- a/apps/webhook_listeners/lib/ResponseDefinitions.php +++ b/apps/webhook_listeners/lib/ResponseDefinitions.php @@ -17,6 +17,7 @@ namespace OCA\WebhookListeners; * uri: string, * event?: string, * eventFilter?: array<string,mixed>, + * userIdFilter?: string, * headers?: array<string,string>, * authMethod: string, * authData?: array<string,mixed>, diff --git a/apps/webhook_listeners/tests/Db/WebhookListenerMapperTest.php b/apps/webhook_listeners/tests/Db/WebhookListenerMapperTest.php index fc42a0a9597..327d5740077 100644 --- a/apps/webhook_listeners/tests/Db/WebhookListenerMapperTest.php +++ b/apps/webhook_listeners/tests/Db/WebhookListenerMapperTest.php @@ -58,6 +58,7 @@ class WebhookListenerMapperTest extends TestCase { UserCreatedEvent::class, null, null, + null, AuthMethod::None, null, ); @@ -72,6 +73,7 @@ class WebhookListenerMapperTest extends TestCase { NodeWrittenEvent::class, null, null, + null, AuthMethod::None, null, ); @@ -92,6 +94,7 @@ class WebhookListenerMapperTest extends TestCase { NodeWrittenEvent::class, null, null, + null, AuthMethod::None, null, ); @@ -111,6 +114,7 @@ class WebhookListenerMapperTest extends TestCase { NodeWrittenEvent::class, null, null, + null, AuthMethod::Header, ['secretHeader' => 'header'], ); |