@bitblit/ratchet-warden-common 4.0.115-alpha → 4.0.119-alpha
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 +1 -1
- package/lib/build/ratchet-warden-common-info.d.ts +1 -1
- package/lib/common/model/warden-jwt-token.d.ts +1 -1
- package/lib/index.d.ts +37 -1
- package/lib/index.mjs +3 -0
- package/lib/index.mjs.map +1 -0
- package/package.json +11 -10
- package/lib/build/ratchet-warden-common-info.js +0 -14
- package/lib/client/provider/warden-client-abstract-recent-login-provider.js +0 -44
- package/lib/client/provider/warden-client-current-logged-in-jwt-token-provider.js +0 -1
- package/lib/client/provider/warden-client-local-storage-logged-in-user-provider.js +0 -29
- package/lib/client/provider/warden-client-local-storage-recent-login-provider.js +0 -23
- package/lib/client/provider/warden-client-recent-login-provider.js +0 -1
- package/lib/client/provider/warden-client-transient-memory-logged-in-user-provider.js +0 -12
- package/lib/client/provider/warden-client-transient-memory-recent-login-provider.js +0 -10
- package/lib/client/provider/warden-command-exchange-provider.js +0 -1
- package/lib/client/provider/warden-logged-in-user-provider.js +0 -1
- package/lib/client/provider/warden-logged-in-user-wrapper.js +0 -1
- package/lib/client/provider/warden-recent-login-descriptor.js +0 -1
- package/lib/client/provider/warden-user-service-event-processing-provider.js +0 -1
- package/lib/client/provider/warden-user-service-options.js +0 -1
- package/lib/client/warden-client.js +0 -134
- package/lib/client/warden-client.spec.js +0 -22
- package/lib/client/warden-delegating-current-user-providing-user-service-event-processing-provider.js +0 -41
- package/lib/client/warden-user-service.js +0 -253
- package/lib/client/warden-user-service.spec.js +0 -19
- package/lib/common/command/create-account.js +0 -1
- package/lib/common/command/remove-web-authn-registration.js +0 -1
- package/lib/common/command/warden-command-response.js +0 -1
- package/lib/common/command/warden-command.js +0 -1
- package/lib/common/command/web-authn-object-wrapper.js +0 -1
- package/lib/common/model/warden-contact-type.js +0 -5
- package/lib/common/model/warden-contact.js +0 -1
- package/lib/common/model/warden-customer-message-type.js +0 -4
- package/lib/common/model/warden-entry-summary.js +0 -1
- package/lib/common/model/warden-entry.js +0 -1
- package/lib/common/model/warden-jwt-token.js +0 -1
- package/lib/common/model/warden-login-request.js +0 -1
- package/lib/common/model/warden-login-results.js +0 -1
- package/lib/common/model/warden-store-registration-response-type.js +0 -6
- package/lib/common/model/warden-store-registration-response.js +0 -1
- package/lib/common/model/warden-team-role.js +0 -1
- package/lib/common/model/warden-user-decoration.js +0 -1
- package/lib/common/model/warden-web-authn-entry.js +0 -1
- package/lib/common/model/warden-web-authn-transport-future-type.js +0 -9
- package/lib/common/util/warden-utils.js +0 -105
- package/lib/common/util/warden-utils.spec.js +0 -10
- package/lib/index.js +0 -1
package/package.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitblit/ratchet-warden-common",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.119-alpha",
|
|
4
4
|
"description": "Typescript library to simplify using simplewebauthn and secondary auth methods over GraphQL",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"bin": {},
|
|
7
7
|
"type": "module",
|
|
8
|
-
"module": "index.js",
|
|
9
8
|
"files": [
|
|
10
9
|
"lib/*",
|
|
11
10
|
"bin/*"
|
|
12
11
|
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./lib/index.d.ts",
|
|
15
|
+
"import": "./lib/index.mjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
13
18
|
"contributors": [
|
|
14
19
|
"Christopher Weiss <bitblit@gmail.com>"
|
|
15
20
|
],
|
|
@@ -31,9 +36,9 @@
|
|
|
31
36
|
"docs": "typedoc",
|
|
32
37
|
"lint": "eslint src/**/*.ts",
|
|
33
38
|
"lint-fix": "eslint --fix src/**/*.ts",
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"build": "tsc"
|
|
39
|
+
"generate-barrels": "barrelsby -q --delete -d src -e .*\\.spec\\.ts && sed -i 's/\\x27;/.js\\x27;/' src/index.ts",
|
|
40
|
+
"build": "yarn clean && yarn generate-barrels && rollup -c rollup.config.js",
|
|
41
|
+
"force-build": "tsc --build --force"
|
|
37
42
|
},
|
|
38
43
|
"repository": {
|
|
39
44
|
"type": "git",
|
|
@@ -52,15 +57,11 @@
|
|
|
52
57
|
},
|
|
53
58
|
"license": "Apache-2.0",
|
|
54
59
|
"dependencies": {
|
|
55
|
-
"@bitblit/ratchet-common": "4.0.
|
|
60
|
+
"@bitblit/ratchet-common": "4.0.119-alpha",
|
|
56
61
|
"@simplewebauthn/browser": "7.2.0",
|
|
57
62
|
"@simplewebauthn/typescript-types": "7.0.0",
|
|
58
63
|
"jwt-decode": "3.1.2"
|
|
59
64
|
},
|
|
60
65
|
"peerDependencies": {
|
|
61
|
-
"@bitblit/ratchet-jest": "4.0.115-alpha",
|
|
62
|
-
"@simplewebauthn/browser": "^7.2.0",
|
|
63
|
-
"@simplewebauthn/typescript-types": "^7.0.0",
|
|
64
|
-
"jwt-decode": "^3.1.2"
|
|
65
66
|
}
|
|
66
67
|
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export class RatchetWardenCommonInfo {
|
|
2
|
-
constructor() { }
|
|
3
|
-
static buildInformation() {
|
|
4
|
-
const val = {
|
|
5
|
-
version: 'LOCAL-SNAPSHOT',
|
|
6
|
-
hash: 'LOCAL-HASH',
|
|
7
|
-
branch: 'LOCAL-BRANCH',
|
|
8
|
-
tag: 'LOCAL-TAG',
|
|
9
|
-
timeBuiltISO: 'LOCAL-TIME-ISO',
|
|
10
|
-
notes: 'LOCAL-NOTES',
|
|
11
|
-
};
|
|
12
|
-
return val;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
|
|
2
|
-
import { StringRatchet } from '@bitblit/ratchet-common/lib/lang/string-ratchet.js';
|
|
3
|
-
import { WardenUtils } from '../../common/util/warden-utils.js';
|
|
4
|
-
export class WardenClientAbstractRecentLoginProvider {
|
|
5
|
-
saveRecentLogin(entry) {
|
|
6
|
-
if (entry?.userId) {
|
|
7
|
-
Logger.info('Saving recent login : %j', entry);
|
|
8
|
-
let list = this.fetchCache();
|
|
9
|
-
list = list.filter((s) => s.user.userId !== entry.userId);
|
|
10
|
-
list.push({
|
|
11
|
-
user: entry,
|
|
12
|
-
lastLoginEpochMS: Date.now(),
|
|
13
|
-
});
|
|
14
|
-
this.updateCache(list);
|
|
15
|
-
}
|
|
16
|
-
else {
|
|
17
|
-
Logger.warn('Cannot save recent login - no login provided : %s', entry);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
saveNewUser(userId, label, contact) {
|
|
21
|
-
if (StringRatchet.trimToNull(userId) && WardenUtils.validContact(contact)) {
|
|
22
|
-
this.saveRecentLogin({
|
|
23
|
-
userId: userId,
|
|
24
|
-
contactMethods: [contact],
|
|
25
|
-
webAuthnAuthenticatorIds: [],
|
|
26
|
-
userLabel: label,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
Logger.warn('Cannot save new user - invalid data : %s : %j', userId, contact);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
removeUser(userId) {
|
|
34
|
-
let list = this.fetchCache();
|
|
35
|
-
list = list.filter((c) => c.user.userId !== userId);
|
|
36
|
-
this.updateCache(list);
|
|
37
|
-
}
|
|
38
|
-
fetchAllLogins() {
|
|
39
|
-
return Object.assign([], this.fetchCache());
|
|
40
|
-
}
|
|
41
|
-
clearAllLogins() {
|
|
42
|
-
this.updateCache([]);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { StringRatchet } from '@bitblit/ratchet-common/lib/lang/string-ratchet.js';
|
|
2
|
-
import { ErrorRatchet } from '@bitblit/ratchet-common/lib/lang/error-ratchet.js';
|
|
3
|
-
import { RequireRatchet } from '@bitblit/ratchet-common/lib/lang/require-ratchet.js';
|
|
4
|
-
export class WardenClientLocalStorageLoggedInUserProvider {
|
|
5
|
-
localStorageKey;
|
|
6
|
-
constructor(localStorageKey) {
|
|
7
|
-
this.localStorageKey = localStorageKey;
|
|
8
|
-
RequireRatchet.notNullUndefinedOrOnlyWhitespaceString(this.localStorageKey, 'localStorageKey');
|
|
9
|
-
if (!localStorage) {
|
|
10
|
-
ErrorRatchet.throwFormattedErr('Local storage not available on this platform');
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
fetchLoggedInUserWrapper() {
|
|
14
|
-
const asString = localStorage.getItem(this.localStorageKey);
|
|
15
|
-
const rval = StringRatchet.trimToNull(asString) ? JSON.parse(asString) : null;
|
|
16
|
-
return rval;
|
|
17
|
-
}
|
|
18
|
-
logOutUser() {
|
|
19
|
-
this.setLoggedInUserWrapper(null);
|
|
20
|
-
}
|
|
21
|
-
setLoggedInUserWrapper(wrapper) {
|
|
22
|
-
if (wrapper) {
|
|
23
|
-
localStorage.setItem(this.localStorageKey, JSON.stringify(wrapper));
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
localStorage.removeItem(this.localStorageKey);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { StringRatchet } from '@bitblit/ratchet-common/lib/lang/string-ratchet.js';
|
|
2
|
-
import { ErrorRatchet } from '@bitblit/ratchet-common/lib/lang/error-ratchet.js';
|
|
3
|
-
import { RequireRatchet } from '@bitblit/ratchet-common/lib/lang/require-ratchet.js';
|
|
4
|
-
import { WardenClientAbstractRecentLoginProvider } from './warden-client-abstract-recent-login-provider.js';
|
|
5
|
-
export class WardenClientLocalStorageRecentLoginProvider extends WardenClientAbstractRecentLoginProvider {
|
|
6
|
-
localStorageKey;
|
|
7
|
-
constructor(localStorageKey) {
|
|
8
|
-
super();
|
|
9
|
-
this.localStorageKey = localStorageKey;
|
|
10
|
-
RequireRatchet.notNullUndefinedOrOnlyWhitespaceString(this.localStorageKey, 'localStorageKey');
|
|
11
|
-
if (!localStorage) {
|
|
12
|
-
ErrorRatchet.throwFormattedErr('Local storage not available on this platform');
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
fetchCache() {
|
|
16
|
-
const asString = StringRatchet.trimToNull(localStorage.getItem(StringRatchet.trimToNull(this.localStorageKey)));
|
|
17
|
-
return asString ? JSON.parse(asString) : [];
|
|
18
|
-
}
|
|
19
|
-
updateCache(newValue) {
|
|
20
|
-
const asString = newValue ? JSON.stringify(newValue) : '[]';
|
|
21
|
-
localStorage.setItem(StringRatchet.trimToNull(this.localStorageKey), asString);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { WardenClientAbstractRecentLoginProvider } from './warden-client-abstract-recent-login-provider.js';
|
|
2
|
-
export class WardenClientTransientMemoryRecentLoginProvider extends WardenClientAbstractRecentLoginProvider {
|
|
3
|
-
_cache = [];
|
|
4
|
-
fetchCache() {
|
|
5
|
-
return this._cache;
|
|
6
|
-
}
|
|
7
|
-
updateCache(newValue) {
|
|
8
|
-
this._cache = newValue;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
|
|
2
|
-
import { StringRatchet } from '@bitblit/ratchet-common/lib/lang/string-ratchet.js';
|
|
3
|
-
import { ErrorRatchet } from '@bitblit/ratchet-common/lib/lang/error-ratchet.js';
|
|
4
|
-
import { RequireRatchet } from '@bitblit/ratchet-common/lib/lang/require-ratchet.js';
|
|
5
|
-
export class WardenClient {
|
|
6
|
-
commandSender;
|
|
7
|
-
jwtProvider;
|
|
8
|
-
constructor(commandSender, jwtProvider) {
|
|
9
|
-
this.commandSender = commandSender;
|
|
10
|
-
this.jwtProvider = jwtProvider;
|
|
11
|
-
RequireRatchet.notNullOrUndefined(commandSender, 'commandSender');
|
|
12
|
-
RequireRatchet.notNullOrUndefined(jwtProvider, 'jwtProvider');
|
|
13
|
-
}
|
|
14
|
-
async exchangeCommand(cmd, returnErrors) {
|
|
15
|
-
const asString = JSON.stringify(cmd);
|
|
16
|
-
const resp = await this.commandSender.sendCommand(asString, this.jwtProvider.fetchCurrentLoggedInJwtToken());
|
|
17
|
-
const parsed = JSON.parse(resp);
|
|
18
|
-
if (parsed?.error && !returnErrors) {
|
|
19
|
-
ErrorRatchet.throwFormattedErr('%s', parsed.error);
|
|
20
|
-
}
|
|
21
|
-
return parsed;
|
|
22
|
-
}
|
|
23
|
-
async createAccount(contact, sendCode, label, tags) {
|
|
24
|
-
const cmd = {
|
|
25
|
-
createAccount: {
|
|
26
|
-
contact: contact,
|
|
27
|
-
sendCode: sendCode,
|
|
28
|
-
label: label,
|
|
29
|
-
tags: tags,
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
const rval = await this.exchangeCommand(cmd);
|
|
33
|
-
return rval.createAccount;
|
|
34
|
-
}
|
|
35
|
-
async generateWebAuthnAuthenticationChallengeForUserId(userId) {
|
|
36
|
-
const cmd = {
|
|
37
|
-
generateWebAuthnAuthenticationChallengeForUserId: userId,
|
|
38
|
-
};
|
|
39
|
-
const rval = await this.exchangeCommand(cmd);
|
|
40
|
-
const parsed = JSON.parse(rval.generateWebAuthnAuthenticationChallengeForUserId.dataAsJson);
|
|
41
|
-
return parsed;
|
|
42
|
-
}
|
|
43
|
-
async generateWebAuthnRegistrationChallengeForLoggedInUser() {
|
|
44
|
-
const cmd = {
|
|
45
|
-
generateWebAuthnRegistrationChallengeForLoggedInUser: true,
|
|
46
|
-
};
|
|
47
|
-
const rval = await this.exchangeCommand(cmd);
|
|
48
|
-
const parsed = JSON.parse(rval.generateWebAuthnRegistrationChallengeForLoggedInUser.dataAsJson);
|
|
49
|
-
return parsed;
|
|
50
|
-
}
|
|
51
|
-
async removeWebAuthnRegistration(userId, credId) {
|
|
52
|
-
const cmd = {
|
|
53
|
-
removeWebAuthnRegistration: {
|
|
54
|
-
userId: userId,
|
|
55
|
-
credentialId: credId,
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
const rval = await this.exchangeCommand(cmd);
|
|
59
|
-
return rval.removeWebAuthnRegistration;
|
|
60
|
-
}
|
|
61
|
-
async removeWebAuthnRegistrationFromLoggedInUser(input) {
|
|
62
|
-
const cmd = {
|
|
63
|
-
removeWebAuthnRegistrationFromLoggedInUser: input,
|
|
64
|
-
};
|
|
65
|
-
const rval = await this.exchangeCommand(cmd);
|
|
66
|
-
return rval.removeWebAuthnRegistrationFromLoggedInUser;
|
|
67
|
-
}
|
|
68
|
-
async removeContactFromLoggedInUser(input) {
|
|
69
|
-
const cmd = {
|
|
70
|
-
removeContactFromLoggedInUser: input,
|
|
71
|
-
};
|
|
72
|
-
const rval = await this.exchangeCommand(cmd);
|
|
73
|
-
return rval.removeContactFromLoggedInUser;
|
|
74
|
-
}
|
|
75
|
-
async sendExpiringValidationToken(contact) {
|
|
76
|
-
const cmd = {
|
|
77
|
-
sendExpiringValidationToken: contact,
|
|
78
|
-
};
|
|
79
|
-
const rval = await this.exchangeCommand(cmd);
|
|
80
|
-
return rval.sendExpiringValidationToken;
|
|
81
|
-
}
|
|
82
|
-
async addContactToLoggedInUser(contact) {
|
|
83
|
-
const cmd = {
|
|
84
|
-
addContactToLoggedInUser: contact,
|
|
85
|
-
};
|
|
86
|
-
const rval = await this.exchangeCommand(cmd);
|
|
87
|
-
return rval.addContactToLoggedInUser;
|
|
88
|
-
}
|
|
89
|
-
async addWebAuthnRegistrationToLoggedInUser(data) {
|
|
90
|
-
const cmd = {
|
|
91
|
-
addWebAuthnRegistrationToLoggedInUser: {
|
|
92
|
-
dataAsJson: JSON.stringify(data),
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
const rval = await this.exchangeCommand(cmd);
|
|
96
|
-
return rval.addWebAuthnRegistrationToLoggedInUser;
|
|
97
|
-
}
|
|
98
|
-
async performLoginCmd(login) {
|
|
99
|
-
const loginCmd = {
|
|
100
|
-
performLogin: login,
|
|
101
|
-
};
|
|
102
|
-
const cmdResponse = await this.exchangeCommand(loginCmd);
|
|
103
|
-
return cmdResponse.performLogin;
|
|
104
|
-
}
|
|
105
|
-
async refreshJwtToken(oldJwtToken) {
|
|
106
|
-
let rval = null;
|
|
107
|
-
if (StringRatchet.trimToNull(oldJwtToken)) {
|
|
108
|
-
try {
|
|
109
|
-
const resp = await this.exchangeCommand({ refreshJwtToken: oldJwtToken });
|
|
110
|
-
rval = resp.refreshJwtToken;
|
|
111
|
-
}
|
|
112
|
-
catch (err) {
|
|
113
|
-
Logger.error('JwtRefresh Failed : %s', err);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return rval;
|
|
117
|
-
}
|
|
118
|
-
async executeExpiringTokenBasedLogin(contact, expiringToken) {
|
|
119
|
-
let rval = null;
|
|
120
|
-
try {
|
|
121
|
-
const loginCmd = {
|
|
122
|
-
contact: contact,
|
|
123
|
-
expiringToken: expiringToken,
|
|
124
|
-
};
|
|
125
|
-
rval = await this.performLoginCmd(loginCmd);
|
|
126
|
-
if (rval?.jwtToken) {
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
catch (err) {
|
|
130
|
-
Logger.error('ExpiringToken login Failed : %s', err);
|
|
131
|
-
}
|
|
132
|
-
return rval;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { JestRatchet } from '@bitblit/ratchet-jest/lib/jest/jest-ratchet.js';
|
|
2
|
-
import { WardenClient } from './warden-client.js';
|
|
3
|
-
import { jest } from '@jest/globals';
|
|
4
|
-
let mockCommandExchangeProvider;
|
|
5
|
-
let mockLoggedInJwtTokenProvider;
|
|
6
|
-
describe('#wardenClient', function () {
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
mockCommandExchangeProvider = JestRatchet.mock(jest.fn);
|
|
9
|
-
mockLoggedInJwtTokenProvider = JestRatchet.mock(jest.fn);
|
|
10
|
-
});
|
|
11
|
-
it('should instantiate and exchange commands', async () => {
|
|
12
|
-
const wc = new WardenClient(mockCommandExchangeProvider, mockLoggedInJwtTokenProvider);
|
|
13
|
-
expect(wc).not.toBeNull();
|
|
14
|
-
const cmd = {
|
|
15
|
-
generateWebAuthnAuthenticationChallengeForUserId: 'test',
|
|
16
|
-
};
|
|
17
|
-
mockCommandExchangeProvider.sendCommand.mockResolvedValue('{"generateWebAuthnAuthenticationChallengeForUserId": { "dataAsJson": {} }}');
|
|
18
|
-
const result = await wc.exchangeCommand(cmd);
|
|
19
|
-
expect(result).not.toBeNull();
|
|
20
|
-
expect(result.generateWebAuthnRegistrationChallengeForLoggedInUser).not.toBeNull();
|
|
21
|
-
});
|
|
22
|
-
});
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { BehaviorSubject } from 'rxjs';
|
|
2
|
-
export class WardenDelegatingCurrentUserProvidingUserServiceEventProcessingProvider {
|
|
3
|
-
wrapped;
|
|
4
|
-
_currentUserSubject = new BehaviorSubject(null);
|
|
5
|
-
constructor(wrapped) {
|
|
6
|
-
this.wrapped = wrapped;
|
|
7
|
-
}
|
|
8
|
-
fetchCurrentLoggedInJwtToken() {
|
|
9
|
-
return this?._currentUserSubject?.getValue()?.jwtToken;
|
|
10
|
-
}
|
|
11
|
-
get currentUserSubject() {
|
|
12
|
-
return this._currentUserSubject;
|
|
13
|
-
}
|
|
14
|
-
onAutomaticLogout() {
|
|
15
|
-
if (this.wrapped) {
|
|
16
|
-
this.wrapped.onAutomaticLogout();
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
onAutomaticTokenRefresh(refreshUser) {
|
|
20
|
-
if (this.wrapped) {
|
|
21
|
-
this.wrapped.onAutomaticTokenRefresh(refreshUser);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
onLoginFailure(reason) {
|
|
25
|
-
if (this.wrapped) {
|
|
26
|
-
this.wrapped.onLoginFailure(reason);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
onLogout() {
|
|
30
|
-
if (this.wrapped) {
|
|
31
|
-
this.wrapped.onLogout();
|
|
32
|
-
}
|
|
33
|
-
this.currentUserSubject.next(null);
|
|
34
|
-
}
|
|
35
|
-
onSuccessfulLogin(newUser) {
|
|
36
|
-
if (this.wrapped) {
|
|
37
|
-
this.wrapped.onSuccessfulLogin(newUser);
|
|
38
|
-
}
|
|
39
|
-
this.currentUserSubject.next(newUser);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
|
|
2
|
-
import { StringRatchet } from '@bitblit/ratchet-common/lib/lang/string-ratchet.js';
|
|
3
|
-
import { JwtRatchet } from '@bitblit/ratchet-common/lib/jwt/jwt-ratchet.js';
|
|
4
|
-
import { timer } from 'rxjs';
|
|
5
|
-
export class WardenUserService {
|
|
6
|
-
options;
|
|
7
|
-
loggedInTimerSubscription;
|
|
8
|
-
_autoRefreshEnabled = false;
|
|
9
|
-
constructor(options) {
|
|
10
|
-
this.options = options;
|
|
11
|
-
Logger.info('Initializing user service');
|
|
12
|
-
const stored = this.options.loggedInUserProvider.fetchLoggedInUserWrapper();
|
|
13
|
-
if (WardenUserService.wrapperIsExpired(stored)) {
|
|
14
|
-
Logger.info('Stored token is expired, removing it');
|
|
15
|
-
this.options.loggedInUserProvider.logOutUser();
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
this.options.eventProcessor.onSuccessfulLogin(stored);
|
|
19
|
-
}
|
|
20
|
-
const timerSeconds = this.options.loginCheckTimerPingSeconds || 2.5;
|
|
21
|
-
this.loggedInTimerSubscription = timer(0, timerSeconds * 1000).subscribe((t) => this.checkForAutoLogoutOrRefresh(t));
|
|
22
|
-
}
|
|
23
|
-
cleanShutDown() {
|
|
24
|
-
if (this.loggedInTimerSubscription) {
|
|
25
|
-
this.loggedInTimerSubscription.unsubscribe();
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
get serviceOptions() {
|
|
29
|
-
return this.options;
|
|
30
|
-
}
|
|
31
|
-
async createAccount(contact, sendCode, label, tags) {
|
|
32
|
-
const rval = await this.options.wardenClient.createAccount(contact, sendCode, label, tags);
|
|
33
|
-
if (this.options.recentLoginProvider && StringRatchet.trimToNull(rval)) {
|
|
34
|
-
this.options.recentLoginProvider.saveNewUser(rval, label, contact);
|
|
35
|
-
}
|
|
36
|
-
return rval;
|
|
37
|
-
}
|
|
38
|
-
async addContactToLoggedInUser(contact) {
|
|
39
|
-
return this.options.wardenClient.addContactToLoggedInUser(contact);
|
|
40
|
-
}
|
|
41
|
-
get autoRefreshEnabled() {
|
|
42
|
-
return this._autoRefreshEnabled;
|
|
43
|
-
}
|
|
44
|
-
set autoRefreshEnabled(newValue) {
|
|
45
|
-
if (newValue) {
|
|
46
|
-
if (this.options.allowAutoRefresh) {
|
|
47
|
-
this._autoRefreshEnabled = true;
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
throw new Error('Cannot enable auto-refresh - this is disabled in the user service options');
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
this._autoRefreshEnabled = false;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
async checkForAutoLogoutOrRefresh(t) {
|
|
58
|
-
Logger.debug('Checking for auto-logout or refresh : %s', t);
|
|
59
|
-
const current = this.fetchLoggedInUserWrapper();
|
|
60
|
-
if (current) {
|
|
61
|
-
const thresholdSeconds = this.options.autoLoginHandlingThresholdSeconds || 10;
|
|
62
|
-
const secondsLeft = current.expirationEpochSeconds - Math.floor(Date.now() / 1000);
|
|
63
|
-
if (secondsLeft < thresholdSeconds) {
|
|
64
|
-
if (this.autoRefreshEnabled) {
|
|
65
|
-
Logger.info('Under threshold, initiating auto-refresh');
|
|
66
|
-
const result = await this.refreshToken();
|
|
67
|
-
this.options.eventProcessor.onAutomaticTokenRefresh(result);
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
Logger.info('Under threshold, initiating auto-logout');
|
|
71
|
-
this.logout();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
logout() {
|
|
77
|
-
this.options.loggedInUserProvider.logOutUser();
|
|
78
|
-
this.options.eventProcessor.onLogout();
|
|
79
|
-
}
|
|
80
|
-
static wrapperIsExpired(value) {
|
|
81
|
-
const rval = value?.userObject?.exp && value.expirationEpochSeconds < Date.now() / 1000;
|
|
82
|
-
return rval;
|
|
83
|
-
}
|
|
84
|
-
fetchLoggedInUserWrapper() {
|
|
85
|
-
let tmp = this.options.loggedInUserProvider.fetchLoggedInUserWrapper();
|
|
86
|
-
if (tmp) {
|
|
87
|
-
if (WardenUserService.wrapperIsExpired(tmp)) {
|
|
88
|
-
Logger.info('Token is expired - auto logout triggered');
|
|
89
|
-
this.logout();
|
|
90
|
-
tmp = null;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return tmp;
|
|
94
|
-
}
|
|
95
|
-
loggedInUserHasRole(role) {
|
|
96
|
-
let rval = false;
|
|
97
|
-
if (StringRatchet.trimToNull(role)) {
|
|
98
|
-
const t = this.fetchLoggedInUserWrapper();
|
|
99
|
-
const testRole = role.toLowerCase();
|
|
100
|
-
rval = t?.userObject?.roles && !!t.userObject.roles.find((r) => r.toLowerCase() === testRole);
|
|
101
|
-
}
|
|
102
|
-
return rval;
|
|
103
|
-
}
|
|
104
|
-
isLoggedIn() {
|
|
105
|
-
const t = this.fetchLoggedInUserWrapper();
|
|
106
|
-
return !!t;
|
|
107
|
-
}
|
|
108
|
-
fetchLoggedInUserJwtObject() {
|
|
109
|
-
const t = this.fetchLoggedInUserWrapper();
|
|
110
|
-
return t ? t.userObject : null;
|
|
111
|
-
}
|
|
112
|
-
fetchLoggedInUserJwtToken() {
|
|
113
|
-
const t = this.fetchLoggedInUserWrapper();
|
|
114
|
-
return t ? t.jwtToken : null;
|
|
115
|
-
}
|
|
116
|
-
fetchLoggedInUserObject() {
|
|
117
|
-
const t = this.fetchLoggedInUserJwtObject();
|
|
118
|
-
return t ? t.user : null;
|
|
119
|
-
}
|
|
120
|
-
fetchLoggedInUserExpirationEpochSeconds() {
|
|
121
|
-
const t = this.fetchLoggedInUserJwtObject();
|
|
122
|
-
return t ? t.exp : null;
|
|
123
|
-
}
|
|
124
|
-
fetchLoggedInUserRemainingSeconds() {
|
|
125
|
-
const t = this.fetchLoggedInUserJwtObject();
|
|
126
|
-
return t ? t.exp - Math.floor(Date.now() / 1000) : null;
|
|
127
|
-
}
|
|
128
|
-
updateLoggedInUserFromTokenString(token) {
|
|
129
|
-
let rval = null;
|
|
130
|
-
if (!StringRatchet.trimToNull(token)) {
|
|
131
|
-
Logger.info('Called updateLoggedInUserFromTokenString with empty string - logging out');
|
|
132
|
-
this.logout();
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
Logger.info('updateLoggedInUserFromTokenString : %s', token);
|
|
136
|
-
const parsed = JwtRatchet.decodeTokenNoVerify(token);
|
|
137
|
-
if (parsed) {
|
|
138
|
-
rval = {
|
|
139
|
-
userObject: parsed,
|
|
140
|
-
jwtToken: token,
|
|
141
|
-
expirationEpochSeconds: parsed.exp,
|
|
142
|
-
};
|
|
143
|
-
this.options.loggedInUserProvider.setLoggedInUserWrapper(rval);
|
|
144
|
-
this.updateRecentLoginsFromWardenEntrySummary(parsed.loginData);
|
|
145
|
-
this.options.eventProcessor.onSuccessfulLogin(rval);
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
Logger.warn('Failed to parse token %s - ignoring login and triggering failure');
|
|
149
|
-
this.options.eventProcessor.onLoginFailure('Could not parse token string');
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return rval;
|
|
153
|
-
}
|
|
154
|
-
async refreshToken() {
|
|
155
|
-
let rval = null;
|
|
156
|
-
const currentWrapper = this.fetchLoggedInUserWrapper();
|
|
157
|
-
if (!currentWrapper) {
|
|
158
|
-
Logger.info('Could not refresh - no token available');
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
const newToken = await this.options.wardenClient.refreshJwtToken(currentWrapper.jwtToken);
|
|
162
|
-
rval = await this.updateLoggedInUserFromTokenString(newToken);
|
|
163
|
-
}
|
|
164
|
-
return rval;
|
|
165
|
-
}
|
|
166
|
-
async sendExpiringCode(contact) {
|
|
167
|
-
return this.options.wardenClient.sendExpiringValidationToken(contact);
|
|
168
|
-
}
|
|
169
|
-
async processWardenLoginResults(resp) {
|
|
170
|
-
let rval = null;
|
|
171
|
-
if (resp) {
|
|
172
|
-
Logger.info('Warden: response : %j ', resp);
|
|
173
|
-
if (resp.jwtToken) {
|
|
174
|
-
Logger.info('Applying login');
|
|
175
|
-
rval = await this.updateLoggedInUserFromTokenString(resp.jwtToken);
|
|
176
|
-
}
|
|
177
|
-
else if (resp.error) {
|
|
178
|
-
this.options.eventProcessor.onLoginFailure(resp.error);
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
Logger.error('Response contained neither token nor error');
|
|
182
|
-
this.options.eventProcessor.onLoginFailure('Response contained neither token nor error');
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
Logger.error('Login call failed');
|
|
187
|
-
this.options.eventProcessor.onLoginFailure('Login call returned null');
|
|
188
|
-
}
|
|
189
|
-
return rval;
|
|
190
|
-
}
|
|
191
|
-
updateRecentLoginsFromWardenEntrySummary(res) {
|
|
192
|
-
if (this.options.recentLoginProvider && res) {
|
|
193
|
-
Logger.info('UserService : Saving recent login %j', res);
|
|
194
|
-
this.options.recentLoginProvider.saveRecentLogin(res);
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
Logger.info('Not saving recent login - no storage configured or no data passed');
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
updateRecentLoginsFromLoggedInUserWrapper(res) {
|
|
201
|
-
this.updateRecentLoginsFromWardenEntrySummary(res?.userObject?.loginData);
|
|
202
|
-
}
|
|
203
|
-
async executeWebAuthnBasedLogin(userId) {
|
|
204
|
-
const resp = await this.executeWebAuthnLoginToWardenLoginResults(userId);
|
|
205
|
-
const rval = await this.processWardenLoginResults(resp);
|
|
206
|
-
this.updateRecentLoginsFromLoggedInUserWrapper(rval);
|
|
207
|
-
return rval;
|
|
208
|
-
}
|
|
209
|
-
async removeWebAuthnRegistrationFromLoggedInUser(input) {
|
|
210
|
-
const rval = await this.options.wardenClient.removeWebAuthnRegistrationFromLoggedInUser(input);
|
|
211
|
-
return rval;
|
|
212
|
-
}
|
|
213
|
-
async removeContactFromLoggedInUser(input) {
|
|
214
|
-
const rval = await this.options.wardenClient.removeContactFromLoggedInUser(input);
|
|
215
|
-
return rval;
|
|
216
|
-
}
|
|
217
|
-
async executeValidationTokenBasedLogin(contact, token) {
|
|
218
|
-
Logger.info('Warden: executeValidationTokenBasedLogin : %j : %s ', contact, token);
|
|
219
|
-
const resp = await this.options.wardenClient.performLoginCmd({ contact: contact, expiringToken: token });
|
|
220
|
-
const rval = await this.processWardenLoginResults(resp);
|
|
221
|
-
this.updateRecentLoginsFromLoggedInUserWrapper(rval);
|
|
222
|
-
return rval;
|
|
223
|
-
}
|
|
224
|
-
async saveCurrentDeviceAsWebAuthnForCurrentUser() {
|
|
225
|
-
const input = await this.options.wardenClient.generateWebAuthnRegistrationChallengeForLoggedInUser();
|
|
226
|
-
const startRegistration = (await import('@simplewebauthn/browser')).startRegistration;
|
|
227
|
-
const creds = await startRegistration(input);
|
|
228
|
-
const output = await this.options.wardenClient.addWebAuthnRegistrationToLoggedInUser(creds);
|
|
229
|
-
this.updateRecentLoginsFromWardenEntrySummary(output);
|
|
230
|
-
return output;
|
|
231
|
-
}
|
|
232
|
-
async executeWebAuthnLoginToWardenLoginResults(userId) {
|
|
233
|
-
let rval = null;
|
|
234
|
-
try {
|
|
235
|
-
const input = await this.options.wardenClient.generateWebAuthnAuthenticationChallengeForUserId(userId);
|
|
236
|
-
Logger.info('Got login challenge : %s', input);
|
|
237
|
-
const startAuthentication = (await import('@simplewebauthn/browser')).startAuthentication;
|
|
238
|
-
const creds = await startAuthentication(input);
|
|
239
|
-
Logger.info('Got creds: %j', creds);
|
|
240
|
-
const loginCmd = {
|
|
241
|
-
userId: userId,
|
|
242
|
-
webAuthn: creds,
|
|
243
|
-
};
|
|
244
|
-
rval = await this.options.wardenClient.performLoginCmd(loginCmd);
|
|
245
|
-
if (rval?.jwtToken) {
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
catch (err) {
|
|
249
|
-
Logger.error('WebauthN Failed : %s', err);
|
|
250
|
-
}
|
|
251
|
-
return rval;
|
|
252
|
-
}
|
|
253
|
-
}
|