mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-19 11:01:15 +00:00
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>
This commit is contained in:
@@ -6,10 +6,10 @@ import { UserRepository } from '@db/repositories/user.repository';
|
||||
import { ActiveWorkflowManager } from '@/ActiveWorkflowManager';
|
||||
import { MessageEventBus } from '@/eventbus/MessageEventBus/MessageEventBus';
|
||||
import { License } from '@/License';
|
||||
import { LICENSE_FEATURES, inE2ETests } from '@/constants';
|
||||
import { LICENSE_FEATURES, LICENSE_QUOTAS, UNLIMITED_LICENSE_QUOTA, inE2ETests } from '@/constants';
|
||||
import { Patch, Post, RestController } from '@/decorators';
|
||||
import type { UserSetupPayload } from '@/requests';
|
||||
import type { BooleanLicenseFeature, IPushDataType } from '@/Interfaces';
|
||||
import type { BooleanLicenseFeature, IPushDataType, NumericLicenseFeature } from '@/Interfaces';
|
||||
import { MfaService } from '@/Mfa/mfa.service';
|
||||
import { Push } from '@/push';
|
||||
import { CacheService } from '@/services/cache/cache.service';
|
||||
@@ -25,21 +25,23 @@ if (!inE2ETests) {
|
||||
const tablesToTruncate = [
|
||||
'auth_identity',
|
||||
'auth_provider_sync_history',
|
||||
'event_destinations',
|
||||
'shared_workflow',
|
||||
'shared_credentials',
|
||||
'webhook_entity',
|
||||
'workflows_tags',
|
||||
'credentials_entity',
|
||||
'tag_entity',
|
||||
'workflow_statistics',
|
||||
'workflow_entity',
|
||||
'event_destinations',
|
||||
'execution_entity',
|
||||
'settings',
|
||||
'installed_packages',
|
||||
'installed_nodes',
|
||||
'installed_packages',
|
||||
'project',
|
||||
'project_relation',
|
||||
'settings',
|
||||
'shared_credentials',
|
||||
'shared_workflow',
|
||||
'tag_entity',
|
||||
'user',
|
||||
'variables',
|
||||
'webhook_entity',
|
||||
'workflow_entity',
|
||||
'workflow_statistics',
|
||||
'workflows_tags',
|
||||
];
|
||||
|
||||
type ResetRequest = Request<
|
||||
@@ -81,21 +83,35 @@ export class E2EController {
|
||||
[LICENSE_FEATURES.MULTIPLE_MAIN_INSTANCES]: false,
|
||||
[LICENSE_FEATURES.WORKER_VIEW]: false,
|
||||
[LICENSE_FEATURES.ADVANCED_PERMISSIONS]: false,
|
||||
[LICENSE_FEATURES.PROJECT_ROLE_ADMIN]: false,
|
||||
[LICENSE_FEATURES.PROJECT_ROLE_EDITOR]: false,
|
||||
[LICENSE_FEATURES.PROJECT_ROLE_VIEWER]: false,
|
||||
};
|
||||
|
||||
private numericFeatures: Record<NumericLicenseFeature, number> = {
|
||||
[LICENSE_QUOTAS.TRIGGER_LIMIT]: -1,
|
||||
[LICENSE_QUOTAS.VARIABLES_LIMIT]: -1,
|
||||
[LICENSE_QUOTAS.USERS_LIMIT]: -1,
|
||||
[LICENSE_QUOTAS.WORKFLOW_HISTORY_PRUNE_LIMIT]: -1,
|
||||
[LICENSE_QUOTAS.TEAM_PROJECT_LIMIT]: 0,
|
||||
};
|
||||
|
||||
constructor(
|
||||
license: License,
|
||||
private readonly settingsRepo: SettingsRepository,
|
||||
private readonly userRepo: UserRepository,
|
||||
private readonly workflowRunner: ActiveWorkflowManager,
|
||||
private readonly mfaService: MfaService,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly push: Push,
|
||||
private readonly passwordUtility: PasswordUtility,
|
||||
private readonly eventBus: MessageEventBus,
|
||||
private readonly userRepository: UserRepository,
|
||||
) {
|
||||
license.isFeatureEnabled = (feature: BooleanLicenseFeature) =>
|
||||
this.enabledFeatures[feature] ?? false;
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
license.getFeatureValue<NumericLicenseFeature> = (feature: NumericLicenseFeature) =>
|
||||
this.numericFeatures[feature] ?? UNLIMITED_LICENSE_QUOTA;
|
||||
}
|
||||
|
||||
@Post('/reset', { skipAuth: true })
|
||||
@@ -119,6 +135,12 @@ export class E2EController {
|
||||
this.enabledFeatures[feature] = enabled;
|
||||
}
|
||||
|
||||
@Patch('/quota', { skipAuth: true })
|
||||
setQuota(req: Request<{}, {}, { feature: NumericLicenseFeature; value: number }>) {
|
||||
const { value, feature } = req.body;
|
||||
this.numericFeatures[feature] = value;
|
||||
}
|
||||
|
||||
@Patch('/queue-mode', { skipAuth: true })
|
||||
async setQueueMode(req: Request<{}, {}, { enabled: boolean }>) {
|
||||
const { enabled } = req.body;
|
||||
@@ -163,34 +185,34 @@ export class E2EController {
|
||||
members: UserSetupPayload[],
|
||||
admin: UserSetupPayload,
|
||||
) {
|
||||
const instanceOwner = this.userRepo.create({
|
||||
id: uuid(),
|
||||
...owner,
|
||||
password: await this.passwordUtility.hash(owner.password),
|
||||
role: 'global:owner',
|
||||
});
|
||||
|
||||
if (owner?.mfaSecret && owner.mfaRecoveryCodes?.length) {
|
||||
const { encryptedRecoveryCodes, encryptedSecret } =
|
||||
this.mfaService.encryptSecretAndRecoveryCodes(owner.mfaSecret, owner.mfaRecoveryCodes);
|
||||
instanceOwner.mfaSecret = encryptedSecret;
|
||||
instanceOwner.mfaRecoveryCodes = encryptedRecoveryCodes;
|
||||
owner.mfaSecret = encryptedSecret;
|
||||
owner.mfaRecoveryCodes = encryptedRecoveryCodes;
|
||||
}
|
||||
|
||||
const adminUser = this.userRepo.create({
|
||||
id: uuid(),
|
||||
...admin,
|
||||
password: await this.passwordUtility.hash(admin.password),
|
||||
role: 'global:admin',
|
||||
});
|
||||
const userCreatePromises = [
|
||||
this.userRepository.createUserWithProject({
|
||||
id: uuid(),
|
||||
...owner,
|
||||
password: await this.passwordUtility.hash(owner.password),
|
||||
role: 'global:owner',
|
||||
}),
|
||||
];
|
||||
|
||||
const users = [];
|
||||
|
||||
users.push(instanceOwner, adminUser);
|
||||
userCreatePromises.push(
|
||||
this.userRepository.createUserWithProject({
|
||||
id: uuid(),
|
||||
...admin,
|
||||
password: await this.passwordUtility.hash(admin.password),
|
||||
role: 'global:admin',
|
||||
}),
|
||||
);
|
||||
|
||||
for (const { password, ...payload } of members) {
|
||||
users.push(
|
||||
this.userRepo.create({
|
||||
userCreatePromises.push(
|
||||
this.userRepository.createUserWithProject({
|
||||
id: uuid(),
|
||||
...payload,
|
||||
password: await this.passwordUtility.hash(password),
|
||||
@@ -199,7 +221,7 @@ export class E2EController {
|
||||
);
|
||||
}
|
||||
|
||||
await this.userRepo.insert(users);
|
||||
await Promise.all(userCreatePromises);
|
||||
|
||||
await this.settingsRepo.update(
|
||||
{ key: 'userManagement.isInstanceOwnerSetUp' },
|
||||
|
||||
Reference in New Issue
Block a user