refactor(core): Decouple Public API events from internal hooks (no-changelog) (#10121)

This commit is contained in:
Iván Ovejero 2024-07-22 10:09:02 +02:00 committed by GitHub
parent 936cb57d79
commit a7ae23b47f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 68 additions and 42 deletions

View file

@ -504,29 +504,6 @@ export class InternalHooks {
);
}
async onUserInvokedApi(userInvokedApiData: {
user_id: string;
path: string;
method: string;
api_version: string;
}): Promise<void> {
return await this.telemetry.track('User invoked API', userInvokedApiData);
}
async onApiKeyDeleted(apiKeyDeletedData: { user: User; public_api: boolean }): Promise<void> {
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> {
void this.telemetry.track('API key created', {
user_id: apiKeyCreatedData.user.id,
public_api: apiKeyCreatedData.public_api,
});
}
async onUserPasswordResetRequestClick(userPasswordResetData: { user: User }): Promise<void> {
void this.telemetry.track('User requested password reset while logged out', {
user_id: userPasswordResetData.user.id,

View file

@ -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;

View file

@ -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 };
}

View file

@ -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,
});
}

View file

@ -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;

View file

@ -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,
});
}
}