UNPKG

@ideem/zsm-client-sdk

Version:

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 relian

126 lines (115 loc) 7.41 kB
import eventCoordinator from './EventCoordinator.js'; import {zsmPluginManager} from './PluginManager.js'; class UMFAClientBase { /** * Base class for UMFAClient, providing methods for user enrollment and authentication. * @constructor * @param {Object} config - The configuration for ZSM initialization (ref: ./zsm_app_config.json) */ constructor(config) { if(eventCoordinator.done) eventCoordinator.reset(); eventCoordinator.update('UMFAClientBase'); this.config = config; const WebAuthnClient = zsmPluginManager.classes('WEBAUTHNCLIENT'); this.zsmAPI = new WebAuthnClient(config); this.checkEnrollment = this.checkEnrollment.bind(this); this.enroll = this.enroll.bind(this); this.authenticate = this.authenticate.bind(this); this.unenroll = this.unenroll.bind(this); this.resetDevice = this.resetDevice.bind(this); eventCoordinator.update('UMFAClientBase', 'READY'); } get userIdentifier() { return this.zsmAPI.userIdentifier; } get credentialID() { return this.zsmAPI.credentialID; } /** * @name checkEnrollment * @description Checks if a ZSM credential is enrolled on the device for the specified user * @param {string} userIdentifier The identifier for the user * @returns {Promise<Object>|boolean} Resolves with the enrollment details or false if not enrolled, or an error if checking fails * @throws {Error} If the userIdentifier is not provided or is empty * @throws {Error} If an error occurs while checking enrollment * @memberOf UMFAClientBase */ async checkEnrollment(userIdentifier) { try { if(userIdentifier == null || userIdentifier === '') throw new Error(`[UMFAClient] :: checkEnrollment :: A userIdentifier String is required! Received: ${userIdentifier}.`); return await this.zsmAPI.webauthnRetrieve(userIdentifier); } catch(e) { return new Error(e.message || e || '[UMFAClient] :: checkEnrollment :: An error occurred while attempting to check enrollment.'); } } /** * @name enroll * @description Enrolls a user by creating a ZSM credential on the device * @param {string} userIdentifier The identifier for the user * @returns {Promise<Object>|boolean} Resolves with the created credential, false if user is already enrolled, or an error if enrollment fails * @throws {Error} If the userIdentifier is not provided or is empty * @throws {Error} If an error occurs during enrollment * @throws {Error} If the object returned from the ZSM API is not valid (no credential) * @memberOf UMFAClientBase */ async enroll(userIdentifier) { try { if(userIdentifier == null || userIdentifier === '') throw new Error(`[UMFAClient] :: enroll :: A userIdentifier String is required! Received: ${userIdentifier}.`); const userIsEnrolled = await this.checkEnrollment(userIdentifier); if(userIsEnrolled !== false) return false; const createResult = await this.zsmAPI.webauthnCreateThenPartialGet(userIdentifier); if(createResult instanceof Error) throw(`[UMFAClient] :: enroll :: Unable to associate ${userIdentifier}'s identity with device profile.\nDetails:\n${createResult}`); if(!createResult?.credential) throw(`[UMFAClient] :: enroll :: Unable to acquire authentication token for ${userIdentifier}!`); return createResult.credential; }catch(e) { return new Error(e.message || e || '[UMFAClient] :: enroll :: An error occurred during enrollment.'); } } /** * @name authenticate * @description Authenticates a user by retrieving their ZSM credential * @param {string} userIdentifier The identifier for the user * @returns {Promise<Object>} Resolves with the authentication result or an error if authentication fails * @throws {Error} If the userIdentifier is not provided or is empty * @throws {Error} If an error occurs during authentication * @memberOf UMFAClientBase */ async authenticate(userIdentifier) { try { if(userIdentifier == null || userIdentifier === '') throw new Error(`[UMFAClient] :: authenticate :: A userIdentifier String is required! Received: ${userIdentifier}.`); let userIsEnrolled = await this.checkEnrollment(userIdentifier); if(userIsEnrolled === false) throw(`${userIdentifier} is not enrolled.`); let authCredential = await this.zsmAPI.webauthnPartialGet(userIdentifier); return authCredential.credential; }catch(e) { return new Error(e.message || e || '[UMFAClient] :: authenticate :: An error occurred during authentication.'); } } /** * @name unenroll * @description Unenrolls a user by removing their ZSM credential from the device * @param {string} userIdentifier The identifier for the user * @returns {Promise<boolean>} Resolves with true if unenrollment was successful, false if the user was not enrolled, or an error if unenrollment fails * @throws {Error} If the userIdentifier is not provided or is empty * @throws {Error} If an error occurs during unenrollment * @memberOf UMFAClientBase */ async unenroll(userIdentifier) { try { let userIsEnrolled = await this.checkEnrollment(userIdentifier); if(userIsEnrolled === false) return false; let unenrollResult = await this.zsmAPI.unbindFromDevice(userIdentifier); if(unenrollResult instanceof Error) throw(`Unable to unenroll ${userIdentifier}'s identity from this device.\nDetails:\n${unenrollResult}`); return unenrollResult === true; } catch(e) { return new Error(e.message || e || '[UMFAClient] :: unenroll :: An error occurred during unenrollment.'); } } /** * @name resetDevice * @description Pass-through method to call WebAuthnClient's webauthnReset * @returns {Promise<void>} No results are returned * @memberOf UMFAClientBase, WebAuthnClient */ async resetDevice() { this.zsmAPI.webauthnReset(); } } export default UMFAClientBase;