@clairejs/server 3.25.0 → 3.25.2
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/README.md +2 -1
- package/dist/common/request/endpoint-metadata.d.ts +1 -0
- package/dist/http/auth/AbstractRbacAuthorizer.d.ts +22 -0
- package/dist/http/auth/AbstractRbacAuthorizer.js +59 -0
- package/dist/http/controller/AbstractHttpRequestHandler.js +2 -1
- package/dist/http/utils.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@ import { AbstractAccessCondition } from "../../http/security/abstract-access-con
|
|
|
5
5
|
export interface EndpointMetadata extends ApiInfo, ObjectFieldMetadata {
|
|
6
6
|
controller: any;
|
|
7
7
|
accessConditionCls?: Constructor<AbstractAccessCondition<any>>[];
|
|
8
|
+
accessConditionInstances?: AbstractAccessCondition<any>[];
|
|
8
9
|
params?: {
|
|
9
10
|
[index: number]: {
|
|
10
11
|
source?: RequestDataSource;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { HttpRequest } from "../common/HttpRequest";
|
|
2
|
+
import { EndpointMetadata } from "../../common/request/endpoint-metadata";
|
|
3
|
+
import { AbstractRequestAuthorizer } from "./AbstractHttpAuthorizer";
|
|
4
|
+
interface UserPrincipal {
|
|
5
|
+
principalId: string;
|
|
6
|
+
tfa?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface PermissionDetailResponse {
|
|
9
|
+
isSuperUser?: boolean;
|
|
10
|
+
permissions?: {
|
|
11
|
+
conditions?: {
|
|
12
|
+
conditionName: string;
|
|
13
|
+
conditionValue: string;
|
|
14
|
+
}[];
|
|
15
|
+
}[];
|
|
16
|
+
}
|
|
17
|
+
export declare abstract class AbstractRbacAuthorizer extends AbstractRequestAuthorizer {
|
|
18
|
+
abstract getPermissionDetail(principal: string, endpoint: string): Promise<PermissionDetailResponse>;
|
|
19
|
+
abstract getUserFromRequest(req: HttpRequest): Promise<UserPrincipal>;
|
|
20
|
+
authorize(req: HttpRequest, endpoint: EndpointMetadata): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Errors } from "@clairejs/core";
|
|
2
|
+
import { AbstractRequestAuthorizer } from "./AbstractHttpAuthorizer";
|
|
3
|
+
export class AbstractRbacAuthorizer extends AbstractRequestAuthorizer {
|
|
4
|
+
async authorize(req, endpoint) {
|
|
5
|
+
if (endpoint.publicAccess) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const user = await this.getUserFromRequest(req);
|
|
9
|
+
if (endpoint.tfaRequired && !user.tfa) {
|
|
10
|
+
throw Errors.TFA_REQUIRED();
|
|
11
|
+
}
|
|
12
|
+
const detail = await this.getPermissionDetail(user.principalId, endpoint.id);
|
|
13
|
+
if (detail.isSuperUser) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (!detail.permissions?.length) {
|
|
17
|
+
throw Errors.ACCESS_DENIED();
|
|
18
|
+
}
|
|
19
|
+
let passed = false;
|
|
20
|
+
let failedCondition = "";
|
|
21
|
+
for (const permission of detail.permissions) {
|
|
22
|
+
if (!permission.conditions?.length) {
|
|
23
|
+
passed = true;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
let allConditionCheckPassed = true;
|
|
27
|
+
for (const condition of permission.conditions) {
|
|
28
|
+
const matchedCondition = endpoint.accessConditionInstances?.find((c) => c.getConditionMetadata().name === condition.conditionName);
|
|
29
|
+
if (!matchedCondition) {
|
|
30
|
+
//-- condition not found, skip
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const requestedConditionValue = await matchedCondition.resolveConditionValue(req);
|
|
35
|
+
const permittedConditionValue = JSON.parse(condition.conditionValue);
|
|
36
|
+
allConditionCheckPassed = await matchedCondition.validate(requestedConditionValue, permittedConditionValue);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
//-- this condition does not passed, skip
|
|
40
|
+
allConditionCheckPassed = false;
|
|
41
|
+
}
|
|
42
|
+
if (!allConditionCheckPassed) {
|
|
43
|
+
//-- at least one condition not satisfied, stop condition checking
|
|
44
|
+
failedCondition = condition.conditionName;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
passed = allConditionCheckPassed;
|
|
49
|
+
}
|
|
50
|
+
if (passed) {
|
|
51
|
+
//-- at least one permission and conditions suit checked passed
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (!passed) {
|
|
56
|
+
throw Errors.ACCESS_DENIED(`Condition check failed: ${failedCondition}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -53,7 +53,8 @@ export class AbstractHttpRequestHandler {
|
|
|
53
53
|
this.logger?.warn(`Implicit overriding endpoint: ${overridingEndpoint.method}:${overridingEndpoint.mount} of ${overridingEndpoint.controller?.constructor.name}:${overridingEndpoint.name}`, `Ignore ${endpointInfo.method}:${endpointInfo.mount} of ${endpointInfo.controller?.constructor.name}:${endpointInfo.name}`);
|
|
54
54
|
}
|
|
55
55
|
else {
|
|
56
|
-
endpointInfo.
|
|
56
|
+
endpointInfo.accessConditionInstances = endpointInfo.accessConditionCls?.map((cls) => injector.resolve(cls));
|
|
57
|
+
endpointInfo.accessConditions = endpointInfo.accessConditionInstances?.map((instance) => instance.getConditionMetadata());
|
|
57
58
|
mountedEndpointInfo.push(endpointInfo);
|
|
58
59
|
}
|
|
59
60
|
}
|
package/dist/http/utils.js
CHANGED
|
@@ -11,7 +11,7 @@ export const getApiInfo = async () => {
|
|
|
11
11
|
socketManager ? socketManager.getMountedEndpointInfo() : Promise.resolve([]),
|
|
12
12
|
]);
|
|
13
13
|
const result = {
|
|
14
|
-
apis: [...httpInfo, ...socketInfo].map(({ controller, params, injecteeSuperClass, accessConditionCls, ...api }) => api),
|
|
14
|
+
apis: [...httpInfo, ...socketInfo].map(({ controller, params, injecteeSuperClass, accessConditionCls, accessConditionInstances, ...api }) => api),
|
|
15
15
|
};
|
|
16
16
|
await injector.initInstances();
|
|
17
17
|
return result;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from "./common/request/endpoint-metadata";
|
|
|
5
5
|
export * from "./common/request/RequestOptions";
|
|
6
6
|
export * from "./common/ControllerMetadata";
|
|
7
7
|
export * from "./common/decorator";
|
|
8
|
+
export * from "./http/common/dto";
|
|
8
9
|
export * from "./http/common/HttpResponse";
|
|
9
10
|
export * from "./http/decorators";
|
|
10
11
|
export * from "./http/common/HttpRequest";
|
|
@@ -22,6 +23,7 @@ export * from "./http/security/abstract-access-condition";
|
|
|
22
23
|
export * from "./http/security/access-condition-metadata";
|
|
23
24
|
export * from "./http/security/access-condition-value-type";
|
|
24
25
|
export * from "./http/auth/AbstractHttpAuthorizer";
|
|
26
|
+
export * from "./http/auth/AbstractRbacAuthorizer";
|
|
25
27
|
export * from "./http/repository/ModelRepository";
|
|
26
28
|
export * from "./http/repository/DtoRepository";
|
|
27
29
|
export * from "./http/repository/ICrudRepository";
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export * from "./common/request/RequestOptions";
|
|
|
7
7
|
export * from "./common/ControllerMetadata";
|
|
8
8
|
export * from "./common/decorator";
|
|
9
9
|
//-- http & security
|
|
10
|
+
export * from "./http/common/dto";
|
|
10
11
|
export * from "./http/common/HttpResponse";
|
|
11
12
|
export * from "./http/decorators";
|
|
12
13
|
export * from "./http/common/HttpRequest";
|
|
@@ -24,6 +25,7 @@ export * from "./http/security/abstract-access-condition";
|
|
|
24
25
|
export * from "./http/security/access-condition-metadata";
|
|
25
26
|
export * from "./http/security/access-condition-value-type";
|
|
26
27
|
export * from "./http/auth/AbstractHttpAuthorizer";
|
|
28
|
+
export * from "./http/auth/AbstractRbacAuthorizer";
|
|
27
29
|
export * from "./http/repository/ModelRepository";
|
|
28
30
|
export * from "./http/repository/DtoRepository";
|
|
29
31
|
export * from "./http/repository/ICrudRepository";
|