@tstdl/base 0.93.80 → 0.93.82
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/api/server/gateway.js +1 -1
- package/authentication/authentication.api.d.ts +9 -0
- package/authentication/authentication.api.js +3 -0
- package/authentication/client/authentication.service.d.ts +23 -15
- package/authentication/client/authentication.service.js +30 -21
- package/authentication/index.d.ts +1 -0
- package/authentication/index.js +1 -0
- package/authentication/models/authentication-credentials.model.d.ts +2 -2
- package/authentication/models/authentication-credentials.model.js +5 -5
- package/authentication/models/authentication-session.model.d.ts +2 -2
- package/authentication/models/authentication-session.model.js +3 -3
- package/authentication/models/subject.model.js +5 -3
- package/authentication/models/token-payload-base.model.d.ts +5 -1
- package/authentication/models/token-payload-base.model.js +10 -2
- package/authentication/models/token.model.d.ts +9 -1
- package/authentication/server/authentication-ancillary.service.d.ts +12 -15
- package/authentication/server/authentication-ancillary.service.js +3 -0
- package/authentication/server/authentication.api-controller.js +5 -5
- package/authentication/server/authentication.audit.d.ts +7 -5
- package/authentication/server/authentication.service.d.ts +32 -22
- package/authentication/server/authentication.service.js +116 -65
- package/authentication/server/subject.service.d.ts +19 -3
- package/authentication/server/subject.service.js +126 -9
- package/authentication/types.d.ts +6 -0
- package/authentication/types.js +1 -0
- package/examples/api/authentication.js +3 -2
- package/examples/api/custom-authentication.js +11 -9
- package/package.json +1 -1
|
@@ -4,25 +4,36 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
+
import { BadRequestError } from '../../errors/bad-request.error.js';
|
|
8
|
+
import { formatPersonName } from '../../formats/formats.js';
|
|
7
9
|
import { Singleton } from '../../injector/index.js';
|
|
8
10
|
import { injectRepository } from '../../orm/server/index.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
+
import { mailPattern } from '../../utils/patterns.js';
|
|
12
|
+
import { assertNotNull, isDefined, isUndefined } from '../../utils/type-guards.js';
|
|
13
|
+
import { ServiceAccount, Subject, SubjectType, SystemAccount, User, UserStatus } from '../models/index.js';
|
|
11
14
|
let SubjectService = class SubjectService {
|
|
12
|
-
subjectRepository = injectRepository(Subject);
|
|
13
|
-
systemAccountRepository = injectRepository(SystemAccount);
|
|
15
|
+
#subjectRepository = injectRepository(Subject);
|
|
16
|
+
#systemAccountRepository = injectRepository(SystemAccount);
|
|
17
|
+
#userRepository = injectRepository(User);
|
|
18
|
+
#serviceAccountRepository = injectRepository(ServiceAccount);
|
|
19
|
+
async getSubject(id) {
|
|
20
|
+
return await this.#subjectRepository.load(id);
|
|
21
|
+
}
|
|
22
|
+
async tryGetSubject(id) {
|
|
23
|
+
return await this.#subjectRepository.tryLoad(id);
|
|
24
|
+
}
|
|
14
25
|
async getSystemAccountSubject(tenantId, identifier) {
|
|
15
|
-
return await this
|
|
16
|
-
let systemAccount = await this
|
|
26
|
+
return await this.#subjectRepository.transaction(async (tx) => {
|
|
27
|
+
let systemAccount = await this.#systemAccountRepository.withTransaction(tx).tryLoadByQuery({
|
|
17
28
|
tenantId,
|
|
18
29
|
identifier,
|
|
19
30
|
});
|
|
20
31
|
if (isUndefined(systemAccount)) {
|
|
21
|
-
systemAccount = await this
|
|
32
|
+
systemAccount = await this.#systemAccountRepository.withTransaction(tx).insert({
|
|
22
33
|
tenantId,
|
|
23
34
|
identifier,
|
|
24
35
|
});
|
|
25
|
-
return await this
|
|
36
|
+
return await this.#subjectRepository.withTransaction(tx).insert({
|
|
26
37
|
type: SubjectType.System,
|
|
27
38
|
tenantId,
|
|
28
39
|
systemAccountId: systemAccount.id,
|
|
@@ -31,12 +42,118 @@ let SubjectService = class SubjectService {
|
|
|
31
42
|
serviceAccountId: null,
|
|
32
43
|
});
|
|
33
44
|
}
|
|
34
|
-
return await this
|
|
45
|
+
return await this.#subjectRepository.withTransaction(tx).loadByQuery({
|
|
35
46
|
tenantId,
|
|
36
47
|
systemAccountId: systemAccount.id,
|
|
37
48
|
});
|
|
38
49
|
});
|
|
39
50
|
}
|
|
51
|
+
async createUser(data) {
|
|
52
|
+
const { tenantId, email, firstName, lastName, status } = data;
|
|
53
|
+
return await this.#userRepository.transaction(async (tx) => {
|
|
54
|
+
const user = await this.#userRepository.withTransaction(tx).insert({
|
|
55
|
+
tenantId,
|
|
56
|
+
email,
|
|
57
|
+
firstName,
|
|
58
|
+
lastName,
|
|
59
|
+
status: status ?? UserStatus.Active,
|
|
60
|
+
});
|
|
61
|
+
await this.#subjectRepository.withTransaction(tx).insert({
|
|
62
|
+
tenantId,
|
|
63
|
+
type: SubjectType.User,
|
|
64
|
+
displayName: `${firstName} ${lastName}`,
|
|
65
|
+
systemAccountId: null,
|
|
66
|
+
userId: user.id,
|
|
67
|
+
serviceAccountId: null,
|
|
68
|
+
});
|
|
69
|
+
return user;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async updateUser(tenantId, userId, data) {
|
|
73
|
+
const { firstName, lastName, status } = data;
|
|
74
|
+
await this.#userRepository.transaction(async (tx) => {
|
|
75
|
+
const updateData = {};
|
|
76
|
+
if (isDefined(firstName)) {
|
|
77
|
+
updateData.firstName = firstName;
|
|
78
|
+
}
|
|
79
|
+
if (isDefined(lastName)) {
|
|
80
|
+
updateData.lastName = lastName;
|
|
81
|
+
}
|
|
82
|
+
if (isDefined(status)) {
|
|
83
|
+
updateData.status = status;
|
|
84
|
+
}
|
|
85
|
+
if (Object.keys(updateData).length > 0) {
|
|
86
|
+
const updatedUser = await this.#userRepository.withTransaction(tx).updateByQuery({ tenantId, userId }, updateData);
|
|
87
|
+
if (isDefined(firstName) || isDefined(lastName)) {
|
|
88
|
+
await this.#subjectRepository.withTransaction(tx).updateByQuery({ tenantId, userId }, { displayName: formatPersonName(updatedUser) });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
async updateUserEmail(tenantId, userId, email) {
|
|
94
|
+
// TODO: future (out of scope right now): validate mail flow
|
|
95
|
+
if (!mailPattern.test(email)) {
|
|
96
|
+
throw new BadRequestError(`Invalid email format.`);
|
|
97
|
+
}
|
|
98
|
+
await this.#userRepository.updateByQuery({ tenantId, userId }, { email });
|
|
99
|
+
}
|
|
100
|
+
async getUserSubject(tenantId, userId) {
|
|
101
|
+
return await this.#subjectRepository.loadByQuery({ tenantId, userId });
|
|
102
|
+
}
|
|
103
|
+
async getUserByEmail(tenantId, email) {
|
|
104
|
+
return await this.#userRepository.loadByQuery({ tenantId, email });
|
|
105
|
+
}
|
|
106
|
+
async tryGetUserByEmail(tenantId, email) {
|
|
107
|
+
return await this.#userRepository.tryLoadByQuery({ tenantId, email });
|
|
108
|
+
}
|
|
109
|
+
async hasUserByEmail(tenantId, email) {
|
|
110
|
+
const user = await this.tryGetUserByEmail(tenantId, email);
|
|
111
|
+
return isDefined(user);
|
|
112
|
+
}
|
|
113
|
+
async getUserBySubject(subject) {
|
|
114
|
+
assertNotNull(subject.userId, 'Subject is not a user subject');
|
|
115
|
+
return await this.#userRepository.load(subject.userId);
|
|
116
|
+
}
|
|
117
|
+
async loadManyUsersByEmails(tenantId, emails) {
|
|
118
|
+
return await this.#userRepository.loadManyByQuery({ tenantId, email: { $in: emails } });
|
|
119
|
+
}
|
|
120
|
+
async createServiceAccount(data) {
|
|
121
|
+
const { tenantId, description, parent } = data;
|
|
122
|
+
return await this.#serviceAccountRepository.transaction(async (tx) => {
|
|
123
|
+
const serviceAccount = await this.#serviceAccountRepository.withTransaction(tx).insert({
|
|
124
|
+
tenantId,
|
|
125
|
+
description,
|
|
126
|
+
parent,
|
|
127
|
+
});
|
|
128
|
+
await this.#subjectRepository.withTransaction(tx).insert({
|
|
129
|
+
tenantId,
|
|
130
|
+
type: SubjectType.ServiceAccount,
|
|
131
|
+
displayName: description,
|
|
132
|
+
userId: null,
|
|
133
|
+
systemAccountId: null,
|
|
134
|
+
serviceAccountId: serviceAccount.id,
|
|
135
|
+
});
|
|
136
|
+
return serviceAccount;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
async updateServiceAccount(tenantId, serviceAccountId, data) {
|
|
140
|
+
const { displayName, description } = data;
|
|
141
|
+
await this.#subjectRepository.transaction(async (tx) => {
|
|
142
|
+
if (isDefined(displayName)) {
|
|
143
|
+
await this.#subjectRepository.withTransaction(tx).updateByQuery({ tenantId, serviceAccountId }, { displayName });
|
|
144
|
+
}
|
|
145
|
+
if (isDefined(description)) {
|
|
146
|
+
await this.#serviceAccountRepository.withTransaction(tx).updateByQuery({ tenantId, serviceAccountId }, { description });
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
async getServiceAccountSubject(tenantId, serviceAccountId) {
|
|
151
|
+
return await this.#subjectRepository.loadByQuery({ tenantId, serviceAccountId });
|
|
152
|
+
}
|
|
153
|
+
async getServiceAccountBySubject(subject) {
|
|
154
|
+
assertNotNull(subject.serviceAccountId, 'Subject is not a service account subject');
|
|
155
|
+
return await this.#serviceAccountRepository.load(subject.serviceAccountId);
|
|
156
|
+
}
|
|
40
157
|
};
|
|
41
158
|
SubjectService = __decorate([
|
|
42
159
|
Singleton()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -17,7 +17,8 @@ import { timeout } from '../../utils/timing.js';
|
|
|
17
17
|
import { Agent } from 'undici';
|
|
18
18
|
async function serverTest() {
|
|
19
19
|
const authenticationService = await injectAsync(AuthenticationServerService);
|
|
20
|
-
await authenticationService.
|
|
20
|
+
const subject = await authenticationService.resolveSubject({ subject: 'foobar' });
|
|
21
|
+
await authenticationService.setCredentials(subject, 'mysuperdupersecret-fvhc54w');
|
|
21
22
|
}
|
|
22
23
|
async function clientTest() {
|
|
23
24
|
const authenticationService = inject(AuthenticationClientService);
|
|
@@ -25,7 +26,7 @@ async function clientTest() {
|
|
|
25
26
|
await timeout(250); // allow server to initialize
|
|
26
27
|
const passwordCheckResult = await authenticationService.checkSecret('123456');
|
|
27
28
|
console.log({ 'password check for "123456"': passwordCheckResult });
|
|
28
|
-
await authenticationService.login('foobar', 'mysuperdupersecret-fvhc54w');
|
|
29
|
+
await authenticationService.login({ subject: 'foobar' }, 'mysuperdupersecret-fvhc54w');
|
|
29
30
|
authenticationService.token$.subscribe((token) => console.log({ token }));
|
|
30
31
|
}
|
|
31
32
|
async function test() {
|
|
@@ -18,7 +18,7 @@ import { AuthenticationAncillaryService, AuthenticationApiController, Authentica
|
|
|
18
18
|
import { configureUndiciHttpClientAdapter } from '../../http/client/adapters/undici.adapter.js';
|
|
19
19
|
import { configureHttpClient } from '../../http/client/module.js';
|
|
20
20
|
import { configureNodeHttpServer } from '../../http/server/node/module.js';
|
|
21
|
-
import { Singleton } from '../../injector/
|
|
21
|
+
import { Singleton } from '../../injector/index.js';
|
|
22
22
|
import { inject, injectAsync } from '../../injector/inject.js';
|
|
23
23
|
import { configureLocalMessageBus } from '../../message-bus/local/module.js';
|
|
24
24
|
import { WebServerModule } from '../../module/modules/index.js';
|
|
@@ -65,17 +65,18 @@ __decorate([
|
|
|
65
65
|
], AuthenticationData.prototype, "deviceId", void 0);
|
|
66
66
|
const CustomAuthenticationApiClient = getAuthenticationApiClient(CustomTokenPaylod, AuthenticationData, emptyObjectSchema);
|
|
67
67
|
let CustomAuthenticationAncillaryService = class CustomAuthenticationAncillaryService extends AuthenticationAncillaryService {
|
|
68
|
-
getTokenPayload(_subject, authenticationData) {
|
|
68
|
+
getTokenPayload(_subject, authenticationData, _context) {
|
|
69
69
|
return { deviceRegistrationId: `registration:${authenticationData.deviceId}` };
|
|
70
70
|
}
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
async resolveSubjects(data) {
|
|
72
|
+
const subjects = await this.subjectRepository.loadManyByQuery({ id: data.subject });
|
|
73
|
+
return subjects;
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
+
canImpersonate(_token, _subject, _authenticationData) {
|
|
75
76
|
throw new Error('Method not implemented.');
|
|
76
77
|
}
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
handleInitSecretReset() {
|
|
79
|
+
// send mail
|
|
79
80
|
}
|
|
80
81
|
};
|
|
81
82
|
CustomAuthenticationAncillaryService = __decorate([
|
|
@@ -83,13 +84,14 @@ CustomAuthenticationAncillaryService = __decorate([
|
|
|
83
84
|
], CustomAuthenticationAncillaryService);
|
|
84
85
|
async function serverTest() {
|
|
85
86
|
const authenticationService = await injectAsync(AuthenticationServerService);
|
|
86
|
-
await authenticationService.
|
|
87
|
+
const subject = await authenticationService.resolveSubject({ subject: 'foobar' });
|
|
88
|
+
await authenticationService.setCredentials(subject, 'supersecret-dupidupudoo9275');
|
|
87
89
|
}
|
|
88
90
|
async function clientTest(application) {
|
|
89
91
|
const authenticationService = inject(AuthenticationClientService);
|
|
90
92
|
await timeout(1500); // allow server to initialize
|
|
91
93
|
authenticationService.initialize();
|
|
92
|
-
await authenticationService.login('foobar', 'supersecret-dupidupudoo9275');
|
|
94
|
+
await authenticationService.login({ subject: 'foobar' }, 'supersecret-dupidupudoo9275');
|
|
93
95
|
authenticationService.token$.subscribe((token) => console.log({ token }));
|
|
94
96
|
application.requestShutdown();
|
|
95
97
|
}
|