@boarteam/boar-pack-users-backend 6.7.0 → 6.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boarteam/boar-pack-users-backend",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.8.0",
|
|
4
4
|
"description": "NestJS Users module including permissions system, authentication strategies etc",
|
|
5
5
|
"main": "src/index",
|
|
6
6
|
"files": [
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"access": "public"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@boarteam/boar-pack-common-backend": "^3.1.
|
|
17
|
+
"@boarteam/boar-pack-common-backend": "^3.1.1",
|
|
18
18
|
"@casl/ability": "^6.7.3",
|
|
19
19
|
"@dataui/crud": "^5.3.4",
|
|
20
20
|
"@dataui/crud-typeorm": "^5.3.4",
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"yalc:push": "yalc push",
|
|
65
65
|
"gen-types": "SWAGGER=true JWT_SECRET=swagger nest start"
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "04d19f79a5bb2e27afcf0496e31ed7c5b990fdd7"
|
|
68
68
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// fields-permission.interceptor.ts
|
|
2
|
+
import { CallHandler, ExecutionContext, ForbiddenException, Injectable, NestInterceptor, } from '@nestjs/common';
|
|
3
|
+
import { permittedFieldsOf } from '@casl/ability/extra';
|
|
4
|
+
import { Observable } from 'rxjs';
|
|
5
|
+
import { Request } from 'express';
|
|
6
|
+
import { Action } from "./action.enum";
|
|
7
|
+
import { Subjects } from "./casl-ability.factory";
|
|
8
|
+
import { PARSED_CRUD_REQUEST_KEY } from "@dataui/crud/lib/constants";
|
|
9
|
+
|
|
10
|
+
type Fields = string[] | undefined;
|
|
11
|
+
|
|
12
|
+
@Injectable()
|
|
13
|
+
export class FieldsPermissionInterceptor implements NestInterceptor {
|
|
14
|
+
constructor(
|
|
15
|
+
private readonly subject: Subjects,
|
|
16
|
+
private readonly action: Action,
|
|
17
|
+
) {
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private anyField = '*';
|
|
21
|
+
|
|
22
|
+
intercept(ctx: ExecutionContext, next: CallHandler): Observable<any> {
|
|
23
|
+
const req = ctx.switchToHttp().getRequest<Request>();
|
|
24
|
+
const ability = req.user?.ability;
|
|
25
|
+
if (!ability) {
|
|
26
|
+
throw new ForbiddenException('No ability found on user');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const permitted = permittedFieldsOf(ability, this.action, this.subject, {
|
|
30
|
+
// how to read fields from each rule
|
|
31
|
+
fieldsFrom: (rule) => rule.fields || [this.anyField],
|
|
32
|
+
}) as string[];
|
|
33
|
+
|
|
34
|
+
if (permitted.includes(this.anyField)) {
|
|
35
|
+
// all fields are permitted
|
|
36
|
+
return next.handle();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
const crudReq = req[PARSED_CRUD_REQUEST_KEY];
|
|
41
|
+
const requested = (crudReq?.parsed?.fields as Fields) ?? [];
|
|
42
|
+
const finalFields =
|
|
43
|
+
(requested && requested.length > 0)
|
|
44
|
+
? requested.filter((f) => permitted.includes(f))
|
|
45
|
+
: permitted;
|
|
46
|
+
|
|
47
|
+
if (!finalFields || finalFields.length === 0) {
|
|
48
|
+
throw new ForbiddenException('No readable fields for this resource');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// enforce selection for Nestjsx/CRUD + TypeORM
|
|
52
|
+
// This makes CRUD build QB with SELECT only these columns.
|
|
53
|
+
if (!crudReq.parsed) crudReq.parsed = {} as any;
|
|
54
|
+
(crudReq.parsed as any).fields = finalFields;
|
|
55
|
+
|
|
56
|
+
return next.handle();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -2,7 +2,7 @@ import { Controller, UseFilters, UseGuards } from '@nestjs/common';
|
|
|
2
2
|
import { UsersService } from './users.service';
|
|
3
3
|
import { Crud } from '@dataui/crud';
|
|
4
4
|
import { User } from './entities/user.entity';
|
|
5
|
-
import {
|
|
5
|
+
import { Action, CheckPolicies } from '../casl';
|
|
6
6
|
import { UserCreateDto } from './dto/user-create.dto';
|
|
7
7
|
import { ApiExtraModels, ApiTags } from '@nestjs/swagger';
|
|
8
8
|
import { UserUpdateDto } from "./dto/user-update.dto";
|
|
@@ -12,6 +12,7 @@ import { UsersEditingGuard } from "./users-editing.guard";
|
|
|
12
12
|
import { ViewUsersPolicy } from "./policies/view-users.policy";
|
|
13
13
|
import { Tools } from "@boarteam/boar-pack-common-backend";
|
|
14
14
|
import { ManageUsersPolicy } from "./policies/manage-users.policy";
|
|
15
|
+
import { FieldsPermissionInterceptor } from "../casl/fields-permission.interceptor";
|
|
15
16
|
|
|
16
17
|
@Crud({
|
|
17
18
|
model: {
|
|
@@ -35,11 +36,17 @@ import { ManageUsersPolicy } from "./policies/manage-users.policy";
|
|
|
35
36
|
decorators: [
|
|
36
37
|
CheckPolicies(new ViewUsersPolicy()),
|
|
37
38
|
],
|
|
39
|
+
interceptors: [
|
|
40
|
+
new FieldsPermissionInterceptor(User, Action.Read),
|
|
41
|
+
],
|
|
38
42
|
},
|
|
39
43
|
getOneBase: {
|
|
40
44
|
decorators: [
|
|
41
45
|
CheckPolicies(new ViewUsersPolicy()),
|
|
42
46
|
],
|
|
47
|
+
interceptors: [
|
|
48
|
+
new FieldsPermissionInterceptor(User, Action.Read),
|
|
49
|
+
],
|
|
43
50
|
},
|
|
44
51
|
createOneBase: {
|
|
45
52
|
interceptors: [
|