fix: When editing nodes only show the credentials in the dropdown that the user is allowed to use in that workflow (#9718)

This commit is contained in:
Danny Martini
2024-06-14 14:48:49 +02:00
committed by GitHub
parent 2dad9ce44c
commit 2cf4364ee0
16 changed files with 682 additions and 22 deletions

View File

@@ -1,12 +1,18 @@
import { Service } from 'typedi';
import { DataSource, In, Repository, Like } from '@n8n/typeorm';
import type { FindManyOptions } from '@n8n/typeorm';
import type { FindManyOptions, FindOptionsWhere } from '@n8n/typeorm';
import { CredentialsEntity } from '../entities/CredentialsEntity';
import type { ListQuery } from '@/requests';
import type { User } from '../entities/User';
import type { Scope } from '@n8n/permissions';
import { RoleService } from '@/services/role.service';
@Service()
export class CredentialsRepository extends Repository<CredentialsEntity> {
constructor(dataSource: DataSource) {
constructor(
dataSource: DataSource,
readonly roleService: RoleService,
) {
super(CredentialsEntity, dataSource.manager);
}
@@ -82,4 +88,64 @@ export class CredentialsRepository extends Repository<CredentialsEntity> {
return await this.find(findManyOptions);
}
/**
* Find all credentials that are owned by a personal project.
*/
async findAllPersonalCredentials(): Promise<CredentialsEntity[]> {
return await this.findBy({ shared: { project: { type: 'personal' } } });
}
/**
* Find all credentials that are part of any project that the workflow is
* part of.
*
* This is useful to for finding credentials that can be used in the
* workflow.
*/
async findAllCredentialsForWorkflow(workflowId: string): Promise<CredentialsEntity[]> {
return await this.findBy({
shared: { project: { sharedWorkflows: { workflowId } } },
});
}
/**
* Find all credentials that are part of that project.
*
* This is useful for finding credentials that can be used in workflows that
* are part of this project.
*/
async findAllCredentialsForProject(projectId: string): Promise<CredentialsEntity[]> {
return await this.findBy({ shared: { projectId } });
}
/**
* Find all credentials that the user has access to taking the scopes into
* account.
*
* This also returns `credentials.shared` which is useful for constructing
* all scopes the user has for the credential using `RoleService.addScopes`.
**/
async findCredentialsForUser(user: User, scopes: Scope[]) {
let where: FindOptionsWhere<CredentialsEntity> = {};
if (!user.hasGlobalScope(scopes, { mode: 'allOf' })) {
const projectRoles = this.roleService.rolesWithScope('project', scopes);
const credentialRoles = this.roleService.rolesWithScope('credential', scopes);
where = {
...where,
shared: {
role: In(credentialRoles),
project: {
projectRelations: {
role: In(projectRoles),
userId: user.id,
},
},
},
};
}
return await this.find({ where, relations: { shared: true } });
}
}

View File

@@ -150,4 +150,36 @@ export class UserRepository extends Repository<User> {
// This is blocked by TypeORM having concurrency issues with transactions
return await createInner(this.manager);
}
/**
* Find the user that owns the personal project that owns the workflow.
*
* Returns null if the workflow does not exist or is owned by a team project.
*/
async findPersonalOwnerForWorkflow(workflowId: string): Promise<User | null> {
return await this.findOne({
where: {
projectRelations: {
role: 'project:personalOwner',
project: { sharedWorkflows: { workflowId, role: 'workflow:owner' } },
},
},
});
}
/**
* Find the user that owns the personal project.
*
* Returns null if the project does not exist or is not a personal project.
*/
async findPersonalOwnerForProject(projectId: string): Promise<User | null> {
return await this.findOne({
where: {
projectRelations: {
role: 'project:personalOwner',
projectId,
},
},
});
}
}