@nmshd/typescript-rest 3.2.0 → 3.2.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/.ci/runChecks.sh +1 -1
- package/.github/workflows/publish.yml +2 -4
- package/.github/workflows/test.yml +2 -2
- package/dist/middlewares/routeRequiresAuthorization.js +23 -17
- package/dist/middlewares/routeRequiresAuthorization.js.map +1 -1
- package/package.json +19 -19
- package/src/middlewares/routeRequiresAuthorization.ts +27 -16
package/.ci/runChecks.sh
CHANGED
|
@@ -8,8 +8,8 @@ jobs:
|
|
|
8
8
|
run-checks:
|
|
9
9
|
runs-on: ubuntu-latest
|
|
10
10
|
steps:
|
|
11
|
-
- uses: actions/checkout@
|
|
12
|
-
- uses: actions/setup-node@
|
|
11
|
+
- uses: actions/checkout@v5
|
|
12
|
+
- uses: actions/setup-node@v6
|
|
13
13
|
with:
|
|
14
14
|
node-version: current
|
|
15
15
|
- run: bash .ci/runChecks.sh
|
|
@@ -28,6 +28,4 @@ jobs:
|
|
|
28
28
|
- run: npm ci
|
|
29
29
|
- run: npm run build
|
|
30
30
|
- run: npx enhanced-publish --if-possible --use-preid-as-tag
|
|
31
|
-
env:
|
|
32
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
33
31
|
needs: ['run-checks']
|
|
@@ -13,11 +13,11 @@ function routeRequiresAuthorization(authenticator, ...permittedRoles) {
|
|
|
13
13
|
throw new Error(`Invalid permitted role(s) specified: ${nonMatchingRoles.join(', ')}. Roles must match the pattern: ${roleRegex}.`);
|
|
14
14
|
}
|
|
15
15
|
return (req, res, next) => {
|
|
16
|
-
const
|
|
16
|
+
const rawUserRoles = authenticator.getRoles(req, res);
|
|
17
17
|
if (debuggerInstance.enabled)
|
|
18
|
-
debuggerInstance('Validating authentication roles: <%j>.',
|
|
19
|
-
const
|
|
20
|
-
const isAuthorized = permittedRoles.some((
|
|
18
|
+
debuggerInstance('Validating authentication roles: <%j>.', rawUserRoles);
|
|
19
|
+
const userRoles = rawUserRoles.map(Role.from);
|
|
20
|
+
const isAuthorized = permittedRoles.some((r) => isRoleMatched(r, userRoles));
|
|
21
21
|
if (!isAuthorized) {
|
|
22
22
|
next(new Errors.ForbiddenError('You are not allowed to access this endpoint.'));
|
|
23
23
|
return;
|
|
@@ -26,19 +26,25 @@ function routeRequiresAuthorization(authenticator, ...permittedRoles) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
function isRoleMatched(permittedRole, userRoles) {
|
|
29
|
-
|
|
30
|
-
const isMatch = userRole.test(permittedRole);
|
|
31
|
-
if (isMatch)
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
29
|
+
return userRoles.some((userRole) => userRole.matches(permittedRole));
|
|
35
30
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
class Role {
|
|
32
|
+
constructor(role) {
|
|
33
|
+
this.roleRegex = this.transformUserRole(role);
|
|
34
|
+
}
|
|
35
|
+
static from(role) {
|
|
36
|
+
return new Role(role);
|
|
37
|
+
}
|
|
38
|
+
transformUserRole(userRole) {
|
|
39
|
+
if (!userRole.includes('*'))
|
|
40
|
+
return new RegExp(`^${userRole}$`);
|
|
41
|
+
const regexString = userRole
|
|
42
|
+
.replaceAll('**', '[a-zA-Z0-9_-]+(:[a-zA-Z0-9_-]+){0,}')
|
|
43
|
+
.replaceAll('*', '[a-zA-Z0-9_-]+');
|
|
44
|
+
return new RegExp(`^${regexString}$`);
|
|
45
|
+
}
|
|
46
|
+
matches(permittedRole) {
|
|
47
|
+
return this.roleRegex.test(permittedRole);
|
|
48
|
+
}
|
|
43
49
|
}
|
|
44
50
|
//# sourceMappingURL=routeRequiresAuthorization.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routeRequiresAuthorization.js","sourceRoot":"","sources":["../../src/middlewares/routeRequiresAuthorization.ts"],"names":[],"mappings":";;AAMA,gEA2BC;AAjCD,+BAA+B;AAE/B,iDAAiD;AAEjD,MAAM,gBAAgB,GAAG,KAAK,CAAC,wDAAwD,CAAC,CAAC;AAEzF,SAAgB,0BAA0B,CACtC,aAA2E,EAC3E,GAAG,cAA0C;IAE7C,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAEnG,MAAM,SAAS,GAAG,uCAAuC,CAAC;IAC1D,MAAM,gBAAgB,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACX,wCAAwC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAmC,SAAS,GAAG,CACrH,CAAC;IACN,CAAC;IAED,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACvD,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACtD,IAAI,gBAAgB,CAAC,OAAO;YAAE,gBAAgB,CAAC,wCAAwC,EAAE,YAAY,CAAC,CAAC;QAEvG,MAAM,
|
|
1
|
+
{"version":3,"file":"routeRequiresAuthorization.js","sourceRoot":"","sources":["../../src/middlewares/routeRequiresAuthorization.ts"],"names":[],"mappings":";;AAMA,gEA2BC;AAjCD,+BAA+B;AAE/B,iDAAiD;AAEjD,MAAM,gBAAgB,GAAG,KAAK,CAAC,wDAAwD,CAAC,CAAC;AAEzF,SAAgB,0BAA0B,CACtC,aAA2E,EAC3E,GAAG,cAA0C;IAE7C,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAEnG,MAAM,SAAS,GAAG,uCAAuC,CAAC;IAC1D,MAAM,gBAAgB,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACX,wCAAwC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAmC,SAAS,GAAG,CACrH,CAAC;IACN,CAAC;IAED,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACvD,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACtD,IAAI,gBAAgB,CAAC,OAAO;YAAE,gBAAgB,CAAC,wCAAwC,EAAE,YAAY,CAAC,CAAC;QAEvG,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QAC7E,IAAI,CAAC,YAAY,EAAE,CAAC;YAChB,IAAI,CAAC,IAAI,MAAM,CAAC,cAAc,CAAC,8CAA8C,CAAC,CAAC,CAAC;YAChF,OAAO;QACX,CAAC;QAED,IAAI,EAAE,CAAC;IACX,CAAC,CAAC;AACN,CAAC;AAED,SAAS,aAAa,CAAC,aAAqB,EAAE,SAAsB;IAChE,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,IAAI;IAGN,YAAoB,IAAY;QAC5B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC;IAEM,MAAM,CAAC,IAAI,CAAC,IAAY;QAC3B,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAEO,iBAAiB,CAAC,QAAgB;QACtC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,MAAM,CAAC,IAAI,QAAQ,GAAG,CAAC,CAAC;QAEhE,MAAM,WAAW,GAAG,QAAQ;aACvB,UAAU,CAAC,IAAI,EAAE,qCAAqC,CAAC;aACvD,UAAU,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QACvC,OAAO,IAAI,MAAM,CAAC,IAAI,WAAW,GAAG,CAAC,CAAC;IAC1C,CAAC;IAEM,OAAO,CAAC,aAAqB;QAChC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC9C,CAAC;CACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nmshd/typescript-rest",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.2",
|
|
4
4
|
"description": "A Library to create RESTFul APIs with Typescript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"API",
|
|
@@ -60,44 +60,44 @@
|
|
|
60
60
|
"sourceMap": true
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@types/body-parser": "1.19.
|
|
64
|
-
"@types/cookie-parser": "^1.4.
|
|
65
|
-
"@types/express": "^5.0.
|
|
66
|
-
"@types/multer": "^
|
|
67
|
-
"body-parser": "^2.2.
|
|
63
|
+
"@types/body-parser": "1.19.6",
|
|
64
|
+
"@types/cookie-parser": "^1.4.9",
|
|
65
|
+
"@types/express": "^5.0.3",
|
|
66
|
+
"@types/multer": "^2.0.0",
|
|
67
|
+
"body-parser": "^2.2.1",
|
|
68
68
|
"cookie-parser": "^1.4.7",
|
|
69
69
|
"express": "^5.1.0",
|
|
70
|
-
"fs-extra": "^11.3.
|
|
70
|
+
"fs-extra": "^11.3.2",
|
|
71
71
|
"lodash": "^4.17.21",
|
|
72
|
-
"multer": "^2.0.
|
|
72
|
+
"multer": "^2.0.2",
|
|
73
73
|
"reflect-metadata": "^0.2.2",
|
|
74
74
|
"require-glob": "^4.1.0",
|
|
75
75
|
"swagger-ui-express": "^5.0.1",
|
|
76
76
|
"yamljs": "^0.3.0"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
|
-
"@js-soft/license-check": "^1.0.
|
|
80
|
-
"@nmshd/typescript-ioc": "^3.2.
|
|
79
|
+
"@js-soft/license-check": "^1.0.10",
|
|
80
|
+
"@nmshd/typescript-ioc": "^3.2.5",
|
|
81
81
|
"@types/debug": "^4.1.12",
|
|
82
82
|
"@types/fs-extra": "^11.0.4",
|
|
83
|
-
"@types/jest": "^
|
|
84
|
-
"@types/lodash": "^4.17.
|
|
85
|
-
"@types/node": "^
|
|
86
|
-
"@types/request": "^2.48.
|
|
83
|
+
"@types/jest": "^30.0.0",
|
|
84
|
+
"@types/lodash": "^4.17.20",
|
|
85
|
+
"@types/node": "^24.7.2",
|
|
86
|
+
"@types/request": "^2.48.13",
|
|
87
87
|
"@types/yamljs": "^0.2.34",
|
|
88
88
|
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
|
89
89
|
"@typescript-eslint/parser": "^6.20.0",
|
|
90
|
-
"cross-env": "^
|
|
90
|
+
"cross-env": "^10.1.0",
|
|
91
91
|
"eslint": "^8.56.0",
|
|
92
92
|
"eslint-config-prettier": "^9.1.0",
|
|
93
93
|
"eslint-plugin-jsdoc": "^48.0.4",
|
|
94
94
|
"eslint-plugin-prefer-arrow": "^1.2.3",
|
|
95
|
-
"jest": "^
|
|
96
|
-
"prettier": "^3.
|
|
95
|
+
"jest": "^30.2.0",
|
|
96
|
+
"prettier": "^3.6.2",
|
|
97
97
|
"request": "^2.88.2",
|
|
98
98
|
"rimraf": "^6.0.1",
|
|
99
|
-
"ts-jest": "^29.
|
|
100
|
-
"typescript": "^5.
|
|
99
|
+
"ts-jest": "^29.4.5",
|
|
100
|
+
"typescript": "^5.9.3"
|
|
101
101
|
},
|
|
102
102
|
"engines": {
|
|
103
103
|
"node": ">=6.0.0"
|
|
@@ -19,11 +19,11 @@ export function routeRequiresAuthorization(
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
return (req: Request, res: Response, next: NextFunction) => {
|
|
22
|
-
const
|
|
23
|
-
if (debuggerInstance.enabled) debuggerInstance('Validating authentication roles: <%j>.',
|
|
22
|
+
const rawUserRoles = authenticator.getRoles(req, res);
|
|
23
|
+
if (debuggerInstance.enabled) debuggerInstance('Validating authentication roles: <%j>.', rawUserRoles);
|
|
24
24
|
|
|
25
|
-
const
|
|
26
|
-
const isAuthorized = permittedRoles.some((
|
|
25
|
+
const userRoles = rawUserRoles.map(Role.from);
|
|
26
|
+
const isAuthorized = permittedRoles.some((r) => isRoleMatched(r, userRoles));
|
|
27
27
|
if (!isAuthorized) {
|
|
28
28
|
next(new Errors.ForbiddenError('You are not allowed to access this endpoint.'));
|
|
29
29
|
return;
|
|
@@ -33,20 +33,31 @@ export function routeRequiresAuthorization(
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
function isRoleMatched(permittedRole: string, userRoles: Array<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
function isRoleMatched(permittedRole: string, userRoles: Array<Role>): boolean {
|
|
37
|
+
return userRoles.some((userRole) => userRole.matches(permittedRole));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class Role {
|
|
41
|
+
private roleRegex: RegExp;
|
|
42
|
+
|
|
43
|
+
private constructor(role: string) {
|
|
44
|
+
this.roleRegex = this.transformUserRole(role);
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
public static from(role: string): Role {
|
|
48
|
+
return new Role(role);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private transformUserRole(userRole: string): RegExp {
|
|
52
|
+
if (!userRole.includes('*')) return new RegExp(`^${userRole}$`);
|
|
44
53
|
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
const regexString = userRole
|
|
55
|
+
.replaceAll('**', '[a-zA-Z0-9_-]+(:[a-zA-Z0-9_-]+){0,}')
|
|
56
|
+
.replaceAll('*', '[a-zA-Z0-9_-]+');
|
|
57
|
+
return new RegExp(`^${regexString}$`);
|
|
58
|
+
}
|
|
47
59
|
|
|
48
|
-
|
|
49
|
-
.
|
|
50
|
-
|
|
51
|
-
return new RegExp(`^${regexString}$`);
|
|
60
|
+
public matches(permittedRole: string): unknown {
|
|
61
|
+
return this.roleRegex.test(permittedRole);
|
|
62
|
+
}
|
|
52
63
|
}
|