@sudoplatform/sudo-user 11.1.0 → 12.0.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/cjs/client/apiClient.js +149 -0
- package/cjs/client/apiClient.js.map +1 -0
- package/cjs/core/api-key-names.js +12 -0
- package/cjs/core/api-key-names.js.map +1 -0
- package/cjs/core/auth-store.js +92 -0
- package/cjs/core/auth-store.js.map +1 -0
- package/cjs/core/crypto.js +3 -0
- package/cjs/core/crypto.js.map +1 -0
- package/cjs/core/key-manager.js +113 -0
- package/cjs/core/key-manager.js.map +1 -0
- package/cjs/core/protected-store.js +3 -0
- package/cjs/core/protected-store.js.map +1 -0
- package/cjs/core/publisher.js +3 -0
- package/cjs/core/publisher.js.map +1 -0
- package/cjs/core/sdk-config.js +61 -0
- package/cjs/core/sdk-config.js.map +1 -0
- package/cjs/core/subscriber.js +3 -0
- package/cjs/core/subscriber.js.map +1 -0
- package/cjs/gen/graphql-types.js +105 -0
- package/cjs/gen/graphql-types.js.map +1 -0
- package/cjs/index.js +13 -0
- package/cjs/index.js.map +1 -0
- package/cjs/runtimes/browser/browser-crypto.js +10 -0
- package/cjs/runtimes/browser/browser-crypto.js.map +1 -0
- package/cjs/runtimes/node/node-crypto.js +9 -0
- package/cjs/runtimes/node/node-crypto.js.map +1 -0
- package/cjs/sdk.js +9 -0
- package/cjs/sdk.js.map +1 -0
- package/cjs/user/auth-provider.js +116 -0
- package/cjs/user/auth-provider.js.map +1 -0
- package/cjs/user/auth.js +136 -0
- package/cjs/user/auth.js.map +1 -0
- package/cjs/user/error.js +33 -0
- package/cjs/user/error.js.map +1 -0
- package/cjs/user/identity-provider.js +245 -0
- package/cjs/user/identity-provider.js.map +1 -0
- package/cjs/user/user-client-interface.js +3 -0
- package/cjs/user/user-client-interface.js.map +1 -0
- package/cjs/user/user-client.js +440 -0
- package/cjs/user/user-client.js.map +1 -0
- package/cjs/user/user-key-names.js +10 -0
- package/cjs/user/user-key-names.js.map +1 -0
- package/cjs/utils/resolvable-promise.js +20 -0
- package/cjs/utils/resolvable-promise.js.map +1 -0
- package/lib/client/apiClient.js +135 -180
- package/lib/client/apiClient.js.map +1 -0
- package/lib/core/api-key-names.js +8 -14
- package/lib/core/api-key-names.js.map +1 -0
- package/lib/core/auth-store.js +82 -138
- package/lib/core/auth-store.js.map +1 -0
- package/lib/core/crypto.js +2 -5
- package/lib/core/crypto.js.map +1 -0
- package/lib/core/key-manager.js +98 -148
- package/lib/core/key-manager.js.map +1 -0
- package/lib/core/protected-store.js +2 -5
- package/lib/core/protected-store.js.map +1 -0
- package/lib/core/publisher.js +2 -5
- package/lib/core/publisher.js.map +1 -0
- package/lib/core/sdk-config.js +56 -56
- package/lib/core/sdk-config.js.map +1 -0
- package/lib/core/subscriber.js +2 -5
- package/lib/core/subscriber.js.map +1 -0
- package/lib/gen/graphql-types.js +96 -135
- package/lib/gen/graphql-types.js.map +1 -0
- package/lib/index.js +6 -67
- package/lib/index.js.map +1 -0
- package/lib/runtimes/browser/browser-crypto.js +6 -14
- package/lib/runtimes/browser/browser-crypto.js.map +1 -0
- package/lib/runtimes/node/node-crypto.js +5 -11
- package/lib/runtimes/node/node-crypto.js.map +1 -0
- package/lib/sdk.js +6 -18
- package/lib/sdk.js.map +1 -0
- package/lib/user/auth-provider.js +81 -131
- package/lib/user/auth-provider.js.map +1 -0
- package/lib/user/auth.js +127 -179
- package/lib/user/auth.js.map +1 -0
- package/lib/user/error.js +15 -33
- package/lib/user/error.js.map +1 -0
- package/lib/user/identity-provider.js +228 -254
- package/lib/user/identity-provider.js.map +1 -0
- package/lib/user/user-client-interface.js +2 -5
- package/lib/user/user-client-interface.js.map +1 -0
- package/lib/user/user-client.js +423 -510
- package/lib/user/user-client.js.map +1 -0
- package/lib/user/user-key-names.js +6 -12
- package/lib/user/user-key-names.js.map +1 -0
- package/lib/utils/resolvable-promise.js +13 -19
- package/lib/utils/resolvable-promise.js.map +1 -0
- package/package.json +36 -28
- package/{lib → types}/client/apiClient.d.ts +0 -0
- package/{lib → types}/core/api-key-names.d.ts +0 -0
- package/{lib → types}/core/auth-store.d.ts +0 -0
- package/{lib → types}/core/crypto.d.ts +0 -0
- package/{lib → types}/core/key-manager.d.ts +0 -0
- package/types/core/protected-store.d.ts +5 -0
- package/{lib → types}/core/publisher.d.ts +0 -0
- package/{lib → types}/core/sdk-config.d.ts +0 -0
- package/{lib → types}/core/subscriber.d.ts +0 -0
- package/{lib → types}/gen/graphql-types.d.ts +0 -0
- package/{lib → types}/index.d.ts +0 -0
- package/{lib/runtimes/node/node-crypto.d.ts → types/runtimes/browser/browser-crypto.d.ts} +0 -0
- package/types/runtimes/node/node-crypto.d.ts +2 -0
- package/{lib → types}/sdk.d.ts +0 -0
- package/{lib → types}/user/auth-provider.d.ts +0 -0
- package/{lib → types}/user/auth.d.ts +0 -0
- package/{lib → types}/user/error.d.ts +0 -0
- package/{lib → types}/user/identity-provider.d.ts +0 -0
- package/{lib → types}/user/user-client-interface.d.ts +0 -0
- package/{lib → types}/user/user-client.d.ts +0 -0
- package/{lib → types}/user/user-key-names.d.ts +0 -0
- package/{lib → types}/utils/resolvable-promise.d.ts +0 -0
- package/types/redux-offline/index.d.ts +0 -4
package/lib/user/user-client.js
CHANGED
|
@@ -1,504 +1,420 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const uid = await this.getUserName();
|
|
190
|
-
|
|
191
|
-
if (uid) {
|
|
192
|
-
const authTokens = await this.identityProvider.refreshTokens(refreshToken);
|
|
193
|
-
await this.storeTokens(uid, authTokens);
|
|
194
|
-
return authTokens;
|
|
195
|
-
} else {
|
|
196
|
-
throw new _sudoCommon.NotRegisteredError('Not registered.');
|
|
197
|
-
}
|
|
198
|
-
} catch (err) {
|
|
199
|
-
const error = err;
|
|
200
|
-
throw new _sudoCommon.AuthenticationError(error.message);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
async getLatestAuthToken() {
|
|
205
|
-
try {
|
|
206
|
-
const idToken = await this.getIdToken();
|
|
207
|
-
const refreshToken = await this.getRefreshToken();
|
|
208
|
-
const expiry = await this.getTokenExpiry();
|
|
209
|
-
|
|
210
|
-
if (idToken && refreshToken && expiry) {
|
|
211
|
-
if (expiry.getTime() > new Date().getTime() + 600 * 1000) {
|
|
212
|
-
return idToken;
|
|
213
|
-
} else {
|
|
214
|
-
try {
|
|
215
|
-
const authTokens = await this.refreshTokens(refreshToken);
|
|
216
|
-
return authTokens.idToken;
|
|
217
|
-
} catch (error) {
|
|
218
|
-
this.logger.info('getLatestAuthToken: Token refresh failed', {
|
|
219
|
-
error
|
|
220
|
-
}); // return an empty id token
|
|
221
|
-
|
|
1
|
+
import { AuthenticationError, DefaultLogger, DefaultSudoKeyManager, FatalError, KeyNotFoundError, NotAuthorizedError, NotRegisteredError, NotSignedInError, PublicKeyFormat, RegisterError, } from '@sudoplatform/sudo-common';
|
|
2
|
+
import { WebSudoCryptoProvider } from '@sudoplatform/sudo-web-crypto-provider';
|
|
3
|
+
import * as JWT from 'jsonwebtoken';
|
|
4
|
+
import { v4 } from 'uuid';
|
|
5
|
+
import { ApiClient } from '../client/apiClient';
|
|
6
|
+
import { apiKeyNames } from '../core/api-key-names';
|
|
7
|
+
import { AuthenticationStore } from '../core/auth-store';
|
|
8
|
+
import { KeyManager } from '../core/key-manager';
|
|
9
|
+
import { getIdentityServiceConfig } from '../core/sdk-config';
|
|
10
|
+
import { CognitoAuthUI } from './auth';
|
|
11
|
+
import { AlreadyRegisteredError } from './error';
|
|
12
|
+
import { CognitoUserPoolIdentityProvider, } from './identity-provider';
|
|
13
|
+
import { userKeyNames } from './user-key-names';
|
|
14
|
+
export class DefaultSudoUserClient {
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.logger = options?.logger ?? new DefaultLogger('SudoUser', 'warn');
|
|
17
|
+
this.config = options?.config ?? getIdentityServiceConfig();
|
|
18
|
+
this.authenticationStore =
|
|
19
|
+
options?.authenticationStore ?? new AuthenticationStore();
|
|
20
|
+
if (options?.sudoKeyManager) {
|
|
21
|
+
this.sudoUserKeyManager = options?.sudoKeyManager;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
const cryptoProvider = new WebSudoCryptoProvider('SudoUserClient', 'com.sudoplatform.appservicename');
|
|
25
|
+
this.sudoUserKeyManager = new DefaultSudoKeyManager(cryptoProvider);
|
|
26
|
+
}
|
|
27
|
+
this.keyManager = new KeyManager(this.sudoUserKeyManager);
|
|
28
|
+
this.launchUriFn = options?.launchUriFn;
|
|
29
|
+
this.identityProvider =
|
|
30
|
+
options?.identityProvider ??
|
|
31
|
+
new CognitoUserPoolIdentityProvider(this.keyManager, this.config, this.logger);
|
|
32
|
+
const federatedSignInConfig = this.config?.federatedSignIn;
|
|
33
|
+
if (federatedSignInConfig) {
|
|
34
|
+
this.authUI =
|
|
35
|
+
options?.authUI ??
|
|
36
|
+
new CognitoAuthUI(this.authenticationStore, federatedSignInConfig, this.keyManager, this.logger, this.launchUriFn);
|
|
37
|
+
}
|
|
38
|
+
this.apiClient =
|
|
39
|
+
options?.apiClient ??
|
|
40
|
+
new ApiClient(this.config.identityService.region, this.config.identityService.apiUrl, this, this.logger);
|
|
41
|
+
}
|
|
42
|
+
get sudoKeyManager() {
|
|
43
|
+
return this.sudoUserKeyManager;
|
|
44
|
+
}
|
|
45
|
+
presentFederatedSignInUI() {
|
|
46
|
+
try {
|
|
47
|
+
this.authUI?.presentFederatedSignInUI();
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
const error = err;
|
|
51
|
+
this.logger.error('Failed to launch the federated sign in UI.', { error });
|
|
52
|
+
throw new AuthenticationError(error.message);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async processFederatedSignInTokens(url) {
|
|
56
|
+
try {
|
|
57
|
+
let authTokens = await this.authUI?.processFederatedSignInTokens(url);
|
|
58
|
+
if (authTokens) {
|
|
59
|
+
authTokens = await this.registerFederatedIdAndRefreshTokens(authTokens);
|
|
60
|
+
return authTokens;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
throw new AuthenticationError('Authentication tokens missing.');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
const error = err;
|
|
68
|
+
this.logger.error('Failed to process the federated sign in redirect.', {
|
|
69
|
+
error,
|
|
70
|
+
});
|
|
71
|
+
throw new AuthenticationError(error.message);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async getIdToken() {
|
|
75
|
+
return await this.keyManager.getString(apiKeyNames.idToken);
|
|
76
|
+
}
|
|
77
|
+
async getAccessToken() {
|
|
78
|
+
return await this.keyManager.getString(apiKeyNames.accessToken);
|
|
79
|
+
}
|
|
80
|
+
async getRefreshToken() {
|
|
81
|
+
return await this.keyManager.getString(apiKeyNames.refreshToken);
|
|
82
|
+
}
|
|
83
|
+
async getTokenExpiry() {
|
|
84
|
+
const expiry = await this.keyManager.getString(apiKeyNames.tokenExpiry);
|
|
85
|
+
return expiry ? new Date(Number(expiry) * 1000) : undefined;
|
|
86
|
+
}
|
|
87
|
+
async getRefreshTokenExpiry() {
|
|
88
|
+
let expiry = undefined;
|
|
89
|
+
const timeSinceEpoch = await this.keyManager.getString(apiKeyNames.refreshTokenExpiry);
|
|
90
|
+
if (timeSinceEpoch) {
|
|
91
|
+
expiry = new Date(Number(timeSinceEpoch));
|
|
92
|
+
}
|
|
93
|
+
return expiry;
|
|
94
|
+
}
|
|
95
|
+
async getUserName() {
|
|
96
|
+
try {
|
|
97
|
+
return await this.keyManager.getString(userKeyNames.userId);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async setUserName(name) {
|
|
104
|
+
await this.keyManager.removeItem(userKeyNames.userId);
|
|
105
|
+
await this.keyManager.addString(userKeyNames.userId, name);
|
|
106
|
+
}
|
|
107
|
+
async getUserClaim(name) {
|
|
108
|
+
const idToken = await this.getIdToken();
|
|
109
|
+
if (!idToken)
|
|
110
|
+
return undefined;
|
|
111
|
+
return this.getTokenClaim(idToken, name);
|
|
112
|
+
}
|
|
113
|
+
async getSubject() {
|
|
114
|
+
return await this.getUserClaim('sub');
|
|
115
|
+
}
|
|
116
|
+
async isSignedIn() {
|
|
117
|
+
try {
|
|
118
|
+
const authTokens = await this.getAuthTokens();
|
|
119
|
+
const expiry = await this.getRefreshTokenExpiry();
|
|
120
|
+
if (authTokens &&
|
|
121
|
+
authTokens.idToken &&
|
|
122
|
+
authTokens.accessToken &&
|
|
123
|
+
authTokens.refreshToken &&
|
|
124
|
+
expiry &&
|
|
125
|
+
// Considered signed in up to 1 hour before the expiry of refresh token.
|
|
126
|
+
expiry.getTime() > new Date().getTime() + 60 * 60 * 1000) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
// The key manager throws a KeyNotFoundError if an item is not found
|
|
135
|
+
// in which case we want to indicate that the user is not signed in.
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async refreshTokens(refreshToken) {
|
|
140
|
+
try {
|
|
141
|
+
const uid = await this.getUserName();
|
|
142
|
+
if (uid) {
|
|
143
|
+
const authTokens = await this.identityProvider.refreshTokens(refreshToken);
|
|
144
|
+
await this.storeTokens(uid, authTokens);
|
|
145
|
+
return authTokens;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
throw new NotRegisteredError('Not registered.');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
const error = err;
|
|
153
|
+
throw new AuthenticationError(error.message);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async getLatestAuthToken() {
|
|
157
|
+
try {
|
|
158
|
+
const idToken = await this.getIdToken();
|
|
159
|
+
const refreshToken = await this.getRefreshToken();
|
|
160
|
+
const expiry = await this.getTokenExpiry();
|
|
161
|
+
if (idToken && refreshToken && expiry) {
|
|
162
|
+
if (expiry.getTime() > new Date().getTime() + 600 * 1000) {
|
|
163
|
+
return idToken;
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
try {
|
|
167
|
+
const authTokens = await this.refreshTokens(refreshToken);
|
|
168
|
+
return authTokens.idToken;
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
this.logger.info('getLatestAuthToken: Token refresh failed', {
|
|
172
|
+
error,
|
|
173
|
+
});
|
|
174
|
+
// return an empty id token
|
|
175
|
+
return '';
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
// If tokens are missing then it's likely due to the client not being signed in.
|
|
181
|
+
// Return an empty id token.
|
|
182
|
+
return '';
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
// The key manager throws a KeyNotFoundError if an item is not found
|
|
187
|
+
// which would indicate that the client is likely not signed in.
|
|
188
|
+
// Return an empty id token.
|
|
222
189
|
return '';
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (userId) {
|
|
305
|
-
await this.setUserName(userId);
|
|
306
|
-
return userId;
|
|
307
|
-
} else {
|
|
308
|
-
throw new _sudoCommon.RegisterError('Registration was successful but not user ID was returned.');
|
|
309
|
-
}
|
|
310
|
-
} else {
|
|
311
|
-
throw new _error.AlreadyRegisteredError();
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
async signInWithAuthenticationProvider(authenticationProvider) {
|
|
316
|
-
this.logger.info('Signing in using external authentication provider.');
|
|
317
|
-
const authInfo = await authenticationProvider.getAuthenticationInfo();
|
|
318
|
-
|
|
319
|
-
if (!authInfo.isValid()) {
|
|
320
|
-
throw new _sudoCommon.NotAuthorizedError('Authentication provider returned invalid authentication info.');
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const uid = authInfo.getUsername();
|
|
324
|
-
const token = authInfo.encode();
|
|
325
|
-
const type = authInfo.type;
|
|
326
|
-
let authTokens = await this.identityProvider.signInWithToken(uid, token, type);
|
|
327
|
-
await this.storeTokens(uid, authTokens);
|
|
328
|
-
authTokens = await this.registerFederatedIdAndRefreshTokens(authTokens);
|
|
329
|
-
return authTokens;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
async isRegistered() {
|
|
333
|
-
try {
|
|
334
|
-
const uid = await this.getUserName();
|
|
335
|
-
return uid ? true : false;
|
|
336
|
-
} catch (err) {
|
|
337
|
-
return false;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
async signInWithKey() {
|
|
342
|
-
this.logger.info('Signing in using private key.');
|
|
343
|
-
const uid = await this.getUserName();
|
|
344
|
-
const userKeyId = await this.keyManager.getString('userKeyId');
|
|
345
|
-
|
|
346
|
-
if (uid && userKeyId) {
|
|
347
|
-
let authTokens = await this.identityProvider.signInWithKey(uid, userKeyId);
|
|
348
|
-
|
|
349
|
-
if (authTokens) {
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async signOut() {
|
|
193
|
+
let refreshToken;
|
|
194
|
+
try {
|
|
195
|
+
refreshToken = await this.getRefreshToken();
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
if (err instanceof KeyNotFoundError) {
|
|
199
|
+
throw new NotSignedInError();
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
throw err;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (refreshToken) {
|
|
206
|
+
await this.identityProvider.signOut(refreshToken);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
throw new NotSignedInError();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async globalSignOut() {
|
|
213
|
+
if (!(await this.isSignedIn())) {
|
|
214
|
+
throw new NotSignedInError();
|
|
215
|
+
}
|
|
216
|
+
await this.apiClient.globalSignOut();
|
|
217
|
+
this.clearAuthenticationTokens();
|
|
218
|
+
}
|
|
219
|
+
async registerWithAuthenticationProvider(authenticationProvider, registrationId) {
|
|
220
|
+
this.logger.info('Registering using an external authentication provider.');
|
|
221
|
+
if (!(await this.isRegistered())) {
|
|
222
|
+
const authInfo = await authenticationProvider.getAuthenticationInfo();
|
|
223
|
+
if (!authInfo.isValid()) {
|
|
224
|
+
throw new NotAuthorizedError('Authentication provider returned invalid authentication info.');
|
|
225
|
+
}
|
|
226
|
+
const token = authInfo.encode();
|
|
227
|
+
const jwt = JWT.decode(token, { complete: true });
|
|
228
|
+
let uid;
|
|
229
|
+
if (jwt && jwt.payload['sub']) {
|
|
230
|
+
uid = jwt.payload['sub'];
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
uid = v4();
|
|
234
|
+
}
|
|
235
|
+
const publicKey = await this.generateRegistrationData();
|
|
236
|
+
const data = {
|
|
237
|
+
challengeType: authInfo.type,
|
|
238
|
+
answer: token,
|
|
239
|
+
registrationId: registrationId ? registrationId : v4(),
|
|
240
|
+
publicKey: JSON.stringify(publicKeyToRSAPublicKey(publicKey)),
|
|
241
|
+
};
|
|
242
|
+
const validationData = Object.keys(data).map((key) => {
|
|
243
|
+
return {
|
|
244
|
+
Name: key,
|
|
245
|
+
Value: data[key],
|
|
246
|
+
};
|
|
247
|
+
});
|
|
248
|
+
const userId = await this.identityProvider.register(uid, validationData);
|
|
249
|
+
if (userId) {
|
|
250
|
+
await this.setUserName(userId);
|
|
251
|
+
return userId;
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
throw new RegisterError('Registration was successful but not user ID was returned.');
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
throw new AlreadyRegisteredError();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async signInWithAuthenticationProvider(authenticationProvider) {
|
|
262
|
+
this.logger.info('Signing in using external authentication provider.');
|
|
263
|
+
const authInfo = await authenticationProvider.getAuthenticationInfo();
|
|
264
|
+
if (!authInfo.isValid()) {
|
|
265
|
+
throw new NotAuthorizedError('Authentication provider returned invalid authentication info.');
|
|
266
|
+
}
|
|
267
|
+
const uid = authInfo.getUsername();
|
|
268
|
+
const token = authInfo.encode();
|
|
269
|
+
const type = authInfo.type;
|
|
270
|
+
let authTokens = await this.identityProvider.signInWithToken(uid, token, type);
|
|
350
271
|
await this.storeTokens(uid, authTokens);
|
|
351
272
|
authTokens = await this.registerFederatedIdAndRefreshTokens(authTokens);
|
|
352
273
|
return authTokens;
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
accessToken
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
setAuthenticationStore(authenticationStore) {
|
|
499
|
-
this.authenticationStore = authenticationStore;
|
|
500
|
-
}
|
|
501
|
-
|
|
274
|
+
}
|
|
275
|
+
async isRegistered() {
|
|
276
|
+
try {
|
|
277
|
+
const uid = await this.getUserName();
|
|
278
|
+
return uid ? true : false;
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async signInWithKey() {
|
|
285
|
+
this.logger.info('Signing in using private key.');
|
|
286
|
+
const uid = await this.getUserName();
|
|
287
|
+
const userKeyId = await this.keyManager.getString('userKeyId');
|
|
288
|
+
if (uid && userKeyId) {
|
|
289
|
+
let authTokens = await this.identityProvider.signInWithKey(uid, userKeyId);
|
|
290
|
+
if (authTokens) {
|
|
291
|
+
await this.storeTokens(uid, authTokens);
|
|
292
|
+
authTokens = await this.registerFederatedIdAndRefreshTokens(authTokens);
|
|
293
|
+
return authTokens;
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
throw new FatalError('Unexpected error. Unable to sign in.');
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
throw new NotRegisteredError('Not registered.');
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
async deregister() {
|
|
304
|
+
await this.apiClient.deregister();
|
|
305
|
+
await this.keyManager.reset();
|
|
306
|
+
this.clearAuthenticationTokens();
|
|
307
|
+
}
|
|
308
|
+
async clearAuthenticationTokens() {
|
|
309
|
+
await this.keyManager.removeItem(apiKeyNames.idToken);
|
|
310
|
+
await this.keyManager.removeItem(apiKeyNames.accessToken);
|
|
311
|
+
await this.keyManager.removeItem(apiKeyNames.refreshToken);
|
|
312
|
+
await this.keyManager.removeItem(apiKeyNames.tokenExpiry);
|
|
313
|
+
this.authenticationStore.reset();
|
|
314
|
+
if (this.authUI) {
|
|
315
|
+
this.authUI.reset();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
presentSignOutUI() {
|
|
319
|
+
this.authUI?.presentSignOutUI();
|
|
320
|
+
}
|
|
321
|
+
reset() {
|
|
322
|
+
this.keyManager.reset();
|
|
323
|
+
this.apiClient.reset();
|
|
324
|
+
this.clearAuthenticationTokens();
|
|
325
|
+
}
|
|
326
|
+
getTokenClaim(token, name) {
|
|
327
|
+
let claim = undefined;
|
|
328
|
+
const decoded = JWT.decode(token, { complete: true });
|
|
329
|
+
if (decoded) {
|
|
330
|
+
claim = decoded.payload[name];
|
|
331
|
+
}
|
|
332
|
+
return claim;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Store the authentication tokens and user id of the signed in user. This function
|
|
336
|
+
* is only called when a user has successfully signed in using a private key.
|
|
337
|
+
*/
|
|
338
|
+
async storeTokens(uid, authTokens) {
|
|
339
|
+
await this.keyManager.removeItem(userKeyNames.userId);
|
|
340
|
+
await this.keyManager.removeItem(apiKeyNames.idToken);
|
|
341
|
+
await this.keyManager.removeItem(apiKeyNames.accessToken);
|
|
342
|
+
await this.keyManager.removeItem(apiKeyNames.refreshToken);
|
|
343
|
+
await this.keyManager.removeItem(apiKeyNames.tokenExpiry);
|
|
344
|
+
await this.keyManager.addString(userKeyNames.userId, uid);
|
|
345
|
+
await this.keyManager.addString(apiKeyNames.idToken, authTokens.idToken);
|
|
346
|
+
await this.keyManager.addString(apiKeyNames.accessToken, authTokens.accessToken);
|
|
347
|
+
await this.keyManager.addString(apiKeyNames.refreshToken, authTokens.refreshToken);
|
|
348
|
+
const decoded = JWT.decode(authTokens.idToken, { complete: true });
|
|
349
|
+
if (decoded) {
|
|
350
|
+
const tokenExpiry = decoded.payload['exp'];
|
|
351
|
+
await this.keyManager.addString(apiKeyNames.tokenExpiry, tokenExpiry);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
async registerFederatedIdAndRefreshTokens(authTokens) {
|
|
355
|
+
const identityId = this.getTokenClaim(authTokens.idToken, 'custom:identityId');
|
|
356
|
+
if (identityId) {
|
|
357
|
+
return authTokens;
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
await this.apiClient.registerFederatedId({
|
|
361
|
+
idToken: authTokens.idToken,
|
|
362
|
+
});
|
|
363
|
+
// Refresh the ID token so the identity ID is present as a claim.
|
|
364
|
+
const newAuthTokens = await this.refreshTokens(authTokens.refreshToken);
|
|
365
|
+
return newAuthTokens;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async generateRegistrationData() {
|
|
369
|
+
const keyId = await this.keyManager.generateKeyPair();
|
|
370
|
+
await this.keyManager.removeItem(userKeyNames.userKeyId);
|
|
371
|
+
await this.keyManager.addString(userKeyNames.userKeyId, keyId);
|
|
372
|
+
const publicKey = await this.keyManager.exportPublicKey(keyId);
|
|
373
|
+
return publicKey;
|
|
374
|
+
}
|
|
375
|
+
async getAuthTokens() {
|
|
376
|
+
const idToken = await this.getIdToken();
|
|
377
|
+
const accessToken = await this.getAccessToken();
|
|
378
|
+
const refreshToken = await this.getRefreshToken();
|
|
379
|
+
const tokenExpiry = await this.getTokenExpiry();
|
|
380
|
+
if (idToken && accessToken && refreshToken && tokenExpiry) {
|
|
381
|
+
return {
|
|
382
|
+
idToken: idToken,
|
|
383
|
+
accessToken: accessToken,
|
|
384
|
+
refreshToken: refreshToken,
|
|
385
|
+
tokenExpiry: tokenExpiry.getTime(),
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Provide a custom auth UI. This is mainly used for unit testing (optional).
|
|
394
|
+
*/
|
|
395
|
+
setAuthUI(authUI) {
|
|
396
|
+
this.authUI = authUI;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Provide a custom identity provider. This is mainly used for unit testing (optional).
|
|
400
|
+
*/
|
|
401
|
+
setIdentityProvider(identityProvider) {
|
|
402
|
+
this.identityProvider = identityProvider;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Provide a custom function to open the sign in url.
|
|
406
|
+
* This is mainly used for unit testing (optional).
|
|
407
|
+
*/
|
|
408
|
+
setLaunchUriFn(launchUriFn) {
|
|
409
|
+
this.launchUriFn = launchUriFn;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Provide a custom authentication store.
|
|
413
|
+
* This is mainly used for unit testing (optional).
|
|
414
|
+
*/
|
|
415
|
+
setAuthenticationStore(authenticationStore) {
|
|
416
|
+
this.authenticationStore = authenticationStore;
|
|
417
|
+
}
|
|
502
418
|
}
|
|
503
419
|
/**
|
|
504
420
|
* Convert PublicKey of any format to an RSAPublicKey format public key
|
|
@@ -506,17 +422,14 @@ class DefaultSudoUserClient {
|
|
|
506
422
|
* @param publicKey PublicKey to convert
|
|
507
423
|
* @returns RSAPublicKey formatted PublicKey
|
|
508
424
|
*/
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
exports.DefaultSudoUserClient = DefaultSudoUserClient;
|
|
512
|
-
|
|
513
425
|
function publicKeyToRSAPublicKey(publicKey) {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
}
|
|
426
|
+
if (publicKey.keyFormat === PublicKeyFormat.RSAPublicKey) {
|
|
427
|
+
return publicKey;
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
...publicKey,
|
|
431
|
+
publicKey: publicKey.publicKey.replace('MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A', ''),
|
|
432
|
+
keyFormat: PublicKeyFormat.RSAPublicKey,
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
//# sourceMappingURL=user-client.js.map
|