@travetto/auth 3.0.0-rc.0 → 3.0.0-rc.10
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 +28 -42
- package/{index.ts → __index__.ts} +0 -0
- package/package.json +7 -5
- package/src/types/authenticator.ts +8 -1
- package/src/types/principal.ts +1 -1
- package/src/util.ts +15 -68
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!-- This file was generated by @travetto/doc and should not be modified directly -->
|
|
2
|
-
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/auth/
|
|
2
|
+
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/auth/DOC.ts and execute "npx trv doc" to rebuild -->
|
|
3
3
|
# Authentication
|
|
4
4
|
## Authentication scaffolding for the travetto framework
|
|
5
5
|
|
|
@@ -63,7 +63,14 @@ As referenced above, a [Principal Structure](https://github.com/travetto/travett
|
|
|
63
63
|
```typescript
|
|
64
64
|
export interface Authenticator<T = unknown, P extends Principal = Principal, C = unknown> {
|
|
65
65
|
/**
|
|
66
|
-
*
|
|
66
|
+
* Allows for the authenticator to be initialized if needed
|
|
67
|
+
* @param ctx
|
|
68
|
+
*/
|
|
69
|
+
initialize?(ctx: C): Promise<void>;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Verify the payload, ensuring the payload is correctly identified.
|
|
73
|
+
*
|
|
67
74
|
* @returns Valid principal if authenticated
|
|
68
75
|
* @returns undefined if authentication is valid, but incomplete (multi-step)
|
|
69
76
|
* @throws AppError if authentication fails
|
|
@@ -105,50 +112,24 @@ Overall, the structure is simple, but drives home the primary use cases of the f
|
|
|
105
112
|
* To have access to the principal
|
|
106
113
|
|
|
107
114
|
## Common Utilities
|
|
108
|
-
The [AuthUtil](https://github.com/travetto/travetto/tree/main/module/auth/src/util.ts#
|
|
115
|
+
The [AuthUtil](https://github.com/travetto/travetto/tree/main/module/auth/src/util.ts#L11) provides the following functionality:
|
|
109
116
|
|
|
110
117
|
**Code: Auth util structure**
|
|
111
118
|
```typescript
|
|
112
|
-
import
|
|
113
|
-
import
|
|
119
|
+
import crypto from 'crypto';
|
|
120
|
+
import util from 'util';
|
|
114
121
|
import { AppError, Util } from '@travetto/base';
|
|
115
122
|
const pbkdf2 = util.promisify(crypto.pbkdf2);
|
|
116
|
-
type PermSet = Set<string> | ReadonlySet<string>;
|
|
117
|
-
type PermissionChecker = {
|
|
118
|
-
all: (perms: PermSet) => boolean;
|
|
119
|
-
any: (perms: PermSet) => boolean;
|
|
120
|
-
};
|
|
121
|
-
type PermissionCheckerSet = {
|
|
122
|
-
includes: (perms: PermSet) => boolean;
|
|
123
|
-
excludes: (perms: PermSet) => boolean;
|
|
124
|
-
check: (value: PermSet) => boolean;
|
|
125
|
-
};
|
|
126
123
|
/**
|
|
127
124
|
* Standard auth utilities
|
|
128
125
|
*/
|
|
129
126
|
export class AuthUtil {
|
|
130
127
|
/**
|
|
131
|
-
* Build
|
|
132
|
-
*
|
|
133
|
-
* @param perms Set of permissions to check
|
|
134
|
-
* @param defaultIfEmpty If no perms passed, default to empty
|
|
135
|
-
*/
|
|
136
|
-
/**
|
|
137
|
-
* Build a permission checker off of an include, and exclude set
|
|
128
|
+
* Build matcher for role permissions in allow/deny fashion
|
|
138
129
|
*
|
|
139
|
-
* @param
|
|
140
|
-
* @param exclude Which permissions to exclude
|
|
141
|
-
* @param matchAll Whether not all permissions should be matched
|
|
130
|
+
* @param roles Roles to build matcher for
|
|
142
131
|
*/
|
|
143
|
-
static
|
|
144
|
-
/**
|
|
145
|
-
* Build a permission checker off of an include, and exclude set
|
|
146
|
-
*
|
|
147
|
-
* @param include Which permissions to include
|
|
148
|
-
* @param exclude Which permissions to exclude
|
|
149
|
-
* @param matchAll Whether not all permissions should be matched
|
|
150
|
-
*/
|
|
151
|
-
static checkPermissions(permissions: Iterable<string>, include: Iterable<string>, exclude: Iterable<string>, mode: 'all' | 'any' = 'any'): void ;
|
|
132
|
+
static roleMatcher(roles: string[]): (perms: Set<string>) => boolean ;
|
|
152
133
|
/**
|
|
153
134
|
* Generate a hash for a given value
|
|
154
135
|
*
|
|
@@ -170,13 +151,18 @@ export class AuthUtil {
|
|
|
170
151
|
}
|
|
171
152
|
```
|
|
172
153
|
|
|
173
|
-
`
|
|
154
|
+
`roleMatcher` is probably the only functionality that needs to be explained. The function extends the core allow/deny matcher functionality from [Base](https://github.com/travetto/travetto/tree/main/module/base#readme "Environment config and common utilities for travetto applications.")'s Util class.
|
|
155
|
+
|
|
156
|
+
An example of role checks could be:
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
* Admin
|
|
160
|
+
* !Editor
|
|
161
|
+
* Owner+Author
|
|
174
162
|
|
|
163
|
+
The code would check the list in order, which would result in the following logic:
|
|
175
164
|
|
|
176
|
-
*
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
* Else
|
|
181
|
-
* The user does not have all permissions in the exclusion list
|
|
182
|
-
* The include list is empty, or the user has all permissions in the include list.
|
|
165
|
+
* If the user is an admin, always allow
|
|
166
|
+
* If the user has the editor role, deny
|
|
167
|
+
* If the user is both an owner and an author allow
|
|
168
|
+
* By default, deny due to the presence of positive checks
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/auth",
|
|
3
|
-
"
|
|
4
|
-
"version": "3.0.0-rc.0",
|
|
3
|
+
"version": "3.0.0-rc.10",
|
|
5
4
|
"description": "Authentication scaffolding for the travetto framework",
|
|
6
5
|
"keywords": [
|
|
7
6
|
"authentication",
|
|
@@ -15,16 +14,19 @@
|
|
|
15
14
|
"name": "Travetto Framework"
|
|
16
15
|
},
|
|
17
16
|
"files": [
|
|
18
|
-
"
|
|
17
|
+
"__index__.ts",
|
|
19
18
|
"src"
|
|
20
19
|
],
|
|
21
|
-
"main": "
|
|
20
|
+
"main": "__index__.ts",
|
|
22
21
|
"repository": {
|
|
23
22
|
"url": "https://github.com/travetto/travetto.git",
|
|
24
23
|
"directory": "module/auth"
|
|
25
24
|
},
|
|
26
25
|
"dependencies": {
|
|
27
|
-
"@travetto/base": "^3.0.0-rc.
|
|
26
|
+
"@travetto/base": "^3.0.0-rc.10"
|
|
27
|
+
},
|
|
28
|
+
"travetto": {
|
|
29
|
+
"displayName": "Authentication"
|
|
28
30
|
},
|
|
29
31
|
"private": false,
|
|
30
32
|
"publishConfig": {
|
|
@@ -7,7 +7,14 @@ import { Principal } from './principal';
|
|
|
7
7
|
*/
|
|
8
8
|
export interface Authenticator<T = unknown, P extends Principal = Principal, C = unknown> {
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Allows for the authenticator to be initialized if needed
|
|
11
|
+
* @param ctx
|
|
12
|
+
*/
|
|
13
|
+
initialize?(ctx: C): Promise<void>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Verify the payload, ensuring the payload is correctly identified.
|
|
17
|
+
*
|
|
11
18
|
* @returns Valid principal if authenticated
|
|
12
19
|
* @returns undefined if authentication is valid, but incomplete (multi-step)
|
|
13
20
|
* @throws AppError if authentication fails
|
package/src/types/principal.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* A user principal, including permissions and details
|
|
3
3
|
*
|
|
4
4
|
* @concrete ../internal/types:PrincipalTarget
|
|
5
|
-
* @augments `@
|
|
5
|
+
* @augments `@travetto/rest:Context`
|
|
6
6
|
*/
|
|
7
7
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
8
|
export interface Principal<D = { [key: string]: any }> {
|
package/src/util.ts
CHANGED
|
@@ -1,89 +1,36 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import util from 'util';
|
|
3
3
|
|
|
4
4
|
import { AppError, Util } from '@travetto/base';
|
|
5
5
|
|
|
6
6
|
const pbkdf2 = util.promisify(crypto.pbkdf2);
|
|
7
7
|
|
|
8
|
-
type PermSet = Set<string> | ReadonlySet<string>;
|
|
9
|
-
|
|
10
|
-
type PermissionChecker = {
|
|
11
|
-
all: (perms: PermSet) => boolean;
|
|
12
|
-
any: (perms: PermSet) => boolean;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
type PermissionCheckerSet = {
|
|
16
|
-
includes: (perms: PermSet) => boolean;
|
|
17
|
-
excludes: (perms: PermSet) => boolean;
|
|
18
|
-
check: (value: PermSet) => boolean;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
8
|
/**
|
|
22
9
|
* Standard auth utilities
|
|
23
10
|
*/
|
|
24
11
|
export class AuthUtil {
|
|
25
12
|
|
|
26
|
-
static #
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
*
|
|
32
|
-
* @param perms Set of permissions to check
|
|
33
|
-
* @param defaultIfEmpty If no perms passed, default to empty
|
|
34
|
-
*/
|
|
35
|
-
static #buildChecker(perms: Iterable<string>, defaultIfEmpty: boolean): PermissionChecker {
|
|
36
|
-
const permArr = [...perms].map(x => x.toLowerCase());
|
|
37
|
-
let all = (_: PermSet): boolean => defaultIfEmpty;
|
|
38
|
-
let any = (_: PermSet): boolean => defaultIfEmpty;
|
|
39
|
-
if (permArr.length) {
|
|
40
|
-
all = (uPerms: PermSet): boolean => permArr.every(x => uPerms.has(x));
|
|
41
|
-
any = (uPerms: PermSet): boolean => permArr.some(x => uPerms.has(x));
|
|
13
|
+
static #matchPermissionSet(rule: string[], perms: Set<string>): boolean {
|
|
14
|
+
for (const el of rule) {
|
|
15
|
+
if (!perms.has(el)) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
42
18
|
}
|
|
43
|
-
return
|
|
19
|
+
return true;
|
|
44
20
|
}
|
|
45
21
|
|
|
46
22
|
/**
|
|
47
|
-
* Build
|
|
23
|
+
* Build matcher for role permissions in allow/deny fashion
|
|
48
24
|
*
|
|
49
|
-
* @param
|
|
50
|
-
* @param exclude Which permissions to exclude
|
|
51
|
-
* @param matchAll Whether not all permissions should be matched
|
|
25
|
+
* @param roles Roles to build matcher for
|
|
52
26
|
*/
|
|
53
|
-
static
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
this.#checkIncCache.set(incKey, this.#buildChecker(include, true));
|
|
59
|
-
}
|
|
60
|
-
if (!this.#checkExcCache.has(excKey)) {
|
|
61
|
-
this.#checkExcCache.set(excKey, this.#buildChecker(exclude, false));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const includes = this.#checkIncCache.get(incKey)![mode];
|
|
65
|
-
const excludes = this.#checkExcCache.get(excKey)![mode];
|
|
66
|
-
|
|
67
|
-
return {
|
|
68
|
-
includes, excludes, check: (perms: PermSet) => includes(perms) && !excludes(perms)
|
|
69
|
-
};
|
|
27
|
+
static roleMatcher(roles: string[]): (perms: Set<string>) => boolean {
|
|
28
|
+
return Util.allowDenyMatcher<string[], [Set<string>]>(roles,
|
|
29
|
+
x => x.split('|'),
|
|
30
|
+
this.#matchPermissionSet.bind(this),
|
|
31
|
+
);
|
|
70
32
|
}
|
|
71
33
|
|
|
72
|
-
/**
|
|
73
|
-
* Build a permission checker off of an include, and exclude set
|
|
74
|
-
*
|
|
75
|
-
* @param include Which permissions to include
|
|
76
|
-
* @param exclude Which permissions to exclude
|
|
77
|
-
* @param matchAll Whether not all permissions should be matched
|
|
78
|
-
*/
|
|
79
|
-
static checkPermissions(permissions: Iterable<string>, include: Iterable<string>, exclude: Iterable<string>, mode: 'all' | 'any' = 'any'): void {
|
|
80
|
-
const { check } = this.permissionChecker(include, exclude, mode);
|
|
81
|
-
if (!check(!(permissions instanceof Set) ? new Set(permissions) : permissions)) {
|
|
82
|
-
throw new AppError('Insufficient permissions', 'permissions');
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
34
|
/**
|
|
88
35
|
* Generate a hash for a given value
|
|
89
36
|
*
|