@travetto/auth-model 7.0.0-rc.1 → 7.0.0-rc.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 +21 -21
- package/package.json +4 -4
- package/src/model.ts +26 -26
- package/src/util.ts +1 -1
package/README.md
CHANGED
|
@@ -100,29 +100,29 @@ import { User } from './model.ts';
|
|
|
100
100
|
|
|
101
101
|
class AuthConfig {
|
|
102
102
|
@InjectableFactory()
|
|
103
|
-
static getModelAuthService(
|
|
103
|
+
static getModelAuthService(service: ModelCrudSupport) {
|
|
104
104
|
return new ModelAuthService(
|
|
105
|
-
|
|
105
|
+
service,
|
|
106
106
|
User,
|
|
107
|
-
|
|
107
|
+
user => ({ // This converts User to a RegisteredPrincipal
|
|
108
108
|
source: 'model',
|
|
109
109
|
provider: 'model',
|
|
110
|
-
id:
|
|
111
|
-
permissions:
|
|
112
|
-
hash:
|
|
113
|
-
salt:
|
|
114
|
-
resetToken:
|
|
115
|
-
resetExpires:
|
|
116
|
-
password:
|
|
117
|
-
details:
|
|
110
|
+
id: user.id!,
|
|
111
|
+
permissions: user.permissions,
|
|
112
|
+
hash: user.hash,
|
|
113
|
+
salt: user.salt,
|
|
114
|
+
resetToken: user.resetToken,
|
|
115
|
+
resetExpires: user.resetExpires,
|
|
116
|
+
password: user.password,
|
|
117
|
+
details: user,
|
|
118
118
|
}),
|
|
119
|
-
|
|
120
|
-
id:
|
|
121
|
-
permissions: [...(
|
|
122
|
-
hash:
|
|
123
|
-
salt:
|
|
124
|
-
resetToken:
|
|
125
|
-
resetExpires:
|
|
119
|
+
user => User.from(({ // This converts a RegisteredPrincipal to a User
|
|
120
|
+
id: user.id,
|
|
121
|
+
permissions: [...(user.permissions || [])],
|
|
122
|
+
hash: user.hash,
|
|
123
|
+
salt: user.salt,
|
|
124
|
+
resetToken: user.resetToken,
|
|
125
|
+
resetExpires: user.resetExpires,
|
|
126
126
|
})
|
|
127
127
|
)
|
|
128
128
|
);
|
|
@@ -147,11 +147,11 @@ class UserService {
|
|
|
147
147
|
async authenticate(identity: User) {
|
|
148
148
|
try {
|
|
149
149
|
return await this.auth.authenticate(identity);
|
|
150
|
-
} catch (
|
|
151
|
-
if (
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (error instanceof AppError && error.category === 'notfound') {
|
|
152
152
|
return await this.auth.register(identity);
|
|
153
153
|
} else {
|
|
154
|
-
throw
|
|
154
|
+
throw error;
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/auth-model",
|
|
3
|
-
"version": "7.0.0-rc.
|
|
3
|
+
"version": "7.0.0-rc.2",
|
|
4
4
|
"description": "Authentication model support for the Travetto framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"authentication",
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"directory": "module/auth-model"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@travetto/auth": "^7.0.0-rc.
|
|
29
|
-
"@travetto/model": "^7.0.0-rc.
|
|
28
|
+
"@travetto/auth": "^7.0.0-rc.2",
|
|
29
|
+
"@travetto/model": "^7.0.0-rc.2"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@travetto/test": "^7.0.0-rc.
|
|
32
|
+
"@travetto/test": "^7.0.0-rc.2"
|
|
33
33
|
},
|
|
34
34
|
"peerDependenciesMeta": {
|
|
35
35
|
"@travetto/test": {
|
package/src/model.ts
CHANGED
|
@@ -31,8 +31,8 @@ export interface RegisteredPrincipal extends Principal {
|
|
|
31
31
|
password?: string;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
type ToPrincipal<T extends ModelType> = (
|
|
35
|
-
type FromPrincipal<T extends ModelType> = (
|
|
34
|
+
type ToPrincipal<T extends ModelType> = (item: OptionalId<T>) => RegisteredPrincipal;
|
|
35
|
+
type FromPrincipal<T extends ModelType> = (item: Partial<RegisteredPrincipal>) => Partial<T>;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* A model-based auth service
|
|
@@ -74,10 +74,10 @@ export class ModelAuthService<T extends ModelType> implements Authenticator<T>,
|
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
76
|
* Convert identity to a principal
|
|
77
|
-
* @param
|
|
77
|
+
* @param identity The registered identity to resolve
|
|
78
78
|
*/
|
|
79
|
-
async #resolvePrincipal(
|
|
80
|
-
const user = await this.#retrieve(
|
|
79
|
+
async #resolvePrincipal(identity: RegisteredPrincipal): Promise<RegisteredPrincipal> {
|
|
80
|
+
const user = await this.#retrieve(identity.id);
|
|
81
81
|
return this.toPrincipal(user);
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -87,13 +87,13 @@ export class ModelAuthService<T extends ModelType> implements Authenticator<T>,
|
|
|
87
87
|
* @param password The password to authenticate against
|
|
88
88
|
*/
|
|
89
89
|
async #authenticate(userId: string, password: string): Promise<RegisteredPrincipal> {
|
|
90
|
-
const
|
|
90
|
+
const identity = await this.#resolvePrincipal({ id: userId, details: {} });
|
|
91
91
|
|
|
92
|
-
const hash = await AuthModelUtil.generateHash(password,
|
|
93
|
-
if (hash !==
|
|
92
|
+
const hash = await AuthModelUtil.generateHash(password, identity.salt!);
|
|
93
|
+
if (hash !== identity.hash) {
|
|
94
94
|
throw new AuthenticationError('Invalid password');
|
|
95
95
|
} else {
|
|
96
|
-
return
|
|
96
|
+
return identity;
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
@@ -108,20 +108,20 @@ export class ModelAuthService<T extends ModelType> implements Authenticator<T>,
|
|
|
108
108
|
* @param user The user to register
|
|
109
109
|
*/
|
|
110
110
|
async register(user: OptionalId<T>): Promise<T> {
|
|
111
|
-
const
|
|
111
|
+
const identity = this.toPrincipal(user);
|
|
112
112
|
|
|
113
113
|
try {
|
|
114
|
-
if (
|
|
115
|
-
await this.#retrieve(
|
|
114
|
+
if (identity.id) {
|
|
115
|
+
await this.#retrieve(identity.id);
|
|
116
116
|
throw new AuthenticationError('That id is already taken.', { category: 'data' });
|
|
117
117
|
}
|
|
118
|
-
} catch (
|
|
119
|
-
if (!(
|
|
120
|
-
throw
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (!(error instanceof NotFoundError)) {
|
|
120
|
+
throw error;
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
const fields = await AuthModelUtil.generatePassword(
|
|
124
|
+
const fields = await AuthModelUtil.generatePassword(identity.password!);
|
|
125
125
|
const output: Partial<T> = { ...user, ...this.fromPrincipal(fields) };
|
|
126
126
|
return await this.#modelService.create(this.#cls, this.#cls.from(castTo(output)));
|
|
127
127
|
}
|
|
@@ -134,15 +134,15 @@ export class ModelAuthService<T extends ModelType> implements Authenticator<T>,
|
|
|
134
134
|
*/
|
|
135
135
|
async changePassword(userId: string, password: string, oldPassword?: string): Promise<T> {
|
|
136
136
|
const user = await this.#retrieve(userId);
|
|
137
|
-
const
|
|
137
|
+
const identity = this.toPrincipal(user);
|
|
138
138
|
|
|
139
|
-
if (oldPassword ===
|
|
140
|
-
if (
|
|
139
|
+
if (oldPassword === identity.resetToken) {
|
|
140
|
+
if (identity.resetExpires && identity.resetExpires.getTime() < Date.now()) {
|
|
141
141
|
throw new AuthenticationError('Reset token has expired', { category: 'data' });
|
|
142
142
|
}
|
|
143
143
|
} else if (oldPassword !== undefined) {
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
144
|
+
const oldPasswordHash = await AuthModelUtil.generateHash(oldPassword, identity.salt!);
|
|
145
|
+
if (oldPasswordHash !== identity.hash) {
|
|
146
146
|
throw new AuthenticationError('Old password is required to change');
|
|
147
147
|
}
|
|
148
148
|
}
|
|
@@ -158,15 +158,15 @@ export class ModelAuthService<T extends ModelType> implements Authenticator<T>,
|
|
|
158
158
|
*/
|
|
159
159
|
async generateResetToken(userId: string): Promise<RegisteredPrincipal> {
|
|
160
160
|
const user = await this.#retrieve(userId);
|
|
161
|
-
const
|
|
161
|
+
const identity = this.toPrincipal(user);
|
|
162
162
|
const salt = await Util.uuid();
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
identity.resetToken = await AuthModelUtil.generateHash(Util.uuid(), salt, 25000, 32);
|
|
165
|
+
identity.resetExpires = TimeUtil.fromNow(1, 'h');
|
|
166
166
|
|
|
167
|
-
const output: Partial<T> = { ...user, ...this.fromPrincipal(
|
|
167
|
+
const output: Partial<T> = { ...user, ...this.fromPrincipal(identity) };
|
|
168
168
|
await this.#modelService.update(this.#cls, this.#cls.from(castTo(output)));
|
|
169
|
-
return
|
|
169
|
+
return identity;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
/**
|
package/src/util.ts
CHANGED
|
@@ -21,7 +21,7 @@ export class AuthModelUtil {
|
|
|
21
21
|
*/
|
|
22
22
|
static generateHash(value: string, salt: string, iterations = 25000, keylen = 256, digest = 'sha256'): Promise<string> {
|
|
23
23
|
const half = Math.trunc(Math.ceil(keylen / 2));
|
|
24
|
-
return pbkdf2(value, salt, iterations, half, digest).then(
|
|
24
|
+
return pbkdf2(value, salt, iterations, half, digest).then(buffer => buffer.toString('hex').substring(0, keylen));
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|