@ideem/zsm-client-sdk 2.5.1 → 2.6.1
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/CHANGELOG.md +22 -6
- package/ErrorHandler.js +154 -0
- package/EventCoordinator.js +28 -1
- package/FIDO2ClientBase.js +2 -1
- package/README.md +2 -2
- package/RelyingPartyBase.js +38 -18
- package/UMFAClientBase.js +15 -7
- package/WASMRustInterface.js +448 -357
- package/WebAuthnClientBase.js +153 -83
- package/package.json +68 -21
package/WebAuthnClientBase.js
CHANGED
|
@@ -4,6 +4,7 @@ import { uid2iid, iid4uid } from './IdentityIndexing.js';
|
|
|
4
4
|
import { toObject } from './Utils.js';
|
|
5
5
|
import {zsmPluginManager} from './PluginManager.js';
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
eventCoordinator.update('WebAuthnClientBase');
|
|
8
9
|
|
|
9
10
|
const tracePrimer = (obj=false) => {
|
|
@@ -21,7 +22,12 @@ class WebAuthnClientBase {
|
|
|
21
22
|
// Helper function to standardize URL format (ensuring it's parsable and ends with a '/')
|
|
22
23
|
const cleanURL = (url) => URL.canParse(url) ? new URL(url).origin + '/' : false;
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
if(config?.region){
|
|
26
|
+
config.authenticator_host_url ||= config.authenticator_host = `https://zsm-authenticator-${config.region}.useideem.com/`;
|
|
27
|
+
config.zsm_host_url ||= config.zsm_host = `https://zsm-${config.region}.useideem.com/`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const baseConfig = {
|
|
25
31
|
"application_id" : "",
|
|
26
32
|
"api_key" : "",
|
|
27
33
|
"host_url" : "https://zsm-authenticator-demo.useideem.com/",
|
|
@@ -29,9 +35,15 @@ class WebAuthnClientBase {
|
|
|
29
35
|
"log_level" : 'Debug',
|
|
30
36
|
"request_timeout_ms" : 300000,
|
|
31
37
|
"retry_count" : 0,
|
|
32
|
-
"consumer_id" : ""
|
|
38
|
+
"consumer_id" : "",
|
|
39
|
+
"use_passkeys" : true
|
|
33
40
|
};
|
|
34
41
|
|
|
42
|
+
if(config?.use_passkeys===false || config?.use_origin===false){
|
|
43
|
+
delete config.use_passkeys;
|
|
44
|
+
delete config.use_origin;
|
|
45
|
+
}
|
|
46
|
+
|
|
35
47
|
this.zsmApi = undefined; // The ZSM API instance (read: WASM-driven Crypto Module)
|
|
36
48
|
this.relyingParty = undefined; // The Relying Party instance (read: ZSM Authenticator API)
|
|
37
49
|
this.status = undefined; // The status of the WebAuthnClientBase
|
|
@@ -89,7 +101,7 @@ class WebAuthnClientBase {
|
|
|
89
101
|
* @param {Object} config The configuration object for ZSM initialization.
|
|
90
102
|
* @returns {Promise<ZSMAPI>} Resolves with the initialized ZSM API.
|
|
91
103
|
*/
|
|
92
|
-
getZsmApi
|
|
104
|
+
async getZsmApi (config) {}
|
|
93
105
|
|
|
94
106
|
/**
|
|
95
107
|
* @name primeZsmApi
|
|
@@ -98,16 +110,15 @@ class WebAuthnClientBase {
|
|
|
98
110
|
* @ by the initializeZsm thereafter. Fixes several potential race conditions and improves performance.
|
|
99
111
|
* @returns {Promise<ZSMAPI>} Resolves with the initialized ZSM API.
|
|
100
112
|
*/
|
|
101
|
-
primeZsmApi
|
|
113
|
+
async primeZsmApi () { return (!this.zsmApi) ? (this.zsmApi = await this.getZsmApi(Object.assign({}, GLOBAL.mpcConfig, {consumer_id: await iid4uid(GLOBAL.mpcConfig.consumer_id)}))) : this.zsmApi; }
|
|
102
114
|
|
|
103
115
|
/**
|
|
104
116
|
* @name initializeZsm
|
|
105
117
|
* @description Reconfigures the ZSM API, should the consumer_id change (as after an identity_id is obtained)
|
|
106
118
|
* @returns {Promise<ZSMAPI>} Resolves when the ZSM API is reconfigured.
|
|
107
119
|
*/
|
|
108
|
-
initializeZsm
|
|
120
|
+
async initializeZsm () {
|
|
109
121
|
if(GLOBAL.mpcConfig.consumer_id !== this.MPCConfig.consumer_id) {
|
|
110
|
-
// console.log('GLOBAL.mpcConfig :', Object.assign({},GLOBAL.mpcConfig));
|
|
111
122
|
await this.zsmApi.configure(GLOBAL.mpcConfig);
|
|
112
123
|
this.MPCConfig = await Object.assign({}, GLOBAL.mpcConfig);
|
|
113
124
|
await uid2iid(this.config.consumer_id, this.MPCConfig.consumer_id);
|
|
@@ -126,22 +137,72 @@ class WebAuthnClientBase {
|
|
|
126
137
|
*/
|
|
127
138
|
|
|
128
139
|
async checkIdentity (userIdentifier, primeEnroll=false) {
|
|
140
|
+
if(userIdentifier == null
|
|
141
|
+
|| userIdentifier === '') return new Error(`[WebAuthnClient] :: checkIdentity :: A userIdentifier String is required! Received: ${userIdentifier}.`);
|
|
142
|
+
if(userIdentifier && typeof userIdentifier === 'string') this.userIdentifier = userIdentifier;
|
|
143
|
+
|
|
129
144
|
try {
|
|
130
|
-
this.status='CHECKING_IDENTITY_STARTING';
|
|
131
145
|
const resultOfCheck = await this.relyingParty.checkServerSideIdentity(primeEnroll);
|
|
146
|
+
|
|
132
147
|
if(!resultOfCheck) throw new Error('Unable to communicate with identity server!');
|
|
133
|
-
const identityID = resultOfCheck.identity_id;
|
|
148
|
+
const identityID = Array.isArray(resultOfCheck) ? resultOfCheck[0].identity_id : resultOfCheck.identity_id;
|
|
149
|
+
|
|
134
150
|
if(!identityID) throw new Error('Unable to acquire identity_id!');
|
|
151
|
+
|
|
135
152
|
uid2iid(userIdentifier, identityID);
|
|
136
153
|
GLOBAL.mpcConfig.consumer_id = identityID;
|
|
137
|
-
this.status = 'CHECKING_IDENTITY_FINISHED';
|
|
138
154
|
return identityID;
|
|
139
155
|
} catch(err) {
|
|
140
|
-
this.status = 'CHECKING_IDENTITY_FAILED';
|
|
141
156
|
return Promise.reject(err);
|
|
142
157
|
}
|
|
143
158
|
}
|
|
144
159
|
|
|
160
|
+
/**
|
|
161
|
+
* @name webauthnCreate
|
|
162
|
+
* @description Creates a new WebAuthn credential for the specified userIdentifier.
|
|
163
|
+
* @param {string} userIdentifier The user identifier.
|
|
164
|
+
* @returns {Promise<Object>} Resolves with the created credential.
|
|
165
|
+
* @throws {Error} Throws a COUNTED error if unable to retrieve the public key from the Relying Party Server.
|
|
166
|
+
* @throws {Error} [MPC] Throws an error if unable to obtain the createResponse from the Crypto Server.
|
|
167
|
+
* @throws {Error} [MPC] Throws an error if the createResponse is missing the credential.
|
|
168
|
+
* @throws {Error} [MPC] Throws an error if the credential is missing the attestation object.
|
|
169
|
+
* @throws {Error} Throws a COUNTED error if unable to verify the credential with the Relying Party Server.
|
|
170
|
+
*/
|
|
171
|
+
async webauthnCreate (userIdentifier) {
|
|
172
|
+
if(userIdentifier == null
|
|
173
|
+
|| userIdentifier === '') return new Error(`[WebAuthnClient] :: webauthnCreate :: A userIdentifier String is required! Received: ${userIdentifier}.`);
|
|
174
|
+
if(userIdentifier && typeof userIdentifier === 'string') this.userIdentifier = userIdentifier;
|
|
175
|
+
|
|
176
|
+
await this.initializeZsm('webauthnCreate');
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
const publicKey = await this.relyingParty.registrationStart();
|
|
180
|
+
if(publicKey instanceof Error) throw new Error(publicKey);
|
|
181
|
+
else if (!publicKey) throw new Error('[WebAuthnClient] :: webauthnCreate :: Unable to retrieve public key from Relying Party Server!');
|
|
182
|
+
|
|
183
|
+
publicKey.user_id = publicKey.user.id;
|
|
184
|
+
|
|
185
|
+
let createResponse = await this.zsmApi.webauthn_create(publicKey, undefined, userIdentifier, tracePrimer());
|
|
186
|
+
if(!createResponse) throw new Error('[WebAuthnClient - mpc_round] :: webauthnCreate :: Unable to obtain response from Crypto Server!');
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
createResponse = toObject(createResponse);
|
|
190
|
+
GLOBAL.dispatchEvent(new CustomEvent("MPCResponse", {bubbles: true, cancelable: false, detail: createResponse }));
|
|
191
|
+
|
|
192
|
+
if(!createResponse?.result) throw new Error('[WebAuthnClient - mpc_round] :: webauthnCreate :: Unable to obtain credential from Crypto Server!');
|
|
193
|
+
if(!createResponse?.result?.response) throw new Error('[WebAuthnClient - mpc_round] :: webauthnCreate :: Unable to acquire attestation object!');
|
|
194
|
+
|
|
195
|
+
const credential = createResponse.result;
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
const registrationResult = await this.relyingParty.registrationFinish(credential);
|
|
199
|
+
if(registrationResult instanceof Error) throw new Error(registrationResult);
|
|
200
|
+
else if(registrationResult == false) throw new Error('[WebAuthnClient] :: webauthnCreate :: Unable to verify credential Relying Party Server!');
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
return registrationResult;
|
|
204
|
+
};
|
|
205
|
+
|
|
145
206
|
/**
|
|
146
207
|
* @name webauthnCreate
|
|
147
208
|
* @description Creates a new WebAuthn credential for the specified userIdentifier.
|
|
@@ -154,30 +215,28 @@ class WebAuthnClientBase {
|
|
|
154
215
|
* @throws {Error} Throws an error if unable to acquire the identity ID from the Relying Party Server.
|
|
155
216
|
* @throws {Error} Throws an error if the user ID or token is missing from the response body.
|
|
156
217
|
*/
|
|
157
|
-
async
|
|
218
|
+
async webauthnCreateMpcThenFinish (userIdentifier, publicKey, pairing_token) {
|
|
219
|
+
if(userIdentifier == null
|
|
220
|
+
|| userIdentifier === '') return new Error(`[WebAuthnClient] :: webauthnCreateMpcThenFinish :: A userIdentifier String is required! Received: ${userIdentifier}.`);
|
|
221
|
+
if(userIdentifier && typeof userIdentifier === 'string') this.userIdentifier = userIdentifier;
|
|
158
222
|
this.status = 'ENROLLMENT_STARTING';
|
|
159
|
-
await this.initializeZsm('
|
|
160
|
-
|
|
161
|
-
// await this.checkIdentity(userIdentifier, true);
|
|
223
|
+
await this.initializeZsm('webauthnCreateMpcThenFinish');
|
|
162
224
|
|
|
163
|
-
|
|
164
|
-
if(!
|
|
165
|
-
|
|
166
|
-
let createResponse = await this.zsmApi.webauthn_create(publicKey, tracePrimer());
|
|
167
|
-
if(!createResponse) throw new Error('[WebAuthnClient - mpc_round] :: webauthnCreate :: Unable to obtain response from Crypto Server!');
|
|
225
|
+
let createResponse = await this.zsmApi.webauthn_create(publicKey, pairing_token, userIdentifier, tracePrimer());
|
|
226
|
+
if(!createResponse) throw new Error('[WebAuthnClient - mpc_round] :: webauthnCreateMpcThenFinish :: Unable to obtain response from Crypto Server!');
|
|
168
227
|
|
|
169
228
|
createResponse = toObject(createResponse);
|
|
170
229
|
GLOBAL.dispatchEvent(new CustomEvent("MPCResponse", {bubbles: true, cancelable: false, detail: createResponse }));
|
|
171
230
|
|
|
172
|
-
if(!createResponse?.result) throw new Error('[WebAuthnClient - mpc_round] ::
|
|
173
|
-
if(!createResponse?.result?.response) throw new Error('[WebAuthnClient - mpc_round] ::
|
|
231
|
+
if(!createResponse?.result) throw new Error('[WebAuthnClient - mpc_round] :: webauthnCreateMpcThenFinish :: Unable to obtain credential from Crypto Server!');
|
|
232
|
+
if(!createResponse?.result?.response) throw new Error('[WebAuthnClient - mpc_round] :: webauthnCreateMpcThenFinish :: Unable to acquire attestation object!');
|
|
174
233
|
|
|
175
234
|
const credential = createResponse.result;
|
|
176
235
|
|
|
177
236
|
const registrationResult = await this.relyingParty.registrationFinish(credential);
|
|
178
|
-
if (!registrationResult) throw new Error('[WebAuthnClient] ::
|
|
237
|
+
if (!registrationResult) throw new Error('[WebAuthnClient] :: webauthnCreateMpcThenFinish :: Unable to verify credential Relying Party Server!');
|
|
179
238
|
|
|
180
|
-
return registrationResult;
|
|
239
|
+
return registrationResult.credential;
|
|
181
240
|
};
|
|
182
241
|
|
|
183
242
|
/**
|
|
@@ -186,95 +245,96 @@ class WebAuthnClientBase {
|
|
|
186
245
|
* @param {string} userIdentifier The user identifier.
|
|
187
246
|
* @returns {Promise<ZSMAPI>} Resolves with the retrieved credential.
|
|
188
247
|
* @throws {Error} Throws an error if no credential ID is found.
|
|
189
|
-
* @throws {Error} Throws
|
|
248
|
+
* @throws {Error} Throws a COUNTED error if unable to start authentication with the Relying Party Server.
|
|
190
249
|
* @throws {Error} Throws an error if unable to retrieve the public key/challenge from the Relying Party Server.
|
|
191
|
-
* @throws {Error} Throws an error if unable to obtain the
|
|
250
|
+
* @throws {Error} Throws an error if unable to obtain the mpcResponse/credential from the Crypto Server.
|
|
192
251
|
* @throws {Error} Throws an error if unable to verify the credential with the Relying Party Server.
|
|
193
252
|
* @throws {Error} Throws an error if the user ID or token is missing from the response body.
|
|
194
253
|
*/
|
|
195
|
-
webauthnGet
|
|
196
|
-
|
|
254
|
+
async webauthnGet (userIdentifier) {
|
|
255
|
+
if(userIdentifier == null
|
|
256
|
+
|| userIdentifier === '') return new Error(`[WebAuthnClient] :: webauthnGet :: A userIdentifier String is required! Received: ${userIdentifier}.`);
|
|
257
|
+
if(userIdentifier && typeof userIdentifier === 'string') this.userIdentifier = userIdentifier;
|
|
197
258
|
|
|
198
259
|
await this.initializeZsm('webauthnGet');
|
|
199
|
-
await this.webauthnRetrieve(userIdentifier, true)
|
|
200
|
-
|
|
260
|
+
const credentialId = await this.webauthnRetrieve(userIdentifier, true);
|
|
201
261
|
|
|
202
|
-
if (!this.isEnrolled)
|
|
262
|
+
if (!this.isEnrolled) throw new Error(`[WebAuthnClient] :: webauthnGet :: ${userIdentifier} is not enrolled, lacks a credential, or credential is corrupted!`);
|
|
203
263
|
|
|
204
|
-
let authStartResponse = await this.relyingParty.authenticationStart(
|
|
205
|
-
if(!authStartResponse) throw new Error('[WebAuthnClient] :: webauthnGet :: Unable to start authentication with Relying Party Server!');
|
|
264
|
+
let authStartResponse = await this.relyingParty.authenticationStart(credentialId);
|
|
206
265
|
|
|
266
|
+
if (authStartResponse instanceof Error) throw new Error(authStartResponse);
|
|
267
|
+
else if (!authStartResponse) throw new Error('[WebAuthnClient] :: webauthnGet :: Unable to start authentication with Relying Party Server!');
|
|
268
|
+
|
|
207
269
|
authStartResponse = toObject(authStartResponse);
|
|
208
270
|
|
|
209
|
-
if(!authStartResponse?.rcr
|
|
210
|
-
|
|
211
|
-
const pubKey = authStartResponse?.rcr?.publicKey;
|
|
271
|
+
if(!authStartResponse?.rcr?.publicKey?.challenge) throw new Error('[WebAuthnClient] :: webauthnGet :: Unable to locate public key/challenge inside Relying Party Server response!\nResponse Body: ' + JSON.stringify(authStartResponse));
|
|
272
|
+
const publicKey = authStartResponse.rcr.publicKey;
|
|
212
273
|
|
|
213
|
-
|
|
274
|
+
let mpcResponse = await this.zsmApi.webauthn_get(publicKey, undefined, userIdentifier, tracePrimer());
|
|
275
|
+
|
|
214
276
|
|
|
215
|
-
|
|
216
|
-
if(!getResponse) throw new Error('[WebAuthnClient - mpc_round] :: webauthnGet :: Unable to obtain getResponse from Crypto Server!');
|
|
277
|
+
if(!mpcResponse) throw new Error('[WebAuthnClient - mpc_round] :: webauthnGet :: Crypto server did not respond!');
|
|
217
278
|
|
|
218
|
-
|
|
279
|
+
mpcResponse = toObject(mpcResponse);
|
|
280
|
+
if(!mpcResponse?.result) throw new Error('[WebAuthnClient - mpc_round] :: webauthnGet :: Response from Crypto Server did not contain a credential!\nResponse Body: ' + JSON.stringify(mpcResponse));
|
|
219
281
|
|
|
220
|
-
|
|
282
|
+
GLOBAL.dispatchEvent(new CustomEvent("MPCResponse", {bubbles: true, cancelable: false, detail: mpcResponse }));
|
|
221
283
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const credential = getResponse.result;
|
|
284
|
+
const credential = mpcResponse.result;
|
|
225
285
|
let authFinishResponse = await this.relyingParty.authenticationFinish(credential);
|
|
226
286
|
|
|
227
|
-
if
|
|
287
|
+
if (authFinishResponse instanceof Error) throw new Error(authFinishResponse);
|
|
288
|
+
else if (!authFinishResponse) throw new Error('[WebAuthnClient] :: webauthnGet :: Unable to verify credential from Relying Party Server!');
|
|
228
289
|
|
|
229
290
|
authFinishResponse = toObject(authFinishResponse)
|
|
230
|
-
|
|
231
|
-
if (!authFinishResponse.user_id || !authFinishResponse.token) throw new Error('[WebAuthnClient] :: webauthnGet :: User ID or token is missing from response body!');
|
|
291
|
+
if (!authFinishResponse.token) throw new Error('[WebAuthnClient] :: webauthnGet :: Token mismatched or missing from Relying Party Server verification attempt!\nResponse Body: ' + JSON.stringify(authFinishResponse));
|
|
232
292
|
|
|
233
293
|
return {
|
|
234
294
|
signature : credential.response.signature,
|
|
235
295
|
signedChallenge : credential.response.clientDataJSON,
|
|
236
296
|
user_id : authFinishResponse.user_id,
|
|
237
297
|
token : authFinishResponse.token,
|
|
238
|
-
challenge :
|
|
298
|
+
challenge : publicKey.challenge,
|
|
239
299
|
credential
|
|
240
300
|
};
|
|
241
301
|
};
|
|
242
302
|
|
|
303
|
+
|
|
304
|
+
|
|
243
305
|
/**
|
|
244
306
|
* @name webauthnRetrieve
|
|
245
307
|
* @description Looks up the Identity ID for the specified userIdentifier and retrieves its credential ID (if it exists).
|
|
246
308
|
* @ This is used to make a client-only check to see if a given userIdentifier already has an enrollment on the device.
|
|
247
309
|
* @param {string} userIdentifier The user identifier.
|
|
248
|
-
* @param {
|
|
249
|
-
* @
|
|
250
|
-
* @
|
|
310
|
+
* @param {string} targetData The specific data to retrieve. Options are:
|
|
311
|
+
* @ - 'id' or omitted: retrieves the ZSM credential ID (default)
|
|
312
|
+
* @ - 'all': retrieves an object containing all relevant credential data
|
|
313
|
+
* @ - any other string: retrieves the specified field from the response
|
|
314
|
+
* @returns {Promise<Boolean:false>} Returns `false` if retrieval fails (no enrollment found).
|
|
315
|
+
* @returns {Promise<String>} Returns the requested data if found (e.g., ").
|
|
316
|
+
* @returns {Promise<Object>} Resolves with an object containing all relevant credential data.
|
|
317
|
+
* @returns {Promise<Null>} Resolves with null if the requested data is not found.
|
|
318
|
+
* @throws {Error} Throws an error if an uncaught/unhandled error occurs while retrieving the credential.
|
|
251
319
|
*/
|
|
252
|
-
webauthnRetrieve
|
|
320
|
+
async webauthnRetrieve (userIdentifier) {
|
|
321
|
+
if(userIdentifier == null
|
|
322
|
+
|| userIdentifier === '') return new Error(`[WebAuthnClient] :: webauthnRetrieve :: A userIdentifier String is required! Received: ${userIdentifier}.`);
|
|
323
|
+
if(userIdentifier && typeof userIdentifier === 'string') this.userIdentifier = userIdentifier;
|
|
253
324
|
this.credentialID = null;
|
|
254
|
-
if (!silent) {
|
|
255
|
-
this.status = 'CREDENTIAL_RETRIEVING';
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
try {
|
|
259
|
-
this.initializeZsm('webauthnRetrieve');
|
|
260
|
-
let credentialIdentifier = await iid4uid(userIdentifier);
|
|
261
|
-
GLOBAL.mpcConfig.consumer_id = credentialIdentifier;
|
|
262
325
|
|
|
263
|
-
|
|
264
|
-
|
|
326
|
+
this.initializeZsm('webauthnRetrieve');
|
|
327
|
+
let credentialIdentifier = await iid4uid(userIdentifier),
|
|
328
|
+
requestedData = {};
|
|
329
|
+
GLOBAL.mpcConfig.consumer_id = credentialIdentifier;
|
|
265
330
|
|
|
266
|
-
|
|
331
|
+
let response = await this.zsmApi.webauthn_retrieve(userIdentifier);
|
|
332
|
+
response = toObject(response);
|
|
267
333
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
} catch (error) {
|
|
273
|
-
if(!silent){
|
|
274
|
-
this.status = 'CREDENTIAL_RETRIEVAL_FAILED';
|
|
275
|
-
throw error;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
334
|
+
if (response?.error || !response?.result) return false;
|
|
335
|
+
|
|
336
|
+
this.credentialID = response?.result['zsm_credential_id']??null;
|
|
337
|
+
return this.credentialID || false;
|
|
278
338
|
};
|
|
279
339
|
|
|
280
340
|
/**
|
|
@@ -285,10 +345,13 @@ class WebAuthnClientBase {
|
|
|
285
345
|
* @throws {Error} Throws an error if the credential is missing for the userIdentifier provided.
|
|
286
346
|
* @throws {Error} Throws an error if unable to start authentication with the Relying Party Server.
|
|
287
347
|
* @throws {Error} Throws an error if unable to retrieve the public key from the Relying Party Server.
|
|
288
|
-
* @throws {Error} Throws an error if unable to obtain the
|
|
289
|
-
* @emits {CustomEvent} Emits a "MPCResponse" event with the
|
|
348
|
+
* @throws {Error} Throws an error if unable to obtain the mpcResponse/credential from the Crypto Server.
|
|
349
|
+
* @emits {CustomEvent} Emits a "MPCResponse" event with the mpcResponse data.
|
|
290
350
|
*/
|
|
291
|
-
webauthnPartialGet
|
|
351
|
+
async webauthnPartialGet (userIdentifier) {
|
|
352
|
+
if(userIdentifier == null
|
|
353
|
+
|| userIdentifier === '') return new Error(`[WebAuthnClient] :: webauthnPartialGet :: A userIdentifier String is required! Received: ${userIdentifier}.`);
|
|
354
|
+
if(userIdentifier && typeof userIdentifier === 'string') this.userIdentifier = userIdentifier;
|
|
292
355
|
this.status = 'AUTHENTICATION_STARTING';
|
|
293
356
|
await this.initializeZsm('webauthnPartialGet');
|
|
294
357
|
|
|
@@ -302,16 +365,16 @@ class WebAuthnClientBase {
|
|
|
302
365
|
if(!getChallenge?.rcr || !getChallenge.rcr.publicKey) throw new Error('[WebAuthnClient] :: webauthnPartialGet :: Unable to retrieve public key from Relying Party Server!');
|
|
303
366
|
const pubKey = getChallenge.rcr.publicKey;
|
|
304
367
|
|
|
305
|
-
let
|
|
306
|
-
if(!
|
|
368
|
+
let mpcResponse = await this.zsmApi.webauthn_get(pubKey, null, userIdentifier, tracePrimer());
|
|
369
|
+
if(!mpcResponse) throw new Error('[WebAuthnClient - mpc_round] :: webauthnPartialGet :: Unable to obtain mpcResponse from Crypto Server!');
|
|
307
370
|
|
|
308
|
-
|
|
371
|
+
mpcResponse = toObject(mpcResponse);
|
|
309
372
|
|
|
310
|
-
if(!
|
|
373
|
+
if(!mpcResponse?.result) throw new Error('[WebAuthnClient - mpc_round] :: webauthnPartialGet :: Unable to obtain credential from Crypto Server!');
|
|
311
374
|
|
|
312
|
-
GLOBAL.dispatchEvent(new CustomEvent("MPCResponse", {bubbles: true, cancelable: false, detail:
|
|
375
|
+
GLOBAL.dispatchEvent(new CustomEvent("MPCResponse", {bubbles: true, cancelable: false, detail: mpcResponse }));
|
|
313
376
|
|
|
314
|
-
const getCredential =
|
|
377
|
+
const getCredential = mpcResponse.result;
|
|
315
378
|
return {
|
|
316
379
|
signature: getCredential.response.signature,
|
|
317
380
|
signedChallenge: getCredential.response.clientDataJSON,
|
|
@@ -330,7 +393,10 @@ class WebAuthnClientBase {
|
|
|
330
393
|
* @throws {Error<CredentialError>} Throws an CredentialError if the credential is missing for the userIdentifier provided
|
|
331
394
|
* @throws {Error<UnenrollError>} Throws an UnenrollError if a credential matching userIdentifier IS stored on the device, but was unable to be removed.
|
|
332
395
|
*/
|
|
333
|
-
unbindFromDevice
|
|
396
|
+
async unbindFromDevice (userIdentifier) {
|
|
397
|
+
if(userIdentifier == null
|
|
398
|
+
|| userIdentifier === '') return new Error(`[WebAuthnClient] :: unbindFromDevice :: A userIdentifier String is required! Received: ${userIdentifier}.`);
|
|
399
|
+
if(userIdentifier && typeof userIdentifier === 'string') this.userIdentifier = userIdentifier;
|
|
334
400
|
this.status = 'UNENROLL_STARTING';
|
|
335
401
|
if(userIdentifier !== this.userIdentifier) return false;
|
|
336
402
|
await this.initializeZsm('unbindFromDevice');
|
|
@@ -346,7 +412,11 @@ class WebAuthnClientBase {
|
|
|
346
412
|
const cursor = event.target.result;
|
|
347
413
|
if (cursor) {
|
|
348
414
|
const { key, value } = cursor;
|
|
349
|
-
if
|
|
415
|
+
if(
|
|
416
|
+
key.includes(userIdentifier) ||
|
|
417
|
+
(typeof value === 'string' && value.includes(userIdentifier)) ||
|
|
418
|
+
typeof value === 'object' && value?.zsm_credential?.get('rawId') === rawID
|
|
419
|
+
) (store.delete(key), true);
|
|
350
420
|
cursor.continue();
|
|
351
421
|
}
|
|
352
422
|
};
|
package/package.json
CHANGED
|
@@ -1,23 +1,70 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name"
|
|
3
|
-
"version"
|
|
4
|
-
"description"
|
|
5
|
-
"author"
|
|
6
|
-
"keywords"
|
|
7
|
-
"type"
|
|
8
|
-
"main"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
2
|
+
"name" : "@ideem/zsm-client-sdk",
|
|
3
|
+
"version" : "2.6.1",
|
|
4
|
+
"description" : "ZSM makes 2FA easy and invisible for everyone, all the time, using advanced cryptography like MPC to establish cryptographic proof of the origin of any transaction or login attempt, while eliminating opportunities for social engineering. ZSM has no reliance on specific hardware. Our cryptographic module has completed FIPS 140-3 NIST approved lab testing, is FIDO2-ready, and is on the Modules In Progress (MIP) list. Superior Usability. no opt-in, no codes, no downloads, no authenticator apps. Better Security.",
|
|
5
|
+
"author" : "Jason Jurusz <jj@useideem.com>",
|
|
6
|
+
"keywords" : [ "ideem", "zsm", "zsm-client-sdk", "umfaclient", "fido2client", "library", "umfa", "fido", "fido2", "client", "javascript", "multifactor", "multi-factor", "webauthn", "authentication", "security", "cryptography", "mpc", "fips", "nist", "mip", "passkeys" ],
|
|
7
|
+
"type" : "module",
|
|
8
|
+
"main" : "./ZSMClientSDK.js",
|
|
9
|
+
"exports" : {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./ZSMClientSDK.js",
|
|
12
|
+
"default": "./ZSMClientSDK.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"scripts" : {
|
|
16
|
+
"start" : "echo 'This is the Ideem SDK library, not a freestanding application. There is no start script defined. To use, import the library into a browser application.' 1>&2",
|
|
17
|
+
"showVersion" : "echo \"$(npm pkg get name | tr -d \\\") current version: $(npm pkg get version | tr -d \\\")\""
|
|
18
|
+
},
|
|
19
|
+
"collaborators" : [
|
|
20
|
+
"Joel Teply <joel@useideem.com>",
|
|
21
|
+
"Todd Decker <todd@useideem.com>",
|
|
22
|
+
"Brian Koziel <brian@useideem.com>"
|
|
23
|
+
],
|
|
24
|
+
"license" : "LicenseRef-Ideem",
|
|
25
|
+
"repository" : {
|
|
26
|
+
"type" : "git",
|
|
27
|
+
"url" : "git+https://github.com/useideem/vHSM.git"
|
|
28
|
+
},
|
|
29
|
+
"homepage" : "https://useideem.com",
|
|
30
|
+
"bugs" : "https://github.com/useideem/vHSM/issues",
|
|
31
|
+
"files" : [
|
|
32
|
+
"./shims/",
|
|
33
|
+
"./ErrorHandler.js",
|
|
34
|
+
"./EventCoordinator.js",
|
|
35
|
+
"./FIDO2Client.js",
|
|
36
|
+
"./FIDO2ClientBase.js",
|
|
37
|
+
"./GlobalScoping.js",
|
|
38
|
+
"./IdentityIndexing.js",
|
|
39
|
+
"./PluginManager.js",
|
|
40
|
+
"./RelyingParty.js",
|
|
41
|
+
"./RelyingPartyBase.js",
|
|
42
|
+
"./UMFAClient.js",
|
|
43
|
+
"./UMFAClientBase.js",
|
|
44
|
+
"./Utils.js",
|
|
45
|
+
"./WASMRustInterface.js",
|
|
46
|
+
"./WebAuthnClient.js",
|
|
47
|
+
"./WebAuthnClientBase.js",
|
|
48
|
+
"./ZSMClientSDK.js",
|
|
49
|
+
"./CHANGELOG.md",
|
|
50
|
+
"./LICENSE",
|
|
51
|
+
"./README.md"
|
|
52
|
+
],
|
|
53
|
+
"sideEffects" : [
|
|
54
|
+
"./EventCoordinator.js",
|
|
55
|
+
"./FIDO2Client.js",
|
|
56
|
+
"./FIDO2ClientBase.js",
|
|
57
|
+
"./GlobalScoping.js",
|
|
58
|
+
"./IdentityIndexing.js",
|
|
59
|
+
"./PluginManager.js",
|
|
60
|
+
"./RelyingParty.js",
|
|
61
|
+
"./RelyingPartyBase.js",
|
|
62
|
+
"./UMFAClient.js",
|
|
63
|
+
"./UMFAClientBase.js",
|
|
64
|
+
"./Utils.js",
|
|
65
|
+
"./WASMRustInterface.js",
|
|
66
|
+
"./WebAuthnClient.js",
|
|
67
|
+
"./WebAuthnClientBase.js",
|
|
68
|
+
"./ZSMClientSDK.js"
|
|
69
|
+
]
|
|
23
70
|
}
|