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:
Csaba Tuncsik
2024-05-17 10:53:15 +02:00
committed by GitHub
parent b1f977ebd0
commit 596c472ecc
292 changed files with 14129 additions and 3989 deletions

View File

@@ -38,7 +38,6 @@ import type {
import { isString } from '@/utils/typeGuards';
import { isObject } from '@/utils/objectUtils';
import { useSettingsStore } from '@/stores/settings.store';
import { useUsersStore } from '@/stores/users.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import { useCredentialsStore } from '@/stores/credentials.store';
@@ -46,7 +45,6 @@ import { get } from 'lodash-es';
import { useI18n } from './useI18n';
import { EnableNodeToggleCommand } from '@/models/history';
import { useTelemetry } from './useTelemetry';
import { getCredentialPermissions } from '@/permissions';
import { hasPermission } from '@/rbac/permissions';
import type { N8nPlusEndpoint } from '@/plugins/jsplumb/N8nPlusEndpointType';
import * as NodeViewUtils from '@/utils/nodeViewUtils';
@@ -430,14 +428,7 @@ export function useNodeHelpers() {
};
}
const usersStore = useUsersStore();
const currentUser = usersStore.currentUser;
userCredentials = credentialsStore
.getCredentialsByType(credentialTypeDescription.name)
.filter((credential: ICredentialsResponse) => {
const permissions = getCredentialPermissions(currentUser, credential);
return permissions.use;
});
userCredentials = credentialsStore.getCredentialsByType(credentialTypeDescription.name);
if (userCredentials === null) {
userCredentials = [];

View File

@@ -12,6 +12,7 @@ vi.mock('vue-router', () => {
useRouter: () => ({
push: vi.fn(),
}),
useRoute: () => ({}),
};
});

View File

@@ -1,5 +1,4 @@
import {
EnterpriseEditionFeature,
HTTP_REQUEST_NODE_TYPE,
MODAL_CONFIRM,
PLACEHOLDER_EMPTY_WORKFLOW_ID,
@@ -7,7 +6,6 @@ import {
VIEWS,
WEBHOOK_NODE_TYPE,
} from '@/constants';
import { computed } from 'vue';
import type {
IConnections,
@@ -51,16 +49,12 @@ import { useNodeHelpers } from '@/composables/useNodeHelpers';
import { get, isEqual } from 'lodash-es';
import type { IPermissions } from '@/permissions';
import { getWorkflowPermissions } from '@/permissions';
import { useEnvironmentsStore } from '@/stores/environments.ee.store';
import { useRootStore } from '@/stores/n8nRoot.store';
import { useNDVStore } from '@/stores/ndv.store';
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import { useTemplatesStore } from '@/stores/templates.store';
import { useUIStore } from '@/stores/ui.store';
import { useUsersStore } from '@/stores/users.store';
import { useWorkflowsEEStore } from '@/stores/workflows.ee.store';
import { useWorkflowsStore } from '@/stores/workflows.store';
import { getSourceItems } from '@/utils/pairedItemUtils';
import { v4 as uuid } from 'uuid';
@@ -73,6 +67,7 @@ import { tryToParseNumber } from '@/utils/typesUtils';
import { useI18n } from '@/composables/useI18n';
import type { useRouter } from 'vue-router';
import { useTelemetry } from '@/composables/useTelemetry';
import { useProjectsStore } from '@/features/projects/projects.store';
export function resolveParameter(
parameter: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[],
@@ -485,20 +480,15 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
const rootStore = useRootStore();
const templatesStore = useTemplatesStore();
const workflowsStore = useWorkflowsStore();
const workflowsEEStore = useWorkflowsEEStore();
const usersStore = useUsersStore();
const uiStore = useUIStore();
const nodeHelpers = useNodeHelpers();
const projectsStore = useProjectsStore();
const toast = useToast();
const message = useMessage();
const i18n = useI18n();
const telemetry = useTelemetry();
const workflowPermissions = computed<IPermissions>(() => {
return getWorkflowPermissions(usersStore.currentUser, workflowsStore.workflow);
});
function getNodeTypesMaxCount() {
const nodes = workflowsStore.allNodes;
@@ -936,7 +926,7 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
if (error.errorCode === 100) {
telemetry.track('User attempted to save locked workflow', {
workflowId: currentWorkflow,
sharing_role: workflowPermissions.value.isOwner ? 'owner' : 'sharee',
sharing_role: getWorkflowProjectRole(currentWorkflow),
});
const url = router.resolve({
@@ -1031,15 +1021,6 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
const workflowData = await workflowsStore.createNewWorkflow(workflowDataRequest);
workflowsStore.addWorkflow(workflowData);
if (
useSettingsStore().isEnterpriseFeatureEnabled(EnterpriseEditionFeature.Sharing) &&
usersStore.currentUser
) {
workflowsEEStore.setWorkflowOwnedBy({
workflowId: workflowData.id,
ownedBy: usersStore.currentUser,
});
}
if (openInNewWindow) {
const routeData = router.resolve({
@@ -1187,6 +1168,25 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
});
}
function getWorkflowProjectRole(workflowId: string): 'owner' | 'sharee' | 'member' {
const workflow = workflowsStore.workflowsById[workflowId];
if (
workflow?.homeProject?.id === projectsStore.personalProject?.id ||
workflowId === PLACEHOLDER_EMPTY_WORKFLOW_ID
) {
return 'owner';
} else if (
workflow?.sharedWithProjects?.some(
(project) => project.id === projectsStore.personalProject?.id,
)
) {
return 'sharee';
} else {
return 'member';
}
}
return {
resolveParameter,
resolveRequiredParameters,
@@ -1211,6 +1211,6 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
updateNodePositions,
dataHasChanged,
removeForeignCredentialsFromWorkflow,
workflowPermissions,
getWorkflowProjectRole,
};
}