@ideem/zsm-client-sdk 2.5.0 → 2.6.0
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/ErrorHandler.js +154 -0
- package/FIDO2ClientBase.js +1 -0
- package/RelyingPartyBase.js +38 -18
- package/UMFAClientBase.js +25 -13
- package/WASMRustInterface.js +448 -357
- package/WebAuthnClientBase.js +143 -130
- package/package.json +68 -19
- package/shims/VanillaJSLoader.js +0 -96
- package/shims/es-module-shims.js +0 -1067
package/ErrorHandler.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file zsm-client-sdk/ErrorHandler.js
|
|
3
|
+
* @name ErrorHandler
|
|
4
|
+
* @description A centralized error handling singleton for managing sequential errors in ZSM client SDK operations, intended to facilitate self-healing from repeated Relying Party server operation errors.
|
|
5
|
+
* @param {ZSMAPI} zsmAPIInstance An optional instance of a ZSM API (e.g., WebAuthnClient) to facilitate local credential purging.
|
|
6
|
+
* @setter {ZSMAPI} ERR.zsmAPI Sets the ZSM API instance (WebAuthnClient, etc.) to facilitate local credential purging.
|
|
7
|
+
* @setter {string} ERR.userIdentifier Sets the active userIdentifier (used for local credential purging).
|
|
8
|
+
* @method ERR.error(errType, message, options) Generates & returns an Error object, increments sequential error count, and triggers individual or global IDB record purging (by count)
|
|
9
|
+
* @method ERR.reset() Resets the sequential error count to zero.
|
|
10
|
+
* @exports ERR An instance of the ErrorHandler singleton.
|
|
11
|
+
*
|
|
12
|
+
* @notes IMPORTANT: If unable to unbind the active user at 3+ errors, or either setter value is unset, OR the count reaches 5, the entire ideem IndexedDB gets purged.
|
|
13
|
+
*
|
|
14
|
+
* @notes IMPORTANT: the `reset()` method MUST be called to reset the sequential error count upon successful trannsaction with the RP (see: makePostRequest in RelyingPartyBase.js).
|
|
15
|
+
*
|
|
16
|
+
* @notes IMPORTANT: This class relies on a valid userIdentifier and zsmAPIInstance being set PRIOR to invoking the error() method to facilitate local credential purging when necessary.
|
|
17
|
+
* @example ERR.zsmAPI = webAuthnClientInstance; // Set the ZSM API instance (e.g., WebAuthnClient)
|
|
18
|
+
* @example ERR.userIdentifier = 'user123'; // Set the active userIdentifier
|
|
19
|
+
* @example throw new Error("An example error."); // Generate and throw an error via the ErrorHandler
|
|
20
|
+
*
|
|
21
|
+
* @notes The sequential error count is persisted in sessionStorage to survive page reloads within the same browser session.
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
class ErrorHandler {
|
|
25
|
+
#sequentialErrorCount; // Number of sequential errors encountered
|
|
26
|
+
#zsmAPIInstance = null; // Instance of ZSM API (e.g., WebAuthnClient)
|
|
27
|
+
#activeUserIdentifier = null; // Currently active userIdentifier
|
|
28
|
+
|
|
29
|
+
constructor(zsmAPIInstance=null) {
|
|
30
|
+
try { this.#sequentialErrorCount = Number(sessionStorage.getItem('zsmSequentialErrorCt') || 0); } // Try to retrieve sequential error count from sessionStorage...
|
|
31
|
+
catch { this.#sequentialErrorCount = 0; } // ...and roll over to 0 if unable to do so (or it's absent)
|
|
32
|
+
this.#zsmAPIInstance = zsmAPIInstance || null; // Set ZSM API instance if provided, else null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get #count() { return this.#sequentialErrorCount; } // Get sequential error count
|
|
36
|
+
set #count(v) { try { sessionStorage.setItem('zsmSequentialErrorCt', (this.#sequentialErrorCount = v)); }catch(e){} } // Set sequential error count and store in sessionStorage
|
|
37
|
+
get #userIdentifier() { return this.#activeUserIdentifier; } // Get active userIdentifier
|
|
38
|
+
set userIdentifier(id) { return (this.#activeUserIdentifier = id); } // Set active userIdentifier
|
|
39
|
+
get #zsmAPI() { return this.#zsmAPIInstance; } // Get ZSM API instance
|
|
40
|
+
set zsmAPI(instance) { return (this.#zsmAPIInstance = instance); } // Set ZSM API instance
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @name purgeLocalCredentialForActiveUser
|
|
44
|
+
* @description Attempts to purge the local ZSM credential data for the currently active userIdentifier via the associated ZSM API instance. Failing that, purges the entire local IndexedDB database.
|
|
45
|
+
* @throws {Promise<void>} Rollover functionality (full reset) is triggered if userIdentifier or zsmAPIInstance is unset, or unable to unbind active user
|
|
46
|
+
* @returns {Promise<void>}
|
|
47
|
+
* @memberOf ErrorHandler
|
|
48
|
+
* @private
|
|
49
|
+
* @async
|
|
50
|
+
*/
|
|
51
|
+
async #purgeLocalCredentialForActiveUser() {
|
|
52
|
+
try {
|
|
53
|
+
|
|
54
|
+
const uid = this.#userIdentifier; // Use the active userIdentifier...
|
|
55
|
+
if(!uid || uid === '') throw new Error(`No active userIdentifier is set on this ErrorHandler.`); // ...or throw an error if not set
|
|
56
|
+
if(this.#zsmAPI == null) throw new Error(`No ZSM API instance is associated with this ErrorHandler.`); // Throw an error if no WebAuthnClient instance is yet set
|
|
57
|
+
await this.#zsmAPI.unbindFromDevice(uid); // Attempt to unenroll the active user from the device via the WebAuthnClient
|
|
58
|
+
console.info(`[ErrorHandler] :: Local ZSM credential data purged for ${uid}`);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.warn(new Error(`[ErrorHandler] :: purgeLocalCredentialForActiveUser :: ${err.message}.`, err));
|
|
61
|
+
console.warn(`\n\nBecause local credential purge failed, attempting to purge entire local IndexedDB instead.`);
|
|
62
|
+
this.#purgeLocalIDB(); // If unable to unbind the active user, purge the entire IndexedDB instead
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @name purgeLocalIDB
|
|
68
|
+
* @description Attempts to purge the entire local IndexedDB database named 'ideem', removing all credential and ZSM data.
|
|
69
|
+
* @returns {void}
|
|
70
|
+
* @memberOf ErrorHandler
|
|
71
|
+
* @private
|
|
72
|
+
*/
|
|
73
|
+
#purgeLocalIDB() {
|
|
74
|
+
try {
|
|
75
|
+
indexedDB.deleteDatabase('ideem'); // Delete the entire 'ideem' IndexedDB database
|
|
76
|
+
console.info(`[ErrorHandler] :: Local IndexedDB purged of all credential and ZSM data.`);
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.error(`[ErrorHandler] :: purgeLocalIDB :: Unable to purge local IndexedDB (usually this is due to the local store being absent).\nDetails:\n`, err);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @name processErrorCountsForGeneratedError
|
|
84
|
+
* @description Processes the sequential error count after an error has been generated, triggering local credential or IndexedDB purging as necessary.
|
|
85
|
+
* @param {Error} errOP The newly-generated or amended error object.
|
|
86
|
+
* @returns {Error} The same error object passed in, for chaining.
|
|
87
|
+
* @memberOf ErrorHandler
|
|
88
|
+
* @private
|
|
89
|
+
*/
|
|
90
|
+
#processErrorCountsForGeneratedError(errOP) {
|
|
91
|
+
if(this.#count === 3) { // IF sequential error count is exactly 3...
|
|
92
|
+
this.#purgeLocalCredentialForActiveUser(); // ...purge local credential for active user
|
|
93
|
+
} else if(this.#count >= 5) { // ELSE IF sequential error count is 5 or more...
|
|
94
|
+
this.#purgeLocalIDB(); // ...purge entire local IndexedDB
|
|
95
|
+
this.reset(); // ...reset the sequential error count
|
|
96
|
+
}
|
|
97
|
+
return errOP; // Return the [new|amended] error object
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @name reset
|
|
102
|
+
* @description Resets the sequential error count to zero and persists the change in sessionStorage.
|
|
103
|
+
* @param {...any} args Optional arguments to pass through transparently.
|
|
104
|
+
* @returns {void|any|Array<any>} For 0 args: undefined; 1 arg: that arg; multiple args: array of those args.
|
|
105
|
+
* @memberOf ErrorHandler
|
|
106
|
+
*/
|
|
107
|
+
reset(...args) {
|
|
108
|
+
this.#count = 0; // Reset the sequential error count and store it in sessionStorage
|
|
109
|
+
console.info(`[ErrorHandler] :: reset :: Sequential Error Count reset to 0.`); // Log the reset action
|
|
110
|
+
return (typeof args === 'array' && args.length === 0) ? void(0) // Pass through received arguments transparently, if any
|
|
111
|
+
: (typeof args === 'array' && args.length === 1) ? args[0]
|
|
112
|
+
: args;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @name error
|
|
117
|
+
* @description Generates & returns an Error object, increments sequential error count, and triggers individual or global IDB record purging (by count)
|
|
118
|
+
* @param {function|Error} errType Either an Error constructor function (e.g., Error, TypeError; counted) or existing Error object to amend (not counted).
|
|
119
|
+
* @param {string} message The error message to associate with the generated or amended Error object.
|
|
120
|
+
* @param {Object} options Optional additional options to pass to the Error constructor.
|
|
121
|
+
* @returns {Error} The newly-generated or amended Error object.
|
|
122
|
+
* @memberOf ErrorHandler
|
|
123
|
+
* @notes This method is designed to be resilient as hell; if anything's wrong with its invocation, it will STILL return a valid Error object (albeit a generic one).
|
|
124
|
+
*/
|
|
125
|
+
error(errType=Error, message="An error occurred.", options={}) {
|
|
126
|
+
let errOP;
|
|
127
|
+
try {
|
|
128
|
+
if(typeof message !== 'string') message = "An error occurred."; // Ensure message is a string (or supplant it with a default)
|
|
129
|
+
if(options == null || typeof options !== 'object') options = {}; // Ensure options is an object (or supplant it with an empty one)
|
|
130
|
+
if(typeof errType === 'string') { // [NEW ERROR] Only the error message was provided as a string...
|
|
131
|
+
message = errType; // ...so shift it into the message...
|
|
132
|
+
errType = Error; // ...and set errType to the generic Error constructor
|
|
133
|
+
} else if(typeof errType === 'function') { // [NEW ERROR] A constructor function was provided
|
|
134
|
+
errOP = new errType(message, options); // Attempt to create the error object
|
|
135
|
+
if(!(errOP instanceof Error)) { // IF the newly-created object is NOT an Error...
|
|
136
|
+
errOP = new Error(message, options); // ...replace it with a generic Error object (still with message & options)
|
|
137
|
+
}
|
|
138
|
+
this.#count = this.#count + 1; // Increment the sequential error count
|
|
139
|
+
} else if (errType instanceof Error) { // [EXISTING ERROR] An existing error object was provided
|
|
140
|
+
errOP = new errType.constructor(message, options); // Create a new Error object of the previous's prototype...
|
|
141
|
+
errOP.cause = errType; // ...and leverage its cause to preserve the causal stack trace
|
|
142
|
+
} else { // [INVALID INPUT] Neither a constructor function nor an existing error object was provided
|
|
143
|
+
throw new Error(`Invalid errType provided to ErrorHandler.error(): must be either an Error constructor function or an existing Error object.`);
|
|
144
|
+
}
|
|
145
|
+
return this.#processErrorCountsForGeneratedError(errOP); // Post-process the count and return the [new|amended] error object
|
|
146
|
+
}catch(e) {
|
|
147
|
+
this.#count = this.#count + 1; // Increment the sequential error count
|
|
148
|
+
errOP = new Error(`[ErrorHandler] :: error :: An error occurred while attempting to process another error.\nDetails:\n${e.message}\n\nOriginal Error Message:\n${message}`);
|
|
149
|
+
return this.#processErrorCountsForGeneratedError(errOP); // Post-process the count and return the rollover hail mary error object
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const ERR = new ErrorHandler(); // Export a singleton instance of the ErrorHandler
|
|
154
|
+
export default ERR
|
package/FIDO2ClientBase.js
CHANGED
|
@@ -103,6 +103,7 @@ class FIDO2ClientBase {
|
|
|
103
103
|
* @memberOf FIDO2ClientBase
|
|
104
104
|
*/
|
|
105
105
|
async webauthnGet (userIdentifier) {
|
|
106
|
+
|
|
106
107
|
try {
|
|
107
108
|
if(userIdentifier == null
|
|
108
109
|
|| userIdentifier === '') throw new Error(`[FIDO2Client] :: webauthnGet :: A userIdentifier String is required! Received: ${userIdentifier}.`);
|
package/RelyingPartyBase.js
CHANGED
|
@@ -2,6 +2,7 @@ import eventCoordinator from './EventCoordinator.js';
|
|
|
2
2
|
import GLOBAL from './GlobalScoping.js';
|
|
3
3
|
import {uid2iid} from './IdentityIndexing.js';
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
eventCoordinator.update('RelyingPartyBase');
|
|
6
7
|
|
|
7
8
|
function tracePrimer (obj=false) {
|
|
@@ -33,7 +34,7 @@ class RelyingPartyBase {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
get userIdentifier() { return this.customerDefinedIdentifier; }
|
|
36
|
-
set userIdentifier(v) { return this.customerDefinedIdentifier = v; }
|
|
37
|
+
set userIdentifier(v) { return userIdentifier = this.customerDefinedIdentifier = v; }
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
40
|
* @name makePostRequest
|
|
@@ -48,7 +49,7 @@ class RelyingPartyBase {
|
|
|
48
49
|
url = `${this.host.endsWith('/') ? this.host.slice(0,-1) : this.host}/${url.startsWith('/') ? url.slice(1) : url}`;
|
|
49
50
|
body = ((typeof body === 'object') ? body : {});
|
|
50
51
|
if(this.appEnvironment) body = Object.assign(body, {environment: this.appEnvironment});
|
|
51
|
-
body = Object.assign({ customer_defined_identifier : this.customerDefinedIdentifier, application_id : this.applicationId
|
|
52
|
+
body = Object.assign({ customer_defined_identifier : this.customerDefinedIdentifier, application_id : this.applicationId}, body, this.addlRelyingPartyBodyProps, tracePrimer(true));
|
|
52
53
|
let fetchObj = {
|
|
53
54
|
method,
|
|
54
55
|
headers : Object.assign(this.xhrHeaders, ((!headers?.Authorization) ? {'Authorization': `Bearer ${this.apiKey}`} : {}), headers),
|
|
@@ -92,8 +93,10 @@ class RelyingPartyBase {
|
|
|
92
93
|
* @returns {Promise<Object>} Resolves with publicKey object used in the subsequent Crypto Server API call.
|
|
93
94
|
*/
|
|
94
95
|
registrationStart () {
|
|
95
|
-
|
|
96
|
+
|
|
97
|
+
return this.makePostRequest(`api/webauthn/registration/start`)
|
|
96
98
|
.then(data => {
|
|
99
|
+
|
|
97
100
|
if(data.identity_id){
|
|
98
101
|
GLOBAL.mpcConfig.consumer_id = data.identity_id;
|
|
99
102
|
uid2iid(this.userIdentifier, data.identity_id);
|
|
@@ -101,7 +104,7 @@ class RelyingPartyBase {
|
|
|
101
104
|
return (this.publicKey = data.ccr.publicKey)
|
|
102
105
|
})
|
|
103
106
|
.then(result => result)
|
|
104
|
-
.catch(error => Promise.reject(
|
|
107
|
+
.catch(error => Promise.reject(new Error(error)));
|
|
105
108
|
}
|
|
106
109
|
/**
|
|
107
110
|
* @name registrationFinish
|
|
@@ -111,10 +114,12 @@ class RelyingPartyBase {
|
|
|
111
114
|
* @throws {Error} Throws an error if the request fails.
|
|
112
115
|
*/
|
|
113
116
|
registrationFinish (credential) {
|
|
114
|
-
return this.makePostRequest(
|
|
115
|
-
.then(
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
return this.makePostRequest(`api/webauthn/registration/finish`, { credential })
|
|
118
|
+
.then(body => {
|
|
119
|
+
this.credentialID = credential.rawId;
|
|
120
|
+
return {credential, response: body, ...body};
|
|
121
|
+
})
|
|
122
|
+
.catch(error => (this.clearEnrollmentCredentials(), Promise.reject(new Error(error))));
|
|
118
123
|
|
|
119
124
|
}
|
|
120
125
|
|
|
@@ -125,13 +130,21 @@ class RelyingPartyBase {
|
|
|
125
130
|
* @returns {Promise<Object>} Resolves with the authentication challenge.
|
|
126
131
|
* @throws {Error} Throws an error if the request fails.
|
|
127
132
|
*/
|
|
128
|
-
authenticationStart (credential_id=this.credentialID) {
|
|
133
|
+
authenticationStart (credential_id=this.credentialID, credential_type = 'passkey', chain_handoff, chain_credential_id, chain_challenge) {
|
|
134
|
+
const body = {
|
|
135
|
+
credential_type,
|
|
136
|
+
credential_id,
|
|
137
|
+
chain_handoff,
|
|
138
|
+
chain_credential_id,
|
|
139
|
+
chain_challenge,
|
|
140
|
+
}
|
|
129
141
|
return (credential_id != null)
|
|
130
|
-
? this.makePostRequest(
|
|
142
|
+
? this.makePostRequest( `api/webauthn/authentication/start`, { credential_id })
|
|
131
143
|
.then(result => result)
|
|
132
|
-
: (Promise.reject(new Error("[RelyingParty] :: authenticationStart :: No user ID or credential ID provided")))
|
|
144
|
+
: (Promise.reject(new Error("[RelyingParty] :: authenticationStart :: No user ID or credential ID provided")));
|
|
133
145
|
}
|
|
134
146
|
|
|
147
|
+
|
|
135
148
|
/**
|
|
136
149
|
* @name authenticationFinish
|
|
137
150
|
* @description Completes the authentication process by sending the credential to the server.
|
|
@@ -142,17 +155,24 @@ class RelyingPartyBase {
|
|
|
142
155
|
authenticationFinish (credential) {
|
|
143
156
|
return this.makePostRequest("api/webauthn/authentication/finish", { credential })
|
|
144
157
|
.then(result => result)
|
|
145
|
-
.catch(error => Promise.reject(
|
|
158
|
+
.catch(error => Promise.reject(new Error(error)));
|
|
146
159
|
}
|
|
147
160
|
|
|
161
|
+
|
|
148
162
|
/**
|
|
149
163
|
* @name createIdentityThenRegistrationStart
|
|
150
164
|
* @description UMFA-OPTIMIZED FLOW: Creates a server-side Identity and then starts the WebAuthn Registration challenge automatically.
|
|
151
165
|
* @returns {Promise<Object>} Resolves with an object containing the publicKey and identity_id.
|
|
152
166
|
* @throws {Error} Throws an error if the request fails.
|
|
153
167
|
*/
|
|
154
|
-
createIdentityThenRegistrationStart() {
|
|
155
|
-
|
|
168
|
+
createIdentityThenRegistrationStart(credential_type = 'zsm', chain_handoff, chain_credential_id, chain_challenge) {
|
|
169
|
+
const body = {
|
|
170
|
+
credential_type,
|
|
171
|
+
chain_handoff,
|
|
172
|
+
chain_credential_id,
|
|
173
|
+
chain_challenge,
|
|
174
|
+
};
|
|
175
|
+
return this.makePostRequest("api/webauthn/registration/create-identity-then-start", body)
|
|
156
176
|
.then(data => {
|
|
157
177
|
if(data.identity_id){
|
|
158
178
|
GLOBAL.mpcConfig.consumer_id = data.identity_id;
|
|
@@ -161,7 +181,7 @@ class RelyingPartyBase {
|
|
|
161
181
|
return {publicKey:(this.publicKey = data.ccr.publicKey), identity_id:data.identity_id}
|
|
162
182
|
})
|
|
163
183
|
.then(result => result)
|
|
164
|
-
.catch(error => Promise.reject(
|
|
184
|
+
.catch(error => Promise.reject(new Error(error)));
|
|
165
185
|
}
|
|
166
186
|
|
|
167
187
|
/**
|
|
@@ -172,10 +192,10 @@ class RelyingPartyBase {
|
|
|
172
192
|
* @throws {Error} Throws an error if the request fails.
|
|
173
193
|
*/
|
|
174
194
|
registrationFinishAuthenticationStart (credential) {
|
|
175
|
-
return this.makePostRequest(
|
|
195
|
+
return this.makePostRequest(`api/webauthn/registration/finish-then-authentication-start`, { credential })
|
|
176
196
|
.then(result => (this.credentialID = credential.rawId, result))
|
|
177
197
|
.then(credential => credential)
|
|
178
|
-
.catch(error => (this.clearEnrollmentCredentials(), Promise.reject(
|
|
198
|
+
.catch(error => (this.clearEnrollmentCredentials(), Promise.reject(new Error(error))));
|
|
179
199
|
}
|
|
180
200
|
|
|
181
201
|
/**
|
|
@@ -189,7 +209,7 @@ class RelyingPartyBase {
|
|
|
189
209
|
createNewIdentity = createNewIdentity ? { create_new_identity: "true" } : {};
|
|
190
210
|
return this.makePostRequest("api/umfa/check-identity", createNewIdentity)
|
|
191
211
|
.then(result => result)
|
|
192
|
-
.catch(error => Promise.reject(error));
|
|
212
|
+
.catch(error => Promise.reject(new Error(error)));
|
|
193
213
|
}
|
|
194
214
|
}
|
|
195
215
|
//## END RelyingPartyBase =====================================================================================================================================
|
package/UMFAClientBase.js
CHANGED
|
@@ -8,7 +8,6 @@ class UMFAClientBase {
|
|
|
8
8
|
* @param {Object} config - The configuration for ZSM initialization (ref: ./zsm_app_config.json)
|
|
9
9
|
*/
|
|
10
10
|
constructor(config) {
|
|
11
|
-
if(eventCoordinator.done) eventCoordinator.reset();
|
|
12
11
|
eventCoordinator.update('UMFAClientBase');
|
|
13
12
|
this.config = config;
|
|
14
13
|
const WebAuthnClient = zsmPluginManager.classes('WEBAUTHNCLIENT');
|
|
@@ -24,20 +23,33 @@ class UMFAClientBase {
|
|
|
24
23
|
get userIdentifier() { return this.zsmAPI.userIdentifier; }
|
|
25
24
|
get credentialID() { return this.zsmAPI.credentialID; }
|
|
26
25
|
|
|
26
|
+
/**
|
|
27
|
+
* @name checkIdentity
|
|
28
|
+
* @description Pass-through method to call WebAuthnClient's checkIdentity
|
|
29
|
+
* @param {string} userIdentifier The identifier for the user
|
|
30
|
+
* @param {boolean} primeEnroll Whether to create a new identity if it doesn't exist
|
|
31
|
+
* @returns {Promise<Object>} Returns the results of zsmAPI.checkIdentity
|
|
32
|
+
* @memberOf FIDO2ClientBase, WebAuthnClient
|
|
33
|
+
*/
|
|
34
|
+
async checkIdentity (userIdentifier, primeEnroll) { return this.zsmAPI.checkIdentity(userIdentifier, primeEnroll); }
|
|
35
|
+
|
|
27
36
|
/**
|
|
28
37
|
* @name checkEnrollment
|
|
29
38
|
* @description Checks if a ZSM credential is enrolled on the device for the specified user
|
|
30
39
|
* @param {string} userIdentifier The identifier for the user
|
|
40
|
+
* @param {string} targetData The type of data to retrieve ('id' for credential ID, 'all' for full details)
|
|
31
41
|
* @returns {Promise<Object>|boolean} Resolves with the enrollment details or false if not enrolled, or an error if checking fails
|
|
32
42
|
* @throws {Error} If the userIdentifier is not provided or is empty
|
|
33
43
|
* @throws {Error} If an error occurs while checking enrollment
|
|
34
44
|
* @memberOf UMFAClientBase
|
|
35
45
|
*/
|
|
36
|
-
async checkEnrollment(userIdentifier) {
|
|
46
|
+
async checkEnrollment(userIdentifier, targetData='id') {
|
|
37
47
|
try {
|
|
38
48
|
if(userIdentifier == null
|
|
39
49
|
|| userIdentifier === '') throw new Error(`[UMFAClient] :: checkEnrollment :: A userIdentifier String is required! Received: ${userIdentifier}.`);
|
|
40
|
-
|
|
50
|
+
const enrollmentStatus = await this.zsmAPI.webauthnRetrieve(userIdentifier, targetData);
|
|
51
|
+
|
|
52
|
+
return enrollmentStatus;
|
|
41
53
|
} catch(e) {
|
|
42
54
|
return new Error(e.message || e || '[UMFAClient] :: checkEnrollment :: An error occurred while attempting to check enrollment.');
|
|
43
55
|
}
|
|
@@ -54,20 +66,20 @@ class UMFAClientBase {
|
|
|
54
66
|
* @memberOf UMFAClientBase
|
|
55
67
|
*/
|
|
56
68
|
async enroll(userIdentifier) {
|
|
57
|
-
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
// try {
|
|
58
72
|
if(userIdentifier == null
|
|
59
73
|
|| userIdentifier === '') throw new Error(`[UMFAClient] :: enroll :: A userIdentifier String is required! Received: ${userIdentifier}.`);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
74
|
+
const resultOfCheck = await this.zsmAPI.checkIdentity(userIdentifier, true);
|
|
75
|
+
|
|
76
|
+
const createResult = await this.zsmAPI.webauthnCreate(userIdentifier);
|
|
63
77
|
|
|
64
|
-
const createResult = await this.zsmAPI.webauthnCreateThenPartialGet(userIdentifier);
|
|
65
78
|
if(createResult instanceof Error) throw(`[UMFAClient] :: enroll :: Unable to associate ${userIdentifier}'s identity with device profile.\nDetails:\n${createResult}`);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
79
|
+
return createResult;
|
|
80
|
+
// }catch(e) {
|
|
81
|
+
// return new Error(e.message || e || '[UMFAClient] :: enroll :: An error occurred during enrollment.');
|
|
82
|
+
// }
|
|
71
83
|
}
|
|
72
84
|
|
|
73
85
|
/**
|