feat: Add credential update and delete events to log streaming (#9026)

This commit is contained in:
Val
2024-04-08 08:13:39 +01:00
committed by GitHub
parent 7467aa30e6
commit f4f0a36fe1
5 changed files with 84 additions and 2 deletions

View File

@@ -917,6 +917,55 @@ export class InternalHooks {
]); ]);
} }
async onUserUpdatedCredentials(userUpdatedCredentialsData: {
user: User;
credential_name: string;
credential_type: string;
credential_id: string;
}): Promise<void> {
void Promise.all([
this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.credentials.updated',
payload: {
...userToPayload(userUpdatedCredentialsData.user),
credentialName: userUpdatedCredentialsData.credential_name,
credentialType: userUpdatedCredentialsData.credential_type,
credentialId: userUpdatedCredentialsData.credential_id,
},
}),
this.telemetry.track('User updated credentials', {
user_id: userUpdatedCredentialsData.user.id,
credential_type: userUpdatedCredentialsData.credential_type,
credential_id: userUpdatedCredentialsData.credential_id,
}),
]);
}
async onUserDeletedCredentials(userUpdatedCredentialsData: {
user: User;
credential_name: string;
credential_type: string;
credential_id: string;
}): Promise<void> {
void Promise.all([
this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.credentials.deleted',
payload: {
...userToPayload(userUpdatedCredentialsData.user),
credentialName: userUpdatedCredentialsData.credential_name,
credentialType: userUpdatedCredentialsData.credential_type,
credentialId: userUpdatedCredentialsData.credential_id,
},
}),
this.telemetry.track('User deleted credentials', {
user_id: userUpdatedCredentialsData.user.id,
credential_type: userUpdatedCredentialsData.credential_type,
credential_id: userUpdatedCredentialsData.credential_id,
instance_id: this.instanceSettings.instanceId,
}),
]);
}
/** /**
* Community nodes backend telemetry events * Community nodes backend telemetry events
*/ */

View File

@@ -69,7 +69,7 @@ export = {
return res.status(404).json({ message: 'Not Found' }); return res.status(404).json({ message: 'Not Found' });
} }
await removeCredential(credential); await removeCredential(req.user, credential);
return res.json(sanitizeCredentials(credential)); return res.json(sanitizeCredentials(credential));
}, },
], ],

View File

@@ -16,6 +16,7 @@ import type { CredentialRequest } from '@/requests';
import { Container } from 'typedi'; import { Container } from 'typedi';
import { CredentialsRepository } from '@db/repositories/credentials.repository'; import { CredentialsRepository } from '@db/repositories/credentials.repository';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository'; import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import { InternalHooks } from '@/InternalHooks';
export async function getCredentials(credentialId: string): Promise<ICredentialsDb | null> { export async function getCredentials(credentialId: string): Promise<ICredentialsDb | null> {
return await Container.get(CredentialsRepository).findOneBy({ id: credentialId }); return await Container.get(CredentialsRepository).findOneBy({ id: credentialId });
@@ -50,6 +51,13 @@ export async function saveCredential(
encryptedData: ICredentialsDb, encryptedData: ICredentialsDb,
): Promise<CredentialsEntity> { ): Promise<CredentialsEntity> {
await Container.get(ExternalHooks).run('credentials.create', [encryptedData]); await Container.get(ExternalHooks).run('credentials.create', [encryptedData]);
void Container.get(InternalHooks).onUserCreatedCredentials({
user,
credential_name: credential.name,
credential_type: credential.type,
credential_id: credential.id,
public_api: true,
});
return await Db.transaction(async (transactionManager) => { return await Db.transaction(async (transactionManager) => {
const savedCredential = await transactionManager.save<CredentialsEntity>(credential); const savedCredential = await transactionManager.save<CredentialsEntity>(credential);
@@ -70,8 +78,17 @@ export async function saveCredential(
}); });
} }
export async function removeCredential(credentials: CredentialsEntity): Promise<ICredentialsDb> { export async function removeCredential(
user: User,
credentials: CredentialsEntity,
): Promise<ICredentialsDb> {
await Container.get(ExternalHooks).run('credentials.delete', [credentials.id]); await Container.get(ExternalHooks).run('credentials.delete', [credentials.id]);
void Container.get(InternalHooks).onUserDeletedCredentials({
user,
credential_name: credentials.name,
credential_type: credentials.type,
credential_id: credentials.id,
});
return await Container.get(CredentialsRepository).remove(credentials); return await Container.get(CredentialsRepository).remove(credentials);
} }

View File

@@ -252,6 +252,13 @@ export class CredentialsController {
this.logger.verbose('Credential updated', { credentialId }); this.logger.verbose('Credential updated', { credentialId });
void this.internalHooks.onUserUpdatedCredentials({
user: req.user,
credential_name: credential.name,
credential_type: credential.type,
credential_id: credential.id,
});
return { ...rest }; return { ...rest };
} }
@@ -291,6 +298,13 @@ export class CredentialsController {
await this.credentialsService.delete(credential); await this.credentialsService.delete(credential);
void this.internalHooks.onUserDeletedCredentials({
user: req.user,
credential_name: credential.name,
credential_type: credential.type,
credential_id: credential.id,
});
return true; return true;
} }

View File

@@ -27,6 +27,8 @@ export const eventNamesAudit = [
'n8n.audit.user.reset', 'n8n.audit.user.reset',
'n8n.audit.user.credentials.created', 'n8n.audit.user.credentials.created',
'n8n.audit.user.credentials.shared', 'n8n.audit.user.credentials.shared',
'n8n.audit.user.credentials.updated',
'n8n.audit.user.credentials.deleted',
'n8n.audit.user.api.created', 'n8n.audit.user.api.created',
'n8n.audit.user.api.deleted', 'n8n.audit.user.api.deleted',
'n8n.audit.package.installed', 'n8n.audit.package.installed',