@travetto/auth 2.1.5 → 2.2.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/README.md CHANGED
@@ -55,7 +55,7 @@ export interface Principal<D = { [key: string]: any }> {
55
55
  }
56
56
  ```
57
57
 
58
- As referenced above, a [Principal Structure](https://github.com/travetto/travetto/tree/main/module/auth/src/types/principal.ts#L8) is defined as a user with respect to a security context. This can be information the application knows about the user (authorized) or what a separate service may know about a user (3rd-party authenticatino).
58
+ As referenced above, a [Principal Structure](https://github.com/travetto/travetto/tree/main/module/auth/src/types/principal.ts#L8) is defined as a user with respect to a security context. This can be information the application knows about the user (authorized) or what a separate service may know about a user (3rd-party authentication).
59
59
 
60
60
  ## Authentication
61
61
 
@@ -72,7 +72,7 @@ export interface Authenticator<T = unknown, P extends Principal = Principal, C =
72
72
  }
73
73
  ```
74
74
 
75
- The [Authenticator](https://github.com/travetto/travetto/tree/main/module/auth/src/types/authenticator.ts#L8) only requires one method to be defined, and that is `authenticate`. This method receives a generic payload, and a supplemental context as an input. The interface is respon for converting that to an authenticated principal.
75
+ The [Authenticator](https://github.com/travetto/travetto/tree/main/module/auth/src/types/authenticator.ts#L8) only requires one method to be defined, and that is `authenticate`. This method receives a generic payload, and a supplemental context as an input. The interface is responsible for converting that to an authenticated principal.
76
76
 
77
77
  ### Example
78
78
  The [JWT](https://github.com/travetto/travetto/tree/main/module/jwt#readme "JSON Web Token implementation") module is a good example of an authenticator. This is a common use case for simple internal auth.
@@ -105,7 +105,7 @@ Overall, the structure is simple, but drives home the primary use cases of the f
105
105
  * To have access to the principal
106
106
 
107
107
  ## Common Utilities
108
- The [AuthUtil](https://github.com/travetto/travetto/tree/main/module/auth/src/util.ts#L18) provides the following functionality:
108
+ The [AuthUtil](https://github.com/travetto/travetto/tree/main/module/auth/src/util.ts#L24) provides the following functionality:
109
109
 
110
110
  **Code: Auth util structure**
111
111
  ```typescript
@@ -118,6 +118,11 @@ type PermissionChecker = {
118
118
  all: (perms: PermSet) => boolean;
119
119
  any: (perms: PermSet) => boolean;
120
120
  };
121
+ type PermissionCheckerSet = {
122
+ includes: (perms: PermSet) => boolean;
123
+ excludes: (perms: PermSet) => boolean;
124
+ check: (value: PermSet) => boolean;
125
+ };
121
126
  /**
122
127
  * Standard auth utilities
123
128
  */
@@ -135,7 +140,7 @@ export class AuthUtil {
135
140
  * @param exclude Which permissions to exclude
136
141
  * @param matchAll Whether not all permissions should be matched
137
142
  */
138
- static permissionChecker(include: Iterable<string>, exclude: Iterable<string>, mode: 'all' | 'any' = 'any') ;
143
+ static permissionChecker(include: Iterable<string>, exclude: Iterable<string>, mode: 'all' | 'any' = 'any'): PermissionCheckerSet ;
139
144
  /**
140
145
  * Build a permission checker off of an include, and exclude set
141
146
  *
@@ -143,7 +148,7 @@ export class AuthUtil {
143
148
  * @param exclude Which permissions to exclude
144
149
  * @param matchAll Whether not all permissions should be matched
145
150
  */
146
- static checkPermissions(permissions: Iterable<string>, include: Iterable<string>, exclude: Iterable<string>, mode: 'all' | 'any' = 'any') ;
151
+ static checkPermissions(permissions: Iterable<string>, include: Iterable<string>, exclude: Iterable<string>, mode: 'all' | 'any' = 'any'): void ;
147
152
  /**
148
153
  * Generate a hash for a given value
149
154
  *
@@ -153,7 +158,7 @@ export class AuthUtil {
153
158
  * @param keylen Length of hash
154
159
  * @param digest Digest method
155
160
  */
156
- static generateHash(value: string, salt: string, iterations = 25000, keylen = 256, digest = 'sha256') ;
161
+ static generateHash(value: string, salt: string, iterations = 25000, keylen = 256, digest = 'sha256'): Promise<string> ;
157
162
  /**
158
163
  * Generate a salted password, with the ability to validate the password
159
164
  *
@@ -161,7 +166,7 @@ export class AuthUtil {
161
166
  * @param salt Salt value, or if a number, length of salt
162
167
  * @param validator Optional function to validate your password
163
168
  */
164
- static async generatePassword(password: string, salt: number | string = 32) ;
169
+ static async generatePassword(password: string, salt: number | string = 32): Promise<{ salt: string, hash: string }> ;
165
170
  }
166
171
  ```
167
172
 
@@ -248,7 +253,7 @@ export class User implements RegisteredPrincipal {
248
253
 
249
254
  ## Configuration
250
255
 
251
- Additionally, there exists a common practice of mapping various external security principals into a local contract. These external identities, as provided from countless authentication schemes, need to be homogeonized for use. This has been handled in other frameworks by using external configuration, and creating a mapping between the two set of fields. Within this module, the mappings are defined as functions in which you can translate to the model from an identity or to an identity from a model.
256
+ Additionally, there exists a common practice of mapping various external security principals into a local contract. These external identities, as provided from countless authentication schemes, need to be homogenized for use. This has been handled in other frameworks by using external configuration, and creating a mapping between the two set of fields. Within this module, the mappings are defined as functions in which you can translate to the model from an identity or to an identity from a model.
252
257
 
253
258
  **Code: Principal Source configuration**
254
259
  ```typescript
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@travetto/auth",
3
3
  "displayName": "Authentication",
4
- "version": "2.1.5",
4
+ "version": "2.2.0",
5
5
  "description": "Authentication scaffolding for the travetto framework",
6
6
  "keywords": [
7
7
  "authentication",
@@ -25,10 +25,10 @@
25
25
  "directory": "module/auth"
26
26
  },
27
27
  "dependencies": {
28
- "@travetto/base": "^2.1.3"
28
+ "@travetto/base": "^2.2.0"
29
29
  },
30
30
  "optionalPeerDependencies": {
31
- "@travetto/model": "^2.1.5"
31
+ "@travetto/model": "^2.2.0"
32
32
  },
33
33
  "private": false,
34
34
  "publishConfig": {
@@ -67,7 +67,7 @@ export class ModelAuthService<T extends ModelType> implements
67
67
  * Retrieve user by id
68
68
  * @param userId The user id to retrieve
69
69
  */
70
- async #retrieve(userId: string) {
70
+ async #retrieve(userId: string): Promise<T> {
71
71
  return await this.#modelService.get<T>(this.#cls, userId);
72
72
  }
73
73
 
@@ -75,7 +75,7 @@ export class ModelAuthService<T extends ModelType> implements
75
75
  * Convert identity to a principal
76
76
  * @param ident The registered identity to resolve
77
77
  */
78
- async #resolvePrincipal(ident: RegisteredPrincipal) {
78
+ async #resolvePrincipal(ident: RegisteredPrincipal): Promise<RegisteredPrincipal> {
79
79
  const user = await this.#retrieve(ident.id);
80
80
  return this.toPrincipal(user);
81
81
  }
@@ -85,7 +85,7 @@ export class ModelAuthService<T extends ModelType> implements
85
85
  * @param userId The user id to authenticate against
86
86
  * @param password The password to authenticate against
87
87
  */
88
- async #authenticate(userId: string, password: string) {
88
+ async #authenticate(userId: string, password: string): Promise<RegisteredPrincipal> {
89
89
  const ident = await this.#resolvePrincipal({ id: userId, details: {} });
90
90
 
91
91
  const hash = await AuthUtil.generateHash(password, ident.salt!);
@@ -97,7 +97,7 @@ export class ModelAuthService<T extends ModelType> implements
97
97
  }
98
98
  }
99
99
 
100
- async postConstruct() {
100
+ async postConstruct(): Promise<void> {
101
101
  if (isStorageSupported(this.#modelService) && EnvUtil.isDynamic()) {
102
102
  await this.#modelService.createModel?.(this.#cls);
103
103
  }
@@ -107,7 +107,8 @@ export class ModelAuthService<T extends ModelType> implements
107
107
  * Register a user
108
108
  * @param user The user to register
109
109
  */
110
- async register(user: OptionalId<T>) {
110
+ async register(user: OptionalId<T>): Promise<T> {
111
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
111
112
  const ident = this.toPrincipal(user as T);
112
113
 
113
114
  try {
@@ -115,9 +116,9 @@ export class ModelAuthService<T extends ModelType> implements
115
116
  await this.#retrieve(ident.id);
116
117
  throw new AppError('That id is already taken.', 'data');
117
118
  }
118
- } catch (e) {
119
- if (!(e instanceof NotFoundError)) {
120
- throw e;
119
+ } catch (err) {
120
+ if (!(err instanceof NotFoundError)) {
121
+ throw err;
121
122
  }
122
123
  }
123
124
 
@@ -133,11 +134,11 @@ export class ModelAuthService<T extends ModelType> implements
133
134
 
134
135
  /**
135
136
  * Change a password
136
- * @param userId The user id to affet
137
+ * @param userId The user id to affect
137
138
  * @param password The new password
138
139
  * @param oldPassword The old password
139
140
  */
140
- async changePassword(userId: string, password: string, oldPassword?: string) {
141
+ async changePassword(userId: string, password: string, oldPassword?: string): Promise<T> {
141
142
  const user = await this.#retrieve(userId);
142
143
  const ident = this.toPrincipal(user);
143
144
 
@@ -182,7 +183,7 @@ export class ModelAuthService<T extends ModelType> implements
182
183
  * @param principal
183
184
  * @returns Authorized principal
184
185
  */
185
- authorize(principal: RegisteredPrincipal) {
186
+ authorize(principal: RegisteredPrincipal): Promise<RegisteredPrincipal> {
186
187
  return this.#resolvePrincipal(principal);
187
188
  }
188
189
 
@@ -191,7 +192,7 @@ export class ModelAuthService<T extends ModelType> implements
191
192
  * @param payload
192
193
  * @returns Authenticated principal
193
194
  */
194
- authenticate(payload: T) {
195
+ authenticate(payload: T): Promise<RegisteredPrincipal> {
195
196
  const { id, password } = this.toPrincipal(payload);
196
197
  return this.#authenticate(id, password!);
197
198
  }
package/src/util.ts CHANGED
@@ -12,6 +12,12 @@ type PermissionChecker = {
12
12
  any: (perms: PermSet) => boolean;
13
13
  };
14
14
 
15
+ type PermissionCheckerSet = {
16
+ includes: (perms: PermSet) => boolean;
17
+ excludes: (perms: PermSet) => boolean;
18
+ check: (value: PermSet) => boolean;
19
+ };
20
+
15
21
  /**
16
22
  * Standard auth utilities
17
23
  */
@@ -28,11 +34,11 @@ export class AuthUtil {
28
34
  */
29
35
  static #buildChecker(perms: Iterable<string>, defaultIfEmpty: boolean): PermissionChecker {
30
36
  const permArr = [...perms].map(x => x.toLowerCase());
31
- let all = (_: PermSet) => defaultIfEmpty;
32
- let any = (_: PermSet) => defaultIfEmpty;
37
+ let all = (_: PermSet): boolean => defaultIfEmpty;
38
+ let any = (_: PermSet): boolean => defaultIfEmpty;
33
39
  if (permArr.length) {
34
- all = (uPerms: PermSet) => permArr.every(x => uPerms.has(x));
35
- any = (uPerms: PermSet) => permArr.some(x => uPerms.has(x));
40
+ all = (uPerms: PermSet): boolean => permArr.every(x => uPerms.has(x));
41
+ any = (uPerms: PermSet): boolean => permArr.some(x => uPerms.has(x));
36
42
  }
37
43
  return { all, any };
38
44
  }
@@ -44,7 +50,7 @@ export class AuthUtil {
44
50
  * @param exclude Which permissions to exclude
45
51
  * @param matchAll Whether not all permissions should be matched
46
52
  */
47
- static permissionChecker(include: Iterable<string>, exclude: Iterable<string>, mode: 'all' | 'any' = 'any') {
53
+ static permissionChecker(include: Iterable<string>, exclude: Iterable<string>, mode: 'all' | 'any' = 'any'): PermissionCheckerSet {
48
54
  const incKey = [...include].sort().join(',');
49
55
  const excKey = [...exclude].sort().join(',');
50
56
 
@@ -70,7 +76,7 @@ export class AuthUtil {
70
76
  * @param exclude Which permissions to exclude
71
77
  * @param matchAll Whether not all permissions should be matched
72
78
  */
73
- static checkPermissions(permissions: Iterable<string>, include: Iterable<string>, exclude: Iterable<string>, mode: 'all' | 'any' = 'any') {
79
+ static checkPermissions(permissions: Iterable<string>, include: Iterable<string>, exclude: Iterable<string>, mode: 'all' | 'any' = 'any'): void {
74
80
  const { check } = this.permissionChecker(include, exclude, mode);
75
81
  if (!check(!(permissions instanceof Set) ? new Set(permissions) : permissions)) {
76
82
  throw new AppError('Insufficient permissions', 'permissions');
@@ -87,7 +93,7 @@ export class AuthUtil {
87
93
  * @param keylen Length of hash
88
94
  * @param digest Digest method
89
95
  */
90
- static generateHash(value: string, salt: string, iterations = 25000, keylen = 256, digest = 'sha256') {
96
+ static generateHash(value: string, salt: string, iterations = 25000, keylen = 256, digest = 'sha256'): Promise<string> {
91
97
  const half = Math.trunc(Math.ceil(keylen / 2));
92
98
  return pbkdf2(value, salt, iterations, half, digest).then(x => x.toString('hex').substring(0, keylen));
93
99
  }
@@ -99,7 +105,7 @@ export class AuthUtil {
99
105
  * @param salt Salt value, or if a number, length of salt
100
106
  * @param validator Optional function to validate your password
101
107
  */
102
- static async generatePassword(password: string, salt: number | string = 32) {
108
+ static async generatePassword(password: string, salt: number | string = 32): Promise<{ salt: string, hash: string }> {
103
109
  if (!password) {
104
110
  throw new AppError('Password is required', 'data');
105
111
  }
@@ -26,7 +26,7 @@ class User implements RegisteredPrincipal {
26
26
 
27
27
  class TestConfig {
28
28
  @InjectableFactory()
29
- static getauthService(@Inject(TestModelSvcⲐ) svc: ModelCrudSupport): ModelAuthService<User> {
29
+ static getAuthService(@Inject(TestModelSvcⲐ) svc: ModelCrudSupport): ModelAuthService<User> {
30
30
  const src = new ModelAuthService<User>(
31
31
  svc,
32
32
  User,