diff --git a/server/src/modules/app/guards/ability.guard.ts b/server/src/modules/app/guards/ability.guard.ts index 690129f81c..7532b61376 100644 --- a/server/src/modules/app/guards/ability.guard.ts +++ b/server/src/modules/app/guards/ability.guard.ts @@ -94,11 +94,10 @@ export abstract class AbilityGuard implements CanActivate { // Validate all features against resource if any if (!features.every((feature) => ability.can(feature, this.getSubjectType(), resourceId || undefined))) { - throw new ForbiddenException( - JSON.stringify({ - organizationId: app?.organizationId, - }) - ); + throw new ForbiddenException({ + message: 'You do not have permission to access this resource', + organizationId: app?.organizationId, + }); } return true; } diff --git a/server/src/modules/data-queries/ability/app/index.ts b/server/src/modules/data-queries/ability/app/index.ts index b388171e39..a6bd868805 100644 --- a/server/src/modules/data-queries/ability/app/index.ts +++ b/server/src/modules/data-queries/ability/app/index.ts @@ -31,6 +31,9 @@ export class FeatureAbilityFactory extends AbilityFactory const appId = request?.tj_resource_id; + // Always grant RUN_EDITOR and RUN_VIEWER permissions + can([FEATURE_KEY.RUN_EDITOR, FEATURE_KEY.RUN_VIEWER], App); + // Admin or super admin and do all operations if (isAdmin || superAdmin) { can( @@ -86,11 +89,11 @@ export class FeatureAbilityFactory extends AbilityFactory } if (isAllViewable) { - can([FEATURE_KEY.GET, FEATURE_KEY.PREVIEW, FEATURE_KEY.RUN_VIEWER], App); + can([FEATURE_KEY.GET, FEATURE_KEY.PREVIEW, FEATURE_KEY.RUN_VIEWER, FEATURE_KEY.RUN_EDITOR], App); return; } if (resourcePermissions?.viewableAppsId?.length && appId && resourcePermissions?.viewableAppsId?.includes(appId)) { - can([FEATURE_KEY.GET, FEATURE_KEY.PREVIEW, FEATURE_KEY.RUN_VIEWER], App); + can([FEATURE_KEY.GET, FEATURE_KEY.PREVIEW, FEATURE_KEY.RUN_VIEWER, FEATURE_KEY.RUN_EDITOR], App); return; } } diff --git a/server/src/modules/data-queries/ability/data-source/index.ts b/server/src/modules/data-queries/ability/data-source/index.ts index b93f513950..9fd80a297e 100644 --- a/server/src/modules/data-queries/ability/data-source/index.ts +++ b/server/src/modules/data-queries/ability/data-source/index.ts @@ -30,10 +30,14 @@ export class FeatureAbilityFactory extends AbilityFactory const isAllViewable = !!resourcePermissions?.isAllUsable; const dataSourceId = request?.tj_resource_id; + const isStatic = request?.resource_type === 'static'; + + // Always grant RUN_EDITOR and RUN_VIEWER permissions + can([FEATURE_KEY.RUN_EDITOR, FEATURE_KEY.RUN_VIEWER], DataSource); // Define permissions for data queries - if (isAdmin || superAdmin || isAllEditable || isCanCreate || isCanDelete) { + if (isStatic || isAdmin || superAdmin || isAllEditable || isCanCreate || isCanDelete) { can( [ FEATURE_KEY.CREATE, diff --git a/server/src/modules/data-queries/guards/validate-query-source.guard.ts b/server/src/modules/data-queries/guards/validate-query-source.guard.ts index 829c8415b3..a61e6877af 100644 --- a/server/src/modules/data-queries/guards/validate-query-source.guard.ts +++ b/server/src/modules/data-queries/guards/validate-query-source.guard.ts @@ -45,6 +45,7 @@ export class ValidateQuerySourceGuard implements CanActivate { // Attach the found app to the request request.tj_data_source = dataSource; request.tj_resource_id = dataSource.id; + request.resource_type = dataSource?.type; // Return true to allow the request to proceed return true; diff --git a/server/src/modules/data-sources/ability/index.ts b/server/src/modules/data-sources/ability/index.ts index 4e960170bb..13c9be760c 100644 --- a/server/src/modules/data-sources/ability/index.ts +++ b/server/src/modules/data-sources/ability/index.ts @@ -87,19 +87,19 @@ export class FeatureAbilityFactory extends AbilityFactory return; } - if ( - resourcePermissions?.configurableDataSourceId?.length && - dataSourceId && - resourcePermissions?.configurableDataSourceId?.includes(dataSourceId) - ) { - can( - [FEATURE_KEY.GET, FEATURE_KEY.UPDATE, FEATURE_KEY.GET_BY_ENVIRONMENT, FEATURE_KEY.TEST_CONNECTION], - DataSource - ); + if (resourcePermissions?.configurableDataSourceId?.length) { + can([FEATURE_KEY.GET, FEATURE_KEY.TEST_CONNECTION, FEATURE_KEY.GET_BY_ENVIRONMENT], DataSource); + + if (dataSourceId && resourcePermissions?.configurableDataSourceId?.includes(dataSourceId)) { + can( + [FEATURE_KEY.GET, FEATURE_KEY.UPDATE, FEATURE_KEY.GET_BY_ENVIRONMENT, FEATURE_KEY.TEST_CONNECTION], + DataSource + ); + } } if (isAllViewable) { - can([FEATURE_KEY.GET_BY_ENVIRONMENT], DataSource); + can([FEATURE_KEY.GET_BY_ENVIRONMENT, FEATURE_KEY.GET, FEATURE_KEY.TEST_CONNECTION], DataSource); return; } if ( @@ -107,7 +107,7 @@ export class FeatureAbilityFactory extends AbilityFactory dataSourceId && resourcePermissions?.usableDataSourcesId?.includes(dataSourceId) ) { - can([FEATURE_KEY.GET, FEATURE_KEY.GET_BY_ENVIRONMENT], DataSource); + can([FEATURE_KEY.GET, FEATURE_KEY.GET_BY_ENVIRONMENT, FEATURE_KEY.TEST_CONNECTION], DataSource); return; } }