@travetto/auth 5.0.16 → 5.1.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 +81 -56
- package/__index__.ts +2 -1
- package/package.json +2 -2
- package/src/context.ts +80 -0
- package/src/internal/types.ts +1 -1
- package/src/service.ts +75 -0
- package/src/types/authenticator.ts +10 -5
- package/src/types/authorizer.ts +1 -2
- package/LICENSE +0 -21
- package/src/util.ts +0 -44
package/README.md
CHANGED
|
@@ -17,14 +17,13 @@ This module provides the high-level backdrop for managing security principals.
|
|
|
17
17
|
* Standard Types
|
|
18
18
|
* Authentication Contract
|
|
19
19
|
* Authorization Contract
|
|
20
|
-
*
|
|
21
|
-
|
|
22
|
-
* Generating passwords
|
|
20
|
+
* Authorization Services
|
|
21
|
+
* Authorization Context
|
|
23
22
|
|
|
24
23
|
## Standard Types
|
|
25
|
-
The module's goal is to be as flexible as possible. To that end, the primary contract that this module defines, is that of the [Principal
|
|
24
|
+
The module's goal is to be as flexible as possible. To that end, the primary contract that this module defines, is that of the [Principal Contract](https://github.com/travetto/travetto/tree/main/module/auth/src/types/principal.ts#L8).
|
|
26
25
|
|
|
27
|
-
**Code: Principal
|
|
26
|
+
**Code: Principal Contract**
|
|
28
27
|
```typescript
|
|
29
28
|
export interface Principal<D = AnyMap> {
|
|
30
29
|
/**
|
|
@@ -58,18 +57,17 @@ export interface Principal<D = AnyMap> {
|
|
|
58
57
|
}
|
|
59
58
|
```
|
|
60
59
|
|
|
61
|
-
As referenced above, a [Principal
|
|
60
|
+
As referenced above, a [Principal Contract](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).
|
|
62
61
|
|
|
63
|
-
## Authentication
|
|
62
|
+
## Authentication Contract
|
|
64
63
|
|
|
65
|
-
**Code: Authenticator**
|
|
64
|
+
**Code: Authenticator Contract**
|
|
66
65
|
```typescript
|
|
67
|
-
export interface Authenticator<T = unknown, P extends Principal = Principal
|
|
66
|
+
export interface Authenticator<T = unknown, C = unknown, P extends Principal = Principal> {
|
|
68
67
|
/**
|
|
69
|
-
*
|
|
70
|
-
* @param ctx
|
|
68
|
+
* Retrieve the authenticator state for the given request
|
|
71
69
|
*/
|
|
72
|
-
|
|
70
|
+
getState?(context?: C): Promise<AuthenticatorState | undefined> | AuthenticatorState | undefined;
|
|
73
71
|
|
|
74
72
|
/**
|
|
75
73
|
* Verify the payload, ensuring the payload is correctly identified.
|
|
@@ -78,32 +76,31 @@ export interface Authenticator<T = unknown, P extends Principal = Principal, C =
|
|
|
78
76
|
* @returns undefined if authentication is valid, but incomplete (multi-step)
|
|
79
77
|
* @throws AppError if authentication fails
|
|
80
78
|
*/
|
|
81
|
-
authenticate(payload: T,
|
|
79
|
+
authenticate(payload: T, context?: C): Promise<P | undefined> | P | undefined;
|
|
82
80
|
}
|
|
83
81
|
```
|
|
84
82
|
|
|
85
|
-
The [Authenticator](https://github.com/travetto/travetto/tree/main/module/auth/src/types/authenticator.ts#
|
|
83
|
+
The [Authenticator Contract](https://github.com/travetto/travetto/tree/main/module/auth/src/types/authenticator.ts#L14) 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.
|
|
86
84
|
|
|
87
85
|
### Example
|
|
88
86
|
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.
|
|
89
87
|
|
|
90
|
-
## Authorization
|
|
88
|
+
## Authorization Contract
|
|
91
89
|
|
|
92
|
-
**Code: Authorizer**
|
|
90
|
+
**Code: Authorizer Contract**
|
|
93
91
|
```typescript
|
|
94
92
|
export interface Authorizer<P extends Principal = Principal> {
|
|
95
93
|
/**
|
|
96
94
|
* Authorize inbound principal, verifying it's permission to access the system.
|
|
97
|
-
* @param principal
|
|
98
95
|
* @returns New principal that conforms to the required principal shape
|
|
99
96
|
*/
|
|
100
|
-
authorize(principal:
|
|
97
|
+
authorize(principal: P): Promise<P> | P;
|
|
101
98
|
}
|
|
102
99
|
```
|
|
103
100
|
|
|
104
101
|
Authorizers are generally seen as a secondary step post-authentication. Authentication acts as a very basic form of authorization, assuming the principal store is owned by the application.
|
|
105
102
|
|
|
106
|
-
The [Authorizer](https://github.com/travetto/travetto/tree/main/module/auth/src/types/authorizer.ts#L8) only requires one method to be defined, and that is `authorizer`. This method receives an authenticated principal as an input, and is responsible for converting that to an authorized principal.
|
|
103
|
+
The [Authorizer Contract](https://github.com/travetto/travetto/tree/main/module/auth/src/types/authorizer.ts#L8) only requires one method to be defined, and that is `authorizer`. This method receives an authenticated principal as an input, and is responsible for converting that to an authorized principal.
|
|
107
104
|
|
|
108
105
|
### Example
|
|
109
106
|
The [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") extension is a good example of an authenticator. This is a common use case for simple internal auth.
|
|
@@ -113,48 +110,76 @@ Overall, the structure is simple, but drives home the primary use cases of the f
|
|
|
113
110
|
* To have a reference to a user's set of permissions
|
|
114
111
|
* To have access to the principal
|
|
115
112
|
|
|
116
|
-
##
|
|
117
|
-
The [AuthUtil](https://github.com/travetto/travetto/tree/main/module/auth/src/util.ts#L11) provides the following functionality:
|
|
113
|
+
## Authorization Services
|
|
118
114
|
|
|
119
|
-
**Code:
|
|
115
|
+
**Code: Authorization Service**
|
|
120
116
|
```typescript
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Standard auth utilities
|
|
127
|
-
*/
|
|
128
|
-
export class AuthUtil {
|
|
129
|
-
/**
|
|
130
|
-
* Generate a hash for a given value
|
|
131
|
-
*
|
|
132
|
-
* @param value Value to hash
|
|
133
|
-
* @param salt The salt value
|
|
134
|
-
* @param iterations Number of iterations on hashing
|
|
135
|
-
* @param keylen Length of hash
|
|
136
|
-
* @param digest Digest method
|
|
117
|
+
export class AuthService {
|
|
118
|
+
@Inject()
|
|
119
|
+
/**
|
|
120
|
+
* Get authenticators by keys
|
|
137
121
|
*/
|
|
138
|
-
|
|
122
|
+
async getAuthenticators<T = unknown, C = unknown>(keys: symbol[]): Promise<Authenticator<T, C>[]>;
|
|
139
123
|
/**
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
* @param
|
|
143
|
-
* @param salt Salt value, or if a number, length of salt
|
|
144
|
-
* @param validator Optional function to validate your password
|
|
124
|
+
* Authenticate. Supports multi-step login.
|
|
125
|
+
* @param ctx The authenticator context
|
|
126
|
+
* @param authenticators List of valid authentication sources
|
|
145
127
|
*/
|
|
146
|
-
|
|
128
|
+
async authenticate<T, C>(payload: T, context: C, authenticators: symbol[]): Promise<Principal | undefined>;
|
|
147
129
|
}
|
|
148
130
|
```
|
|
149
131
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
132
|
+
The [AuthService](https://github.com/travetto/travetto/tree/main/module/auth/src/service.ts#L12) operates as the owner of the current auth state for a given "request". "Request" here implies a set of operations over a period of time, with the http request/response model being an easy point of reference. This could also tie to a CLI operation, or any other invocation that requires some concept of authentication and authorization.
|
|
133
|
+
|
|
134
|
+
The service allows for storing and retrieving the active [Principal Contract](https://github.com/travetto/travetto/tree/main/module/auth/src/types/principal.ts#L8), and/or the actively persisted auth token. This is extremely useful for other parts of the framework that may request authenticated information (if available). [Rest Auth](https://github.com/travetto/travetto/tree/main/module/auth-rest#readme "Rest authentication integration support for the Travetto framework") makes heavy use of this state for enforcing routes when authentication is required.
|
|
135
|
+
|
|
136
|
+
### Login
|
|
137
|
+
"Logging in" can be thought of going through the action of finding a single source that can authenticate the identity for the request credentials. Some times there may be more than one valid source of authentication that you want to leverage, and the first one to authenticate wins. The [AuthService](https://github.com/travetto/travetto/tree/main/module/auth/src/service.ts#L12) operates in this fashion, in which a set of credentials and potential [Authenticator Contract](https://github.com/travetto/travetto/tree/main/module/auth/src/types/authenticator.ts#L14)s are submitted, and the service will attempt to authenticate.
|
|
138
|
+
|
|
139
|
+
Upon successful authentication, an optional [Authorizer Contract](https://github.com/travetto/travetto/tree/main/module/auth/src/types/authorizer.ts#L8) may be invoked to authorize the authenticated user. The [Authenticator Contract](https://github.com/travetto/travetto/tree/main/module/auth/src/types/authenticator.ts#L14) is assumed to be only one within the system, and should be tied to the specific product you are building for. The [Authorizer Contract](https://github.com/travetto/travetto/tree/main/module/auth/src/types/authorizer.ts#L8) should be assumed to have multiple sources, and are generally specific to external third parties. All of these values are collected via the [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support.") module and will be auto-registered on startup.
|
|
140
|
+
|
|
141
|
+
If this process is too cumbersome or restrictive, manually authenticating and authorizing is still more than permissible, and setting the principal within the service is a logical equivalent to login.
|
|
142
|
+
|
|
143
|
+
## Authorization Context
|
|
144
|
+
When working with framework's authentication, the authenticated information is exposed via the [AuthContext](https://github.com/travetto/travetto/tree/main/module/auth/src/context.ts#L16), object.
|
|
145
|
+
|
|
146
|
+
**Code: Auth Context Outline**
|
|
147
|
+
```typescript
|
|
148
|
+
type AuthContextShape = {
|
|
149
|
+
principal?: Principal;
|
|
150
|
+
authToken?: AuthToken;
|
|
151
|
+
authenticatorState?: AuthenticatorState;
|
|
152
|
+
};
|
|
153
|
+
@Injectable()
|
|
154
|
+
export class AuthContext {
|
|
155
|
+
@Inject()
|
|
156
|
+
/**
|
|
157
|
+
* Get the principal, if set
|
|
158
|
+
*/
|
|
159
|
+
get principal(): Principal | undefined;
|
|
160
|
+
/**
|
|
161
|
+
* Set principal
|
|
162
|
+
*/
|
|
163
|
+
set principal(p: Principal | undefined);
|
|
164
|
+
/**
|
|
165
|
+
* Get the authentication token, if it exists
|
|
166
|
+
*/
|
|
167
|
+
get authToken(): AuthToken | undefined;
|
|
168
|
+
/**
|
|
169
|
+
* Set/overwrite the user's authentication token
|
|
170
|
+
*/
|
|
171
|
+
set authToken(token: AuthToken | undefined);
|
|
172
|
+
/**
|
|
173
|
+
* Get the authenticator state, if it exists
|
|
174
|
+
*/
|
|
175
|
+
get authenticatorState(): AuthenticatorState | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* Set/overwrite the authenticator state
|
|
178
|
+
*/
|
|
179
|
+
set authenticatorState(state: AuthenticatorState | undefined);
|
|
180
|
+
/**
|
|
181
|
+
* Clear context
|
|
182
|
+
*/
|
|
183
|
+
async clear(): Promise<void>;
|
|
184
|
+
}
|
|
185
|
+
```
|
package/__index__.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/auth",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "Authentication scaffolding for the Travetto framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"authentication",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"directory": "module/auth"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@travetto/
|
|
26
|
+
"@travetto/context": "^5.1.0"
|
|
27
27
|
},
|
|
28
28
|
"travetto": {
|
|
29
29
|
"displayName": "Authentication"
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
|
|
2
|
+
import { Inject, Injectable } from '@travetto/di';
|
|
3
|
+
import { AsyncContext, AsyncContextValue } from '@travetto/context';
|
|
4
|
+
|
|
5
|
+
import { AuthToken } from './internal/types';
|
|
6
|
+
import { Principal } from './types/principal';
|
|
7
|
+
import { AuthenticatorState } from './types/authenticator';
|
|
8
|
+
|
|
9
|
+
type AuthContextShape = {
|
|
10
|
+
principal?: Principal;
|
|
11
|
+
authToken?: AuthToken;
|
|
12
|
+
authenticatorState?: AuthenticatorState;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class AuthContext {
|
|
17
|
+
|
|
18
|
+
#auth = new AsyncContextValue<AuthContextShape>(this);
|
|
19
|
+
|
|
20
|
+
@Inject()
|
|
21
|
+
context: AsyncContext;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Initialize context
|
|
25
|
+
* @private
|
|
26
|
+
*/
|
|
27
|
+
init(): void {
|
|
28
|
+
this.#auth.set({});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get the principal, if set
|
|
33
|
+
*/
|
|
34
|
+
get principal(): Principal | undefined {
|
|
35
|
+
return this.#auth.get()?.principal;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Set principal
|
|
40
|
+
*/
|
|
41
|
+
set principal(p: Principal | undefined) {
|
|
42
|
+
this.#auth.get()!.principal = p;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get the authentication token, if it exists
|
|
47
|
+
*/
|
|
48
|
+
get authToken(): AuthToken | undefined {
|
|
49
|
+
return this.#auth.get()?.authToken;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Set/overwrite the user's authentication token
|
|
54
|
+
*/
|
|
55
|
+
set authToken(token: AuthToken | undefined) {
|
|
56
|
+
this.#auth.get()!.authToken = token;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get the authenticator state, if it exists
|
|
61
|
+
*/
|
|
62
|
+
get authenticatorState(): AuthenticatorState | undefined {
|
|
63
|
+
return this.#auth.get()?.authenticatorState;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Set/overwrite the authenticator state
|
|
68
|
+
*/
|
|
69
|
+
set authenticatorState(state: AuthenticatorState | undefined) {
|
|
70
|
+
this.#auth.get()!.authenticatorState = state;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Clear context
|
|
75
|
+
* @private
|
|
76
|
+
*/
|
|
77
|
+
async clear(): Promise<void> {
|
|
78
|
+
this.#auth.set(undefined);
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/internal/types.ts
CHANGED
package/src/service.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
|
|
2
|
+
import { DependencyRegistry, Inject, Injectable } from '@travetto/di';
|
|
3
|
+
|
|
4
|
+
import { AuthenticatorTarget } from './internal/types';
|
|
5
|
+
import { Principal } from './types/principal';
|
|
6
|
+
import { Authenticator } from './types/authenticator';
|
|
7
|
+
import { Authorizer } from './types/authorizer';
|
|
8
|
+
import { AuthenticationError } from './types/error';
|
|
9
|
+
import { AuthContext } from './context';
|
|
10
|
+
|
|
11
|
+
@Injectable()
|
|
12
|
+
export class AuthService {
|
|
13
|
+
|
|
14
|
+
@Inject()
|
|
15
|
+
authContext: AuthContext;
|
|
16
|
+
|
|
17
|
+
#authenticators = new Map<symbol, Promise<Authenticator>>();
|
|
18
|
+
|
|
19
|
+
@Inject()
|
|
20
|
+
authorizer?: Authorizer;
|
|
21
|
+
|
|
22
|
+
async postConstruct(): Promise<void> {
|
|
23
|
+
// Find all authenticators
|
|
24
|
+
for (const source of DependencyRegistry.getCandidateTypes(AuthenticatorTarget)) {
|
|
25
|
+
const dep = DependencyRegistry.getInstance<Authenticator>(AuthenticatorTarget, source.qualifier);
|
|
26
|
+
this.#authenticators.set(source.qualifier, dep);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get authenticators by keys
|
|
32
|
+
*/
|
|
33
|
+
async getAuthenticators<T = unknown, C = unknown>(keys: symbol[]): Promise<Authenticator<T, C>[]> {
|
|
34
|
+
return await Promise.all(keys.map(key => this.#authenticators.get(key)!));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Authenticate. Supports multi-step login.
|
|
39
|
+
* @param ctx The authenticator context
|
|
40
|
+
* @param authenticators List of valid authentication sources
|
|
41
|
+
*/
|
|
42
|
+
async authenticate<T, C>(payload: T, context: C, authenticators: symbol[]): Promise<Principal | undefined> {
|
|
43
|
+
let lastError: Error | undefined;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Attempt to authenticate, checking with multiple authentication sources
|
|
47
|
+
*/
|
|
48
|
+
for (const idp of await this.getAuthenticators<T, C>(authenticators)) {
|
|
49
|
+
try {
|
|
50
|
+
const principal = await idp.authenticate(payload, context);
|
|
51
|
+
|
|
52
|
+
if (idp.getState) {
|
|
53
|
+
this.authContext.authenticatorState = await idp.getState(context);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!principal) { // Multi-step login process
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
return this.authContext.principal = (await this.authorizer?.authorize(principal)) ?? principal;
|
|
60
|
+
} catch (err) {
|
|
61
|
+
if (!(err instanceof Error)) {
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
lastError = err;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (lastError) {
|
|
69
|
+
console.warn('Failed to authenticate', { error: lastError, sources: authenticators.map(x => x.toString()) });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Take the last error and return
|
|
73
|
+
throw new AuthenticationError('Unable to authenticate', { cause: lastError });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
+
import { AnyMap } from '@travetto/runtime';
|
|
1
2
|
import { Principal } from './principal';
|
|
2
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Represents the general shape of additional login context, usually across multiple calls
|
|
6
|
+
*/
|
|
7
|
+
export interface AuthenticatorState extends AnyMap { }
|
|
8
|
+
|
|
3
9
|
/**
|
|
4
10
|
* Supports validation payload of type T into an authenticated principal
|
|
5
11
|
*
|
|
6
12
|
* @concrete ../internal/types#AuthenticatorTarget
|
|
7
13
|
*/
|
|
8
|
-
export interface Authenticator<T = unknown, P extends Principal = Principal
|
|
14
|
+
export interface Authenticator<T = unknown, C = unknown, P extends Principal = Principal> {
|
|
9
15
|
/**
|
|
10
|
-
*
|
|
11
|
-
* @param ctx
|
|
16
|
+
* Retrieve the authenticator state for the given request
|
|
12
17
|
*/
|
|
13
|
-
|
|
18
|
+
getState?(context?: C): Promise<AuthenticatorState | undefined> | AuthenticatorState | undefined;
|
|
14
19
|
|
|
15
20
|
/**
|
|
16
21
|
* Verify the payload, ensuring the payload is correctly identified.
|
|
@@ -19,5 +24,5 @@ export interface Authenticator<T = unknown, P extends Principal = Principal, C =
|
|
|
19
24
|
* @returns undefined if authentication is valid, but incomplete (multi-step)
|
|
20
25
|
* @throws AppError if authentication fails
|
|
21
26
|
*/
|
|
22
|
-
authenticate(payload: T,
|
|
27
|
+
authenticate(payload: T, context?: C): Promise<P | undefined> | P | undefined;
|
|
23
28
|
}
|
package/src/types/authorizer.ts
CHANGED
|
@@ -8,8 +8,7 @@ import { Principal } from './principal';
|
|
|
8
8
|
export interface Authorizer<P extends Principal = Principal> {
|
|
9
9
|
/**
|
|
10
10
|
* Authorize inbound principal, verifying it's permission to access the system.
|
|
11
|
-
* @param principal
|
|
12
11
|
* @returns New principal that conforms to the required principal shape
|
|
13
12
|
*/
|
|
14
|
-
authorize(principal:
|
|
13
|
+
authorize(principal: P): Promise<P> | P;
|
|
15
14
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2020 ArcSine Technologies
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/src/util.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import crypto from 'node:crypto';
|
|
2
|
-
import util from 'node:util';
|
|
3
|
-
|
|
4
|
-
import { AppError, Util } from '@travetto/runtime';
|
|
5
|
-
|
|
6
|
-
const pbkdf2 = util.promisify(crypto.pbkdf2);
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Standard auth utilities
|
|
10
|
-
*/
|
|
11
|
-
export class AuthUtil {
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Generate a hash for a given value
|
|
15
|
-
*
|
|
16
|
-
* @param value Value to hash
|
|
17
|
-
* @param salt The salt value
|
|
18
|
-
* @param iterations Number of iterations on hashing
|
|
19
|
-
* @param keylen Length of hash
|
|
20
|
-
* @param digest Digest method
|
|
21
|
-
*/
|
|
22
|
-
static generateHash(value: string, salt: string, iterations = 25000, keylen = 256, digest = 'sha256'): Promise<string> {
|
|
23
|
-
const half = Math.trunc(Math.ceil(keylen / 2));
|
|
24
|
-
return pbkdf2(value, salt, iterations, half, digest).then(x => x.toString('hex').substring(0, keylen));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Generate a salted password, with the ability to validate the password
|
|
29
|
-
*
|
|
30
|
-
* @param password
|
|
31
|
-
* @param salt Salt value, or if a number, length of salt
|
|
32
|
-
* @param validator Optional function to validate your password
|
|
33
|
-
*/
|
|
34
|
-
static async generatePassword(password: string, salt: number | string = 32): Promise<{ salt: string, hash: string }> {
|
|
35
|
-
if (!password) {
|
|
36
|
-
throw new AppError('Password is required', { category: 'data' });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
salt = typeof salt === 'number' ? Util.uuid(salt) : salt;
|
|
40
|
-
const hash = await this.generateHash(password, salt);
|
|
41
|
-
|
|
42
|
-
return { salt, hash };
|
|
43
|
-
}
|
|
44
|
-
}
|