Skip to content

Commit f4f0a36

Browse files
authored
feat: Add credential update and delete events to log streaming (#9026)
1 parent 7467aa3 commit f4f0a36

File tree

5 files changed

+84
-2
lines changed

5 files changed

+84
-2
lines changed

packages/cli/src/InternalHooks.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,55 @@ export class InternalHooks {
917917
]);
918918
}
919919

920+
async onUserUpdatedCredentials(userUpdatedCredentialsData: {
921+
user: User;
922+
credential_name: string;
923+
credential_type: string;
924+
credential_id: string;
925+
}): Promise<void> {
926+
void Promise.all([
927+
this.eventBus.sendAuditEvent({
928+
eventName: 'n8n.audit.user.credentials.updated',
929+
payload: {
930+
...userToPayload(userUpdatedCredentialsData.user),
931+
credentialName: userUpdatedCredentialsData.credential_name,
932+
credentialType: userUpdatedCredentialsData.credential_type,
933+
credentialId: userUpdatedCredentialsData.credential_id,
934+
},
935+
}),
936+
this.telemetry.track('User updated credentials', {
937+
user_id: userUpdatedCredentialsData.user.id,
938+
credential_type: userUpdatedCredentialsData.credential_type,
939+
credential_id: userUpdatedCredentialsData.credential_id,
940+
}),
941+
]);
942+
}
943+
944+
async onUserDeletedCredentials(userUpdatedCredentialsData: {
945+
user: User;
946+
credential_name: string;
947+
credential_type: string;
948+
credential_id: string;
949+
}): Promise<void> {
950+
void Promise.all([
951+
this.eventBus.sendAuditEvent({
952+
eventName: 'n8n.audit.user.credentials.deleted',
953+
payload: {
954+
...userToPayload(userUpdatedCredentialsData.user),
955+
credentialName: userUpdatedCredentialsData.credential_name,
956+
credentialType: userUpdatedCredentialsData.credential_type,
957+
credentialId: userUpdatedCredentialsData.credential_id,
958+
},
959+
}),
960+
this.telemetry.track('User deleted credentials', {
961+
user_id: userUpdatedCredentialsData.user.id,
962+
credential_type: userUpdatedCredentialsData.credential_type,
963+
credential_id: userUpdatedCredentialsData.credential_id,
964+
instance_id: this.instanceSettings.instanceId,
965+
}),
966+
]);
967+
}
968+
920969
/**
921970
* Community nodes backend telemetry events
922971
*/

packages/cli/src/PublicApi/v1/handlers/credentials/credentials.handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export = {
6969
return res.status(404).json({ message: 'Not Found' });
7070
}
7171

72-
await removeCredential(credential);
72+
await removeCredential(req.user, credential);
7373
return res.json(sanitizeCredentials(credential));
7474
},
7575
],

packages/cli/src/PublicApi/v1/handlers/credentials/credentials.service.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type { CredentialRequest } from '@/requests';
1616
import { Container } from 'typedi';
1717
import { CredentialsRepository } from '@db/repositories/credentials.repository';
1818
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
19+
import { InternalHooks } from '@/InternalHooks';
1920

2021
export async function getCredentials(credentialId: string): Promise<ICredentialsDb | null> {
2122
return await Container.get(CredentialsRepository).findOneBy({ id: credentialId });
@@ -50,6 +51,13 @@ export async function saveCredential(
5051
encryptedData: ICredentialsDb,
5152
): Promise<CredentialsEntity> {
5253
await Container.get(ExternalHooks).run('credentials.create', [encryptedData]);
54+
void Container.get(InternalHooks).onUserCreatedCredentials({
55+
user,
56+
credential_name: credential.name,
57+
credential_type: credential.type,
58+
credential_id: credential.id,
59+
public_api: true,
60+
});
5361

5462
return await Db.transaction(async (transactionManager) => {
5563
const savedCredential = await transactionManager.save<CredentialsEntity>(credential);
@@ -70,8 +78,17 @@ export async function saveCredential(
7078
});
7179
}
7280

73-
export async function removeCredential(credentials: CredentialsEntity): Promise<ICredentialsDb> {
81+
export async function removeCredential(
82+
user: User,
83+
credentials: CredentialsEntity,
84+
): Promise<ICredentialsDb> {
7485
await Container.get(ExternalHooks).run('credentials.delete', [credentials.id]);
86+
void Container.get(InternalHooks).onUserDeletedCredentials({
87+
user,
88+
credential_name: credentials.name,
89+
credential_type: credentials.type,
90+
credential_id: credentials.id,
91+
});
7592
return await Container.get(CredentialsRepository).remove(credentials);
7693
}
7794

packages/cli/src/credentials/credentials.controller.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,13 @@ export class CredentialsController {
252252

253253
this.logger.verbose('Credential updated', { credentialId });
254254

255+
void this.internalHooks.onUserUpdatedCredentials({
256+
user: req.user,
257+
credential_name: credential.name,
258+
credential_type: credential.type,
259+
credential_id: credential.id,
260+
});
261+
255262
return { ...rest };
256263
}
257264

@@ -291,6 +298,13 @@ export class CredentialsController {
291298

292299
await this.credentialsService.delete(credential);
293300

301+
void this.internalHooks.onUserDeletedCredentials({
302+
user: req.user,
303+
credential_name: credential.name,
304+
credential_type: credential.type,
305+
credential_id: credential.id,
306+
});
307+
294308
return true;
295309
}
296310

packages/cli/src/eventbus/EventMessageClasses/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ export const eventNamesAudit = [
2727
'n8n.audit.user.reset',
2828
'n8n.audit.user.credentials.created',
2929
'n8n.audit.user.credentials.shared',
30+
'n8n.audit.user.credentials.updated',
31+
'n8n.audit.user.credentials.deleted',
3032
'n8n.audit.user.api.created',
3133
'n8n.audit.user.api.deleted',
3234
'n8n.audit.package.installed',

0 commit comments

Comments
 (0)