@ideem/zsm-client-sdk 2.9.1 → 2.9.3
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 +13 -3
- package/PasskeysPlusClient.js +1 -1
- package/RelyingParty.js +1 -1
- package/RelyingPartyBase.js +2 -2
- package/UMFAClientBase.js +1 -1
- package/Utils.js +1 -1
- package/WebAuthnClientBase.js +1 -1
- package/ZSMClientSDK.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -12,18 +12,28 @@ and Universal MFA into a browser application.
|
|
|
12
12
|
|
|
13
13
|
----
|
|
14
14
|
|
|
15
|
-
## Release 2.9.
|
|
15
|
+
## Release 2.9.3 - August 13, 2026 [ NPM PACKAGE RELEASE ] **latest release**
|
|
16
|
+
- Minor bug fixes and improvements
|
|
17
|
+
- Resolves a strange conflict experienced by users running third party password managers (e.g. 1Password, Bitwarden, etc.) in which the `hints` KVP on Webauthn publicKey objects was preventing said password managers from properly handling the enrollment and authorization flows (flows still worked, but passkeys would not be saved to the password manager). The SDK now automatically removes the optional `hints` KVP from publicKey objects before passing them to the browser's Webauthn API, which resolves this issue and allows password managers to properly handle passkey enrollment and authorization flows.
|
|
18
|
+
|
|
19
|
+
## Release 2.9.2 - July 7, 2026 [ NPM PACKAGE RELEASE ]
|
|
20
|
+
- Minor bug fixes and improvements
|
|
21
|
+
- Adds support for a new `metadata` property on the `UMFAClient` class, which allows consumers to set arbitrary metadata that will be included in all subsequent API calls made by the SDK to the RP. This allows consumers to pass additional context or information to the server for logging, analytics, or other purposes.
|
|
22
|
+
- Improved api_key omission handling in the SDK, allowing for more flexible configuration of the SDK in different environments.
|
|
23
|
+
|
|
24
|
+
## Release 2.9.1 - June 18, 2026 [ NPM PACKAGE RELEASE ]
|
|
16
25
|
- Minor bug fixes and improvements
|
|
17
26
|
- Provides a workaround for an issue in which certain browser extensions (e.g. credential managers) interfere with the webauthn flows by overriding the `navigator.credentials.get` method.
|
|
18
27
|
- Adds a new property to the data returned by `checkAllEnrollments()` called `isUsingPasswordManager`, which is a boolean that indicates whether or not the `navigator.credentials.get` method has been overridden by an external source (e.g. a browser extension like a password manager). This allows consumers to detect when their users are using password managers that may interfere with the webauthn flows, and adjust their UI/UX accordingly (e.g. by displaying a warning message about potential issues with password managers, or by providing additional guidance on how to use the SDK effectively in conjunction with password managers).
|
|
19
28
|
|
|
20
|
-
|
|
29
|
+
|
|
30
|
+
## Release 2.9.0 - May 17, 2026 [ NPM PACKAGE RELEASE ]
|
|
21
31
|
- Adds an optional `installation_id` override mechanism for bridging contexts:
|
|
22
32
|
- Rust extern `__ideem_get_install_id_override_v1` declared on `globalThis` via `#[wasm_bindgen(catch)]`, embedded in `WASMRustInterface.js` (which runs in the page context).
|
|
23
33
|
- Consumers install the JS-side getter at page scope: `globalThis.__ideem_get_install_id_override_v1 = () => value`.
|
|
24
34
|
- Non-bridging contexts unchanged — `InstallationID::get()` falls through to the existing IndexedDB-derived value when no override getter is installed (the `catch` arm in the extern handles the missing-getter case).
|
|
25
35
|
|
|
26
|
-
## Release 2.8.1 -
|
|
36
|
+
## Release 2.8.1 - May 8, 2026 [ NPM PACKAGE RELEASE ]
|
|
27
37
|
- Minor bug fixes and improvements
|
|
28
38
|
- Alters Webauthn object to provide Passkeys+ support Android WebViews
|
|
29
39
|
|
package/PasskeysPlusClient.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"./EventCoordinator.js";export default class{constructor(){e.update("PasskeysPlus"),this.passkeyAPI=(navigator?.credentials??null)||null,e.update("PasskeysPlus","READY")}pkpSupported=()=>!!this.passkeyAPI&&"function"==typeof this.passkeyAPI.create&&"function"==typeof this.passkeyAPI.get;blockUnsupportedInvocation=()=>{if(!this.pkpSupported())throw new Error("[PK+ PasskeysPlus] :: blockUnsupportedInvocation :: This browser and/or device does not support the PasskeysPlus API!");return!0};toArrayBuffer(e){if("string"!=typeof e||!/^[A-Za-z0-9\-_]+$/.test(e))throw new Error(`[PK+ PasskeysPlus] :: toArrayBuffer :: Invalid base64url string provided: ${e}`);try{const t=atob(e.replace(/-/g,"+").replace(/_/g,"/")+"====".slice(0,-e.length%4)),r=new Uint8Array(t.length);for(let e=0;e<t.length;e++)r[e]=t.charCodeAt(e);return r.buffer}catch(e){throw new Error(`[PK+ PasskeysPlus] :: toArrayBuffer :: Error converting base64url string to ArrayBuffer: ${e.message||e}`)}}pkpCreatePasskeyCredential=async(e,t="preferred")=>{if(!this.blockUnsupportedInvocation())return!1;if(e?.authenticatorSelection&&(e.authenticatorSelection.userVerification=t),e?.extensions?.credentialProtectionPolicy&&delete e.extensions.credentialProtectionPolicy,!e||"object"!=typeof e)throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid publicKey parameter provided: ${e}! It must be an object. Received: ${e}`);if(!(e?.challenge&&e?.rp&&e?.rp?.id&&e?.rp?.name))throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid publicKey structure! It must contain challenge and rp properties with id and name. Received: ${e}`);if(!(e?.user&&e?.user?.id&&e?.user?.id instanceof ArrayBuffer))throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid user ID in publicKey! It must be an ArrayBuffer. Received: ${e?.user?.id}`);if(!e?.pubKeyCredParams||!Array.isArray(e?.pubKeyCredParams)||0===e?.pubKeyCredParams?.length)throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: pubKeyCredParams must be a non-empty array of public key credential parameters. Received: ${e?.pubKeyCredParams}`);if(!e?.authenticatorSelection||"object"!=typeof e?.authenticatorSelection)throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid authenticatorSelection in publicKey! It must be an object. Received: ${e?.authenticatorSelection} (${typeof e?.authenticatorSelection})`);if(e?.authenticatorSelection?.authenticatorAttachment&&!["platform","cross-platform"].includes(e?.authenticatorSelection?.authenticatorAttachment))throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid authenticatorAttachment in authenticatorSelection! It must be either "platform" or "cross-platform". Received: ${e?.authenticatorSelection?.authenticatorAttachment}`);if(e?.authenticatorSelection?.requireResidentKey&&"boolean"!=typeof e?.authenticatorSelection?.requireResidentKey)throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid requireResidentKey in authenticatorSelection! It must be a boolean. Received: ${e?.authenticatorSelection?.requireResidentKey} (${typeof e?.authenticatorSelection?.requireResidentKey})`);if(e?.authenticatorSelection?.userVerification&&!["required","preferred","discouraged"].includes(e?.authenticatorSelection?.userVerification))throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid userVerification in authenticatorSelection! It must be one of "required", "preferred", or "discouraged". Received: ${e?.authenticatorSelection?.userVerification}`);if(!e?.timeout||"number"!=typeof e?.timeout||e?.timeout<=0)throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid timeout in publicKey! It must be a positive number. Received: ${e?.timeout} (${typeof e?.timeout})`);if(e?.excludeCredentials&&(!Array.isArray(e?.excludeCredentials)||e?.excludeCredentials?.length>0&&!e?.excludeCredentials[0].id))throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid credential ID in excludeCredentials! It must be an ArrayBuffer. Received: ${e?.excludeCredentials[0]?.id}`);return await this.passkeyAPI.create({publicKey:{...e,userVerification:t}})};pkpGetPasskeyCredential=async(e,t="preferred")=>{if(!this.blockUnsupportedInvocation())return!1;if(e?.authenticatorSelection&&(e.authenticatorSelection.userVerification=t),!e||"object"!=typeof e)throw new Error("[PK+ PasskeysPlus] :: pkpGetPasskeyCredential :: Invalid publicKey parameter provided!");if(!e?.challenge||!e?.allowCredentials||!Array.isArray(e?.allowCredentials))throw new Error(`[PK+ PasskeysPlus] :: pkpGetPasskeyCredential :: Invalid publicKey structure provided! It must contain challenge and allowCredentials properties. Received: ${e}`);if(0===e?.allowCredentials?.length)throw new Error(`[PK+ PasskeysPlus] :: pkpGetPasskeyCredential :: allowCredentials array must not be empty! It should contain at least one credential ID. Received: ${e?.allowCredentials}`);const r=e?.allowCredentials.reduce((e,t)=>e&&t?.id&&(t.id instanceof ArrayBuffer||ArrayBuffer.isView(t.id)),!0);if(!r)throw new Error(`[PK+ PasskeysPlus] :: pkpGetPasskeyCredential :: Invalid credential ID in allowCredentials! It must be an ArrayBuffer. Received: ${e?.allowCredentials[0]?.id}`);return await this.passkeyAPI.get({publicKey:{...e,userVerification:t}})}}
|
|
1
|
+
import e from"./EventCoordinator.js";export default class{constructor(){e.update("PasskeysPlus"),this.passkeyAPI=(navigator?.credentials??null)||null,e.update("PasskeysPlus","READY")}pkpSupported=()=>!!this.passkeyAPI&&"function"==typeof this.passkeyAPI.create&&"function"==typeof this.passkeyAPI.get;blockUnsupportedInvocation=()=>{if(!this.pkpSupported())throw new Error("[PK+ PasskeysPlus] :: blockUnsupportedInvocation :: This browser and/or device does not support the PasskeysPlus API!");return!0};toArrayBuffer(e){if("string"!=typeof e||!/^[A-Za-z0-9\-_]+$/.test(e))throw new Error(`[PK+ PasskeysPlus] :: toArrayBuffer :: Invalid base64url string provided: ${e}`);try{const t=atob(e.replace(/-/g,"+").replace(/_/g,"/")+"====".slice(0,-e.length%4)),r=new Uint8Array(t.length);for(let e=0;e<t.length;e++)r[e]=t.charCodeAt(e);return r.buffer}catch(e){throw new Error(`[PK+ PasskeysPlus] :: toArrayBuffer :: Error converting base64url string to ArrayBuffer: ${e.message||e}`)}}pkpCreatePasskeyCredential=async(e,t="preferred")=>{if(!this.blockUnsupportedInvocation())return!1;if(e?.authenticatorSelection&&(e.authenticatorSelection.userVerification=t),e?.hints&&delete e.hints,e?.extensions?.credentialProtectionPolicy&&delete e.extensions.credentialProtectionPolicy,!e||"object"!=typeof e)throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid publicKey parameter provided: ${e}! It must be an object. Received: ${e}`);if(!(e?.challenge&&e?.rp&&e?.rp?.id&&e?.rp?.name))throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid publicKey structure! It must contain challenge and rp properties with id and name. Received: ${e}`);if(!(e?.user&&e?.user?.id&&e?.user?.id instanceof ArrayBuffer))throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid user ID in publicKey! It must be an ArrayBuffer. Received: ${e?.user?.id}`);if(!e?.pubKeyCredParams||!Array.isArray(e?.pubKeyCredParams)||0===e?.pubKeyCredParams?.length)throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: pubKeyCredParams must be a non-empty array of public key credential parameters. Received: ${e?.pubKeyCredParams}`);if(!e?.authenticatorSelection||"object"!=typeof e?.authenticatorSelection)throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid authenticatorSelection in publicKey! It must be an object. Received: ${e?.authenticatorSelection} (${typeof e?.authenticatorSelection})`);if(e?.authenticatorSelection?.authenticatorAttachment&&!["platform","cross-platform"].includes(e?.authenticatorSelection?.authenticatorAttachment))throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid authenticatorAttachment in authenticatorSelection! It must be either "platform" or "cross-platform". Received: ${e?.authenticatorSelection?.authenticatorAttachment}`);if(e?.authenticatorSelection?.requireResidentKey&&"boolean"!=typeof e?.authenticatorSelection?.requireResidentKey)throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid requireResidentKey in authenticatorSelection! It must be a boolean. Received: ${e?.authenticatorSelection?.requireResidentKey} (${typeof e?.authenticatorSelection?.requireResidentKey})`);if(e?.authenticatorSelection?.userVerification&&!["required","preferred","discouraged"].includes(e?.authenticatorSelection?.userVerification))throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid userVerification in authenticatorSelection! It must be one of "required", "preferred", or "discouraged". Received: ${e?.authenticatorSelection?.userVerification}`);if(!e?.timeout||"number"!=typeof e?.timeout||e?.timeout<=0)throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid timeout in publicKey! It must be a positive number. Received: ${e?.timeout} (${typeof e?.timeout})`);if(e?.excludeCredentials&&(!Array.isArray(e?.excludeCredentials)||e?.excludeCredentials?.length>0&&!e?.excludeCredentials[0].id))throw new Error(`[PK+ PasskeysPlus] :: pkpCreatePasskeyCredential :: Invalid credential ID in excludeCredentials! It must be an ArrayBuffer. Received: ${e?.excludeCredentials[0]?.id}`);return await this.passkeyAPI.create({publicKey:{...e,userVerification:t}})};pkpGetPasskeyCredential=async(e,t="preferred")=>{if(!this.blockUnsupportedInvocation())return!1;if(e?.authenticatorSelection&&(e.authenticatorSelection.userVerification=t),e?.hints&&delete e.hints,!e||"object"!=typeof e)throw new Error("[PK+ PasskeysPlus] :: pkpGetPasskeyCredential :: Invalid publicKey parameter provided!");if(!e?.challenge||!e?.allowCredentials||!Array.isArray(e?.allowCredentials))throw new Error(`[PK+ PasskeysPlus] :: pkpGetPasskeyCredential :: Invalid publicKey structure provided! It must contain challenge and allowCredentials properties. Received: ${e}`);if(0===e?.allowCredentials?.length)throw new Error(`[PK+ PasskeysPlus] :: pkpGetPasskeyCredential :: allowCredentials array must not be empty! It should contain at least one credential ID. Received: ${e?.allowCredentials}`);const r=e?.allowCredentials.reduce((e,t)=>e&&t?.id&&(t.id instanceof ArrayBuffer||ArrayBuffer.isView(t.id)),!0);if(!r)throw new Error(`[PK+ PasskeysPlus] :: pkpGetPasskeyCredential :: Invalid credential ID in allowCredentials! It must be an ArrayBuffer. Received: ${e?.allowCredentials[0]?.id}`);return await this.passkeyAPI.get({publicKey:{...e,userVerification:t}})}}
|
package/RelyingParty.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"./EventCoordinator.js";import t from"./RelyingPartyBase.js";e.update("RelyingParty");export default class extends t{constructor(t,r,n,o,a){super(t,r,n,o,"undefined"!=a&&null!=a&&a),e.update("RelyingParty","READY")}}
|
|
1
|
+
import e from"./EventCoordinator.js";import t from"./RelyingPartyBase.js";e.update("RelyingParty");export default class extends t{constructor(t,r,n,o,a,s){super(t,r,n,o,"undefined"!=a&&null!=a&&a,s),e.update("RelyingParty","READY")}}
|
package/RelyingPartyBase.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import t from"./EventCoordinator.js";import e from"./GlobalScoping.js";import{uid2iid as i}from"./IdentityIndexing.js";import{b64urlToBuf as r,toObject as n}from"./Utils.js";t.update("RelyingPartyBase");export default class{constructor(e,i,r,n,a){this.host=e,this.apiKey=i,this.applicationId=r,this.appEnvironment=n||null,this.customerDefinedIdentifier=void 0,this.publicKey=void 0,this.identityID=void 0,this.credentialID=void 0,this.traceId=void 0,this.xhrHeaders={"Content-Type":"application/json"},this.addlRelyingPartyBodyProps=a?{use_origin:"true"}:{},t.update("RelyingPartyBase","READY")}get userIdentifier(){return this.customerDefinedIdentifier}set userIdentifier(t){return userIdentifier=this.customerDefinedIdentifier=t}makePostRequest(t,i={},r={},n="POST"){t=`${this.host.endsWith("/")?this.host.slice(0,-1):this.host}/${t.startsWith("/")?t.slice(1):t}`,i="object"==typeof i?i:{},this.appEnvironment&&(i=Object.assign(i,{environment:this.appEnvironment})),i=Object.assign({customer_defined_identifier:this.customerDefinedIdentifier,application_id:this.applicationId},i,this.addlRelyingPartyBodyProps,function(t=!1){const e=[[(new Date).toISOString(),"TRACEPRIMER"]];return t?{trace:e}:e}(!0));let a={method:n,headers:Object.assign(this.xhrHeaders,r?.Authorization?{}:{Authorization:`Bearer ${this.apiKey}`},r),body:JSON.stringify(i)};return fetch(t,a).then(t=>t.ok?t.json():t.json().then(e=>{throw new Error(`[RelyingParty] :: makePostRequest :: Request failed: ${t.statusText}, ${JSON.stringify(e)}`)})).then(t=>(e.dispatchEvent(new CustomEvent("AuthResponse",{bubbles:!0,cancelable:!1,detail:t})),t))}clearEnrollmentCredentials(){return this.publicKey=this.credentialID=null}clearLoginCredentials(){}resetAll(){return this.clearLoginCredentials(),this.clearEnrollmentCredentials()}registrationStart(){return this.makePostRequest("api/webauthn/registration/start").then(t=>(t.identity_id&&(e.mpcConfig.consumer_id=t.identity_id,i(this.userIdentifier,t.identity_id)),this.publicKey=t.ccr.publicKey)).then(t=>t).catch(t=>Promise.reject(new Error(t)))}registrationFinish(t){return t}authenticationStart(t=this.credentialID,e="passkey",i,r,n){return null!=t?this.makePostRequest("api/webauthn/authentication/start",{credential_id:t}).then(t=>t):Promise.reject(new Error("[RelyingParty] :: authenticationStart :: No user ID or credential ID provided"))}authenticationFinish(t){return t}createIdentityThenRegistrationStart(t="zsm",r,n,a){const s={credential_type:t,chain_handoff:r,chain_credential_id:n,chain_challenge:a};return this.makePostRequest("api/webauthn/registration/create-identity-then-start",s).then(t=>(t.identity_id&&(e.mpcConfig.consumer_id=t.identity_id,i(this.userIdentifier,t.identity_id)),{publicKey:this.publicKey=t.ccr.publicKey,identity_id:t.identity_id})).then(t=>t).catch(t=>Promise.reject(new Error(t)))}registrationFinishAuthenticationStart(t){return t}checkServerSideIdentity(t){return t=t?{create_new_identity:"true"}:{},this.makePostRequest("api/umfa/check-identity",t).then(t=>t).catch(t=>Promise.reject(new Error(t)))}
|
|
1
|
+
import t from"./EventCoordinator.js";import e from"./GlobalScoping.js";import{uid2iid as i}from"./IdentityIndexing.js";import{b64urlToBuf as r,toObject as n}from"./Utils.js";t.update("RelyingPartyBase");export default class{constructor(e,i,r,n,a,s){this.host=e,this.apiKey=i,this.applicationId=r,this.appEnvironment=n||null,this.customerDefinedIdentifier=void 0,this.publicKey=void 0,this.identityID=void 0,this.credentialID=void 0,this.traceId=void 0,this.xhrHeaders={"Content-Type":"application/json"},this.addlRelyingPartyBodyProps=a?{use_origin:"true"}:{},this.metadata=s||null,t.update("RelyingPartyBase","READY")}get userIdentifier(){return this.customerDefinedIdentifier}set userIdentifier(t){return userIdentifier=this.customerDefinedIdentifier=t}makePostRequest(t,i={},r={},n="POST"){t=`${this.host.endsWith("/")?this.host.slice(0,-1):this.host}/${t.startsWith("/")?t.slice(1):t}`,i="object"==typeof i?i:{},this.metadata&&Object.keys(this.metadata).length&&(i=Object.assign({},i,{metadata:this.metadata})),this.appEnvironment&&(i=Object.assign({},i,{environment:this.appEnvironment})),i=Object.assign({customer_defined_identifier:this.customerDefinedIdentifier,application_id:this.applicationId},i,this.addlRelyingPartyBodyProps,function(t=!1){const e=[[(new Date).toISOString(),"TRACEPRIMER"]];return t?{trace:e}:e}(!0));let a={method:n,headers:Object.assign(this.xhrHeaders,r?.Authorization?{}:{Authorization:`Bearer ${this.apiKey}`},r),body:JSON.stringify(i)};return fetch(t,a).then(t=>t.ok?t.json():t.json().then(e=>{throw new Error(`[RelyingParty] :: makePostRequest :: Request failed: ${t.statusText}, ${JSON.stringify(e)}`)})).then(t=>(e.dispatchEvent(new CustomEvent("AuthResponse",{bubbles:!0,cancelable:!1,detail:t})),t))}clearEnrollmentCredentials(){return this.publicKey=this.credentialID=null}clearLoginCredentials(){}resetAll(){return this.clearLoginCredentials(),this.clearEnrollmentCredentials()}registrationStart(){return this.makePostRequest("api/webauthn/registration/start").then(t=>(t.identity_id&&(e.mpcConfig.consumer_id=t.identity_id,i(this.userIdentifier,t.identity_id)),this.publicKey=t.ccr.publicKey)).then(t=>t).catch(t=>Promise.reject(new Error(t)))}registrationFinish(t){return t}authenticationStart(t=this.credentialID,e="passkey",i,r,n){return null!=t?this.makePostRequest("api/webauthn/authentication/start",{credential_id:t}).then(t=>t):Promise.reject(new Error("[RelyingParty] :: authenticationStart :: No user ID or credential ID provided"))}authenticationFinish(t){return t}createIdentityThenRegistrationStart(t="zsm",r,n,a){const s={credential_type:t,chain_handoff:r,chain_credential_id:n,chain_challenge:a};return this.makePostRequest("api/webauthn/registration/create-identity-then-start",s).then(t=>(t.identity_id&&(e.mpcConfig.consumer_id=t.identity_id,i(this.userIdentifier,t.identity_id)),{publicKey:this.publicKey=t.ccr.publicKey,identity_id:t.identity_id})).then(t=>t).catch(t=>Promise.reject(new Error(t)))}registrationFinishAuthenticationStart(t){return t}checkServerSideIdentity(t){return t=t?{create_new_identity:"true"}:{},this.makePostRequest("api/umfa/check-identity",t).then(t=>t).catch(t=>Promise.reject(new Error(t)))}
|
|
2
2
|
//! PASSKEYS PLUS RELYING PARTY METHODS =========================================================================================================================
|
|
3
|
-
async pkpRegistrationStart(t,n,a=null){const
|
|
3
|
+
async pkpRegistrationStart(t,n,a=null,s=!1){const o=a?{chain_handoff:"internal",chain_credential_id:a}:{chain_handoff:"internal"},l=await this.makePostRequest("api/passkey/registration/create-identity-then-start",o).then(t=>(t.identity_id&&(e.mpcConfig.consumer_id=t.identity_id,i(this.userIdentifier,t.identity_id)),{publicKey:this.publicKey=t.ccr.publicKey,identity_id:t.identity_id})).then(t=>t).catch(t=>Promise.reject(new Error(t)));if(!l)throw new Error("[PK+ RelyingParty] :: pkpRegistrationStart :: Unable to retrieve Platform Authority Challenge from Relying Party Server!");if(!l?.publicKey)throw new Error("[PK+ RelyingParty] :: pkpRegistrationStart :: Platform Authority Challenge's Public Key was not found!");if(l.publicKey.challenge=r(l.publicKey.challenge),!l?.publicKey?.user)throw new Error("[PK+ RelyingParty] :: pkpRegistrationStart :: User for the Platform Authority Challenge Public Key's user node was not found!");return l.publicKey.user.id=r(l.publicKey.user.id),s?delete l.publicKey.excludeCredentials:Array.isArray(l.publicKey.excludeCredentials)&&l.publicKey.excludeCredentials.forEach(t=>{t&&"string"==typeof t.id&&(t.id=r(t.id))}),l}async pkpRegistrationFinish(t){if(!t)throw new TypeError("[PK+ RelyingParty] :: pkpRegistrationFinish :: No Platform Authenticator Credential provided!");return this.makePostRequest("api/passkey/registration/finish",{credential:t}).then(e=>(this.credentialID=t.rawId,{credential:t,credentialID:this.credentialID,response:{credentialID:this.credentialID,...e}})).catch(t=>{throw this.clearEnrollmentCredentials(),new Error("[PK+ RelyingParty] :: pkpRegistrationFinish :: Unable to complete registration!",{cause:t})})}async pkpAuthenticationStart(t){if(null==t||"object"!=typeof t)throw new TypeError("[PK+ RelyingParty] :: pkpAuthenticationStart :: No Credential Data object provided!");if(!t.hasRemotePasskey&&!t.zsmCredentialID)throw new Error("[PK+ RelyingParty] :: pkpAuthenticationStart :: Credential Data object does not contain a valid Passkeys+ Credential ID or ZSM Credential ID!");const e={credential_id:t?.pkpCredentialID,chain_credential_id:t.zsmCredentialID,chain_handoff:t?.chainHandoff||"internal",chain_challenge:t?.pkpCredential?JSON.stringify(t.pkpCredential):null};let i=await this.makePostRequest("api/passkey/authentication/start",e);if(i instanceof Error||!i)throw new Error("[PK+ RelyingParty] :: pkpAuthenticationStart :: Unable to retrieve Platform Authority Challenge from Relying Party Server!",{cause:i});if(i=n(i),!i?.rcr||!i?.rcr?.publicKey)throw new Error("[PK+ RelyingParty] :: pkpAuthenticationStart :: Platform Authority's RCR challenge and/or publicKey was not found!");const a=i.rcr.publicKey;a.challenge=r(a.challenge);const s=a.allowCredentials;if(!s||!s[0]?.id)throw new Error("[PK+ RelyingParty] :: pkpAuthenticationStart :: Platform Authority Challenge's allowCredentials and/or id was not found!");return s[0].id=r(s[0].id),a}async pkpAuthenticationFinish(t){if(!t||"object"!=typeof t)throw new Error("[PK+ RelyingParty] :: pkpAuthenticationFinish :: No Platform Authenticator Credential provided or is not an object!");return this.makePostRequest("api/passkey/authentication/finish",{credential:t}).then(e=>({credential:t,response:e})).catch(t=>Promise.reject(new Error("[PK+ RelyingParty] :: pkpAuthenticationFinish :: Unable to complete authentication!",{cause:t})))}async getRemoteEnrollmentDetails(t,e,i=!1){const r={customer_defined_identifier:t};return await this.makePostRequest("/api/v1/enrollment-details",r)}}
|
package/UMFAClientBase.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"./EventCoordinator.js";import{zsmPluginManager as t}from"./PluginManager.js";import{encodeUserIdentifier as r}from"./encodeUserIdentifier.js";export default class{constructor(r){e.reset(),e.update("UMFAClientBase"),this.config=r;const s=t.classes("WEBAUTHNCLIENT");this.zsmAPI=new s(r),this.checkEnrollment=this.checkEnrollment.bind(this),this.enroll=this.enroll.bind(this),this.authenticate=this.authenticate.bind(this),this.checkAllEnrollments=this.checkAllEnrollments.bind(this),this.passkeyPlusEnroll=this.passkeyPlusEnroll.bind(this),this.passkeyPlusAuthenticate=this.passkeyPlusAuthenticate.bind(this),this.unenroll=this.unenroll.bind(this),this.resetDevice=this.resetDevice.bind(this),e.update("UMFAClientBase","READY")}get userIdentifier(){return this.zsmAPI.userIdentifier}get credentialID(){return this.zsmAPI.credentialID}typeChecks(e,t,s=null,i=""){if(!t)throw new TypeError(`[UMFAClient] :: ${e} :: A userIdentifier String or Object is required! Received: ${t} (type: ${typeof t}).`);let n;if("object"==typeof t&&(n={...t},t=t.userIdentifier),null!=s){if("boolean"==typeof s)s=!0===s?"preferred":"prevented";else{if("string"!=typeof s)throw new TypeError(`[UMFAClient] :: ${e} :: userVerification must be a boolean or string. Received type: ${typeof s}.`);s=s.toLowerCase()}const t=["preferred","required","discouraged","prevented",...i.split(/, ?/g).filter(Boolean)];if(!new RegExp(`^(${t.join("|")})$`).test(s))throw new TypeError(`[UMFAClient] :: ${e} :: userVerification must be one of the following Strings: "${t.join('", "')}"). Received: ${s}.`)}let a={userIdentifier:t=r(t),userVerification:s};return n&&(a={enrollmentDetails:n,...a}),a}async allowBrowserObserversToSettle(){"undefined"!=typeof window&&("function"==typeof requestAnimationFrame&&await new Promise(e=>requestAnimationFrame(e)),await new Promise(e=>setTimeout(e,0)))}async checkIdentity(e,t){return this.zsmAPI.checkIdentity(r(e),t)}async checkEnrollment(e){({userIdentifier:e}=this.typeChecks("checkEnrollment",e));return await this.zsmAPI.webauthnRetrieve(e)}async checkAllEnrollments(e,t=!1){return this.zsmAPI.webauthnRetrieveAll(r(e),t)}async enroll(e,t="prevented"){await this.allowBrowserObserversToSettle(),({userIdentifier:e,userVerification:t}=this.typeChecks("enroll",e,t,"zsm,re-enroll,reenroll"));const r=/^re-?enroll$/.test(t),s="preferred"===t;let i,n,a;if(r||/^(preferred|required)$/.test(t)){n=await this.checkAllEnrollments(e);try{if(n.passkeySupported)if(r){if(!n.zsmCredentialID&&!n.hasLocalPasskey)return new Error(`[UMFAClient] :: enroll :: Cannot RE-enroll user's passkey; user ${e} is not currently enrolled with either ZSM or Passkeys+ credentials. To enroll the user, call enroll with a userVerification value of "preferred", "required", or "discouraged".`);i=await this.passkeyPlusEnroll(n,"required")}else{if(n.zsmCredentialID&&n.hasLocalPasskey)return new Error(`[UMFAClient] :: enroll :: User ${e} is already enrolled with both ZSM and Passkeys+ credentials. To authenticate one or both credential, call the authenticate method.`);n instanceof Error||!1===n||!n.zsmCredentialID&&!n.hasLocalPasskey?i=await this.passkeyPlusEnroll(n,t):n.zsmCredentialID&&!n.hasLocalPasskey?i=await this.addPasskeyToZSMCredential(n,t):!n.zsmCredentialID&&n.pkpCredential&&(i=await this.addZSMToPasskeyCredential(n,t))}else{if(!s)return new Error(`[UMFAClient] :: enroll :: Passkeys+ is required for enrollment (userVerification set to "required"), but this device does not support Passkeys+. User ${e} cannot be enrolled. Please use a Passkeys+-compatible device to enroll.`);console.warn(`[UMFAClient] :: enroll :: Passkeys+ enrollment has been requested, but this device does not support Passkeys+. User ${e} will be enrolled with ZSM-only credentials. Please use a Passkeys+-compatible device to enroll with Passkeys+ in the future.`)}return void 0===i?new Error(`[UMFAClient] :: enroll :: Unexpected PKP flow: PKP enrollment attempted but no result was returned for user ${e}.`):i}catch(r){if(console.error("ENROLL FLOW :: PASSKEY OPERATION FAILED ::",r),!s)return new Error(`[UMFAClient] :: enroll :: The passkey portion of the Passkeys+ enrollment failed for user ${e} with error: ${r.message||r}. Since userVerification is set to "${t}", the entire enrollment process has failed. You may: retry, downgrade the userVerification mandate to "preferred" or "discouraged" to allow for ZSM-only enrollment.`)}}if(a=n?.zsmCredentialID?n?.zsmCredentialID:await this.checkEnrollment(e),"string"==typeof a)return new Error(`[UMFAClient] :: enroll :: User ${e} is already enrolled with a ZSM credential. To authenticate it, call the authenticate method.`);await this.zsmAPI.checkIdentity(e,!0);const l=await this.zsmAPI.webauthnCreate(e);return l instanceof Error?new Error(`[UMFAClient] :: enroll :: Unable to enroll ${e}!\nDetails:\n${l?.message||l}`,{cause:l?.stack}):l}async authenticate(e,t="prevented"){await this.allowBrowserObserversToSettle(),({userIdentifier:e,userVerification:t}=this.typeChecks("authenticate",e,t,"zsm"));const r=/^(preferred|required)$/.test(t),s="preferred"===t;let i,n,a;if(r){if(n=await this.checkAllEnrollments(e),!n.zsmCredentialID)return new Error(`[UMFAClient] :: authenticate :: User ${e} must be enrolled with a ZSM credential before authenticating. Please enroll the user first.`);if(!n.passkeySupported)return new Error(`[UMFAClient] :: authenticate :: User ${e} is not eligible for Passkeys+ authentication; their device does not support passkey authentication. To authenticate, call the authenticate method with userVerification set to "preferred", "discouraged", or "prevented"/"zsm". To enroll with Passkeys+, call enroll with userVerification set to "preferred" or "required" on a Passkeys+-compatible device.`);if(!n.hasLocalPasskey)return new Error(`[UMFAClient] :: authenticate :: User ${e} must be enrolled with both ZSM and Passkeys+ credentials to authenticate using Passkeys+ (userVerification set to a non-prevented value).`);if(r){try{i=await this.passkeyPlusAuthenticate(n,t)}catch(r){if(!s)return new Error(`[UMFAClient] :: authenticate :: The passkey portion of the Passkeys+ authentication failed for user ${e} with error: ${r.message||r}. Since userVerification is set to "${t}", the entire authentication process has failed. You may: retry or downgrade the userVerification mandate to "preferred" or "discouraged" to allow for ZSM-only authentication.`)}return void 0===i?new Error(`[UMFAClient] :: authenticate :: Unexpected PKP flow: PKP authentication attempted but no result was returned for user ${e}.`):i}}a=n?.zsmCredentialID?n?.zsmCredentialID:await this.checkEnrollment(e);if(!1===("string"==typeof a))return new Error(`[UMFAClient] :: authenticate :: ${e} is not enrolled. To authenticate the user, please enroll them first by calling the enroll method.`);const l=await this.zsmAPI.webauthnPartialGet(e);return l?.credential??l}async addPasskey(e,t="required"){let r,s;return await this.allowBrowserObserversToSettle(),({userIdentifier:e,userVerification:t,enrollmentDetails:r}=this.typeChecks("addPasskey",e,t,"re-enroll,reenroll")),s=r?await this.zsmAPI.pkpCreate(r||e,t):await this.addPasskeyToZSMCredential(r||e,t),s}async passkeyPlusEnroll(e,t="preferred"){await this.allowBrowserObserversToSettle(),({userIdentifier:e,userVerification:t}=this.typeChecks("passkeyPlusEnroll",e,t,"re-enroll,reenroll"));return await this.zsmAPI.pkpCreate(e,t)}async passkeyPlusAuthenticate(e,t="preferred"){await this.allowBrowserObserversToSettle();let r=null;({userIdentifier:e,userVerification:t,enrollmentDetails:r}=this.typeChecks("passkeyPlusAuthenticate",e,t,"re-enroll,reenroll")),r||(r=await this.checkAllEnrollments(e,!0));return await this.zsmAPI.pkpAuthenticate(r,t,!r.zsmCredentialID)}async addZSMToPasskeyCredential(e,t){({userIdentifier:e}=this.typeChecks("addZSMToPasskeyCredential",e));return await this.passkeyPlusAuthenticate(e)}async addPasskeyToZSMCredential(e,t="preferred"){let r=null;({userIdentifier:e,userVerification:t,enrollmentDetails:r}=this.typeChecks("addPasskeyToZSMCredential",e,t,"re-enroll,reenroll"));return await this.zsmAPI.pkpAddPasskeyCredential(r||e,t)}async unenroll(e){if(({userIdentifier:e}=this.typeChecks("unenroll",e)),!1===await this.checkEnrollment(e))return!1;let t=await this.zsmAPI.unbindFromDevice(e);if(t instanceof Error)throw`Unable to unenroll ${e}'s identity from this device.\nDetails:\n${t}`;return!0===t}async resetDevice(){this.zsmAPI.webauthnReset()}}
|
|
1
|
+
import e from"./EventCoordinator.js";import{zsmPluginManager as t}from"./PluginManager.js";import{encodeUserIdentifier as r}from"./encodeUserIdentifier.js";export default class{constructor(r){e.reset(),e.update("UMFAClientBase"),this.config=r;const s=t.classes("WEBAUTHNCLIENT");this.zsmAPI=new s(r),this.checkEnrollment=this.checkEnrollment.bind(this),this.enroll=this.enroll.bind(this),this.authenticate=this.authenticate.bind(this),this.checkAllEnrollments=this.checkAllEnrollments.bind(this),this.passkeyPlusEnroll=this.passkeyPlusEnroll.bind(this),this.passkeyPlusAuthenticate=this.passkeyPlusAuthenticate.bind(this),this.unenroll=this.unenroll.bind(this),this.resetDevice=this.resetDevice.bind(this),e.update("UMFAClientBase","READY")}get userIdentifier(){return this.zsmAPI.userIdentifier}get credentialID(){return this.zsmAPI.credentialID}get metadata(){return this.zsmAPI.metadata}set metadata(e){return this.zsmAPI.metadata=e}typeChecks(e,t,s=null,i=""){if(!t)throw new TypeError(`[UMFAClient] :: ${e} :: A userIdentifier String or Object is required! Received: ${t} (type: ${typeof t}).`);let n;if("object"==typeof t&&(n={...t},t=t.userIdentifier),null!=s){if("boolean"==typeof s)s=!0===s?"preferred":"prevented";else{if("string"!=typeof s)throw new TypeError(`[UMFAClient] :: ${e} :: userVerification must be a boolean or string. Received type: ${typeof s}.`);s=s.toLowerCase()}const t=["preferred","required","discouraged","prevented",...i.split(/, ?/g).filter(Boolean)];if(!new RegExp(`^(${t.join("|")})$`).test(s))throw new TypeError(`[UMFAClient] :: ${e} :: userVerification must be one of the following Strings: "${t.join('", "')}"). Received: ${s}.`)}let a={userIdentifier:t=r(t),userVerification:s};return n&&(a={enrollmentDetails:n,...a}),a}async allowBrowserObserversToSettle(){"undefined"!=typeof window&&("function"==typeof requestAnimationFrame&&await new Promise(e=>requestAnimationFrame(e)),await new Promise(e=>setTimeout(e,0)))}async checkIdentity(e,t){return this.zsmAPI.checkIdentity(r(e),t)}async checkEnrollment(e){({userIdentifier:e}=this.typeChecks("checkEnrollment",e));return await this.zsmAPI.webauthnRetrieve(e)}async checkAllEnrollments(e,t=!1){return this.zsmAPI.webauthnRetrieveAll(r(e),t)}async enroll(e,t="prevented"){await this.allowBrowserObserversToSettle(),({userIdentifier:e,userVerification:t}=this.typeChecks("enroll",e,t,"zsm,re-enroll,reenroll"));const r=/^re-?enroll$/.test(t),s="preferred"===t;let i,n,a;if(r||/^(preferred|required)$/.test(t)){n=await this.checkAllEnrollments(e);try{if(n.passkeySupported)if(r){if(!n.zsmCredentialID&&!n.hasLocalPasskey)return new Error(`[UMFAClient] :: enroll :: Cannot RE-enroll user's passkey; user ${e} is not currently enrolled with either ZSM or Passkeys+ credentials. To enroll the user, call enroll with a userVerification value of "preferred", "required", or "discouraged".`);i=await this.passkeyPlusEnroll(n,"required",!0)}else{if(n.zsmCredentialID&&n.hasLocalPasskey)return new Error(`[UMFAClient] :: enroll :: User ${e} is already enrolled with both ZSM and Passkeys+ credentials. To authenticate one or both credential, call the authenticate method.`);n instanceof Error||!1===n||!n.zsmCredentialID&&!n.hasLocalPasskey?i=await this.passkeyPlusEnroll(n,t):n.zsmCredentialID&&!n.hasLocalPasskey?i=await this.addPasskeyToZSMCredential(n,t):!n.zsmCredentialID&&n.pkpCredential&&(i=await this.addZSMToPasskeyCredential(n,t))}else{if(!s)return new Error(`[UMFAClient] :: enroll :: Passkeys+ is required for enrollment (userVerification set to "required"), but this device does not support Passkeys+. User ${e} cannot be enrolled. Please use a Passkeys+-compatible device to enroll.`);console.warn(`[UMFAClient] :: enroll :: Passkeys+ enrollment has been requested, but this device does not support Passkeys+. User ${e} will be enrolled with ZSM-only credentials. Please use a Passkeys+-compatible device to enroll with Passkeys+ in the future.`)}return void 0===i?new Error(`[UMFAClient] :: enroll :: Unexpected PKP flow: PKP enrollment attempted but no result was returned for user ${e}.`):i}catch(r){if(console.error("ENROLL FLOW :: PASSKEY OPERATION FAILED ::",r),!s)return new Error(`[UMFAClient] :: enroll :: The passkey portion of the Passkeys+ enrollment failed for user ${e} with error: ${r.message||r}. Since userVerification is set to "${t}", the entire enrollment process has failed. You may: retry, downgrade the userVerification mandate to "preferred" or "discouraged" to allow for ZSM-only enrollment.`)}}if(a=n?.zsmCredentialID?n?.zsmCredentialID:await this.checkEnrollment(e),"string"==typeof a)return new Error(`[UMFAClient] :: enroll :: User ${e} is already enrolled with a ZSM credential. To authenticate it, call the authenticate method.`);await this.zsmAPI.checkIdentity(e,!0);const l=await this.zsmAPI.webauthnCreate(e);return l instanceof Error?new Error(`[UMFAClient] :: enroll :: Unable to enroll ${e}!\nDetails:\n${l?.message||l}`,{cause:l?.stack}):l}async authenticate(e,t="prevented"){await this.allowBrowserObserversToSettle(),({userIdentifier:e,userVerification:t}=this.typeChecks("authenticate",e,t,"zsm"));const r=/^(preferred|required)$/.test(t),s="preferred"===t;let i,n,a;if(r){if(n=await this.checkAllEnrollments(e),!n.zsmCredentialID)return new Error(`[UMFAClient] :: authenticate :: User ${e} must be enrolled with a ZSM credential before authenticating. Please enroll the user first.`);if(!n.passkeySupported)return new Error(`[UMFAClient] :: authenticate :: User ${e} is not eligible for Passkeys+ authentication; their device does not support passkey authentication. To authenticate, call the authenticate method with userVerification set to "preferred", "discouraged", or "prevented"/"zsm". To enroll with Passkeys+, call enroll with userVerification set to "preferred" or "required" on a Passkeys+-compatible device.`);if(!n.hasLocalPasskey)return new Error(`[UMFAClient] :: authenticate :: User ${e} must be enrolled with both ZSM and Passkeys+ credentials to authenticate using Passkeys+ (userVerification set to a non-prevented value).`);if(r){try{i=await this.passkeyPlusAuthenticate(n,t)}catch(r){if(!s)return new Error(`[UMFAClient] :: authenticate :: The passkey portion of the Passkeys+ authentication failed for user ${e} with error: ${r.message||r}. Since userVerification is set to "${t}", the entire authentication process has failed. You may: retry or downgrade the userVerification mandate to "preferred" or "discouraged" to allow for ZSM-only authentication.`)}return void 0===i?new Error(`[UMFAClient] :: authenticate :: Unexpected PKP flow: PKP authentication attempted but no result was returned for user ${e}.`):i}}a=n?.zsmCredentialID?n?.zsmCredentialID:await this.checkEnrollment(e);if(!1===("string"==typeof a))return new Error(`[UMFAClient] :: authenticate :: ${e} is not enrolled. To authenticate the user, please enroll them first by calling the enroll method.`);const l=await this.zsmAPI.webauthnPartialGet(e);return l?.credential??l}async addPasskey(e,t="required"){let r,s;return await this.allowBrowserObserversToSettle(),({userIdentifier:e,userVerification:t,enrollmentDetails:r}=this.typeChecks("addPasskey",e,t,"re-enroll,reenroll")),s=r?await this.zsmAPI.pkpCreate(r||e,t):await this.addPasskeyToZSMCredential(r||e,t),s}async passkeyPlusEnroll(e,t="preferred",r=!1){await this.allowBrowserObserversToSettle(),({userIdentifier:e,userVerification:t}=this.typeChecks("passkeyPlusEnroll",e,t,"re-enroll,reenroll"));return await this.zsmAPI.pkpCreate(e,t,!1,r)}async passkeyPlusAuthenticate(e,t="preferred"){await this.allowBrowserObserversToSettle();let r=null;({userIdentifier:e,userVerification:t,enrollmentDetails:r}=this.typeChecks("passkeyPlusAuthenticate",e,t,"re-enroll,reenroll")),r||(r=await this.checkAllEnrollments(e,!0));return await this.zsmAPI.pkpAuthenticate(r,t,!r.zsmCredentialID)}async addZSMToPasskeyCredential(e,t){({userIdentifier:e}=this.typeChecks("addZSMToPasskeyCredential",e));return await this.passkeyPlusAuthenticate(e)}async addPasskeyToZSMCredential(e,t="preferred"){let r=null;({userIdentifier:e,userVerification:t,enrollmentDetails:r}=this.typeChecks("addPasskeyToZSMCredential",e,t,"re-enroll,reenroll"));return await this.zsmAPI.pkpAddPasskeyCredential(r||e,t)}async unenroll(e){if(({userIdentifier:e}=this.typeChecks("unenroll",e)),!1===await this.checkEnrollment(e))return!1;let t=await this.zsmAPI.unbindFromDevice(e);if(t instanceof Error)throw`Unable to unenroll ${e}'s identity from this device.\nDetails:\n${t}`;return!0===t}async resetDevice(){this.zsmAPI.webauthnReset()}}
|
package/Utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=e=>{if("string"!=typeof e||0===e.length)throw new TypeError(`[Utils] :: b64urlToBuf :: This method expects a base64 encoded string as input. Received: "${e}" (of type ${typeof e} and length ${e.length}).`);const t=
|
|
1
|
+
const e=e=>{if("string"!=typeof e||0===e.length)throw new TypeError(`[Utils] :: b64urlToBuf :: This method expects a base64 encoded string as input. Received: "${e}" (of type ${typeof e} and length ${e.length}).`);const t=e.replace(/-/g,"+").replace(/_/g,"/"),r=t.padEnd(4*Math.ceil(t.length/4),"="),n=atob(r);return Uint8Array.from(n,e=>e.charCodeAt(0)).buffer},t=e=>null===e||"object"!=typeof e?e:e instanceof Map?Object.fromEntries([...e].map(([e,r])=>[e,t(r)])):Array.isArray(e)?e.map(t):Object.fromEntries(Object.entries(e).map(([e,r])=>[e,t(r)]));export{e as b64urlToBuf,t as toObject};
|
package/WebAuthnClientBase.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"./EventCoordinator.js";import t from"./GlobalScoping.js";import{uid2iid as r,iid4uid as i}from"./IdentityIndexing.js";import{toObject as n}from"./Utils.js";import{zsmPluginManager as s}from"./PluginManager.js";import a from"./PasskeysPlusClient.js";e.update("WebAuthnClientBase");const o=(e=!1)=>{const t=[[(new Date).toISOString(),"TRACEPRIMER"]];return e?{trace:t}:t};export default class{constructor(r){const n=e=>!!(e=>{try{return new URL(e),!0}catch{return!1}})(e)&&new URL(e).origin+"/";this.passkeysPlus=new a,r?.region&&(r.authenticator_host_url||=r.authenticator_host=`https://zsm-authenticator-${r.region}.useideem.com/`,r.zsm_host_url||=r.zsm_host=`https://zsm-${r.region}.useideem.com/`);const o={application_id:"",api_key:"",host_url:"https://zsm-authenticator-demo.useideem.com/",installation_description:"undefined"!=typeof navigator?navigator?.userAgent:"No Agent Found",log_level:"Debug",request_timeout_ms:3e5,retry_count:0,consumer_id:"",use_passkeys:!0};!1!==r?.use_passkeys&&!1!==r?.use_origin||(delete r.use_passkeys,delete r.use_origin),this.zsmApi=void 0,this.relyingParty=void 0,this.status=void 0,this.config=void 0,r.host_url=n(r.host_url)||null,null==r.host_url&&null!=r.host&&(r.host_url=n(r.host)||`https://zsm-authenticator-${r.host}.useideem.com/`),n(r.host_url)||delete r.host_url,r=Object.assign(o,r),r?.authenticator_host_url||(r.authenticator_host=r.authenticator_host_url=r.host_url),r?.zsm_host_url||(r.zsm_host_url=r.zsm_host=r.host_url.replace("zsm-authenticator","zsm")),r.host_url=r.zsm_host_url,r.api_key??=r?.application_id??"NO APPLICATION_ID PROVIDED! CHECK YOUR zsm_app_config.json!",this.config=t.zsmAppConfig=r,i(this.config.consumer_id).then(e=>{t.mpcConfig=Object.assign({},r,{consumer_id:e}),t.mpcConfig?.use_passkeys&&(t.mpcConfig.use_origin=!0,delete t.mpcConfig.use_passkeys),this.MPCConfig=Object.assign({},t.mpcConfig),this.zsmApi=this.primeZsmApi();const i=s.classes("RELYINGPARTY");this.relyingParty=new i(this.config.authenticator_host_url,this.config.api_key,this.config.application_id,this.config.application_environment,this.config?.use_passkeys??void 0),this.userIdentifier=r.consumer_id}).then(()=>t.dispatchEvent(new CustomEvent("WebAuthnClientReady",{bubbles:!0,cancelable:!1,detail:!0}))).catch(e=>console.error("Error during initialization:",e)).finally(()=>e.update("WebAuthnClientBase","READY"))}get userIdentifier(){return this.relyingParty.customerDefinedIdentifier}set userIdentifier(e){return this.relyingParty.customerDefinedIdentifier=e}get customerDefinedIdentifier(){return this.relyingParty.customerDefinedIdentifier}set customerDefinedIdentifier(e){return this.relyingParty.customerDefinedIdentifier=e}get token(){return this.relyingParty.token}get credentialID(){return this.relyingParty.credentialID}set credentialID(e){return this.relyingParty.credentialID=e}get isEnrolled(){return!!this.credentialID}async getZsmApi(e){}async primeZsmApi(){return this.zsmApi?this.zsmApi:this.zsmApi=await this.getZsmApi(Object.assign({},t.mpcConfig,{consumer_id:await i(t.mpcConfig.consumer_id)}))}async initializeZsm(){return t.mpcConfig.consumer_id!==this.MPCConfig.consumer_id&&(await this.zsmApi.configure(t.mpcConfig),this.MPCConfig=await Object.assign({},t.mpcConfig),await r(this.config.consumer_id,this.MPCConfig.consumer_id)),await this.zsmApi}async checkIdentity(e,i=!1){if(null==e||""===e)throw new Error(`[WebAuthnClient] :: checkIdentity :: A userIdentifier String is required! Received: ${e}.`);e&&"string"==typeof e&&(this.userIdentifier=e);try{const n=await this.relyingParty.checkServerSideIdentity(i);if(!n)throw new Error("Unable to communicate with identity server!");const s=Array.isArray(n)?n[0].identity_id:n.identity_id;if(!s)throw new Error("Unable to acquire identity_id!");return r(e,s),t.mpcConfig.consumer_id=s,s}catch(e){return Promise.reject(e)}}async webauthnRetrieve(e,r=!1,s=!1){if(null==e||"string"!=typeof e||""===e)throw new Error(`[WebAuthnClient] :: webauthnRetrieve :: A userIdentifier String is required! Received: ${e} (of type ${typeof e}).`);e&&"string"==typeof e&&(this.userIdentifier=e),this.credentialID=null,this.initializeZsm("webauthnRetrieve");let a=await i(e);t.mpcConfig.consumer_id=a;const o=await this.zsmApi.webauthn_retrieve(e);let l=n(o);if(!r)return!(l?.error||!l?.result)&&(this.credentialID=l.result.zsm_credential_id??null);l=l?.error||!l?.result?{}:l.result;let u=!1;try{u=!!navigator?.credentials}catch{}this.credentialID=l.zsm_credential_id??null;let h=l;if(s||u&&!l?.has_remote_passkey&&!l?.passkey_credential_id||!l?.zsm_active||!l?.zsm_active){let t=await this.checkRemoteEnrollmentDetails(e,h);!t||t instanceof Error||(h=Object.assign({},l,t))}const c={userIdentifier:e,enrollmentActive:h?.zsm_active??!1,passkeySupported:u,passkeyEligible:u&&!(!h?.passkey_credential_id&&!h?.has_remote_passkey),hasLocalPasskey:u&&!!h?.passkey_credential_id,hasRemotePasskey:!!h?.rcr??null,pkpCredentialID:h?.passkey_credential_id??null,pkpCredID:h?.passkey_credential_id??null,hasZSMCred:!!h?.zsm_credential||!1,zsmCredential:h?.zsm_credential??null,zsmCredentialID:h?.zsm_credential_id??null,zsmCredID:h?.zsm_credential_id??null,isUsingPasswordManager:CredentialsContainer.prototype.get.toString()===navigator.credentials.get.toString()};return!0===c.hasLocalPasskey&&(c.hasRemotePasskey=!0),h?.rcr&&(c.pkpCredential=h.rcr,c.hasLocalPasskey=!0,c.pkpCredentialID||(c.pkpCredentialID=h.rcr?.publicKey?.allowCredentials?.flatMap(e=>e.id)??null,c.pkpCredentialID.length&&(c.pkpCredentialID=c.pkpCredentialID[0]))),c}async webauthnRetrieveAll(e,t=!1){return await this.webauthnRetrieve(e,!0,t)}async checkRemoteEnrollmentDetails(e,t){try{const r=await this.relyingParty.getRemoteEnrollmentDetails(e,t);return!(r instanceof Error||!r||null==r.identity_id)&&r}catch(e){return console.error("Error checking remote enrollment details:",e),!1}}async webauthnCreate(e){if(!e)throw new Error(`[WebAuthnClient] :: webauthnCreate :: A userIdentifier String is required! Received: ${e}.`);e&&"string"==typeof e&&(this.userIdentifier=e),await this.initializeZsm("webauthnCreate");const r=await this.relyingParty.registrationStart();if(r instanceof Error)throw new Error(r);if(!r)throw new Error("[WebAuthnClient] :: webauthnCreate :: Unable to retrieve public key from Relying Party Server!");r.user_id=r.user.id;let i=await this.zsmApi.webauthn_create(r,void 0,e,o());if(!i)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreate :: Unable to obtain response from Crypto Server!");if(i=n(i),t.dispatchEvent(new CustomEvent("MPCResponse",{bubbles:!0,cancelable:!1,detail:i})),!i?.result)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreate :: Unable to obtain credential from Crypto Server!");if(!i?.result?.response)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreate :: Unable to acquire attestation object!");const s=i.result,a=await this.relyingParty.registrationFinish(s);if(a instanceof Error)throw new Error(a);if(0==a)throw new Error("[WebAuthnClient] :: webauthnCreate :: Unable to verify credential Relying Party Server!");return a}async webauthnGet(e){if(null==e||""===e)throw new Error(`[WebAuthnClient] :: webauthnGet :: A userIdentifier String is required! Received: ${e}.`);e&&"string"==typeof e&&(this.userIdentifier=e),await this.initializeZsm("webauthnGet");const r=await this.webauthnRetrieve(e,!0);if(!this.isEnrolled)throw new Error(`[WebAuthnClient] :: webauthnGet :: ${e} is not enrolled, lacks a credential, or credential is corrupted!`);let i=await this.relyingParty.authenticationStart(r);if(i instanceof Error)throw new Error(i);if(!i)throw new Error("[WebAuthnClient] :: webauthnGet :: Unable to start authentication with Relying Party Server!");if(i=n(i),!i?.rcr?.publicKey?.challenge)throw new Error("[WebAuthnClient] :: webauthnGet :: Unable to locate public key/challenge inside Relying Party Server response!\nResponse Body: "+JSON.stringify(i));const s=i.rcr.publicKey;let a=await this.zsmApi.webauthn_get(s,void 0,e,o());if(!a)throw new Error("[WebAuthnClient - mpc_round] :: webauthnGet :: Crypto server did not respond!");if(a=n(a),!a?.result)throw new Error("[WebAuthnClient - mpc_round] :: webauthnGet :: Response from Crypto Server did not contain a credential!\nResponse Body: "+JSON.stringify(a));return t.dispatchEvent(new CustomEvent("MPCResponse",{bubbles:!0,cancelable:!1,detail:a})),a.result}async webauthnPartialGet(e){if(null==e||""===e)throw new Error(`[WebAuthnClient] :: webauthnPartialGet :: A userIdentifier String is required! Received: ${e}.`);if(e&&"string"==typeof e&&(this.userIdentifier=e),this.status="AUTHENTICATION_STARTING",await this.initializeZsm("webauthnPartialGet"),!this.isEnrolled)throw new Error(`[WebAuthnClient] :: webauthnPartialGet :: Credential is missing for ${e}`);let r=await this.relyingParty.authenticationStart(this.credentialID);if(!r)throw new Error("[WebAuthnClient] :: webauthnPartialGet :: Unable to start authentication with Relying Party Server!");if(r=n(r),!r?.rcr||!r.rcr.publicKey)throw new Error("[WebAuthnClient] :: webauthnPartialGet :: Unable to retrieve public key from Relying Party Server!");const i=r.rcr.publicKey;let s=await this.zsmApi.webauthn_get(i,null,e,o());if(!s)throw new Error("[WebAuthnClient - mpc_round] :: webauthnPartialGet :: Unable to obtain mpcResponse from Crypto Server!");if(s=n(s),!s?.result)throw new Error("[WebAuthnClient - mpc_round] :: webauthnPartialGet :: Unable to obtain credential from Crypto Server!");return t.dispatchEvent(new CustomEvent("MPCResponse",{bubbles:!0,cancelable:!1,detail:s})),s.result}async unbindFromDevice(e){if(null==e||""===e)throw new Error(`[WebAuthnClient] :: unbindFromDevice :: A userIdentifier String is required! Received: ${e}.`);if(e&&"string"==typeof e&&(this.userIdentifier=e),this.status="UNENROLL_STARTING",e!==this.userIdentifier)return!1;await this.initializeZsm("unbindFromDevice");const t=await this.webauthnRetrieve(e);if(!t)return!1;const r=await i(e);return await new Promise((i,n)=>{const s=indexedDB.open("ideem",1);s.onerror=()=>n(new Error(`[WebAuthnClient] :: unbindFromDevice :: Unable to open indexedDB for ${e}`)),s.onsuccess=s=>{const a=s.target.result.transaction("zsm","readwrite"),o=a.objectStore("zsm");a.oncomplete=()=>i(),a.onerror=()=>n(new Error(`[WebAuthnClient] :: unbindFromDevice :: transaction failed for ${e}`)),a.onabort=()=>n(new Error(`[WebAuthnClient] :: unbindFromDevice :: transaction aborted for ${e}`));const l=o.openCursor();l.onerror=()=>n(new Error(`[WebAuthnClient] :: unbindFromDevice :: cursor failed for ${e}`)),l.onsuccess=i=>{const n=i.target.result;if(n){const{key:i,value:s}=n,a="string"==typeof s&&(s.includes(e)||s===r),l="object"==typeof s&&null!==s&&s.zsm_credential instanceof Map&&s.zsm_credential.get("rawId")===t;(i.includes(e)||a||l)&&o.delete(i),n.continue()}}}}),this.status="UNENROLL_COMPLETE",!0}async webauthnCreateFromPKP(e,r,i){if(null==e||""===e)throw new TypeError(`[PK+ WebAuthnClient] :: webauthnCreateFromPKP :: A userIdentifier String is required! Received: ${e}.`);if(e&&"string"==typeof e&&(this.userIdentifier=e),!r)throw new TypeError("[WebAuthnClient] :: webauthnCreateFromPKP :: Missing publicKey parameter!");if(!i)throw new TypeError("[WebAuthnClient] :: webauthnCreateFromPKP :: Missing pairing_token parameter!");await this.initializeZsm("webauthnCreate");let s=await this.zsmApi.webauthn_create(r,i,e);if(!s)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreateFromPKP :: Unable to obtain response from Crypto Server!");if(s=n(s),t.dispatchEvent(new CustomEvent("MPCResponse",{bubbles:!0,cancelable:!1,detail:s})),!s?.result)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreateFromPKP :: Unable to obtain credential from Crypto Server!");if(!s?.result?.response)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreateFromPKP :: Unable to acquire attestation object!");return s.result}async webauthnGetFromPKP(e,r,i){if(null==e||""===e)throw new Error(`[PK+ WebAuthnClient] :: webauthnGetFromPKP :: A userIdentifier String is required! Received: ${e}.`);if(e&&"string"==typeof e&&(this.userIdentifier=e),!r)throw new TypeError("[WebAuthnClient] :: webauthnGetFromPKP :: Missing publicKey parameter!");if(!i)throw new TypeError("[WebAuthnClient] :: webauthnGetFromPKP :: Missing pairing_token parameter!");let s=await this.zsmApi.webauthn_get(r,i,e);if(!s)throw new Error("[WebAuthnClient - mpc_round] :: webauthnGetFromPKP :: Crypto server did not respond!");if(s=n(s),!s?.result)throw new Error("[WebAuthnClient - mpc_round] :: webauthnGetFromPKP :: Response from Crypto Server did not contain a credential!\nResponse Body: "+JSON.stringify(s));t.dispatchEvent(new CustomEvent("MPCResponse",{bubbles:!0,cancelable:!1,detail:s}));return s.result}async pkpCreate(e,t="preferred",i=!1){let n=null;if(i&&"object"==typeof e){const r=Object.assign({},e);if(n=e.zsmCredentialID,this.userIdentifier=e=e.userIdentifier,null==e||"string"!=typeof e||""===e)throw new TypeError(`[PK+ WebAuthnClient] :: pkpCreate :: A userIdentifier String is required! Received: ${e}.`);this.userIdentifier=e;const i=await this.relyingParty.pkpAuthenticationStart(r);if(!i)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: No response from ZSM API's attempt to interface with Relying Party Server!");const s=await this.passkeysPlus.pkpGetPasskeyCredential(i,t);if(!s)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: Unable to call Platform Authenticator to create Passkey!");const a=await this.relyingParty.pkpAuthenticationFinish(s);if(!a)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: Platform Authenticator response was invalid!");const o=a?.response?.ccr?.publicKey??a?.response?.rcr?.publicKey;let l=await this.webauthnGetFromPKP(e,o,a.response.token);return this.zsmCredentialId=l.rawId,Promise.resolve(l)}{if(null==e||"string"!=typeof e||""===e)throw new TypeError(`[PK+ WebAuthnClient] :: pkpCreate :: A userIdentifier String is required! Received: ${e}.`);this.userIdentifier=e;const i=await this.relyingParty.pkpRegistrationStart(e,t,n);if(!i)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: No response from ZSM API's attempt to interface with Relying Party Server!");const s=i?.publicKey;if(!s)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: No publicKey found in Relying Party Challenge!");const a=await this.passkeysPlus.pkpCreatePasskeyCredential(s,t);if(!a)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: Unable to call Platform Authenticator to create Passkey!");const o=await this.relyingParty.pkpRegistrationFinish(a);if(!o)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: Platform Authenticator response was invalid!");r("pk:"+e,a.id);const l=o?.response?.ccr?.publicKey??o?.response?.rcr?.publicKey;let u=await this.webauthnCreateFromPKP(e,l,o.response.token);return this.zsmCredentialId=u.rawId,Promise.resolve(u)}}async pkpAuthenticate(e,t="preferred",r=!1){let i=null;if(e&&"object"==typeof e&&(i={...e},this.userIdentifier=e=e.userIdentifier),null==e||""===e)throw new Error(`[PK+ WebAuthnClient] :: pkpAuthenticate :: A userIdentifier String is required! Received: ${e}.`);let n=null;if(this.userIdentifier=e,n=await this.relyingParty.pkpAuthenticationStart(i),!n)throw new Error("[PK+ WebAuthnClient] :: pkpAuthenticate :: Unable to retrieve Platform Authority Challenge from Relying Party Server!");const s=await this.passkeysPlus.pkpGetPasskeyCredential(n,t);if(!s)throw new Error("[PK+ WebAuthnClient] :: pkpAuthenticate :: Unable to call Platform Authenticator to create Passkey!");const a=await this.relyingParty.pkpAuthenticationFinish(s);if(!a)throw new Error("[PK+ WebAuthnClient] :: pkpAuthenticate :: Platform Authenticator response was invalid!");const o=a?.response?.ccr?.publicKey??a?.response?.rcr?.publicKey;return r?await this.webauthnCreateFromPKP(e,o,a.response.token):await this.webauthnGetFromPKP(e,o,a.response.token)}async pkpAddZSMCredential(e){if(null==e||""===e)throw new Error(`[PK+ WebAuthnClient] :: pkpAddZSMCredential :: A userIdentifier String is required! Received: ${e}.`);e&&"string"==typeof e&&(this.userIdentifier=e);const t=await this.webauthnRetrieveAll(e);if(!1===t)throw new Error("[PK+ WebAuthnClient] :: pkpAddZSMCredential :: Cannot add ZSM; no passkey credentials registered for this user!");return t.userIdentifier=e,this.pkpAuthenticate(t,"required",!0)}async pkpAddPasskeyCredential(e,t="preferred"){let r=null;if(e&&"object"==typeof e?(r={...e},this.userIdentifier=e=e.userIdentifier):(this.userIdentifier=e,r=await this.webauthnRetrieveAll(e,!0)),r instanceof Error)throw new Error(`[WebAuthnClient] :: pkpAddPasskeyCredential :: Unable to retrieve existing credentials for userIdentifier: ${e}. Details: ${r.message||r}`);if(!r?.zsmCredentialID)throw new Error(`[WebAuthnClient] :: pkpAddPasskeyCredential :: userIdentifier: ${e} does not have an existing ZSM credential!`);return this.pkpCreate(r.hasLocalPasskey?Object.assign({},r,{userIdentifier:e}):e,t,r.hasLocalPasskey)}async checkForPasskeysOnOtherDevice(e){if(null==e||""===e)throw new Error(`[PK+ WebAuthnClient] :: checkForPasskeysOnOtherDevice :: A userIdentifier String is required! Received: ${e}.`);e&&"string"==typeof e&&(this.userIdentifier=e);try{this.userIdentifier=e;const t=await this.relyingParty.makePostRequest("api/passkey/bootstrap/start").catch(e=>!1);return!(!t||t instanceof Error)&&(0!==(t?.rcr?.publicKey?.allowCredentials?.length??0)&&((t?.rcr?.publicKey?.allowCredentials?.length??0)>=1?(r("pk:"+e,t.rcr.publicKey.allowCredentials[0].id),t.rcr.publicKey.allowCredentials[0].id):(t?.rcr?.publicKey?.challenge&&(t.rcr.publicKey.challenge=this.passkeysPlus.toArrayBuffer(t.rcr.publicKey.challenge)),t?.rcr?.publicKey?.allowCredentials&&(t.rcr.publicKey.allowCredentials=t.rcr.publicKey.allowCredentials.map(e=>({...e,id:this.passkeysPlus.toArrayBuffer(e.id)}))),t)))}catch(e){return!1}}webauthnReset=()=>this.relyingParty.resetAll();resetDevice=this.webauthnReset}
|
|
1
|
+
import e from"./EventCoordinator.js";import t from"./GlobalScoping.js";import{uid2iid as r,iid4uid as i}from"./IdentityIndexing.js";import{toObject as n}from"./Utils.js";import{zsmPluginManager as s}from"./PluginManager.js";import a from"./PasskeysPlusClient.js";e.update("WebAuthnClientBase");const o=(e=!1)=>{const t=[[(new Date).toISOString(),"TRACEPRIMER"]];return e?{trace:t}:t};export default class{constructor(r){const n=e=>!!(e=>{try{return new URL(e),!0}catch{return!1}})(e)&&new URL(e).origin+"/";this.passkeysPlus=new a,r?.region&&(r.authenticator_host_url||=r.authenticator_host=`https://zsm-authenticator-${r.region}.useideem.com/`,r.zsm_host_url||=r.zsm_host=`https://zsm-${r.region}.useideem.com/`);const o={application_id:"",api_key:"",host_url:"https://zsm-authenticator-demo.useideem.com/",installation_description:"undefined"!=typeof navigator?navigator?.userAgent:"No Agent Found",log_level:"Debug",request_timeout_ms:3e5,retry_count:0,consumer_id:"",use_passkeys:!0};!1!==r?.use_passkeys&&!1!==r?.use_origin||(delete r.use_passkeys,delete r.use_origin),this.zsmApi=void 0,this.relyingParty=void 0,this.status=void 0,this.config=void 0,r.host_url=n(r.host_url)||null,null==r.host_url&&null!=r.host&&(r.host_url=n(r.host)||`https://zsm-authenticator-${r.host}.useideem.com/`),n(r.host_url)||delete r.host_url,r=Object.assign(o,r),r?.authenticator_host_url||(r.authenticator_host=r.authenticator_host_url=r.host_url),r?.zsm_host_url||(r.zsm_host_url=r.zsm_host=r.host_url.replace("zsm-authenticator","zsm")),r.host_url=r.zsm_host_url,r.api_key||=r?.application_id||"NO APPLICATION_ID PROVIDED! CHECK YOUR zsm_app_config.json!",this.config=t.zsmAppConfig=r,i(this.config.consumer_id).then(e=>{t.mpcConfig=Object.assign({},r,{consumer_id:e}),t.mpcConfig?.use_passkeys&&(t.mpcConfig.use_origin=!0,delete t.mpcConfig.use_passkeys),this.MPCConfig=Object.assign({},t.mpcConfig),this.zsmApi=this.primeZsmApi();const i=s.classes("RELYINGPARTY");this.relyingParty=new i(this.config.authenticator_host_url,this.config.api_key,this.config.application_id,this.config.application_environment,this.config?.use_passkeys??void 0,this.config.metadata),this.userIdentifier=r.consumer_id}).then(()=>t.dispatchEvent(new CustomEvent("WebAuthnClientReady",{bubbles:!0,cancelable:!1,detail:!0}))).catch(e=>console.error("Error during initialization:",e)).finally(()=>e.update("WebAuthnClientBase","READY"))}get userIdentifier(){return this.relyingParty.customerDefinedIdentifier}set userIdentifier(e){return this.relyingParty.customerDefinedIdentifier=e}get customerDefinedIdentifier(){return this.relyingParty.customerDefinedIdentifier}set customerDefinedIdentifier(e){return this.relyingParty.customerDefinedIdentifier=e}get token(){return this.relyingParty.token}get credentialID(){return this.relyingParty.credentialID}set credentialID(e){return this.relyingParty.credentialID=e}get isEnrolled(){return!!this.credentialID}get metadata(){return this.relyingParty.metadata}set metadata(e){return this.relyingParty.metadata=e}async getZsmApi(e){}async primeZsmApi(){return this.zsmApi?this.zsmApi:this.zsmApi=await this.getZsmApi(Object.assign({},t.mpcConfig,{consumer_id:await i(t.mpcConfig.consumer_id)}))}async initializeZsm(){return t.mpcConfig.consumer_id!==this.MPCConfig.consumer_id&&(await this.zsmApi.configure(t.mpcConfig),this.MPCConfig=await Object.assign({},t.mpcConfig),await r(this.config.consumer_id,this.MPCConfig.consumer_id)),await this.zsmApi}async checkIdentity(e,i=!1){if(null==e||""===e)throw new Error(`[WebAuthnClient] :: checkIdentity :: A userIdentifier String is required! Received: ${e}.`);e&&"string"==typeof e&&(this.userIdentifier=e);try{const n=await this.relyingParty.checkServerSideIdentity(i);if(!n)throw new Error("Unable to communicate with identity server!");const s=Array.isArray(n)?n[0].identity_id:n.identity_id;if(!s)throw new Error("Unable to acquire identity_id!");return r(e,s),t.mpcConfig.consumer_id=s,s}catch(e){return Promise.reject(e)}}async webauthnRetrieve(e,r=!1,s=!1){if(null==e||"string"!=typeof e||""===e)throw new Error(`[WebAuthnClient] :: webauthnRetrieve :: A userIdentifier String is required! Received: ${e} (of type ${typeof e}).`);e&&"string"==typeof e&&(this.userIdentifier=e),this.credentialID=null,this.initializeZsm("webauthnRetrieve");let a=await i(e);t.mpcConfig.consumer_id=a;const o=await this.zsmApi.webauthn_retrieve(e);let l=n(o);if(!r)return!(l?.error||!l?.result)&&(this.credentialID=l.result.zsm_credential_id??null);l=l?.error||!l?.result?{}:l.result;let u=!1;try{u=!!navigator?.credentials}catch{}this.credentialID=l.zsm_credential_id??null;let h=l;if(s||u&&!l?.has_remote_passkey&&!l?.passkey_credential_id||!l?.zsm_active||!l?.zsm_active){let t=await this.checkRemoteEnrollmentDetails(e,h);!t||t instanceof Error||(h=Object.assign({},l,t))}const c={userIdentifier:e,enrollmentActive:h?.zsm_active??!1,passkeySupported:u,passkeyEligible:u&&!(!h?.passkey_credential_id&&!h?.has_remote_passkey),hasLocalPasskey:u&&!!h?.passkey_credential_id,hasRemotePasskey:!!h?.rcr??null,pkpCredentialID:h?.passkey_credential_id??null,pkpCredID:h?.passkey_credential_id??null,hasZSMCred:!!h?.zsm_credential||!1,zsmCredential:h?.zsm_credential??null,zsmCredentialID:h?.zsm_credential_id??null,zsmCredID:h?.zsm_credential_id??null,isUsingPasswordManager:CredentialsContainer.prototype.get.toString()===navigator.credentials.get.toString()};return!0===c.hasLocalPasskey&&(c.hasRemotePasskey=!0),h?.rcr&&(c.pkpCredential=h.rcr,c.hasLocalPasskey=!0,c.pkpCredentialID||(c.pkpCredentialID=h.rcr?.publicKey?.allowCredentials?.flatMap(e=>e.id)??null,c.pkpCredentialID.length&&(c.pkpCredentialID=c.pkpCredentialID[0]))),c}async webauthnRetrieveAll(e,t=!1){return await this.webauthnRetrieve(e,!0,t)}async checkRemoteEnrollmentDetails(e,t){try{const r=await this.relyingParty.getRemoteEnrollmentDetails(e,t);return!(r instanceof Error||!r||null==r.identity_id)&&r}catch(e){return console.error("Error checking remote enrollment details:",e),!1}}async webauthnCreate(e){if(!e)throw new Error(`[WebAuthnClient] :: webauthnCreate :: A userIdentifier String is required! Received: ${e}.`);e&&"string"==typeof e&&(this.userIdentifier=e),await this.initializeZsm("webauthnCreate");const r=await this.relyingParty.registrationStart();if(r instanceof Error)throw new Error(r);if(!r)throw new Error("[WebAuthnClient] :: webauthnCreate :: Unable to retrieve public key from Relying Party Server!");r.user_id=r.user.id;let i=await this.zsmApi.webauthn_create(r,void 0,e,o());if(!i)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreate :: Unable to obtain response from Crypto Server!");if(i=n(i),t.dispatchEvent(new CustomEvent("MPCResponse",{bubbles:!0,cancelable:!1,detail:i})),!i?.result)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreate :: Unable to obtain credential from Crypto Server!");if(!i?.result?.response)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreate :: Unable to acquire attestation object!");const s=i.result,a=await this.relyingParty.registrationFinish(s);if(a instanceof Error)throw new Error(a);if(0==a)throw new Error("[WebAuthnClient] :: webauthnCreate :: Unable to verify credential Relying Party Server!");return a}async webauthnGet(e){if(null==e||""===e)throw new Error(`[WebAuthnClient] :: webauthnGet :: A userIdentifier String is required! Received: ${e}.`);e&&"string"==typeof e&&(this.userIdentifier=e),await this.initializeZsm("webauthnGet");const r=await this.webauthnRetrieve(e,!0);if(!this.isEnrolled)throw new Error(`[WebAuthnClient] :: webauthnGet :: ${e} is not enrolled, lacks a credential, or credential is corrupted!`);let i=await this.relyingParty.authenticationStart(r);if(i instanceof Error)throw new Error(i);if(!i)throw new Error("[WebAuthnClient] :: webauthnGet :: Unable to start authentication with Relying Party Server!");if(i=n(i),!i?.rcr?.publicKey?.challenge)throw new Error("[WebAuthnClient] :: webauthnGet :: Unable to locate public key/challenge inside Relying Party Server response!\nResponse Body: "+JSON.stringify(i));const s=i.rcr.publicKey;let a=await this.zsmApi.webauthn_get(s,void 0,e,o());if(!a)throw new Error("[WebAuthnClient - mpc_round] :: webauthnGet :: Crypto server did not respond!");if(a=n(a),!a?.result)throw new Error("[WebAuthnClient - mpc_round] :: webauthnGet :: Response from Crypto Server did not contain a credential!\nResponse Body: "+JSON.stringify(a));return t.dispatchEvent(new CustomEvent("MPCResponse",{bubbles:!0,cancelable:!1,detail:a})),a.result}async webauthnPartialGet(e){if(null==e||""===e)throw new Error(`[WebAuthnClient] :: webauthnPartialGet :: A userIdentifier String is required! Received: ${e}.`);if(e&&"string"==typeof e&&(this.userIdentifier=e),this.status="AUTHENTICATION_STARTING",await this.initializeZsm("webauthnPartialGet"),!this.isEnrolled)throw new Error(`[WebAuthnClient] :: webauthnPartialGet :: Credential is missing for ${e}`);let r=await this.relyingParty.authenticationStart(this.credentialID);if(!r)throw new Error("[WebAuthnClient] :: webauthnPartialGet :: Unable to start authentication with Relying Party Server!");if(r=n(r),!r?.rcr||!r.rcr.publicKey)throw new Error("[WebAuthnClient] :: webauthnPartialGet :: Unable to retrieve public key from Relying Party Server!");const i=r.rcr.publicKey;let s=await this.zsmApi.webauthn_get(i,null,e,o());if(!s)throw new Error("[WebAuthnClient - mpc_round] :: webauthnPartialGet :: Unable to obtain mpcResponse from Crypto Server!");if(s=n(s),!s?.result)throw new Error("[WebAuthnClient - mpc_round] :: webauthnPartialGet :: Unable to obtain credential from Crypto Server!");return t.dispatchEvent(new CustomEvent("MPCResponse",{bubbles:!0,cancelable:!1,detail:s})),s.result}async unbindFromDevice(e){if(null==e||""===e)throw new Error(`[WebAuthnClient] :: unbindFromDevice :: A userIdentifier String is required! Received: ${e}.`);if(e&&"string"==typeof e&&(this.userIdentifier=e),this.status="UNENROLL_STARTING",e!==this.userIdentifier)return!1;await this.initializeZsm("unbindFromDevice");const t=await this.webauthnRetrieve(e);if(!t)return!1;const r=await i(e);return await new Promise((i,n)=>{const s=indexedDB.open("ideem",1);s.onerror=()=>n(new Error(`[WebAuthnClient] :: unbindFromDevice :: Unable to open indexedDB for ${e}`)),s.onsuccess=s=>{const a=s.target.result.transaction("zsm","readwrite"),o=a.objectStore("zsm");a.oncomplete=()=>i(),a.onerror=()=>n(new Error(`[WebAuthnClient] :: unbindFromDevice :: transaction failed for ${e}`)),a.onabort=()=>n(new Error(`[WebAuthnClient] :: unbindFromDevice :: transaction aborted for ${e}`));const l=o.openCursor();l.onerror=()=>n(new Error(`[WebAuthnClient] :: unbindFromDevice :: cursor failed for ${e}`)),l.onsuccess=i=>{const n=i.target.result;if(n){const{key:i,value:s}=n,a="string"==typeof s&&(s.includes(e)||s===r),l="object"==typeof s&&null!==s&&s.zsm_credential instanceof Map&&s.zsm_credential.get("rawId")===t;(i.includes(e)||a||l)&&o.delete(i),n.continue()}}}}),this.status="UNENROLL_COMPLETE",!0}async webauthnCreateFromPKP(e,r,i){if(null==e||""===e)throw new TypeError(`[PK+ WebAuthnClient] :: webauthnCreateFromPKP :: A userIdentifier String is required! Received: ${e}.`);if(e&&"string"==typeof e&&(this.userIdentifier=e),!r)throw new TypeError("[WebAuthnClient] :: webauthnCreateFromPKP :: Missing publicKey parameter!");if(!i)throw new TypeError("[WebAuthnClient] :: webauthnCreateFromPKP :: Missing pairing_token parameter!");await this.initializeZsm("webauthnCreate");let s=await this.zsmApi.webauthn_create(r,i,e);if(!s)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreateFromPKP :: Unable to obtain response from Crypto Server!");if(s=n(s),t.dispatchEvent(new CustomEvent("MPCResponse",{bubbles:!0,cancelable:!1,detail:s})),!s?.result)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreateFromPKP :: Unable to obtain credential from Crypto Server!");if(!s?.result?.response)throw new Error("[WebAuthnClient - mpc_round] :: webauthnCreateFromPKP :: Unable to acquire attestation object!");return s.result}async webauthnGetFromPKP(e,r,i){if(null==e||""===e)throw new Error(`[PK+ WebAuthnClient] :: webauthnGetFromPKP :: A userIdentifier String is required! Received: ${e}.`);if(e&&"string"==typeof e&&(this.userIdentifier=e),!r)throw new TypeError("[WebAuthnClient] :: webauthnGetFromPKP :: Missing publicKey parameter!");if(!i)throw new TypeError("[WebAuthnClient] :: webauthnGetFromPKP :: Missing pairing_token parameter!");let s=await this.zsmApi.webauthn_get(r,i,e);if(!s)throw new Error("[WebAuthnClient - mpc_round] :: webauthnGetFromPKP :: Crypto server did not respond!");if(s=n(s),!s?.result)throw new Error("[WebAuthnClient - mpc_round] :: webauthnGetFromPKP :: Response from Crypto Server did not contain a credential!\nResponse Body: "+JSON.stringify(s));t.dispatchEvent(new CustomEvent("MPCResponse",{bubbles:!0,cancelable:!1,detail:s}));return s.result}async pkpCreate(e,t="preferred",i=!1,n=!1){let s=null;if(i&&"object"==typeof e){const r=Object.assign({},e);if(s=e.zsmCredentialID,this.userIdentifier=e=e.userIdentifier,null==e||"string"!=typeof e||""===e)throw new TypeError(`[PK+ WebAuthnClient] :: pkpCreate :: A userIdentifier String is required! Received: ${e}.`);this.userIdentifier=e;const i=await this.relyingParty.pkpAuthenticationStart(r);if(!i)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: No response from ZSM API's attempt to interface with Relying Party Server!");const n=await this.passkeysPlus.pkpGetPasskeyCredential(i,t);if(!n)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: Unable to call Platform Authenticator to create Passkey!");const a=await this.relyingParty.pkpAuthenticationFinish(n);if(!a)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: Platform Authenticator response was invalid!");const o=a?.response?.ccr?.publicKey??a?.response?.rcr?.publicKey;let l=await this.webauthnGetFromPKP(e,o,a.response.token);return this.zsmCredentialId=l.rawId,Promise.resolve(l)}{if(null==e||"string"!=typeof e||""===e)throw new TypeError(`[PK+ WebAuthnClient] :: pkpCreate :: A userIdentifier String is required! Received: ${e}.`);this.userIdentifier=e;const i=await this.relyingParty.pkpRegistrationStart(e,t,s,n);if(!i)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: No response from ZSM API's attempt to interface with Relying Party Server!");const a=i?.publicKey;if(!a)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: No publicKey found in Relying Party Challenge!");const o=await this.passkeysPlus.pkpCreatePasskeyCredential(a,t);if(!o)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: Unable to call Platform Authenticator to create Passkey!");const l=await this.relyingParty.pkpRegistrationFinish(o);if(!l)throw new Error("[PK+ WebAuthnClient] :: pkpCreate :: Platform Authenticator response was invalid!");r("pk:"+e,o.id);const u=l?.response?.ccr?.publicKey??l?.response?.rcr?.publicKey;let h=await this.webauthnCreateFromPKP(e,u,l.response.token);return this.zsmCredentialId=h.rawId,Promise.resolve(h)}}async pkpAuthenticate(e,t="preferred",r=!1){let i=null;if(e&&"object"==typeof e&&(i={...e},this.userIdentifier=e=e.userIdentifier),null==e||""===e)throw new Error(`[PK+ WebAuthnClient] :: pkpAuthenticate :: A userIdentifier String is required! Received: ${e}.`);let n=null;if(this.userIdentifier=e,n=await this.relyingParty.pkpAuthenticationStart(i),!n)throw new Error("[PK+ WebAuthnClient] :: pkpAuthenticate :: Unable to retrieve Platform Authority Challenge from Relying Party Server!");const s=await this.passkeysPlus.pkpGetPasskeyCredential(n,t);if(!s)throw new Error("[PK+ WebAuthnClient] :: pkpAuthenticate :: Unable to call Platform Authenticator to create Passkey!");const a=await this.relyingParty.pkpAuthenticationFinish(s);if(!a)throw new Error("[PK+ WebAuthnClient] :: pkpAuthenticate :: Platform Authenticator response was invalid!");const o=a?.response?.ccr?.publicKey??a?.response?.rcr?.publicKey;return r?await this.webauthnCreateFromPKP(e,o,a.response.token):await this.webauthnGetFromPKP(e,o,a.response.token)}async pkpAddZSMCredential(e){if(null==e||""===e)throw new Error(`[PK+ WebAuthnClient] :: pkpAddZSMCredential :: A userIdentifier String is required! Received: ${e}.`);e&&"string"==typeof e&&(this.userIdentifier=e);const t=await this.webauthnRetrieveAll(e);if(!1===t)throw new Error("[PK+ WebAuthnClient] :: pkpAddZSMCredential :: Cannot add ZSM; no passkey credentials registered for this user!");return t.userIdentifier=e,this.pkpAuthenticate(t,"required",!0)}async pkpAddPasskeyCredential(e,t="preferred"){let r=null;if(e&&"object"==typeof e?(r={...e},this.userIdentifier=e=e.userIdentifier):(this.userIdentifier=e,r=await this.webauthnRetrieveAll(e,!0)),r instanceof Error)throw new Error(`[WebAuthnClient] :: pkpAddPasskeyCredential :: Unable to retrieve existing credentials for userIdentifier: ${e}. Details: ${r.message||r}`);if(!r?.zsmCredentialID)throw new Error(`[WebAuthnClient] :: pkpAddPasskeyCredential :: userIdentifier: ${e} does not have an existing ZSM credential!`);return this.pkpCreate(r.hasLocalPasskey?Object.assign({},r,{userIdentifier:e}):e,t,r.hasLocalPasskey)}async checkForPasskeysOnOtherDevice(e){if(null==e||""===e)throw new Error(`[PK+ WebAuthnClient] :: checkForPasskeysOnOtherDevice :: A userIdentifier String is required! Received: ${e}.`);e&&"string"==typeof e&&(this.userIdentifier=e);try{this.userIdentifier=e;const t=await this.relyingParty.makePostRequest("api/passkey/bootstrap/start").catch(e=>!1);return!(!t||t instanceof Error)&&(0!==(t?.rcr?.publicKey?.allowCredentials?.length??0)&&((t?.rcr?.publicKey?.allowCredentials?.length??0)>=1?(r("pk:"+e,t.rcr.publicKey.allowCredentials[0].id),t.rcr.publicKey.allowCredentials[0].id):(t?.rcr?.publicKey?.challenge&&(t.rcr.publicKey.challenge=this.passkeysPlus.toArrayBuffer(t.rcr.publicKey.challenge)),t?.rcr?.publicKey?.allowCredentials&&(t.rcr.publicKey.allowCredentials=t.rcr.publicKey.allowCredentials.map(e=>({...e,id:this.passkeysPlus.toArrayBuffer(e.id)}))),t)))}catch(e){return!1}}webauthnReset=()=>this.relyingParty.resetAll();resetDevice=this.webauthnReset}
|
package/ZSMClientSDK.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"./EventCoordinator.js";import{UMFAClient as s}from"./UMFAClient.js";import{FIDO2Client as r}from"./FIDO2Client.js";import t from"./RelyingParty.js";import n from"./WebAuthnClient.js";import{zsmPluginManager as o}from"./PluginManager.js";import i from"./GlobalScoping.js";class l{constructor(s){o.freezePlugins();const r=new(o.classes("UMFAClient"))(s);return e.setCoreSDKClass("UMFAClient",r),r}}class C{constructor(s){o.freezePlugins();const r=new(o.classes("FIDO2Client"))(s);return e.setCoreSDKClass("FIDO2Client",r),r}}o.registerPlugin("Core",{classDefs:{UMFAClient:s,FIDO2Client:r,RelyingParty:t,WebAuthnClient:n},mode:"OVERRIDE"});const a="2.9.
|
|
1
|
+
import e from"./EventCoordinator.js";import{UMFAClient as s}from"./UMFAClient.js";import{FIDO2Client as r}from"./FIDO2Client.js";import t from"./RelyingParty.js";import n from"./WebAuthnClient.js";import{zsmPluginManager as o}from"./PluginManager.js";import i from"./GlobalScoping.js";class l{constructor(s){o.freezePlugins();const r=new(o.classes("UMFAClient"))(s);return e.setCoreSDKClass("UMFAClient",r),r}}class C{constructor(s){o.freezePlugins();const r=new(o.classes("FIDO2Client"))(s);return e.setCoreSDKClass("FIDO2Client",r),r}}o.registerPlugin("Core",{classDefs:{UMFAClient:s,FIDO2Client:r,RelyingParty:t,WebAuthnClient:n},mode:"OVERRIDE"});const a="2.9.3",m=i.ZSMVersions=i.ZSMVersions?{...i.ZSMVersions,CORE:a}:{CORE:a};export{l as UMFAClient,C as FIDO2Client,m as ZSMVersions};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name" : "@ideem/zsm-client-sdk",
|
|
3
|
-
"version" : "2.9.
|
|
3
|
+
"version" : "2.9.3",
|
|
4
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
5
|
"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" ],
|
|
6
6
|
"author" : "Jason Jurusz <jj@useideem.com>",
|