Browse Source

fix: middleware corrections

pull/8708/head
Pranav C 5 months ago
parent
commit
82b89d1ffe
  1. 29
      packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue
  2. 6
      packages/nc-gui/components/smartsheet/header/Menu.vue
  3. 5
      packages/nc-gui/lib/acl.ts
  4. 52
      packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts

29
packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue

@ -446,6 +446,10 @@ const onTableIdCopy = async () => {
message.error(e.message)
}
}
const getSource = (sourceId: string) => {
return base.value.sources?.find((s) => s.id === sourceId)
}
</script>
<template>
@ -633,7 +637,7 @@ const onTableIdCopy = async () => {
</NcDropdown>
<NcButton
v-if="isUIAllowed('tableCreate', { roles: baseRole })"
v-if="isUIAllowed('tableCreate', { roles: baseRole, source: base?.sources?.[0] })"
v-e="['c:base:create-table']"
:disabled="!base?.sources?.[0]?.enabled"
class="nc-sidebar-node-btn"
@ -886,9 +890,17 @@ const onTableIdCopy = async () => {
</div>
</NcTooltip>
<template v-if="isUIAllowed('tableRename') || isUIAllowed('tableDelete')">
<template
v-if="
isUIAllowed('tableRename', { source: getSource(contextMenuTarget.value?.source_id) }) ||
isUIAllowed('tableDelete', { source: getSource(contextMenuTarget.value?.source_id) })
"
>
<NcDivider />
<NcMenuItem v-if="isUIAllowed('tableRename')" @click="openRenameTableDialog(contextMenuTarget.value, true)">
<NcMenuItem
v-if="isUIAllowed('tableRename', { source: getSource(contextMenuTarget.value?.source_id) })"
@click="openRenameTableDialog(contextMenuTarget.value, true)"
>
<div v-e="['c:table:rename']" class="nc-base-option-item flex gap-2 items-center">
<GeneralIcon icon="rename" class="text-gray-700" />
{{ $t('general.rename') }} {{ $t('objects.table') }}
@ -896,7 +908,10 @@ const onTableIdCopy = async () => {
</NcMenuItem>
<NcMenuItem
v-if="isUIAllowed('tableDuplicate') && (contextMenuBase?.is_meta || contextMenuBase?.is_local)"
v-if="
isUIAllowed('tableDuplicate', { source: getSource(contextMenuTarget.value?.source_id) }) &&
(contextMenuBase?.is_meta || contextMenuBase?.is_local)
"
@click="duplicateTable(contextMenuTarget.value)"
>
<div v-e="['c:table:duplicate']" class="nc-base-option-item flex gap-2 items-center">
@ -905,7 +920,11 @@ const onTableIdCopy = async () => {
</div>
</NcMenuItem>
<NcDivider />
<NcMenuItem v-if="isUIAllowed('table-delete')" class="!hover:bg-red-50" @click="tableDelete">
<NcMenuItem
v-if="isUIAllowed('tableDelete', { source: getSource(contextMenuTarget.value?.source_id) })"
class="!hover:bg-red-50"
@click="tableDelete"
>
<div class="nc-base-option-item flex gap-2 items-center text-red-600">
<GeneralIcon icon="delete" />
{{ $t('general.delete') }} {{ $t('objects.table') }}

6
packages/nc-gui/components/smartsheet/header/Menu.vue

@ -383,7 +383,11 @@ const filterOrGroupByThisField = (event: SmartsheetStoreEvents) => {
{{ $t('general.edit') }}
</div>
</NcMenuItem>
<NcMenuItem v-if="isExpandedForm && !column?.pk" :disabled="!isDuplicateAllowed" @click="openDuplicateDlg">
<NcMenuItem
v-if="isUIAllowed('duplicateColumn') && isExpandedForm && !column?.pk"
:disabled="!isDuplicateAllowed"
@click="openDuplicateDlg"
>
<div v-e="['a:field:duplicate']" class="nc-column-duplicate nc-header-menu-item">
<component :is="iconMap.duplicate" class="text-gray-700" />
<!-- Duplicate -->

5
packages/nc-gui/lib/acl.ts

@ -130,6 +130,9 @@ export const sourceRestrictions = {
csvImport: true,
jsonImport: true,
excelImport: true,
duplicateColumn: true,
duplicateModel: true,
tableDuplicate: true,
},
[SourceRestriction.META_READONLY]: {
tableCreate: true,
@ -142,6 +145,8 @@ export const sourceRestrictions = {
excelImport: true,
fieldAdd: true,
fieldAlter: true,
duplicateColumn: true,
duplicateModel: true,
},
}

52
packages/nocodb/src/middlewares/extract-ids/extract-ids.middleware.ts

@ -1,6 +1,11 @@
import { Injectable, SetMetadata, UseInterceptors } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { extractRolesObj, OrgUserRoles, ProjectRoles } from 'nocodb-sdk';
import {
extractRolesObj,
OrgUserRoles,
ProjectRoles,
SourceRestriction,
} from 'nocodb-sdk';
import { map } from 'rxjs';
import type { Observable } from 'rxjs';
import type {
@ -28,6 +33,8 @@ import {
import rolePermissions from '~/utils/acl';
import { NcError } from '~/helpers/catchError';
import { RootScopes } from '~/utils/globals';
import { sourceRestrictions } from '~/utils/acl';
import { Source } from '~/models';
export const rolesLabel = {
[OrgUserRoles.SUPER_ADMIN]: 'Super Admin',
@ -455,6 +462,49 @@ export class AclMiddleware implements NestInterceptor {
);
}
// check if permission have source level permission restriction
// 1. Check if it's present in the source restriction list
// 2. If present, check if write permission is allowed
if (
sourceRestrictions[SourceRestriction.META_READONLY][permissionName] ||
sourceRestrictions[SourceRestriction.DATA_READONLY][permissionName]
) {
let source: Source;
// if tableCreate and source ID is empty, then extract the default source from base
if (!req.ncSourceId && req.ncBaseId && permissionName === 'tableCreate') {
const sources = await Source.list(req.context, {
baseId: req.ncBaseId,
});
if (req.params.sourceId) {
source = sources.find((s) => s.id === req.params.sourceId);
} else {
source = sources.find((s) => s.isMeta());
}
} else if (req.ncSourceId) {
source = await Source.get(req.context, req.ncSourceId);
}
// todo: replace with better error and this is not an expected error
if (!source) {
NcError.notFound('Source not found or source id not extracted');
}
if (
source.meta?.[SourceRestriction.META_READONLY] &&
sourceRestrictions[SourceRestriction.META_READONLY][permissionName]
) {
NcError.sourceMetaReadOnly(source.alias);
}
if (
source.meta?.[SourceRestriction.DATA_READONLY] &&
sourceRestrictions[SourceRestriction.DATA_READONLY][permissionName]
) {
NcError.sourceDataReadOnly(source.alias);
}
}
return next.handle().pipe(
map((data) => {
return data;

Loading…
Cancel
Save