diff --git a/apps/webhook_listeners/appinfo/info.xml b/apps/webhook_listeners/appinfo/info.xml
index fae9f417aba31..65a02f0299762 100644
--- a/apps/webhook_listeners/appinfo/info.xml
+++ b/apps/webhook_listeners/appinfo/info.xml
@@ -18,7 +18,7 @@ Administrators can configure webhook listeners via the app's OCS API. The app al
]]>
- 1.4.1
+ 1.5.0
agpl
Côme Chilliet
WebhookListeners
@@ -49,4 +49,8 @@ Administrators can configure webhook listeners via the app's OCS API. The app al
OCA\WebhookListeners\Settings\Admin
OCA\WebhookListeners\Settings\AdminSection
+
+
+ OCA\WebhookListeners\BackgroundJobs\WebhookTokenCleanup
+
diff --git a/apps/webhook_listeners/composer/composer/autoload_classmap.php b/apps/webhook_listeners/composer/composer/autoload_classmap.php
index 959b4c1d2ae25..22349364e08aa 100644
--- a/apps/webhook_listeners/composer/composer/autoload_classmap.php
+++ b/apps/webhook_listeners/composer/composer/autoload_classmap.php
@@ -9,16 +9,21 @@
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'OCA\\WebhookListeners\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
'OCA\\WebhookListeners\\BackgroundJobs\\WebhookCall' => $baseDir . '/../lib/BackgroundJobs/WebhookCall.php',
+ 'OCA\\WebhookListeners\\BackgroundJobs\\WebhookTokenCleanup' => $baseDir . '/../lib/BackgroundJobs/WebhookTokenCleanup.php',
'OCA\\WebhookListeners\\Command\\ListWebhooks' => $baseDir . '/../lib/Command/ListWebhooks.php',
'OCA\\WebhookListeners\\Controller\\WebhooksController' => $baseDir . '/../lib/Controller/WebhooksController.php',
'OCA\\WebhookListeners\\Db\\AuthMethod' => $baseDir . '/../lib/Db/AuthMethod.php',
+ 'OCA\\WebhookListeners\\Db\\EphemeralToken' => $baseDir . '/../lib/Db/EphemeralToken.php',
+ 'OCA\\WebhookListeners\\Db\\EphemeralTokenMapper' => $baseDir . '/../lib/Db/EphemeralTokenMapper.php',
'OCA\\WebhookListeners\\Db\\WebhookListener' => $baseDir . '/../lib/Db/WebhookListener.php',
'OCA\\WebhookListeners\\Db\\WebhookListenerMapper' => $baseDir . '/../lib/Db/WebhookListenerMapper.php',
'OCA\\WebhookListeners\\Listener\\WebhooksEventListener' => $baseDir . '/../lib/Listener/WebhooksEventListener.php',
'OCA\\WebhookListeners\\Migration\\Version1000Date20240527153425' => $baseDir . '/../lib/Migration/Version1000Date20240527153425.php',
'OCA\\WebhookListeners\\Migration\\Version1001Date20240716184935' => $baseDir . '/../lib/Migration/Version1001Date20240716184935.php',
+ 'OCA\\WebhookListeners\\Migration\\Version1500Date20251007130000' => $baseDir . '/../lib/Migration/Version1500Date20251007130000.php',
'OCA\\WebhookListeners\\ResponseDefinitions' => $baseDir . '/../lib/ResponseDefinitions.php',
'OCA\\WebhookListeners\\Service\\PHPMongoQuery' => $baseDir . '/../lib/Service/PHPMongoQuery.php',
+ 'OCA\\WebhookListeners\\Service\\TokenService' => $baseDir . '/../lib/Service/TokenService.php',
'OCA\\WebhookListeners\\Settings\\Admin' => $baseDir . '/../lib/Settings/Admin.php',
'OCA\\WebhookListeners\\Settings\\AdminSection' => $baseDir . '/../lib/Settings/AdminSection.php',
);
diff --git a/apps/webhook_listeners/composer/composer/autoload_static.php b/apps/webhook_listeners/composer/composer/autoload_static.php
index b9b367315f66f..3527838629b3a 100644
--- a/apps/webhook_listeners/composer/composer/autoload_static.php
+++ b/apps/webhook_listeners/composer/composer/autoload_static.php
@@ -24,16 +24,21 @@ class ComposerStaticInitWebhookListeners
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'OCA\\WebhookListeners\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
'OCA\\WebhookListeners\\BackgroundJobs\\WebhookCall' => __DIR__ . '/..' . '/../lib/BackgroundJobs/WebhookCall.php',
+ 'OCA\\WebhookListeners\\BackgroundJobs\\WebhookTokenCleanup' => __DIR__ . '/..' . '/../lib/BackgroundJobs/WebhookTokenCleanup.php',
'OCA\\WebhookListeners\\Command\\ListWebhooks' => __DIR__ . '/..' . '/../lib/Command/ListWebhooks.php',
'OCA\\WebhookListeners\\Controller\\WebhooksController' => __DIR__ . '/..' . '/../lib/Controller/WebhooksController.php',
'OCA\\WebhookListeners\\Db\\AuthMethod' => __DIR__ . '/..' . '/../lib/Db/AuthMethod.php',
+ 'OCA\\WebhookListeners\\Db\\EphemeralToken' => __DIR__ . '/..' . '/../lib/Db/EphemeralToken.php',
+ 'OCA\\WebhookListeners\\Db\\EphemeralTokenMapper' => __DIR__ . '/..' . '/../lib/Db/EphemeralTokenMapper.php',
'OCA\\WebhookListeners\\Db\\WebhookListener' => __DIR__ . '/..' . '/../lib/Db/WebhookListener.php',
'OCA\\WebhookListeners\\Db\\WebhookListenerMapper' => __DIR__ . '/..' . '/../lib/Db/WebhookListenerMapper.php',
'OCA\\WebhookListeners\\Listener\\WebhooksEventListener' => __DIR__ . '/..' . '/../lib/Listener/WebhooksEventListener.php',
'OCA\\WebhookListeners\\Migration\\Version1000Date20240527153425' => __DIR__ . '/..' . '/../lib/Migration/Version1000Date20240527153425.php',
'OCA\\WebhookListeners\\Migration\\Version1001Date20240716184935' => __DIR__ . '/..' . '/../lib/Migration/Version1001Date20240716184935.php',
+ 'OCA\\WebhookListeners\\Migration\\Version1500Date20251007130000' => __DIR__ . '/..' . '/../lib/Migration/Version1500Date20251007130000.php',
'OCA\\WebhookListeners\\ResponseDefinitions' => __DIR__ . '/..' . '/../lib/ResponseDefinitions.php',
'OCA\\WebhookListeners\\Service\\PHPMongoQuery' => __DIR__ . '/..' . '/../lib/Service/PHPMongoQuery.php',
+ 'OCA\\WebhookListeners\\Service\\TokenService' => __DIR__ . '/..' . '/../lib/Service/TokenService.php',
'OCA\\WebhookListeners\\Settings\\Admin' => __DIR__ . '/..' . '/../lib/Settings/Admin.php',
'OCA\\WebhookListeners\\Settings\\AdminSection' => __DIR__ . '/..' . '/../lib/Settings/AdminSection.php',
);
diff --git a/apps/webhook_listeners/lib/BackgroundJobs/WebhookCall.php b/apps/webhook_listeners/lib/BackgroundJobs/WebhookCall.php
index c8d06ca70471e..d9a2cf532adce 100644
--- a/apps/webhook_listeners/lib/BackgroundJobs/WebhookCall.php
+++ b/apps/webhook_listeners/lib/BackgroundJobs/WebhookCall.php
@@ -12,6 +12,7 @@
use OCA\AppAPI\PublicFunctions;
use OCA\WebhookListeners\Db\AuthMethod;
use OCA\WebhookListeners\Db\WebhookListenerMapper;
+use OCA\WebhookListeners\Service\TokenService;
use OCP\App\IAppManager;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\QueuedJob;
@@ -30,6 +31,7 @@ public function __construct(
private WebhookListenerMapper $mapper,
private LoggerInterface $logger,
private IAppManager $appManager,
+ private TokenService $tokenService,
ITimeFactory $timeFactory,
) {
parent::__construct($timeFactory);
@@ -42,6 +44,9 @@ protected function run($argument): void {
[$data, $webhookId] = $argument;
$webhookListener = $this->mapper->getById($webhookId);
$client = $this->clientService->newClient();
+
+ // adding Ephemeral auth tokens to the call
+ $data['tokens'] = $this->tokenService->getTokens($webhookListener, $data['user']['uid'] ?? null);
$options = [
'verify' => $this->certificateManager->getAbsoluteBundlePath(),
'headers' => $webhookListener->getHeaders() ?? [],
diff --git a/apps/webhook_listeners/lib/BackgroundJobs/WebhookTokenCleanup.php b/apps/webhook_listeners/lib/BackgroundJobs/WebhookTokenCleanup.php
new file mode 100644
index 0000000000000..45f934333d065
--- /dev/null
+++ b/apps/webhook_listeners/lib/BackgroundJobs/WebhookTokenCleanup.php
@@ -0,0 +1,33 @@
+setInterval(5 * 60);
+ }
+
+ /**
+ * @param array $argument
+ */
+ protected function run($argument): void {
+ $this->tokenMapper->invalidateOldTokens();
+ }
+}
diff --git a/apps/webhook_listeners/lib/Controller/WebhooksController.php b/apps/webhook_listeners/lib/Controller/WebhooksController.php
index 97bc8aa875eb5..0eb6913f9d896 100644
--- a/apps/webhook_listeners/lib/Controller/WebhooksController.php
+++ b/apps/webhook_listeners/lib/Controller/WebhooksController.php
@@ -112,6 +112,11 @@ public function show(int $id): DataResponse {
* @param ?array $headers Array of headers to send
* @param "none"|"header"|null $authMethod Authentication method to use
* @param ?array $authData Array of data for authentication
+ * @param ?array{user_ids?:list,user_roles?:list} $tokenNeeded
+ * List of user ids for which to include auth tokens in the event.
+ * Has two fields: "user_ids" list of user uids for which tokens are needed, "user_roles" list of roles (users not defined by their ID but by the role they have in the webhook event) for which tokens can be included.
+ * Possible roles: "owner" for the user creating the webhook, "trigger" for the user triggering the webhook call.
+ * Requested auth tokens are valid for 1 hour after receiving them in the event call request.
*
* @return DataResponse
*
@@ -134,6 +139,7 @@ public function create(
?string $authMethod,
#[\SensitiveParameter]
?array $authData,
+ ?array $tokenNeeded = null,
): DataResponse {
$appId = null;
if ($this->session->get('app_api') === true) {
@@ -156,6 +162,7 @@ public function create(
$headers,
$authMethod,
$authData,
+ $tokenNeeded,
);
return new DataResponse($webhookListener->jsonSerialize());
} catch (\UnexpectedValueException $e) {
@@ -180,6 +187,11 @@ public function create(
* @param ?array $headers Array of headers to send
* @param "none"|"header"|null $authMethod Authentication method to use
* @param ?array $authData Array of data for authentication
+ * @param ?array{user_ids?:list,user_roles?:list} $tokenNeeded
+ * List of user ids for which to include auth tokens in the event.
+ * Has two fields: "user_ids" list of user uids for which tokens are needed, "user_roles" list of roles (users not defined by their ID but by the role they have in the webhook event) for which tokens can be included.
+ * Possible roles: "owner" for the user creating the webhook, "trigger" for the user triggering the webhook call.
+ * Requested auth tokens are valid for 1 hour after receiving them in the event call request.
*
* @return DataResponse
*
@@ -203,6 +215,7 @@ public function update(
?string $authMethod,
#[\SensitiveParameter]
?array $authData,
+ ?array $tokenNeeded = null,
): DataResponse {
$appId = null;
if ($this->session->get('app_api') === true) {
@@ -226,6 +239,7 @@ public function update(
$headers,
$authMethod,
$authData,
+ $tokenNeeded,
);
return new DataResponse($webhookListener->jsonSerialize());
} catch (\UnexpectedValueException $e) {
diff --git a/apps/webhook_listeners/lib/Db/EphemeralToken.php b/apps/webhook_listeners/lib/Db/EphemeralToken.php
new file mode 100644
index 0000000000000..41aad2ba2a935
--- /dev/null
+++ b/apps/webhook_listeners/lib/Db/EphemeralToken.php
@@ -0,0 +1,54 @@
+addType('tokenId', 'integer');
+ $this->addType('userId', 'string');
+ $this->addType('createdAt', 'integer');
+ }
+
+ public function jsonSerialize(): array {
+ $fields = array_keys($this->getFieldTypes());
+ return array_combine(
+ $fields,
+ array_map(
+ fn ($field) => $this->getter($field),
+ $fields
+ )
+ );
+ }
+}
diff --git a/apps/webhook_listeners/lib/Db/EphemeralTokenMapper.php b/apps/webhook_listeners/lib/Db/EphemeralTokenMapper.php
new file mode 100644
index 0000000000000..9b5201096a44e
--- /dev/null
+++ b/apps/webhook_listeners/lib/Db/EphemeralTokenMapper.php
@@ -0,0 +1,121 @@
+
+ */
+
+class EphemeralTokenMapper extends QBMapper {
+ public const TABLE_NAME = 'webhook_tokens';
+ public const TOKEN_LIFETIME = 1 * 1 * 60; // one hour in seconds
+
+ public function __construct(
+ IDBConnection $db,
+ private LoggerInterface $logger,
+ private ITimeFactory $time,
+ private PublicKeyTokenMapper $tokenMapper,
+ ) {
+ parent::__construct($db, self::TABLE_NAME, EphemeralToken::class);
+ }
+
+ /**
+ * @throws DoesNotExistException
+ * @throws MultipleObjectsReturnedException
+ * @throws Exception
+ */
+ public function getById(int $id): EphemeralToken {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
+
+ return $this->findEntity($qb);
+ }
+
+ /**
+ * @throws Exception
+ * @return EphemeralToken[]
+ */
+ public function getAll(): array {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('*')
+ ->from($this->getTableName());
+
+ return $this->findEntities($qb);
+ }
+
+
+ /**
+ * @param int $olderThan
+ * @return EphemeralToken[]
+ * @throws Exception
+ */
+ public function getOlderThan($olderThan): array {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->lt('created_at', $qb->createNamedParameter($olderThan, IQueryBuilder::PARAM_INT)));
+
+ return $this->findEntities($qb);
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function addEphemeralToken(
+ int $tokenId,
+ ?string $userId,
+ int $createdAt,
+ ): EphemeralToken {
+ $tempToken = EphemeralToken::fromParams(
+ [
+ 'tokenId' => $tokenId,
+ 'userId' => $userId,
+ 'createdAt' => $createdAt,
+ ]
+ );
+ return $this->insert($tempToken);
+ }
+ public function invalidateOldTokens(int $token_lifetime = self::TOKEN_LIFETIME) {
+ $olderThan = $this->time->getTime() - $token_lifetime;
+ try {
+ $tokensToDelete = $this->getOlderThan($olderThan);
+ } catch (Exception $e) {
+ $this->logger->error('Webhook token deletion failed: ' . $e->getMessage(), ['exception' => $e]);
+ return;
+ }
+
+
+ $this->logger->debug('Invalidating ephemeral webhook tokens older than ' . date('c', $olderThan), ['app' => 'webhook_listeners']);
+ foreach ($tokensToDelete as $token) {
+ try {
+ $this->tokenMapper->delete($this->tokenMapper->getTokenById($token->getTokenId())); // delete token itself
+ $this->delete($token); // delete db row in webhook_tokens
+ } catch (Exception $e) {
+ $this->logger->error('Webhook token deletion failed: ' . $e->getMessage(), ['exception' => $e]);
+ }
+
+ }
+ }
+}
diff --git a/apps/webhook_listeners/lib/Db/WebhookListener.php b/apps/webhook_listeners/lib/Db/WebhookListener.php
index af974e7b0e25f..845624c87ad24 100644
--- a/apps/webhook_listeners/lib/Db/WebhookListener.php
+++ b/apps/webhook_listeners/lib/Db/WebhookListener.php
@@ -23,6 +23,7 @@
* @method ?string getAuthData()
* @method void setAuthData(?string $data)
* @method string getAuthMethod()
+ * @method ?array getTokenNeeded()
* @psalm-suppress PropertyNotSetInConstructor
*/
class WebhookListener extends Entity implements \JsonSerializable {
@@ -84,8 +85,15 @@ class WebhookListener extends Entity implements \JsonSerializable {
*/
protected $authData = null;
+ /**
+ * @var array
+ * @psalm-suppress PropertyNotSetInConstructor
+ */
+ protected $tokenNeeded;
+
private ICrypto $crypto;
+
public function __construct(
?ICrypto $crypto = null,
) {
@@ -103,6 +111,7 @@ public function __construct(
$this->addType('headers', 'json');
$this->addType('authMethod', 'string');
$this->addType('authData', 'string');
+ $this->addType('tokenNeeded', 'json');
}
public function getAuthMethodEnum(): AuthMethod {
diff --git a/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php b/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php
index 75456cc0b7555..bef8223b31599 100644
--- a/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php
+++ b/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php
@@ -82,6 +82,7 @@ public function addWebhookListener(
AuthMethod $authMethod,
#[\SensitiveParameter]
?array $authData,
+ ?array $tokenNeeded = [],
): WebhookListener {
/* Remove any superfluous antislash */
$event = ltrim($event, '\\');
@@ -99,6 +100,7 @@ public function addWebhookListener(
'userIdFilter' => $userIdFilter ?? '',
'headers' => $headers,
'authMethod' => $authMethod->value,
+ 'tokenNeeded' => $tokenNeeded ?? [],
]
);
$webhookListener->setAuthDataClear($authData);
@@ -122,6 +124,7 @@ public function updateWebhookListener(
AuthMethod $authMethod,
#[\SensitiveParameter]
?array $authData,
+ ?array $tokenNeeded = [],
): WebhookListener {
/* Remove any superfluous antislash */
$event = ltrim($event, '\\');
@@ -140,6 +143,7 @@ public function updateWebhookListener(
'userIdFilter' => $userIdFilter ?? '',
'headers' => $headers,
'authMethod' => $authMethod->value,
+ 'tokenNeeded' => $tokenNeeded ?? [],
]
);
$webhookListener->setAuthDataClear($authData);
diff --git a/apps/webhook_listeners/lib/Migration/Version1500Date20251007130000.php b/apps/webhook_listeners/lib/Migration/Version1500Date20251007130000.php
new file mode 100644
index 0000000000000..4ca578da98936
--- /dev/null
+++ b/apps/webhook_listeners/lib/Migration/Version1500Date20251007130000.php
@@ -0,0 +1,67 @@
+hasTable(WebhookListenerMapper::TABLE_NAME)) {
+ $table = $schema->getTable(WebhookListenerMapper::TABLE_NAME);
+ if (!$table->hasColumn('token_needed')) {
+ $schemaHasChanged = true;
+ $table->addColumn('token_needed', Types::TEXT, [
+ 'notnull' => false,
+ ]);
+ }
+ }
+
+ if (!$schema->hasTable(EphemeralTokenMapper::TABLE_NAME)) {
+ $schemaHasChanged = true;
+ $table = $schema->createTable(EphemeralTokenMapper::TABLE_NAME);
+ $table->addColumn('id', Types::BIGINT, [
+ 'autoincrement' => true,
+ 'notnull' => true,
+ ]);
+ $table->addColumn('token_id', Types::BIGINT, [
+ 'notnull' => true,
+ 'length' => 4,
+ 'unsigned' => true,
+ ]);
+ $table->addColumn('user_id', Types::STRING, [
+ 'notnull' => false,
+ 'length' => 64,
+ ]);
+ $table->addColumn('created_at', Types::BIGINT, [
+ 'notnull' => true,
+ 'length' => 4,
+ 'unsigned' => true,
+ ]);
+ $table->setPrimaryKey(['id']);
+ }
+ return $schemaHasChanged ? $schema : null;
+ }
+}
diff --git a/apps/webhook_listeners/lib/ResponseDefinitions.php b/apps/webhook_listeners/lib/ResponseDefinitions.php
index 725e00b118ab6..b0c3850bb1bbd 100644
--- a/apps/webhook_listeners/lib/ResponseDefinitions.php
+++ b/apps/webhook_listeners/lib/ResponseDefinitions.php
@@ -21,6 +21,7 @@
* headers?: array,
* authMethod: string,
* authData?: array,
+ * tokenNeeded?: ?array{user_ids?:array,user_roles?:array},
* }
*/
class ResponseDefinitions {
diff --git a/apps/webhook_listeners/lib/Service/TokenService.php b/apps/webhook_listeners/lib/Service/TokenService.php
new file mode 100644
index 0000000000000..e75d1b8f4e006
--- /dev/null
+++ b/apps/webhook_listeners/lib/Service/TokenService.php
@@ -0,0 +1,122 @@
+ ['jane', 'bob'], 'user_roles' => ['owner', 'trigger']]
+ * as requested tokens in the registered webhook produces a result like
+ * ['user_ids' => [['jane' => 'abcdtokenabcd1'], ['bob','=> 'abcdtokenabcd2']], 'user_roles' => ['owner' => ['admin' => 'abcdtokenabcd3'], 'trigger' => ['user1' => 'abcdtokenabcd4']]]
+ * Created auth tokens are valid for 1 hour.
+ *
+ * @param WebhookListener $webhookListener
+ * @param ?string $triggerUserId the user that triggered the webhook call
+ * @return array{user_ids?:array,user_roles?:array{owner?:array,trigger?:array}}
+ */
+ public function getTokens(WebhookListener $webhookListener, ?string $triggerUserId): array {
+ $tokens = [
+ 'user_ids' => [],
+ 'user_roles' => [],
+ ];
+ $tokenNeeded = $webhookListener->getTokenNeeded();
+ if (isset($tokenNeeded['user_ids'])) {
+ foreach ($tokenNeeded['user_ids'] as $userId) {
+ try {
+ $tokens['user_ids'][$userId] = $this->createEphemeralToken($userId);
+ } catch (\Exception $e) {
+ $this->logger->error('Webhook token creation for user ' . $userId . ' failed: ' . $e->getMessage(), ['exception' => $e]);
+ }
+
+ }
+ }
+ if (isset($tokenNeeded['user_roles'])) {
+ foreach ($tokenNeeded['user_roles'] as $user_role) {
+ switch ($user_role) {
+ case 'owner':
+ // token for the person who created the flow
+ $ownerId = $webhookListener->getUserId();
+ if (is_null($ownerId)) { // no owner uid available
+ break;
+ }
+ $tokens['user_roles']['owner'] = [
+ $ownerId => $this->createEphemeralToken($ownerId)
+ ];
+ break;
+ case 'trigger':
+ // token for the person who triggered the webhook
+ if (is_null($triggerUserId)) { // no trigger uid available
+ break;
+ }
+ $tokens['user_roles']['trigger'] = [
+ $triggerUserId => $this->createEphemeralToken($triggerUserId)
+ ];
+ break;
+ default:
+ $this->logger->error('Webhook token creation for user role ' . $user_role . ' not defined. ', ['Not defined' => $user_role]);
+
+ }
+ }
+ }
+ return $tokens;
+ }
+ private function createEphemeralToken(string $userId): string {
+ $token = $this->generateRandomDeviceToken();
+
+ // we need the user`s language to have the token name showing up in the session list in the correct language
+ $user = $this->userManager->get($userId);
+ $lang = $this->l10nFactory->getUserLanguage($user);
+ $l = $this->l10nFactory->get('webhook_listeners', $lang);
+ $name = $l->t('Ephemeral webhook authentication');
+ $password = null;
+ $deviceToken = $this->tokenProvider->generateToken(
+ $token,
+ $userId,
+ $userId,
+ $password,
+ $name,
+ IToken::PERMANENT_TOKEN);
+
+ $this->tokenMapper->addEphemeralToken(
+ $deviceToken->getId(),
+ $userId,
+ $this->time->getTime());
+ return $token;
+ }
+
+ private function generateRandomDeviceToken(): string {
+ $groups = [];
+ for ($i = 0; $i < 5; $i++) {
+ $groups[] = $this->random->generate(5, ISecureRandom::CHAR_HUMAN_READABLE);
+ }
+ return implode('-', $groups);
+ }
+}
diff --git a/apps/webhook_listeners/openapi.json b/apps/webhook_listeners/openapi.json
index 36c80a43de84d..2a01c8bcb6885 100644
--- a/apps/webhook_listeners/openapi.json
+++ b/apps/webhook_listeners/openapi.json
@@ -92,6 +92,24 @@
"additionalProperties": {
"type": "object"
}
+ },
+ "tokenNeeded": {
+ "type": "object",
+ "nullable": true,
+ "properties": {
+ "user_ids": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "user_roles": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
}
}
}
@@ -304,6 +322,26 @@
"additionalProperties": {
"type": "object"
}
+ },
+ "tokenNeeded": {
+ "type": "object",
+ "nullable": true,
+ "default": null,
+ "description": "List of user ids for which to include auth tokens in the event. Has two fields: \"user_ids\" list of user uids for which tokens are needed, \"user_roles\" list of roles (users not defined by their ID but by the role they have in the webhook event) for which tokens can be included. Possible roles: \"owner\" for the user creating the webhook, \"trigger\" for the user triggering the webhook call. Requested auth tokens are valid for 1 hour after receiving them in the event call request.",
+ "properties": {
+ "user_ids": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "user_roles": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
}
}
}
@@ -703,6 +741,26 @@
"additionalProperties": {
"type": "object"
}
+ },
+ "tokenNeeded": {
+ "type": "object",
+ "nullable": true,
+ "default": null,
+ "description": "List of user ids for which to include auth tokens in the event. Has two fields: \"user_ids\" list of user uids for which tokens are needed, \"user_roles\" list of roles (users not defined by their ID but by the role they have in the webhook event) for which tokens can be included. Possible roles: \"owner\" for the user creating the webhook, \"trigger\" for the user triggering the webhook call. Requested auth tokens are valid for 1 hour after receiving them in the event call request.",
+ "properties": {
+ "user_ids": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "user_roles": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
}
}
}
diff --git a/openapi.json b/openapi.json
index 4307c29839e24..592bc2657acbd 100644
--- a/openapi.json
+++ b/openapi.json
@@ -4687,6 +4687,24 @@
"additionalProperties": {
"type": "object"
}
+ },
+ "tokenNeeded": {
+ "type": "object",
+ "nullable": true,
+ "properties": {
+ "user_ids": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "user_roles": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
}
}
}
@@ -38254,6 +38272,26 @@
"additionalProperties": {
"type": "object"
}
+ },
+ "tokenNeeded": {
+ "type": "object",
+ "nullable": true,
+ "default": null,
+ "description": "List of user ids for which to include auth tokens in the event. Has two fields: \"user_ids\" list of user uids for which tokens are needed, \"user_roles\" list of roles (users not defined by their ID but by the role they have in the webhook event) for which tokens can be included. Possible roles: \"owner\" for the user creating the webhook, \"trigger\" for the user triggering the webhook call. Requested auth tokens are valid for 1 hour after receiving them in the event call request.",
+ "properties": {
+ "user_ids": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "user_roles": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
}
}
}
@@ -38653,6 +38691,26 @@
"additionalProperties": {
"type": "object"
}
+ },
+ "tokenNeeded": {
+ "type": "object",
+ "nullable": true,
+ "default": null,
+ "description": "List of user ids for which to include auth tokens in the event. Has two fields: \"user_ids\" list of user uids for which tokens are needed, \"user_roles\" list of roles (users not defined by their ID but by the role they have in the webhook event) for which tokens can be included. Possible roles: \"owner\" for the user creating the webhook, \"trigger\" for the user triggering the webhook call. Requested auth tokens are valid for 1 hour after receiving them in the event call request.",
+ "properties": {
+ "user_ids": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "user_roles": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
}
}
}