diff --git a/packages/cli/src/InternalHooks.ts b/packages/cli/src/InternalHooks.ts index 454f4be002..1d2a9471a7 100644 --- a/packages/cli/src/InternalHooks.ts +++ b/packages/cli/src/InternalHooks.ts @@ -504,29 +504,6 @@ export class InternalHooks { ); } - async onUserInvokedApi(userInvokedApiData: { - user_id: string; - path: string; - method: string; - api_version: string; - }): Promise { - return await this.telemetry.track('User invoked API', userInvokedApiData); - } - - async onApiKeyDeleted(apiKeyDeletedData: { user: User; public_api: boolean }): Promise { - void this.telemetry.track('API key deleted', { - user_id: apiKeyDeletedData.user.id, - public_api: apiKeyDeletedData.public_api, - }); - } - - async onApiKeyCreated(apiKeyCreatedData: { user: User; public_api: boolean }): Promise { - void this.telemetry.track('API key created', { - user_id: apiKeyCreatedData.user.id, - public_api: apiKeyCreatedData.public_api, - }); - } - async onUserPasswordResetRequestClick(userPasswordResetData: { user: User }): Promise { void this.telemetry.track('User requested password reset while logged out', { user_id: userPasswordResetData.user.id, diff --git a/packages/cli/src/PublicApi/index.ts b/packages/cli/src/PublicApi/index.ts index d1fb02ef31..3ebb67f210 100644 --- a/packages/cli/src/PublicApi/index.ts +++ b/packages/cli/src/PublicApi/index.ts @@ -12,12 +12,12 @@ import type { JsonObject } from 'swagger-ui-express'; import config from '@/config'; -import { InternalHooks } from '@/InternalHooks'; import { License } from '@/License'; import { UserRepository } from '@db/repositories/user.repository'; import { UrlService } from '@/services/url.service'; import type { AuthenticatedRequest } from '@/requests'; import { GlobalConfig } from '@n8n/config'; +import { EventService } from '@/eventbus/event.service'; async function createApiRouter( version: string, @@ -100,11 +100,11 @@ async function createApiRouter( if (!user) return false; - void Container.get(InternalHooks).onUserInvokedApi({ - user_id: user.id, + Container.get(EventService).emit('public-api-invoked', { + userId: user.id, path: req.path, method: req.method, - api_version: version, + apiVersion: version, }); req.user = user; diff --git a/packages/cli/src/controllers/me.controller.ts b/packages/cli/src/controllers/me.controller.ts index bc7ebd0609..1e3fc22ca2 100644 --- a/packages/cli/src/controllers/me.controller.ts +++ b/packages/cli/src/controllers/me.controller.ts @@ -198,8 +198,7 @@ export class MeController { await this.userService.update(req.user.id, { apiKey }); - void this.internalHooks.onApiKeyCreated({ user: req.user, public_api: false }); - this.eventService.emit('api-key-created', { user: req.user }); + this.eventService.emit('public-api-key-created', { user: req.user, publicApi: false }); return { apiKey }; } @@ -219,8 +218,7 @@ export class MeController { async deleteAPIKey(req: AuthenticatedRequest) { await this.userService.update(req.user.id, { apiKey: null }); - void this.internalHooks.onApiKeyDeleted({ user: req.user, public_api: false }); - this.eventService.emit('api-key-deleted', { user: req.user }); + this.eventService.emit('public-api-key-deleted', { user: req.user, publicApi: false }); return { success: true }; } diff --git a/packages/cli/src/eventbus/audit-event-relay.service.ts b/packages/cli/src/eventbus/audit-event-relay.service.ts index 09a283d544..96cc7366f6 100644 --- a/packages/cli/src/eventbus/audit-event-relay.service.ts +++ b/packages/cli/src/eventbus/audit-event-relay.service.ts @@ -38,8 +38,8 @@ export class AuditEventRelay { this.eventService.on('user-password-reset-request-click', (event) => this.userPasswordResetRequestClick(event), ); - this.eventService.on('api-key-created', (event) => this.apiKeyCreated(event)); - this.eventService.on('api-key-deleted', (event) => this.apiKeyDeleted(event)); + this.eventService.on('public-api-key-created', (event) => this.apiKeyCreated(event)); + this.eventService.on('public-api-key-deleted', (event) => this.apiKeyDeleted(event)); this.eventService.on('email-failed', (event) => this.emailFailed(event)); this.eventService.on('credentials-created', (event) => this.credentialsCreated(event)); this.eventService.on('credentials-deleted', (event) => this.credentialsDeleted(event)); @@ -257,18 +257,22 @@ export class AuditEventRelay { */ @Redactable() - private apiKeyCreated({ user }: Event['api-key-created']) { + private apiKeyCreated(event: Event['public-api-key-created']) { + if ('publicApi' in event) return; + void this.eventBus.sendAuditEvent({ eventName: 'n8n.audit.user.api.created', - payload: user, + payload: event.user, }); } @Redactable() - private apiKeyDeleted({ user }: Event['api-key-deleted']) { + private apiKeyDeleted(event: Event['public-api-key-deleted']) { + if ('publicApi' in event) return; + void this.eventBus.sendAuditEvent({ eventName: 'n8n.audit.user.api.deleted', - payload: user, + payload: event.user, }); } diff --git a/packages/cli/src/eventbus/event.types.ts b/packages/cli/src/eventbus/event.types.ts index 3c74fe7ee5..7f512cb03d 100644 --- a/packages/cli/src/eventbus/event.types.ts +++ b/packages/cli/src/eventbus/event.types.ts @@ -105,13 +105,20 @@ export type Event = { user: UserLike; }; - 'api-key-created': { - user: UserLike; + 'public-api-invoked': { + userId: string; + path: string; + method: string; + apiVersion: string; }; - 'api-key-deleted': { - user: UserLike; - }; + 'public-api-key-created': + | { user: UserLike } // audit + | { user: UserLike; publicApi: boolean }; // telemetry + + 'public-api-key-deleted': + | { user: UserLike } // audit + | { user: UserLike; publicApi: boolean }; // telemetry 'email-failed': { user: UserLike; diff --git a/packages/cli/src/telemetry/telemetry-event-relay.service.ts b/packages/cli/src/telemetry/telemetry-event-relay.service.ts index d3313d18c3..bc7df8183e 100644 --- a/packages/cli/src/telemetry/telemetry-event-relay.service.ts +++ b/packages/cli/src/telemetry/telemetry-event-relay.service.ts @@ -50,6 +50,15 @@ export class TelemetryEventRelay { this.eventService.on('external-secrets-provider-settings-saved', (event) => { this.externalSecretsProviderSettingsSaved(event); }); + this.eventService.on('public-api-invoked', (event) => { + this.publicApiInvoked(event); + }); + this.eventService.on('public-api-key-created', (event) => { + this.publicApiKeyCreated(event); + }); + this.eventService.on('public-api-key-deleted', (event) => { + this.publicApiKeyDeleted(event); + }); } private teamProjectUpdated({ userId, role, members, projectId }: Event['team-project-updated']) { @@ -190,4 +199,35 @@ export class TelemetryEventRelay { error_message: errorMessage, }); } + + private publicApiInvoked({ userId, path, method, apiVersion }: Event['public-api-invoked']) { + void this.telemetry.track('User invoked API', { + user_id: userId, + path, + method, + api_version: apiVersion, + }); + } + + private publicApiKeyCreated(event: Event['public-api-key-created']) { + if (!('publicApi' in event)) return; + + const { user, publicApi } = event; + + void this.telemetry.track('API key created', { + user_id: user.id, + public_api: publicApi, + }); + } + + private publicApiKeyDeleted(event: Event['public-api-key-deleted']) { + if (!('publicApi' in event)) return; + + const { user, publicApi } = event; + + void this.telemetry.track('API key deleted', { + user_id: user.id, + public_api: publicApi, + }); + } }