@nu-art/user-account-backend 0.500.0 → 0.500.6
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/_entity/account/ModuleBE_AccountDB.d.ts +15 -13
- package/_entity/account/ModuleBE_AccountDB.js +74 -59
- package/_entity/account/module-pack.d.ts +1 -1
- package/_entity/failed-login-attempt/module-pack.d.ts +1 -1
- package/_entity/login-attempts/module-pack.d.ts +1 -1
- package/_entity/session/ModuleBE_SessionDB.d.ts +17 -17
- package/_entity/session/ModuleBE_SessionDB.js +57 -45
- package/module-pack.d.ts +2 -2
- package/package.json +13 -13
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { Dispatcher } from '@nu-art/ts-common';
|
|
2
2
|
import { DB_BaseObject } from '@nu-art/db-api-shared';
|
|
3
|
-
import { firestore } from 'firebase-admin';
|
|
4
3
|
import { ModuleBE_BaseDB } from '@nu-art/db-api-backend';
|
|
5
4
|
import { FirestoreQuery } from '@nu-art/firebase-shared';
|
|
6
5
|
import { _SessionKey_Account, AccountEmail, AccountEmailWithDevice, AccountToAssertPassword, AccountToSpice, AccountType, API_UserAccount, DatabaseDef_Account, DB_Account, PasswordAssertionConfig, SafeDB_Account, UI_Account } from '@nu-art/user-account-shared';
|
|
7
6
|
import { BaseSessionClaims, CollectSessionData } from '../session/ModuleBE_SessionDB.js';
|
|
8
|
-
import Transaction = firestore.Transaction;
|
|
9
7
|
type BaseAccount = {
|
|
10
8
|
email: string;
|
|
11
9
|
type: AccountType;
|
|
@@ -16,16 +14,19 @@ type SpicedAccount = BaseAccount & {
|
|
|
16
14
|
};
|
|
17
15
|
type AccountToCreate = SpicedAccount | BaseAccount;
|
|
18
16
|
export interface OnNewUserRegistered {
|
|
19
|
-
__onNewUserRegistered(account: SafeDB_Account
|
|
17
|
+
__onNewUserRegistered(account: SafeDB_Account): void;
|
|
20
18
|
}
|
|
21
19
|
export interface OnUserLogin {
|
|
22
|
-
__onUserLogin(account: SafeDB_Account
|
|
20
|
+
__onUserLogin(account: SafeDB_Account): void;
|
|
23
21
|
}
|
|
24
22
|
export interface OnPreLogout {
|
|
25
23
|
__onPreLogout: () => Promise<void>;
|
|
26
24
|
}
|
|
27
|
-
export declare const dispatch_onAccountLogin: Dispatcher<OnUserLogin, "__onUserLogin", [account: SafeDB_Account
|
|
25
|
+
export declare const dispatch_onAccountLogin: Dispatcher<OnUserLogin, "__onUserLogin", [account: SafeDB_Account], void>;
|
|
28
26
|
export declare const dispatch_onPreLogout: Dispatcher<OnPreLogout, "__onPreLogout", [], void>;
|
|
27
|
+
export interface OnAccountDeleted {
|
|
28
|
+
__onAccountDeleted: (account: SafeDB_Account) => Promise<void>;
|
|
29
|
+
}
|
|
29
30
|
type Config = {
|
|
30
31
|
canRegister: boolean;
|
|
31
32
|
passwordAssertion?: PasswordAssertionConfig;
|
|
@@ -46,8 +47,8 @@ export declare class ModuleBE_AccountDB_Class extends ModuleBE_BaseDB<DatabaseDe
|
|
|
46
47
|
getSessions(params: API_UserAccount['getSessions']['Params']): Promise<API_UserAccount['getSessions']['Response']>;
|
|
47
48
|
changeThumbnail(body: API_UserAccount['changeThumbnail']['Body']): Promise<API_UserAccount['changeThumbnail']['Response']>;
|
|
48
49
|
getPasswordAssertionConfig(_params: API_UserAccount['getPasswordAssertionConfig']['Params']): Promise<API_UserAccount['getPasswordAssertionConfig']['Response']>;
|
|
50
|
+
deleteAccount(params: API_UserAccount['deleteAccount']['Params']): Promise<API_UserAccount['deleteAccount']['Response']>;
|
|
49
51
|
manipulateQuery(query: FirestoreQuery<DB_Account>): FirestoreQuery<DB_Account>;
|
|
50
|
-
canDeleteItems(dbItems: DB_Account[], transaction?: FirebaseFirestore.Transaction): Promise<void>;
|
|
51
52
|
__collectSessionData(data: BaseSessionClaims): Promise<{
|
|
52
53
|
key: "account";
|
|
53
54
|
value: {
|
|
@@ -71,22 +72,22 @@ export declare class ModuleBE_AccountDB_Class extends ModuleBE_BaseDB<DatabaseDe
|
|
|
71
72
|
saltedPassword?: string | undefined;
|
|
72
73
|
};
|
|
73
74
|
}>;
|
|
74
|
-
protected preWriteProcessing(dbInstance: UI_Account, originalDbInstance: DatabaseDef_Account['dbType']
|
|
75
|
+
protected preWriteProcessing(dbInstance: UI_Account, originalDbInstance: DatabaseDef_Account['dbType']): Promise<void>;
|
|
75
76
|
impl: {
|
|
76
77
|
fixEmail: (objectWithEmail: {
|
|
77
78
|
email: string;
|
|
78
79
|
}) => void;
|
|
79
80
|
assertPasswordCheck: (accountToAssert: AccountToAssertPassword) => void;
|
|
80
81
|
spiceAccount: (accountToSpice: AccountToSpice) => SpicedAccount;
|
|
81
|
-
create: (accountToCreate: AccountToCreate
|
|
82
|
+
create: (accountToCreate: AccountToCreate) => Promise<SafeDB_Account>;
|
|
82
83
|
setAccountMemKeys: (account: SafeDB_Account) => Promise<void>;
|
|
83
|
-
onAccountCreated: (account: SafeDB_Account
|
|
84
|
-
onAccountLogin: (account: SafeDB_Account
|
|
85
|
-
queryUnsafeAccount: (credentials: AccountEmail
|
|
86
|
-
querySafeAccount: (credentials: AccountEmail
|
|
84
|
+
onAccountCreated: (account: SafeDB_Account) => Promise<void>;
|
|
85
|
+
onAccountLogin: (account: SafeDB_Account) => Promise<void>;
|
|
86
|
+
queryUnsafeAccount: (credentials: AccountEmail) => Promise<DB_Account>;
|
|
87
|
+
querySafeAccount: (credentials: AccountEmail) => Promise<SafeDB_Account>;
|
|
87
88
|
};
|
|
88
89
|
account: {
|
|
89
|
-
register: (accountWithPassword: API_UserAccount["registerAccount"]["Body"]
|
|
90
|
+
register: (accountWithPassword: API_UserAccount["registerAccount"]["Body"]) => Promise<API_UserAccount["registerAccount"]["Response"]>;
|
|
90
91
|
login: (credentials: API_UserAccount["login"]["Body"]) => Promise<API_UserAccount["login"]["Response"]>;
|
|
91
92
|
create: (createAccountRequest: API_UserAccount["createAccount"]["Body"]) => Promise<API_UserAccount["createAccount"]["Response"]>;
|
|
92
93
|
saml: (oAuthAccount: AccountEmailWithDevice) => Promise<import("@nu-art/user-account-shared").DB_Session>;
|
|
@@ -97,6 +98,7 @@ export declare class ModuleBE_AccountDB_Class extends ModuleBE_BaseDB<DatabaseDe
|
|
|
97
98
|
sessions: import("@nu-art/user-account-shared").DB_Session[];
|
|
98
99
|
}>;
|
|
99
100
|
changeThumbnail: (request: API_UserAccount["changeThumbnail"]["Body"]) => Promise<API_UserAccount["changeThumbnail"]["Response"]>;
|
|
101
|
+
delete: (request: API_UserAccount["deleteAccount"]["Params"]) => Promise<API_UserAccount["deleteAccount"]["Response"]>;
|
|
100
102
|
};
|
|
101
103
|
password: {
|
|
102
104
|
assertPasswordExistence: (email: string, password?: string, passwordCheck?: string) => void;
|
|
@@ -32,10 +32,9 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
32
32
|
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
33
33
|
done = true;
|
|
34
34
|
};
|
|
35
|
-
import { ApiException, BadImplementationException, cloneObj, compare, dispatch_onApplicationException, Dispatcher, exists, generateHex, hashPasswordWithSalt, md5,
|
|
35
|
+
import { ApiException, BadImplementationException, cloneObj, compare, dispatch_onApplicationException, Dispatcher, exists, generateHex, hashPasswordWithSalt, md5, Year } from '@nu-art/ts-common';
|
|
36
36
|
import { ModuleBE_BaseDB } from '@nu-art/db-api-backend';
|
|
37
37
|
import { ApiHandler } from '@nu-art/http-server';
|
|
38
|
-
import { FirestoreInterfaceV3 } from '@nu-art/firebase-backend/firestore-v3/FirestoreInterfaceV3';
|
|
39
38
|
import { HttpCodes } from '@nu-art/ts-common/core/exceptions/http-codes';
|
|
40
39
|
import { ApiDef_UserAccount, assertPasswordRules, DBDef_Accounts } from '@nu-art/user-account-shared';
|
|
41
40
|
import { Header_Authorization, MemKey_AccountEmail, MemKey_AccountId, MemKey_AccountType, MemKey_DB_Session, SessionKey_Account_BE } from '../session/consts.js';
|
|
@@ -44,6 +43,7 @@ import { ModuleBE_FailedLoginAttemptDB } from '../failed-login-attempt/ModuleBE_
|
|
|
44
43
|
export const dispatch_onAccountLogin = new Dispatcher('__onUserLogin');
|
|
45
44
|
const dispatch_onAccountRegistered = new Dispatcher('__onNewUserRegistered');
|
|
46
45
|
export const dispatch_onPreLogout = new Dispatcher('__onPreLogout');
|
|
46
|
+
const dispatch_OnAccountDeleted = new Dispatcher('__onAccountDeleted');
|
|
47
47
|
let ModuleBE_AccountDB_Class = (() => {
|
|
48
48
|
let _classSuper = ModuleBE_BaseDB;
|
|
49
49
|
let _instanceExtraInitializers = [];
|
|
@@ -58,6 +58,7 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
58
58
|
let _getSessions_decorators;
|
|
59
59
|
let _changeThumbnail_decorators;
|
|
60
60
|
let _getPasswordAssertionConfig_decorators;
|
|
61
|
+
let _deleteAccount_decorators;
|
|
61
62
|
return class ModuleBE_AccountDB_Class extends _classSuper {
|
|
62
63
|
static {
|
|
63
64
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
@@ -72,6 +73,7 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
72
73
|
_getSessions_decorators = [ApiHandler(ApiDef_UserAccount.getSessions)];
|
|
73
74
|
_changeThumbnail_decorators = [ApiHandler(ApiDef_UserAccount.changeThumbnail)];
|
|
74
75
|
_getPasswordAssertionConfig_decorators = [ApiHandler(ApiDef_UserAccount.getPasswordAssertionConfig)];
|
|
76
|
+
_deleteAccount_decorators = [ApiHandler(ApiDef_UserAccount.deleteAccount)];
|
|
75
77
|
__esDecorate(this, null, _refreshSession_decorators, { kind: "method", name: "refreshSession", static: false, private: false, access: { has: obj => "refreshSession" in obj, get: obj => obj.refreshSession }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
76
78
|
__esDecorate(this, null, _registerAccount_decorators, { kind: "method", name: "registerAccount", static: false, private: false, access: { has: obj => "registerAccount" in obj, get: obj => obj.registerAccount }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
77
79
|
__esDecorate(this, null, _changePassword_decorators, { kind: "method", name: "changePassword", static: false, private: false, access: { has: obj => "changePassword" in obj, get: obj => obj.changePassword }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -83,6 +85,7 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
83
85
|
__esDecorate(this, null, _getSessions_decorators, { kind: "method", name: "getSessions", static: false, private: false, access: { has: obj => "getSessions" in obj, get: obj => obj.getSessions }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
84
86
|
__esDecorate(this, null, _changeThumbnail_decorators, { kind: "method", name: "changeThumbnail", static: false, private: false, access: { has: obj => "changeThumbnail" in obj, get: obj => obj.changeThumbnail }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
85
87
|
__esDecorate(this, null, _getPasswordAssertionConfig_decorators, { kind: "method", name: "getPasswordAssertionConfig", static: false, private: false, access: { has: obj => "getPasswordAssertionConfig" in obj, get: obj => obj.getPasswordAssertionConfig }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
88
|
+
__esDecorate(this, null, _deleteAccount_decorators, { kind: "method", name: "deleteAccount", static: false, private: false, access: { has: obj => "deleteAccount" in obj, get: obj => obj.deleteAccount }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
86
89
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
87
90
|
}
|
|
88
91
|
Middleware = (__runInitializers(this, _instanceExtraInitializers), async () => {
|
|
@@ -134,15 +137,18 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
134
137
|
: this.config.passwordAssertion
|
|
135
138
|
};
|
|
136
139
|
}
|
|
140
|
+
async deleteAccount(params) {
|
|
141
|
+
return this.account.delete(params);
|
|
142
|
+
}
|
|
137
143
|
manipulateQuery(query) {
|
|
138
144
|
return {
|
|
139
145
|
...query,
|
|
140
146
|
select: ['__created', '_v', '__updated', 'email', '_newPasswordRequired', 'type', '_id', 'thumbnail', 'displayName', '_auditorId', 'description']
|
|
141
147
|
};
|
|
142
148
|
}
|
|
143
|
-
canDeleteItems(dbItems, transaction) {
|
|
144
|
-
|
|
145
|
-
}
|
|
149
|
+
// canDeleteItems(dbItems: DB_Account[], transaction?: FirebaseFirestore.Transaction): Promise<void> {
|
|
150
|
+
// throw HttpCodes._5XX.NOT_IMPLEMENTED('Account Deletion is not implemented yet');
|
|
151
|
+
// }
|
|
146
152
|
async __collectSessionData(data) {
|
|
147
153
|
const account = await this.query.uniqueAssert(data.accountId);
|
|
148
154
|
return {
|
|
@@ -153,7 +159,7 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
153
159
|
},
|
|
154
160
|
};
|
|
155
161
|
}
|
|
156
|
-
async preWriteProcessing(dbInstance, originalDbInstance
|
|
162
|
+
async preWriteProcessing(dbInstance, originalDbInstance) {
|
|
157
163
|
try {
|
|
158
164
|
dbInstance._auditorId = MemKey_AccountId.get();
|
|
159
165
|
}
|
|
@@ -178,53 +184,45 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
178
184
|
saltedPassword: hashPasswordWithSalt(salt, accountToSpice.password)
|
|
179
185
|
};
|
|
180
186
|
},
|
|
181
|
-
create: async (accountToCreate
|
|
187
|
+
create: async (accountToCreate) => {
|
|
182
188
|
let dbAccount = (await this.query.custom({
|
|
183
189
|
where: { email: accountToCreate.email },
|
|
184
190
|
limit: 1
|
|
185
|
-
}
|
|
191
|
+
}))[0];
|
|
186
192
|
if (dbAccount)
|
|
187
193
|
throw new ApiException(422, `User with email "${accountToCreate.email}" already exists`);
|
|
188
|
-
dbAccount = await this.create.item(accountToCreate
|
|
194
|
+
dbAccount = await this.create.item(accountToCreate);
|
|
189
195
|
return makeAccountSafe(dbAccount);
|
|
190
196
|
},
|
|
191
197
|
setAccountMemKeys: async (account) => {
|
|
192
198
|
MemKey_AccountId.set(account._id);
|
|
193
199
|
MemKey_AccountEmail.set(account.email);
|
|
194
200
|
},
|
|
195
|
-
onAccountCreated: async (account
|
|
196
|
-
await dispatch_onAccountRegistered.dispatchModuleAsync(account
|
|
201
|
+
onAccountCreated: async (account) => {
|
|
202
|
+
await dispatch_onAccountRegistered.dispatchModuleAsync(account);
|
|
197
203
|
},
|
|
198
|
-
onAccountLogin: async (account
|
|
199
|
-
await dispatch_onAccountLogin.dispatchModuleAsync(account
|
|
204
|
+
onAccountLogin: async (account) => {
|
|
205
|
+
await dispatch_onAccountLogin.dispatchModuleAsync(account);
|
|
200
206
|
},
|
|
201
|
-
queryUnsafeAccount: async (credentials
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (results.length
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
await dispatch_onApplicationException.dispatchModuleAsync(apiException, this);
|
|
212
|
-
throw apiException;
|
|
213
|
-
}
|
|
214
|
-
else if (results.length > 1) {
|
|
215
|
-
this.logWarningBold(`Too many accounts using this email! '${credentials.email}'`);
|
|
216
|
-
throw new MUSTNeverHappenException('Too many accounts using this email');
|
|
217
|
-
}
|
|
218
|
-
return results[0].data();
|
|
207
|
+
queryUnsafeAccount: async (credentials) => {
|
|
208
|
+
const results = await this.query.unManipulatedQuery({ where: { email: credentials.email } });
|
|
209
|
+
if (results.length === 0) {
|
|
210
|
+
const apiException = new ApiException(401, `There is no account for email '${credentials.email}'.`);
|
|
211
|
+
await dispatch_onApplicationException.dispatchModuleAsync(apiException, this);
|
|
212
|
+
throw apiException;
|
|
213
|
+
}
|
|
214
|
+
if (results.length > 1)
|
|
215
|
+
throw new BadImplementationException(`Too many accounts using this email: '${credentials.email}'`);
|
|
216
|
+
return results[0];
|
|
219
217
|
},
|
|
220
|
-
querySafeAccount: async (credentials
|
|
221
|
-
const account = await this.impl.queryUnsafeAccount(credentials
|
|
218
|
+
querySafeAccount: async (credentials) => {
|
|
219
|
+
const account = await this.impl.queryUnsafeAccount(credentials);
|
|
222
220
|
return makeAccountSafe(account);
|
|
223
221
|
}
|
|
224
222
|
};
|
|
225
223
|
account = {
|
|
226
224
|
// this flow is for creating real human users with email and password
|
|
227
|
-
register: async (accountWithPassword
|
|
225
|
+
register: async (accountWithPassword) => {
|
|
228
226
|
if (!this.config.canRegister)
|
|
229
227
|
throw new ApiException(418, 'Registration is disabled!!');
|
|
230
228
|
this.impl.fixEmail(accountWithPassword);
|
|
@@ -233,10 +231,10 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
233
231
|
email: accountWithPassword.email,
|
|
234
232
|
password: accountWithPassword.password
|
|
235
233
|
});
|
|
236
|
-
const dbSafeAccount = await this.runTransaction(async (
|
|
237
|
-
const dbSafeAccount = await this.impl.create(spicedAccount
|
|
234
|
+
const dbSafeAccount = await this.runTransaction(async () => {
|
|
235
|
+
const dbSafeAccount = await this.impl.create(spicedAccount);
|
|
238
236
|
await this.impl.setAccountMemKeys(dbSafeAccount);
|
|
239
|
-
await this.impl.onAccountCreated(dbSafeAccount
|
|
237
|
+
await this.impl.onAccountCreated(dbSafeAccount);
|
|
240
238
|
return dbSafeAccount;
|
|
241
239
|
});
|
|
242
240
|
await this.account.login({
|
|
@@ -248,14 +246,11 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
248
246
|
},
|
|
249
247
|
login: async (credentials) => {
|
|
250
248
|
this.impl.fixEmail(credentials);
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
await this.impl.onAccountLogin(safeAccount, transaction);
|
|
257
|
-
return safeAccount;
|
|
258
|
-
});
|
|
249
|
+
const dbAccount = await this.impl.queryUnsafeAccount({ email: credentials.email });
|
|
250
|
+
await this.password.assertPasswordMatch(dbAccount, credentials.password);
|
|
251
|
+
const safeAccount = makeAccountSafe(dbAccount);
|
|
252
|
+
MemKey_AccountId.set(safeAccount._id);
|
|
253
|
+
await this.impl.onAccountLogin(safeAccount);
|
|
259
254
|
const initialClaims = {
|
|
260
255
|
accountId: safeAccount._id,
|
|
261
256
|
deviceId: credentials.deviceId,
|
|
@@ -268,35 +263,35 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
268
263
|
const password = createAccountRequest.password;
|
|
269
264
|
let dbSafeAccount;
|
|
270
265
|
this.impl.fixEmail(createAccountRequest);
|
|
271
|
-
return this.runTransaction(async (
|
|
266
|
+
return this.runTransaction(async () => {
|
|
272
267
|
if (exists(password) || exists(createAccountRequest.passwordCheck)) {
|
|
273
268
|
this.impl.assertPasswordCheck(createAccountRequest);
|
|
274
269
|
const spicedAccount = this.impl.spiceAccount(createAccountRequest);
|
|
275
|
-
dbSafeAccount = await this.impl.create(spicedAccount
|
|
270
|
+
dbSafeAccount = await this.impl.create(spicedAccount);
|
|
276
271
|
}
|
|
277
272
|
else
|
|
278
|
-
dbSafeAccount = await this.impl.create(createAccountRequest
|
|
279
|
-
await this.impl.onAccountCreated(dbSafeAccount
|
|
273
|
+
dbSafeAccount = await this.impl.create(createAccountRequest);
|
|
274
|
+
await this.impl.onAccountCreated(dbSafeAccount);
|
|
280
275
|
return dbSafeAccount;
|
|
281
276
|
});
|
|
282
277
|
},
|
|
283
278
|
saml: async (oAuthAccount) => {
|
|
284
279
|
this.impl.fixEmail(oAuthAccount);
|
|
285
|
-
const dbSafeAccount = await this.runTransaction(async (
|
|
280
|
+
const dbSafeAccount = await this.runTransaction(async () => {
|
|
286
281
|
let dbSafeAccount;
|
|
287
282
|
try {
|
|
288
|
-
dbSafeAccount = await this.impl.querySafeAccount({ ...oAuthAccount }
|
|
283
|
+
dbSafeAccount = await this.impl.querySafeAccount({ ...oAuthAccount });
|
|
289
284
|
this.logInfo('SAML login account');
|
|
290
285
|
MemKey_AccountId.set(dbSafeAccount._id);
|
|
291
|
-
await this.impl.onAccountLogin(dbSafeAccount
|
|
286
|
+
await this.impl.onAccountLogin(dbSafeAccount);
|
|
292
287
|
}
|
|
293
288
|
catch (e) {
|
|
294
289
|
if (e.responseCode !== 401)
|
|
295
290
|
throw e;
|
|
296
291
|
this.logInfo('SAML register account');
|
|
297
|
-
dbSafeAccount = await this.impl.create({ email: oAuthAccount.email, type: 'user' }
|
|
292
|
+
dbSafeAccount = await this.impl.create({ email: oAuthAccount.email, type: 'user' });
|
|
298
293
|
MemKey_AccountId.set(dbSafeAccount._id);
|
|
299
|
-
await this.impl.onAccountCreated(dbSafeAccount
|
|
294
|
+
await this.impl.onAccountCreated(dbSafeAccount);
|
|
300
295
|
}
|
|
301
296
|
return dbSafeAccount;
|
|
302
297
|
});
|
|
@@ -304,7 +299,7 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
304
299
|
return ModuleBE_SessionDB._session.create({ initialClaims });
|
|
305
300
|
},
|
|
306
301
|
changePassword: async (passwordToChange) => {
|
|
307
|
-
return this.runTransaction(async (
|
|
302
|
+
return this.runTransaction(async () => {
|
|
308
303
|
const email = MemKey_AccountEmail.get();
|
|
309
304
|
const deviceId = MemKey_DB_Session.get().deviceId;
|
|
310
305
|
await this.account.login({ email, deviceId, password: passwordToChange.oldPassword }); // perform login to make sure the old password holds
|
|
@@ -321,7 +316,7 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
321
316
|
...safeAccount,
|
|
322
317
|
salt: spicedAccount.salt,
|
|
323
318
|
saltedPassword: spicedAccount.saltedPassword
|
|
324
|
-
}
|
|
319
|
+
});
|
|
325
320
|
const initialClaims = {
|
|
326
321
|
accountId: updatedAccount._id,
|
|
327
322
|
deviceId,
|
|
@@ -332,10 +327,10 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
332
327
|
});
|
|
333
328
|
},
|
|
334
329
|
setPassword: async (passwordBody) => {
|
|
335
|
-
return this.runTransaction(async (
|
|
330
|
+
return this.runTransaction(async () => {
|
|
336
331
|
const email = MemKey_AccountEmail.get();
|
|
337
332
|
const deviceId = MemKey_DB_Session.get().deviceId;
|
|
338
|
-
const dbAccount = await this.impl.queryUnsafeAccount({ email }
|
|
333
|
+
const dbAccount = await this.impl.queryUnsafeAccount({ email });
|
|
339
334
|
if (dbAccount.saltedPassword)
|
|
340
335
|
throw HttpCodes._4XX.FORBIDDEN('account already has password');
|
|
341
336
|
const safeAccount = makeAccountSafe(dbAccount);
|
|
@@ -345,7 +340,7 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
345
340
|
...safeAccount,
|
|
346
341
|
salt: spicedAccount.salt,
|
|
347
342
|
saltedPassword: spicedAccount.saltedPassword
|
|
348
|
-
}
|
|
343
|
+
});
|
|
349
344
|
const initialClaims = {
|
|
350
345
|
accountId: updatedAccount._id,
|
|
351
346
|
deviceId,
|
|
@@ -373,6 +368,26 @@ let ModuleBE_AccountDB_Class = (() => {
|
|
|
373
368
|
return {
|
|
374
369
|
account: (await account.get()),
|
|
375
370
|
};
|
|
371
|
+
},
|
|
372
|
+
delete: async (request) => {
|
|
373
|
+
return await this.runTransaction(async () => {
|
|
374
|
+
const account = await this.query.unique(request.accountId);
|
|
375
|
+
if (!account)
|
|
376
|
+
throw HttpCodes._4XX.NOT_FOUND(`Account with id ${request.accountId} Not Found!`);
|
|
377
|
+
try {
|
|
378
|
+
const safeAccount = makeAccountSafe(account);
|
|
379
|
+
await dispatch_OnAccountDeleted.dispatchModuleAsyncSerial(safeAccount);
|
|
380
|
+
await this.delete.item(account);
|
|
381
|
+
return { account };
|
|
382
|
+
}
|
|
383
|
+
catch (err) {
|
|
384
|
+
const error = err;
|
|
385
|
+
if (error.responseCode === 422)
|
|
386
|
+
throw error;
|
|
387
|
+
this.logError('Failed deleting account', err);
|
|
388
|
+
throw HttpCodes._5XX.INTERNAL_SERVER_ERROR('Failed to delete account', error.message, error);
|
|
389
|
+
}
|
|
390
|
+
});
|
|
376
391
|
}
|
|
377
392
|
};
|
|
378
393
|
password = {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Module } from '@nu-art/ts-common';
|
|
2
|
-
export declare const ModulePackBE_AccountDB: (import("./ModuleBE_AccountDB.js").ModuleBE_AccountDB_Class | import("@nu-art/db-api-backend").ModuleBE_BaseApi_Class<import("@nu-art/user-account-shared").DatabaseDef_Account>)[];
|
|
2
|
+
export declare const ModulePackBE_AccountDB: (import("./ModuleBE_AccountDB.js").ModuleBE_AccountDB_Class | import("@nu-art/db-api-backend").ModuleBE_BaseApi_Class<import("@nu-art/user-account-shared").DatabaseDef_Account, any>)[];
|
|
3
3
|
export declare const ModulePackBE_SAML: Module[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const ModulePackBE_FailedLoginAttemptDB: (import("./ModuleBE_FailedLoginAttemptDB.js").ModuleBE_FailedLoginAttemptDB_Class | import("@nu-art/db-api-backend").ModuleBE_BaseApi_Class<import("@nu-art/user-account-shared").DatabaseDef_FailedLoginAttempt>)[];
|
|
1
|
+
export declare const ModulePackBE_FailedLoginAttemptDB: (import("./ModuleBE_FailedLoginAttemptDB.js").ModuleBE_FailedLoginAttemptDB_Class | import("@nu-art/db-api-backend").ModuleBE_BaseApi_Class<import("@nu-art/user-account-shared").DatabaseDef_FailedLoginAttempt, any>)[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const ModulePackBE_LoginAttemptDB: (import("./ModuleBE_LoginAttemptDB.js").ModuleBE_LoginAttemptDB_Class | import("@nu-art/db-api-backend").ModuleBE_BaseApi_Class<import("@nu-art/user-account-shared").DatabaseDef_LoginAttempt>)[];
|
|
1
|
+
export declare const ModulePackBE_LoginAttemptDB: (import("./ModuleBE_LoginAttemptDB.js").ModuleBE_LoginAttemptDB_Class | import("@nu-art/db-api-backend").ModuleBE_BaseApi_Class<import("@nu-art/user-account-shared").DatabaseDef_LoginAttempt, any>)[];
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { AnyPrimitive, Dispatcher, RecursiveObjectOfPrimitives, TypedKeyValue } from '@nu-art/ts-common';
|
|
2
|
-
import { firestore } from 'firebase-admin';
|
|
3
2
|
import { ModuleBE_BaseDB } from '@nu-art/db-api-backend';
|
|
4
|
-
import { DatabaseDef_Account, DatabaseDef_Session, DB_Session } from '@nu-art/user-account-shared';
|
|
5
|
-
import
|
|
3
|
+
import { DatabaseDef_Account, DatabaseDef_Session, DB_Session, SafeDB_Account } from '@nu-art/user-account-shared';
|
|
4
|
+
import { OnAccountDeleted } from '../account/ModuleBE_AccountDB.js';
|
|
6
5
|
export type BaseSessionClaims = {
|
|
7
6
|
accountId: DatabaseDef_Account['id'];
|
|
8
7
|
deviceId: string;
|
|
@@ -14,9 +13,9 @@ export type Props_CreateSession = {
|
|
|
14
13
|
initialClaims: BaseSessionClaims;
|
|
15
14
|
};
|
|
16
15
|
export interface CollectSessionData<R extends TypedKeyValue<any, AnyPrimitive>> {
|
|
17
|
-
__collectSessionData(data: BaseSessionClaims
|
|
16
|
+
__collectSessionData(data: BaseSessionClaims): Promise<R>;
|
|
18
17
|
}
|
|
19
|
-
export declare const dispatch_CollectSessionData: Dispatcher<CollectSessionData<TypedKeyValue<any, RecursiveObjectOfPrimitives>>, "__collectSessionData", [data: BaseSessionClaims
|
|
18
|
+
export declare const dispatch_CollectSessionData: Dispatcher<CollectSessionData<TypedKeyValue<any, RecursiveObjectOfPrimitives>>, "__collectSessionData", [data: BaseSessionClaims], TypedKeyValue<any, RecursiveObjectOfPrimitives>>;
|
|
20
19
|
export declare const Const_Default_SessionJWT_SecretKey = "jwt-signer--account-session";
|
|
21
20
|
type Config = {
|
|
22
21
|
sessionTTLms: number;
|
|
@@ -29,40 +28,41 @@ type Config = {
|
|
|
29
28
|
};
|
|
30
29
|
export declare class ModuleBE_SessionDB_Class extends ModuleBE_BaseDB<DatabaseDef_Session, Config> implements CollectSessionData<TypedKeyValue<'session', {
|
|
31
30
|
deviceId: string;
|
|
32
|
-
}
|
|
31
|
+
}>>, OnAccountDeleted {
|
|
33
32
|
private jwtHandler;
|
|
33
|
+
__onAccountDeleted: (account: SafeDB_Account) => Promise<void>;
|
|
34
34
|
constructor();
|
|
35
35
|
init(): void;
|
|
36
36
|
private collectSessionData;
|
|
37
37
|
preWriteProcessing: (instance: DatabaseDef_Session["dbType"]) => Promise<void>;
|
|
38
38
|
token: {
|
|
39
|
-
create: (initialClaims: BaseSessionClaims, ttlInMs?: number
|
|
39
|
+
create: (initialClaims: BaseSessionClaims, ttlInMs?: number) => Promise<string>;
|
|
40
40
|
refresh: (jwtOrigin: string) => Promise<string>;
|
|
41
41
|
verify: (jwt: string) => Promise<BaseSessionClaims & RecursiveObjectOfPrimitives & import("@nu-art/ts-common").JWT_BaseClaims>;
|
|
42
42
|
};
|
|
43
43
|
private __session;
|
|
44
44
|
_session: {
|
|
45
45
|
query: {
|
|
46
|
-
byJwt: (jwt: string
|
|
46
|
+
byJwt: (jwt: string) => Promise<DB_Session>;
|
|
47
47
|
};
|
|
48
48
|
return: (dbSession: DB_Session) => Promise<string>;
|
|
49
|
-
save: (content: Props_CreateSession, jwt: string
|
|
50
|
-
create: ((content: Props_CreateSession, ttlInMs?: number
|
|
51
|
-
andReturn: (content: Props_CreateSession, ttlInMs?: number
|
|
49
|
+
save: (content: Props_CreateSession, jwt: string) => Promise<DB_Session>;
|
|
50
|
+
create: ((content: Props_CreateSession, ttlInMs?: number) => Promise<DB_Session>) & {
|
|
51
|
+
andReturn: (content: Props_CreateSession, ttlInMs?: number) => Promise<string>;
|
|
52
52
|
};
|
|
53
53
|
rotate: {
|
|
54
54
|
refreshIfNeeded: {
|
|
55
|
-
byJwt: (jwt: string
|
|
56
|
-
bySession: (dbSession?: DB_Session
|
|
55
|
+
byJwt: (jwt: string) => Promise<DB_Session | undefined>;
|
|
56
|
+
bySession: (dbSession?: DB_Session) => Promise<DB_Session>;
|
|
57
57
|
};
|
|
58
58
|
reissue: {
|
|
59
|
-
byJwt: (jwt: string
|
|
60
|
-
bySession: (dbSession?: DB_Session
|
|
59
|
+
byJwt: (jwt: string) => Promise<DB_Session>;
|
|
60
|
+
bySession: (dbSession?: DB_Session) => Promise<DB_Session>;
|
|
61
61
|
};
|
|
62
62
|
};
|
|
63
63
|
invalidate: {
|
|
64
|
-
byJwt: (jwt: string
|
|
65
|
-
bySession: (dbSession?: DB_Session
|
|
64
|
+
byJwt: (jwt: string) => Promise<void>;
|
|
65
|
+
bySession: (dbSession?: DB_Session) => Promise<void>;
|
|
66
66
|
};
|
|
67
67
|
};
|
|
68
68
|
readonly Middleware: () => Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ApiException, currentTimeMillis, Day, Dispatcher, filterKeys, isErrorOfType, JwtTools,
|
|
1
|
+
import { ApiException, currentTimeMillis, Day, Dispatcher, filterKeys, isErrorOfType, JwtTools, MUSTNeverHappenException } from '@nu-art/ts-common';
|
|
2
2
|
import { ModuleBE_BaseDB } from '@nu-art/db-api-backend';
|
|
3
3
|
import { AccountType_Service, DBDef_Session } from '@nu-art/user-account-shared';
|
|
4
4
|
import { Header_Authorization, MemKey_DB_Session, MemKey_Jwt, MemKey_SessionData, SessionKey_Account_BE } from './consts.js';
|
|
@@ -8,11 +8,14 @@ import { HttpCodes } from '@nu-art/ts-common/core/exceptions/http-codes';
|
|
|
8
8
|
import { _EmptyQuery } from '@nu-art/firebase-shared';
|
|
9
9
|
import { ModuleBE_AccountDB } from '../account/ModuleBE_AccountDB.js';
|
|
10
10
|
import { ResponseHeaderKey_JWTToken } from '@nu-art/api-types';
|
|
11
|
-
import { dbObjectToId,
|
|
11
|
+
import { dbObjectToId, hashToUniqueId } from '@nu-art/db-api-shared';
|
|
12
12
|
export const dispatch_CollectSessionData = new Dispatcher('__collectSessionData');
|
|
13
13
|
export const Const_Default_SessionJWT_SecretKey = 'jwt-signer--account-session';
|
|
14
14
|
export class ModuleBE_SessionDB_Class extends ModuleBE_BaseDB {
|
|
15
15
|
jwtHandler;
|
|
16
|
+
__onAccountDeleted = async (account) => {
|
|
17
|
+
await this.delete.where({ accountId: account._id });
|
|
18
|
+
};
|
|
16
19
|
constructor() {
|
|
17
20
|
super(DBDef_Session);
|
|
18
21
|
this.setDefaultConfig({
|
|
@@ -33,8 +36,8 @@ export class ModuleBE_SessionDB_Class extends ModuleBE_BaseDB {
|
|
|
33
36
|
...this.config.jwtSigner
|
|
34
37
|
});
|
|
35
38
|
}
|
|
36
|
-
collectSessionData = async (content
|
|
37
|
-
const collectedData = (await dispatch_CollectSessionData.dispatchModuleAsync(content
|
|
39
|
+
collectSessionData = async (content) => {
|
|
40
|
+
const collectedData = (await dispatch_CollectSessionData.dispatchModuleAsync(content));
|
|
38
41
|
return collectedData.reduce((sessionData, moduleSessionData) => {
|
|
39
42
|
// We don't skip existing keys. This allows us to override session data provided by infra, with session data provided by app. If wanted, add flag to symbolize this is intentional to all relevant places.
|
|
40
43
|
sessionData[moduleSessionData.key] = moduleSessionData.value;
|
|
@@ -50,8 +53,8 @@ export class ModuleBE_SessionDB_Class extends ModuleBE_BaseDB {
|
|
|
50
53
|
delete instance.prevSession;
|
|
51
54
|
};
|
|
52
55
|
token = {
|
|
53
|
-
create: async (initialClaims, ttlInMs
|
|
54
|
-
const claims = await this.collectSessionData(initialClaims
|
|
56
|
+
create: async (initialClaims, ttlInMs) => {
|
|
57
|
+
const claims = await this.collectSessionData(initialClaims);
|
|
55
58
|
return await this.jwtHandler.create(claims, ttlInMs ?? this.config.sessionTTLms);
|
|
56
59
|
},
|
|
57
60
|
refresh: async (jwtOrigin) => {
|
|
@@ -83,7 +86,7 @@ export class ModuleBE_SessionDB_Class extends ModuleBE_BaseDB {
|
|
|
83
86
|
// Determine if the session should be rotated:
|
|
84
87
|
return remainingTTL / totalTTL < this.config.rotationFactor;
|
|
85
88
|
},
|
|
86
|
-
refresh: async (dbSession = MemKey_DB_Session.get()
|
|
89
|
+
refresh: async (dbSession = MemKey_DB_Session.get()) => {
|
|
87
90
|
this.logInfo(`Refreshing JWT for Account: ${dbSession.accountId}`);
|
|
88
91
|
const jwt = await this.token.refresh(dbSession.sessionIdJwt);
|
|
89
92
|
const content = {
|
|
@@ -95,9 +98,9 @@ export class ModuleBE_SessionDB_Class extends ModuleBE_BaseDB {
|
|
|
95
98
|
label: `refreshed from ${dbSession._id}`,
|
|
96
99
|
}
|
|
97
100
|
};
|
|
98
|
-
return await this._session.save(content, jwt
|
|
101
|
+
return await this._session.save(content, jwt);
|
|
99
102
|
},
|
|
100
|
-
reissue: async (dbSession = MemKey_DB_Session.get()
|
|
103
|
+
reissue: async (dbSession = MemKey_DB_Session.get()) => {
|
|
101
104
|
this.logInfo(`Reissuing JWT for Account: ${dbSession.accountId} from Session: ${dbSession._id}`);
|
|
102
105
|
const claims = await this.token.verify(dbSession.sessionIdJwt);
|
|
103
106
|
const initialClaims = {
|
|
@@ -105,24 +108,24 @@ export class ModuleBE_SessionDB_Class extends ModuleBE_BaseDB {
|
|
|
105
108
|
deviceId: claims.deviceId,
|
|
106
109
|
label: `reissued from ${dbSession._id}`,
|
|
107
110
|
};
|
|
108
|
-
const jwt = await this.token.create(initialClaims, (claims.exp - claims.iat) * 1000
|
|
111
|
+
const jwt = await this.token.create(initialClaims, (claims.exp - claims.iat) * 1000);
|
|
109
112
|
const content = {
|
|
110
113
|
linkedSessionId: dbSession._id,
|
|
111
114
|
prevSessions: dbSession.validSessionJwtMd5s,
|
|
112
115
|
initialClaims: initialClaims
|
|
113
116
|
};
|
|
114
|
-
return await this._session.save(content, jwt
|
|
117
|
+
return await this._session.save(content, jwt);
|
|
115
118
|
}
|
|
116
119
|
};
|
|
117
120
|
_session = {
|
|
118
121
|
query: {
|
|
119
|
-
byJwt: async (jwt
|
|
122
|
+
byJwt: async (jwt) => {
|
|
120
123
|
return await this.query.uniqueCustom({
|
|
121
124
|
// We use an md5 to save and query for the session object. The original sessionId(JWT) is too big.
|
|
122
|
-
where: { validSessionJwtMd5s: { $ac:
|
|
125
|
+
where: { validSessionJwtMd5s: { $ac: hashToUniqueId(jwt) } },
|
|
123
126
|
orderBy: [{ key: '__created', order: 'desc' }],
|
|
124
127
|
limit: 1
|
|
125
|
-
}
|
|
128
|
+
});
|
|
126
129
|
}
|
|
127
130
|
},
|
|
128
131
|
return: async (dbSession) => {
|
|
@@ -132,8 +135,8 @@ export class ModuleBE_SessionDB_Class extends ModuleBE_BaseDB {
|
|
|
132
135
|
MemKey_Jwt.set(jwt);
|
|
133
136
|
return jwt;
|
|
134
137
|
},
|
|
135
|
-
save: async (content, jwt
|
|
136
|
-
const _id =
|
|
138
|
+
save: async (content, jwt) => {
|
|
139
|
+
const _id = hashToUniqueId(jwt);
|
|
137
140
|
const validSessionJwtMd5s = content.prevSessions ? [_id, ...content.prevSessions] : [_id];
|
|
138
141
|
if (validSessionJwtMd5s.length > this.config.maxPrevSession)
|
|
139
142
|
validSessionJwtMd5s.length = this.config.maxPrevSession;
|
|
@@ -148,56 +151,56 @@ export class ModuleBE_SessionDB_Class extends ModuleBE_BaseDB {
|
|
|
148
151
|
}, ['linkedSessionId', 'label']);
|
|
149
152
|
const idsToDelete = dbSession.validSessionJwtMd5s.slice(1);
|
|
150
153
|
if (idsToDelete.length)
|
|
151
|
-
await this.delete.all(idsToDelete
|
|
152
|
-
return await this.set.item(dbSession
|
|
154
|
+
await this.delete.all(idsToDelete);
|
|
155
|
+
return await this.set.item(dbSession);
|
|
153
156
|
},
|
|
154
|
-
create: Object.assign(async (content, ttlInMs
|
|
157
|
+
create: Object.assign(async (content, ttlInMs) => {
|
|
155
158
|
this.logInfo(`Creating JWT for Account: ${content.initialClaims.accountId}`);
|
|
156
|
-
const jwt = await this.token.create(content.initialClaims, ttlInMs
|
|
157
|
-
return await this._session.save(content, jwt
|
|
159
|
+
const jwt = await this.token.create(content.initialClaims, ttlInMs);
|
|
160
|
+
return await this._session.save(content, jwt);
|
|
158
161
|
}, {
|
|
159
|
-
andReturn: async (content, ttlInMs
|
|
160
|
-
const dbSession = await this._session.create(content, ttlInMs
|
|
162
|
+
andReturn: async (content, ttlInMs) => {
|
|
163
|
+
const dbSession = await this._session.create(content, ttlInMs);
|
|
161
164
|
return await this._session.return(dbSession);
|
|
162
165
|
},
|
|
163
166
|
}),
|
|
164
167
|
rotate: {
|
|
165
168
|
refreshIfNeeded: {
|
|
166
|
-
byJwt: async (jwt
|
|
169
|
+
byJwt: async (jwt) => {
|
|
167
170
|
if (!(await this.__session.shouldRefresh(jwt)))
|
|
168
171
|
return;
|
|
169
|
-
const dbSession = await this._session.query.byJwt(jwt
|
|
172
|
+
const dbSession = await this._session.query.byJwt(jwt);
|
|
170
173
|
this.logInfo(`Refreshing Session by JWT for account(${dbSession.accountId}) sessionId(${dbSession._id})`);
|
|
171
|
-
return await this.__session.refresh(dbSession
|
|
174
|
+
return await this.__session.refresh(dbSession);
|
|
172
175
|
},
|
|
173
|
-
bySession: async (dbSession = MemKey_DB_Session.get()
|
|
176
|
+
bySession: async (dbSession = MemKey_DB_Session.get()) => {
|
|
174
177
|
if (!(await this.__session.shouldRefresh(dbSession.sessionIdJwt)))
|
|
175
178
|
return dbSession;
|
|
176
179
|
this.logInfo(`Refreshing Session by dbSession for account(${dbSession.accountId}) sessionId(${dbSession._id})`);
|
|
177
|
-
return await this.__session.refresh(dbSession
|
|
180
|
+
return await this.__session.refresh(dbSession);
|
|
178
181
|
}
|
|
179
182
|
},
|
|
180
183
|
reissue: {
|
|
181
|
-
byJwt: async (jwt
|
|
184
|
+
byJwt: async (jwt) => {
|
|
182
185
|
await this.jwtHandler.assert(jwt);
|
|
183
|
-
const dbSession = await this._session.query.byJwt(jwt
|
|
184
|
-
return await this.__session.reissue(dbSession
|
|
186
|
+
const dbSession = await this._session.query.byJwt(jwt);
|
|
187
|
+
return await this.__session.reissue(dbSession);
|
|
185
188
|
},
|
|
186
|
-
bySession: async (dbSession = MemKey_DB_Session.get()
|
|
189
|
+
bySession: async (dbSession = MemKey_DB_Session.get()) => {
|
|
187
190
|
await this.jwtHandler.assert(dbSession.sessionIdJwt);
|
|
188
|
-
return await this.__session.reissue(dbSession
|
|
191
|
+
return await this.__session.reissue(dbSession);
|
|
189
192
|
}
|
|
190
193
|
}
|
|
191
194
|
},
|
|
192
195
|
invalidate: {
|
|
193
|
-
byJwt: async (jwt
|
|
194
|
-
const session = await this._session.query.byJwt(jwt
|
|
195
|
-
return await this._session.invalidate.bySession(session
|
|
196
|
+
byJwt: async (jwt) => {
|
|
197
|
+
const session = await this._session.query.byJwt(jwt);
|
|
198
|
+
return await this._session.invalidate.bySession(session);
|
|
196
199
|
},
|
|
197
|
-
bySession: async (dbSession = MemKey_DB_Session.get()
|
|
200
|
+
bySession: async (dbSession = MemKey_DB_Session.get()) => {
|
|
198
201
|
if (!dbSession)
|
|
199
202
|
throw HttpCodes._4XX.UNAUTHORIZED('No session in context to invalidate');
|
|
200
|
-
await this.set.item({ ...dbSession, validSessionJwtMd5s: [] }
|
|
203
|
+
await this.set.item({ ...dbSession, validSessionJwtMd5s: [] });
|
|
201
204
|
this.logInfo(`Session invalidated for account: ${dbSession.accountId}, sessionId: ${dbSession._id}`);
|
|
202
205
|
}
|
|
203
206
|
}
|
|
@@ -214,8 +217,16 @@ export class ModuleBE_SessionDB_Class extends ModuleBE_BaseDB {
|
|
|
214
217
|
};
|
|
215
218
|
async locateSession(jwt) {
|
|
216
219
|
try {
|
|
217
|
-
const { dbSession, claims } = await this.runTransaction(async (
|
|
218
|
-
let dbSession
|
|
220
|
+
const { dbSession, claims } = await this.runTransaction(async () => {
|
|
221
|
+
let dbSession;
|
|
222
|
+
try {
|
|
223
|
+
dbSession = await this._session.query.byJwt(jwt);
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
if (isErrorOfType(err, ApiException)?.responseCode === HttpCodes._4XX.NOT_FOUND.code)
|
|
227
|
+
throw HttpCodes._4XX.UNAUTHORIZED('JWT received in request was not found', err);
|
|
228
|
+
throw err;
|
|
229
|
+
}
|
|
219
230
|
const latestJwtValidationResult = await this.jwtHandler.verifySignature(dbSession.sessionIdJwt);
|
|
220
231
|
if (!latestJwtValidationResult.validated)
|
|
221
232
|
throw new MUSTNeverHappenException(`JWT received from DB is invalid Session id = ${dbSession._id}`);
|
|
@@ -262,12 +273,13 @@ export class ModuleBE_SessionDB_Class extends ModuleBE_BaseDB {
|
|
|
262
273
|
sessionIdsToDelete.add(session._id);
|
|
263
274
|
}
|
|
264
275
|
}
|
|
265
|
-
session.validSessionJwtMd5s
|
|
266
|
-
if (id !== session._id)
|
|
267
|
-
sessionIdsToDelete.add(id);
|
|
268
|
-
});
|
|
269
|
-
if (!session.validSessionJwtMd5s.length)
|
|
276
|
+
if (!session.validSessionJwtMd5s?.length)
|
|
270
277
|
sessionIdsToDelete.add(session._id);
|
|
278
|
+
else
|
|
279
|
+
session.validSessionJwtMd5s.forEach(id => {
|
|
280
|
+
if (id !== session._id)
|
|
281
|
+
sessionIdsToDelete.add(id);
|
|
282
|
+
});
|
|
271
283
|
});
|
|
272
284
|
//Second pass - collect all sessions that are expired or has the old "sessionData" property in their decoded data
|
|
273
285
|
await Promise.all(sessions.map(async (session) => {
|
package/module-pack.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Module } from '@nu-art/ts-common';
|
|
2
|
-
export declare const ModulePackBE_Accounts: Module<any
|
|
3
|
-
export declare const ModulePackBE_Accounts_WOSAML: Module<any
|
|
2
|
+
export declare const ModulePackBE_Accounts: Module<any>[];
|
|
3
|
+
export declare const ModulePackBE_Accounts_WOSAML: Module<any>[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nu-art/user-account-backend",
|
|
3
|
-
"version": "0.500.
|
|
3
|
+
"version": "0.500.6",
|
|
4
4
|
"description": "User Account Backend",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"TacB0sS",
|
|
@@ -34,16 +34,16 @@
|
|
|
34
34
|
"test": "ts-mocha -w -p src/test/tsconfig.json --timeout 0 --inspect=8107 --watch-files 'src/test/**/*.test.ts' src/test/**/*.test.ts"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@nu-art/db-api-backend": "0.500.
|
|
38
|
-
"@nu-art/db-api-shared": "0.500.
|
|
39
|
-
"@nu-art/user-account-shared": "0.500.
|
|
40
|
-
"@nu-art/firebase-backend": "0.500.
|
|
41
|
-
"@nu-art/firebase-shared": "0.500.
|
|
42
|
-
"@nu-art/http-server": "
|
|
43
|
-
"@nu-art/slack-backend": "0.500.
|
|
44
|
-
"@nu-art/slack-shared": "0.500.
|
|
45
|
-
"@nu-art/ts-common": "0.500.
|
|
46
|
-
"@nu-art/api-types": "
|
|
37
|
+
"@nu-art/db-api-backend": "0.500.6",
|
|
38
|
+
"@nu-art/db-api-shared": "0.500.6",
|
|
39
|
+
"@nu-art/user-account-shared": "0.500.6",
|
|
40
|
+
"@nu-art/firebase-backend": "0.500.6",
|
|
41
|
+
"@nu-art/firebase-shared": "0.500.6",
|
|
42
|
+
"@nu-art/http-server": "0.500.6",
|
|
43
|
+
"@nu-art/slack-backend": "0.500.6",
|
|
44
|
+
"@nu-art/slack-shared": "0.500.6",
|
|
45
|
+
"@nu-art/ts-common": "0.500.6",
|
|
46
|
+
"@nu-art/api-types": "0.500.6",
|
|
47
47
|
"express": "^4.18.2",
|
|
48
48
|
"firebase": "^11.9.0",
|
|
49
49
|
"firebase-admin": "13.4.0",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"xmlbuilder": "^15.1.1"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@nu-art/testalot": "0.500.
|
|
59
|
-
"@nu-art/google-services-backend": "0.500.
|
|
58
|
+
"@nu-art/testalot": "0.500.6",
|
|
59
|
+
"@nu-art/google-services-backend": "0.500.6",
|
|
60
60
|
"@types/react": "^18.0.0",
|
|
61
61
|
"@types/express": "^4.17.17",
|
|
62
62
|
"@types/history": "^4.7.2",
|