Files
Automata/packages/cli/src/credentials/credentials.service.ee.ts
Csaba Tuncsik 596c472ecc feat: RBAC (#8922)
Signed-off-by: Oleg Ivaniv <me@olegivaniv.com>
Co-authored-by: Val <68596159+valya@users.noreply.github.com>
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
Co-authored-by: Valya Bullions <valya@n8n.io>
Co-authored-by: Danny Martini <danny@n8n.io>
Co-authored-by: Danny Martini <despair.blue@gmail.com>
Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
Co-authored-by: Omar Ajoue <krynble@gmail.com>
Co-authored-by: oleg <me@olegivaniv.com>
Co-authored-by: Michael Kret <michael.k@radency.com>
Co-authored-by: Michael Kret <88898367+michael-radency@users.noreply.github.com>
Co-authored-by: Elias Meire <elias@meire.dev>
Co-authored-by: Giulio Andreini <andreini@netseven.it>
Co-authored-by: Giulio Andreini <g.andreini@gmail.com>
Co-authored-by: Ayato Hayashi <go12limchangyong@gmail.com>
2024-05-17 10:53:15 +02:00

95 lines
3.1 KiB
TypeScript

import { In, type EntityManager } from '@n8n/typeorm';
import type { User } from '@db/entities/User';
import { CredentialsService } from './credentials.service';
import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository';
import type { CredentialsEntity } from '@/databases/entities/CredentialsEntity';
import { Service } from 'typedi';
import type { ICredentialDataDecryptedObject } from 'n8n-workflow';
import { NotFoundError } from '@/errors/response-errors/not-found.error';
import { OwnershipService } from '@/services/ownership.service';
import { Project } from '@/databases/entities/Project';
@Service()
export class EnterpriseCredentialsService {
constructor(
private readonly sharedCredentialsRepository: SharedCredentialsRepository,
private readonly ownershipService: OwnershipService,
private readonly credentialsService: CredentialsService,
) {}
async shareWithProjects(
credential: CredentialsEntity,
shareWithIds: string[],
entityManager?: EntityManager,
) {
const em = entityManager ?? this.sharedCredentialsRepository.manager;
const projects = await em.find(Project, {
where: { id: In(shareWithIds), type: 'personal' },
});
const newSharedCredentials = projects
// We filter by role === 'project:personalOwner' above and there should
// always only be one owner.
.map((project) =>
this.sharedCredentialsRepository.create({
credentialsId: credential.id,
role: 'credential:user',
projectId: project.id,
}),
);
return await em.save(newSharedCredentials);
}
async getOne(user: User, credentialId: string, includeDecryptedData: boolean) {
let credential: CredentialsEntity | null = null;
let decryptedData: ICredentialDataDecryptedObject | null = null;
credential = includeDecryptedData
? // Try to get the credential with `credential:update` scope, which
// are required for decrypting the data.
await this.sharedCredentialsRepository.findCredentialForUser(
credentialId,
user,
// TODO: replace credential:update with credential:decrypt once it lands
// see: https://n8nio.slack.com/archives/C062YRE7EG4/p1708531433206069?thread_ts=1708525972.054149&cid=C062YRE7EG4
['credential:read', 'credential:update'],
)
: null;
if (credential) {
// Decrypt the data if we found the credential with the `credential:update`
// scope.
decryptedData = this.credentialsService.redact(
this.credentialsService.decrypt(credential),
credential,
);
} else {
// Otherwise try to find them with only the `credential:read` scope. In
// that case we return them without the decrypted data.
credential = await this.sharedCredentialsRepository.findCredentialForUser(
credentialId,
user,
['credential:read'],
);
}
if (!credential) {
throw new NotFoundError(
'Could not load the credential. If you think this is an error, ask the owner to share it with you again',
);
}
credential = this.ownershipService.addOwnedByAndSharedWith(credential);
const { data: _, ...rest } = credential;
if (decryptedData) {
return { data: decryptedData, ...rest };
}
return { ...rest };
}
}