@bitblit/ratchet-warden-common 4.0.341-alpha → 4.0.342-alpha
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/lib/index.mjs +1 -1
- package/package.json +3 -3
package/lib/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{RequireRatchet as e,ErrorRatchet as t,Logger as n,StringRatchet as r,JwtRatchet as o}from"@bitblit/ratchet-common";import{BehaviorSubject as s,timer as i}from"rxjs";import{startRegistration as a,startAuthentication as c}from"@simplewebauthn/browser";class l{constructor(){}static buildInformation(){return{version:"341",hash:"4a9cbce7e86bc1a61c2ee609fb5069ba34425c62",branch:"alpha-2024-04-19-8",tag:"alpha-2024-04-19-8",timeBuiltISO:"2024-04-19T17:22:51-0700",notes:"No notes"}}}class g{commandSender;jwtProvider;constructor(t,n){this.commandSender=t,this.jwtProvider=n,e.notNullOrUndefined(t,"commandSender"),e.notNullOrUndefined(n,"jwtProvider")}async exchangeCommand(e,n){const r=JSON.stringify(e),o=await this.commandSender.sendCommand(r,this.jwtProvider.fetchCurrentLoggedInJwtToken()),s=JSON.parse(o);return s?.error&&!n&&t.throwFormattedErr("%s",s.error),s}async createAccount(e,t,n,r){const o={createAccount:{contact:e,sendCode:t,label:n,tags:r}};return(await this.exchangeCommand(o)).createAccount}async sendMagicLinkRaw(e){if(e){const t={sendMagicLink:e};return(await this.exchangeCommand(t)).sendMagicLink}return n.warn("Skipping magic link command - none supplied"),!1}async sendMagicLinkByUserId(e,t,n,r){const o={contactLookup:{userId:e,contactType:n},landingUrl:t,meta:r};return this.sendMagicLinkRaw(o)}async sendMagicLink(e,t,n){const r={contact:e,landingUrl:t,meta:n};return this.sendMagicLinkRaw(r)}async generateWebAuthnAuthenticationChallengeForUserId(e){const t={generateWebAuthnAuthenticationChallengeForUserId:e},n=await this.exchangeCommand(t);return JSON.parse(n.generateWebAuthnAuthenticationChallengeForUserId.dataAsJson)}async generateWebAuthnRegistrationChallengeForLoggedInUser(){const e=await this.exchangeCommand({generateWebAuthnRegistrationChallengeForLoggedInUser:!0});return JSON.parse(e.generateWebAuthnRegistrationChallengeForLoggedInUser.dataAsJson)}async removeWebAuthnRegistration(e,t){const n={removeWebAuthnRegistration:{userId:e,credentialId:t}};return(await this.exchangeCommand(n)).removeWebAuthnRegistration}async removeWebAuthnRegistrationFromLoggedInUser(e){const t={removeWebAuthnRegistrationFromLoggedInUser:e};return(await this.exchangeCommand(t)).removeWebAuthnRegistrationFromLoggedInUser}async removeContactFromLoggedInUser(e){const t={removeContactFromLoggedInUser:e};return(await this.exchangeCommand(t)).removeContactFromLoggedInUser}async sendExpiringValidationToken(e){const t={sendExpiringValidationToken:e};return(await this.exchangeCommand(t)).sendExpiringValidationToken}async addContactToLoggedInUser(e){const t={addContactToLoggedInUser:e};return(await this.exchangeCommand(t)).addContactToLoggedInUser}async addWebAuthnRegistrationToLoggedInUser(e,t,n){const r={addWebAuthnRegistrationToLoggedInUser:{webAuthn:{dataAsJson:JSON.stringify(n)},applicationName:e,deviceLabel:t}};return(await this.exchangeCommand(r)).addWebAuthnRegistrationToLoggedInUser}async performLoginCmd(e){const t={performLogin:e};return(await this.exchangeCommand(t)).performLogin}async refreshJwtToken(e){let t=null;if(r.trimToNull(e))try{t=(await this.exchangeCommand({refreshJwtToken:e})).refreshJwtToken}catch(e){n.error("JwtRefresh Failed : %s",e)}return t}async executeExpiringTokenBasedLogin(e,t){let r=null;try{const n={contact:e,expiringToken:t};r=await this.performLoginCmd(n)}catch(e){n.error("ExpiringToken login Failed : %s",e)}return r}}var d,u,h,p;!function(e){e.TextCapablePhoneNumber="TextCapablePhoneNumber",e.EmailAddress="EmailAddress"}(d||(d={}));class m{constructor(){}static extractContactsOfType(e,t){let n=null;return e?.contactMethods&&(n=e.contactMethods.filter((e=>e.type===t)).map((e=>e.value))),n}static validLoginRequest(e){let t=!1;return e&&(r.trimToNull(e.userId)||m.validContact(e.contact))&&(r.trimToNull(e.expiringToken)||r.trimToNull(e.jwtTokenToRefresh)||e.webAuthn)&&(t=!0),t}static stringToWardenContact(e){let t=null;const r=m.stringToContactType(e);return r?t={type:r,value:e}:n.error("Failed to convert a string to a contact type",e),t}static teamRolesToRoles(e){return e?.length?e.map((e=>m.teamRoleToRoleString(e))):[]}static roleStringsToTeamRoles(e){return e?.length?e.map((e=>m.roleStringToTeamRole(e))):[]}static roleStringToTeamRole(e){let t=null;if(e&&e.indexOf("_/_")>=0){const n=e.split("_/_");t={team:n[0],role:n[1]}}return t}static teamRoleToRoleString(e){let t=null;return e?.role&&e?.team&&(t=e.team+"_/_"+e.role),t}static stringToContactType(e){let t=null;return r.trimToNull(e)&&(t=m.stringIsEmailAddress(e)?d.EmailAddress:null,t=!t&&m.stringIsPhoneNumber(e)?d.TextCapablePhoneNumber:t),t}static validContact(e){let t=!1;if(e?.type&&r.trimToNull(e?.value))switch(e.type){case d.EmailAddress:t=m.stringIsEmailAddress(e.value);break;case d.TextCapablePhoneNumber:t=m.stringIsPhoneNumber(e.value);break;default:t=!1}return t}static stringIsEmailAddress(e){return!!e.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)}static stringIsPhoneNumber(e){return!!e.match(/^[\\+]?[(]?[0-9]{3}[)]?[-\\s\\.]?[0-9]{3}[-\\s\\.]?[0-9]{4,6}$/im)}static stripWardenEntryToSummary(e){return e?{userId:e.userId,userLabel:e.userLabel,contactMethods:e.contactMethods,webAuthnAuthenticatorSummaries:(e.webAuthnAuthenticators||[]).map((e=>m.stripWardenWebAuthnEntryToSummary(e)))}:null}static stripWardenWebAuthnEntryToSummary(e){return e?{origin:e.origin,applicationName:e.applicationName,deviceLabel:e.deviceLabel,credentialIdBase64:e.credentialIdBase64}:null}static wrapperIsExpired(e){return e?.userObject?.exp&&e.expirationEpochSeconds<Date.now()/1e3}}class L{wrapped;serveExpiredCredentials;_currentUserSubject=new s(null);constructor(e,t=!1){this.wrapped=e,this.serveExpiredCredentials=t}fetchCurrentLoggedInJwtToken(){let e=this?._currentUserSubject?.getValue();return!this.serveExpiredCredentials&&e&&m.wrapperIsExpired(e)&&(n.info("Current wrapper in the subject is expired - autostripping"),this.currentUserSubject.next(null),e=null),e?.jwtToken}get currentUserSubject(){return this._currentUserSubject}onAutomaticLogout(){this.wrapped&&this.wrapped.onAutomaticLogout()}onAutomaticTokenRefresh(e){this?.wrapped?.onAutomaticTokenRefresh&&this.wrapped.onAutomaticTokenRefresh(e)}onLoginFailure(e){this?.wrapped?.onLoginFailure&&this.wrapped.onLoginFailure(e)}onLogout(){this?.wrapped?.onLogout&&this.wrapped.onLogout(),this.currentUserSubject.next(null)}onSuccessfulLogin(e){this?.wrapped?.onSuccessfulLogin&&this.wrapped.onSuccessfulLogin(e),this.currentUserSubject.next(e)}}class f{options;loggedInTimerSubscription;_autoRefreshEnabled=!1;constructor(e){this.options=e,n.info("Initializing user service");const t=this.options.loggedInUserProvider.fetchLoggedInUserWrapper();m.wrapperIsExpired(t)?(n.info("Stored token is expired, removing it"),this.options.loggedInUserProvider.logOutUser()):this.options.eventProcessor.onSuccessfulLogin(t);const r=this.options.loginCheckTimerPingSeconds||2.5;this.loggedInTimerSubscription=i(0,1e3*r).subscribe((e=>this.checkForAutoLogoutOrRefresh(e)))}cleanShutDown(){this.loggedInTimerSubscription&&this.loggedInTimerSubscription.unsubscribe()}get serviceOptions(){return this.options}async createAccount(e,t,n,o){const s=await this.options.wardenClient.createAccount(e,t,n,o);return this.options.recentLoginProvider&&r.trimToNull(s)&&this.options.recentLoginProvider.saveNewUser(s,n,e),s}async addContactToLoggedInUser(e){return this.options.wardenClient.addContactToLoggedInUser(e)}get autoRefreshEnabled(){return this._autoRefreshEnabled}set autoRefreshEnabled(e){if(e){if(!this.options.allowAutoRefresh)throw new Error("Cannot enable auto-refresh - this is disabled in the user service options");this._autoRefreshEnabled=!0}else this._autoRefreshEnabled=!1}async checkForAutoLogoutOrRefresh(e){n.debug("Checking for auto-logout or refresh : %s",e);const t=this.fetchLoggedInUserWrapper();if(t){const e=this.options.autoLoginHandlingThresholdSeconds||10;if(t.expirationEpochSeconds-Math.floor(Date.now()/1e3)<e)if(this.autoRefreshEnabled){n.info("Under threshold, initiating auto-refresh");const e=await this.refreshToken();this.options.eventProcessor.onAutomaticTokenRefresh(e)}else n.info("Under threshold, initiating auto-logout"),this.logout()}}logout(){this.options.loggedInUserProvider.logOutUser(),this.options.eventProcessor.onLogout()}fetchLoggedInUserWrapper(){let e=this.options.loggedInUserProvider.fetchLoggedInUserWrapper();return e&&m.wrapperIsExpired(e)&&(n.info("Token is expired - auto logout triggered"),this.logout(),e=null),e}loggedInUserHasRole(e){let t=!1;if(r.trimToNull(e)){const n=this.fetchLoggedInUserWrapper(),r=e.toLowerCase();t=n?.userObject?.roles&&!!n.userObject.roles.find((e=>e.toLowerCase()===r))}return t}isLoggedIn(){return!!this.fetchLoggedInUserWrapper()}fetchLoggedInUserJwtObject(){const e=this.fetchLoggedInUserWrapper();return e?e.userObject:null}fetchLoggedInUserJwtToken(){const e=this.fetchLoggedInUserWrapper();return e?e.jwtToken:null}fetchLoggedInUserObject(){const e=this.fetchLoggedInUserJwtObject();return e?e.user:null}fetchLoggedInUserExpirationEpochSeconds(){const e=this.fetchLoggedInUserJwtObject();return e?e.exp:null}fetchLoggedInUserRemainingSeconds(){const e=this.fetchLoggedInUserJwtObject();return e?e.exp-Math.floor(Date.now()/1e3):null}updateLoggedInUserFromTokenString(e){let t=null;if(r.trimToNull(e)){n.info("updateLoggedInUserFromTokenString : %s",e);const r=o.decodeTokenNoVerify(e);r?(t={userObject:r,jwtToken:e,expirationEpochSeconds:r.exp},this.options.loggedInUserProvider.setLoggedInUserWrapper(t),this.updateRecentLoginsFromWardenEntrySummary(r.loginData),this.options.eventProcessor.onSuccessfulLogin(t)):(n.warn("Failed to parse token %s - ignoring login and triggering failure"),this.options.eventProcessor.onLoginFailure("Could not parse token string"))}else n.info("Called updateLoggedInUserFromTokenString with empty string - logging out"),this.logout();return t}async refreshToken(){let e=null;const t=this.fetchLoggedInUserWrapper();if(t){const n=await this.options.wardenClient.refreshJwtToken(t.jwtToken);e=this.updateLoggedInUserFromTokenString(n)}else n.info("Could not refresh - no token available");return e}async sendExpiringCode(e){return this.options.wardenClient.sendExpiringValidationToken(e)}async processWardenLoginResults(e){let t=null;return e?(n.info("Warden: response : %j ",e),e.jwtToken?(n.info("Applying login"),t=this.updateLoggedInUserFromTokenString(e.jwtToken)):e.error?this.options.eventProcessor.onLoginFailure(e.error):(n.error("Response contained neither token nor error"),this.options.eventProcessor.onLoginFailure("Response contained neither token nor error"))):(n.error("Login call failed"),this.options.eventProcessor.onLoginFailure("Login call returned null")),t}updateRecentLoginsFromWardenEntrySummary(e){this.options.recentLoginProvider&&e?(n.info("UserService : Saving recent login %j",e),this.options.recentLoginProvider.saveRecentLogin(e)):n.info("Not saving recent login - no storage configured or no data passed")}updateRecentLoginsFromLoggedInUserWrapper(e){this.updateRecentLoginsFromWardenEntrySummary(e?.userObject?.loginData)}async executeWebAuthnBasedLogin(e){const t=await this.executeWebAuthnLoginToWardenLoginResults(e),n=await this.processWardenLoginResults(t);return this.updateRecentLoginsFromLoggedInUserWrapper(n),n}async removeWebAuthnRegistrationFromLoggedInUser(e){return await this.options.wardenClient.removeWebAuthnRegistrationFromLoggedInUser(e)}async removeContactFromLoggedInUser(e){return await this.options.wardenClient.removeContactFromLoggedInUser(e)}async executeValidationTokenBasedLogin(e,t,r){n.info("Warden: executeValidationTokenBasedLogin : %j : %s : %s",e,t,r);const o=await this.options.wardenClient.performLoginCmd({contact:e,expiringToken:t,createUserIfMissing:r}),s=await this.processWardenLoginResults(o);return this.updateRecentLoginsFromLoggedInUserWrapper(s),s}async saveCurrentDeviceAsWebAuthnForCurrentUser(){const e=await this.options.wardenClient.generateWebAuthnRegistrationChallengeForLoggedInUser(),t=await a(e),n=r.trimToEmpty(this.options?.deviceLabelGenerator?this.options.deviceLabelGenerator():this.defaultDeviceLabelGenerator()),o=await this.options.wardenClient.addWebAuthnRegistrationToLoggedInUser(this.options.applicationName,n,t);return this.updateRecentLoginsFromWardenEntrySummary(o),o}defaultDeviceLabelGenerator(){let e="";return navigator?(e=navigator.userAgentData&&navigator.userAgentData.brands&&navigator.userAgentData.brands[1]&&navigator.userAgentData.brands[1].brand?navigator.userAgentData.brands[1].brand:navigator.userAgent,navigator.platform&&(e+=" on "+navigator.platform)):e="Unknown device",e}async executeWebAuthnLoginToWardenLoginResults(e){let t=null;try{const r=await this.options.wardenClient.generateWebAuthnAuthenticationChallengeForUserId(e);n.info("Got login challenge : %s",r);const o=await c(r);n.info("Got creds: %j",o);const s={userId:e,webAuthn:o};t=await this.options.wardenClient.performLoginCmd(s)}catch(e){n.error("WebauthN Failed : %s",e)}return t}}class w{saveRecentLogin(e){if(e?.userId){n.info("Saving recent login : %j",e);let t=this.fetchCache();t=t.filter((t=>t.user.userId!==e.userId)),t.push({user:e,lastLoginEpochMS:Date.now()}),this.updateCache(t)}else n.warn("Cannot save recent login - no login provided : %s",e)}saveNewUser(e,t,o){r.trimToNull(e)&&m.validContact(o)?this.saveRecentLogin({userId:e,contactMethods:[o],webAuthnAuthenticatorSummaries:[],userLabel:t}):n.warn("Cannot save new user - invalid data : %s : %j",e,o)}removeUser(e){let t=this.fetchCache();t=t.filter((t=>t.user.userId!==e)),this.updateCache(t)}fetchAllLogins(){return Object.assign([],this.fetchCache())}clearAllLogins(){this.updateCache([])}}class b{localStorageKey;constructor(n){this.localStorageKey=n,e.notNullUndefinedOrOnlyWhitespaceString(this.localStorageKey,"localStorageKey"),localStorage||t.throwFormattedErr("Local storage not available on this platform")}fetchLoggedInUserWrapper(){const e=localStorage.getItem(this.localStorageKey);return r.trimToNull(e)?JSON.parse(e):null}logOutUser(){this.setLoggedInUserWrapper(null)}setLoggedInUserWrapper(e){e?localStorage.setItem(this.localStorageKey,JSON.stringify(e)):localStorage.removeItem(this.localStorageKey)}}class I extends w{localStorageKey;constructor(n){super(),this.localStorageKey=n,e.notNullUndefinedOrOnlyWhitespaceString(this.localStorageKey,"localStorageKey"),localStorage||t.throwFormattedErr("Local storage not available on this platform")}fetchCache(){const e=r.trimToNull(localStorage.getItem(r.trimToNull(this.localStorageKey)));return e?JSON.parse(e):[]}updateCache(e){const t=e?JSON.stringify(e):"[]";localStorage.setItem(r.trimToNull(this.localStorageKey),t)}}class C{wrapper;fetchLoggedInUserWrapper(){return this.wrapper}logOutUser(){this.wrapper=null}setLoggedInUserWrapper(e){this.wrapper=e}}class T extends w{_cache=[];fetchCache(){return this._cache}updateCache(e){this._cache=e}}!function(e){e.ExpiringCode="ExpiringCode",e.MagicLink="MagicLink",e.Custom="Custom"}(u||(u={})),function(e){e.Verified="Verified",e.Failed="Failed",e.Error="Error"}(h||(h={})),function(e){e.ble="ble",e.internal="internal",e.nfc="nfc",e.usb="usb",e.cable="cable",e.hybrid="hybrid"}(p||(p={}));export{l as RatchetWardenCommonInfo,g as WardenClient,w as WardenClientAbstractRecentLoginProvider,b as WardenClientLocalStorageLoggedInUserProvider,I as WardenClientLocalStorageRecentLoginProvider,C as WardenClientTransientMemoryLoggedInUserProvider,T as WardenClientTransientMemoryRecentLoginProvider,d as WardenContactType,u as WardenCustomerMessageType,L as WardenDelegatingCurrentUserProvidingUserServiceEventProcessingProvider,h as WardenStoreRegistrationResponseType,f as WardenUserService,m as WardenUtils,p as WardenWebAuthnTransportFutureType};
|
|
1
|
+
import{RequireRatchet as e,ErrorRatchet as t,Logger as n,StringRatchet as r,JwtRatchet as o}from"@bitblit/ratchet-common";import{BehaviorSubject as s,timer as i}from"rxjs";import{startRegistration as a,startAuthentication as c}from"@simplewebauthn/browser";class l{constructor(){}static buildInformation(){return{version:"342",hash:"e7af85481519246f37b03eba86de39cee0704573",branch:"alpha-2024-05-08-2",tag:"alpha-2024-05-08-2",timeBuiltISO:"2024-05-08T23:41:37-0700",notes:"No notes"}}}class g{commandSender;jwtProvider;constructor(t,n){this.commandSender=t,this.jwtProvider=n,e.notNullOrUndefined(t,"commandSender"),e.notNullOrUndefined(n,"jwtProvider")}async exchangeCommand(e,n){const r=JSON.stringify(e),o=await this.commandSender.sendCommand(r,this.jwtProvider.fetchCurrentLoggedInJwtToken()),s=JSON.parse(o);return s?.error&&!n&&t.throwFormattedErr("%s",s.error),s}async createAccount(e,t,n,r){const o={createAccount:{contact:e,sendCode:t,label:n,tags:r}};return(await this.exchangeCommand(o)).createAccount}async sendMagicLinkRaw(e){if(e){const t={sendMagicLink:e};return(await this.exchangeCommand(t)).sendMagicLink}return n.warn("Skipping magic link command - none supplied"),!1}async sendMagicLinkByUserId(e,t,n,r){const o={contactLookup:{userId:e,contactType:n},landingUrl:t,meta:r};return this.sendMagicLinkRaw(o)}async sendMagicLink(e,t,n){const r={contact:e,landingUrl:t,meta:n};return this.sendMagicLinkRaw(r)}async generateWebAuthnAuthenticationChallengeForUserId(e){const t={generateWebAuthnAuthenticationChallengeForUserId:e},n=await this.exchangeCommand(t);return JSON.parse(n.generateWebAuthnAuthenticationChallengeForUserId.dataAsJson)}async generateWebAuthnRegistrationChallengeForLoggedInUser(){const e=await this.exchangeCommand({generateWebAuthnRegistrationChallengeForLoggedInUser:!0});return JSON.parse(e.generateWebAuthnRegistrationChallengeForLoggedInUser.dataAsJson)}async removeWebAuthnRegistration(e,t){const n={removeWebAuthnRegistration:{userId:e,credentialId:t}};return(await this.exchangeCommand(n)).removeWebAuthnRegistration}async removeWebAuthnRegistrationFromLoggedInUser(e){const t={removeWebAuthnRegistrationFromLoggedInUser:e};return(await this.exchangeCommand(t)).removeWebAuthnRegistrationFromLoggedInUser}async removeContactFromLoggedInUser(e){const t={removeContactFromLoggedInUser:e};return(await this.exchangeCommand(t)).removeContactFromLoggedInUser}async sendExpiringValidationToken(e){const t={sendExpiringValidationToken:e};return(await this.exchangeCommand(t)).sendExpiringValidationToken}async addContactToLoggedInUser(e){const t={addContactToLoggedInUser:e};return(await this.exchangeCommand(t)).addContactToLoggedInUser}async addWebAuthnRegistrationToLoggedInUser(e,t,n){const r={addWebAuthnRegistrationToLoggedInUser:{webAuthn:{dataAsJson:JSON.stringify(n)},applicationName:e,deviceLabel:t}};return(await this.exchangeCommand(r)).addWebAuthnRegistrationToLoggedInUser}async performLoginCmd(e){const t={performLogin:e};return(await this.exchangeCommand(t)).performLogin}async refreshJwtToken(e){let t=null;if(r.trimToNull(e))try{t=(await this.exchangeCommand({refreshJwtToken:e})).refreshJwtToken}catch(e){n.error("JwtRefresh Failed : %s",e)}return t}async executeExpiringTokenBasedLogin(e,t){let r=null;try{const n={contact:e,expiringToken:t};r=await this.performLoginCmd(n)}catch(e){n.error("ExpiringToken login Failed : %s",e)}return r}}var d,u,h,p;!function(e){e.TextCapablePhoneNumber="TextCapablePhoneNumber",e.EmailAddress="EmailAddress"}(d||(d={}));class m{constructor(){}static extractContactsOfType(e,t){let n=null;return e?.contactMethods&&(n=e.contactMethods.filter((e=>e.type===t)).map((e=>e.value))),n}static validLoginRequest(e){let t=!1;return e&&(r.trimToNull(e.userId)||m.validContact(e.contact))&&(r.trimToNull(e.expiringToken)||r.trimToNull(e.jwtTokenToRefresh)||e.webAuthn)&&(t=!0),t}static stringToWardenContact(e){let t=null;const r=m.stringToContactType(e);return r?t={type:r,value:e}:n.error("Failed to convert a string to a contact type",e),t}static teamRolesToRoles(e){return e?.length?e.map((e=>m.teamRoleToRoleString(e))):[]}static roleStringsToTeamRoles(e){return e?.length?e.map((e=>m.roleStringToTeamRole(e))):[]}static roleStringToTeamRole(e){let t=null;if(e&&e.indexOf("_/_")>=0){const n=e.split("_/_");t={team:n[0],role:n[1]}}return t}static teamRoleToRoleString(e){let t=null;return e?.role&&e?.team&&(t=e.team+"_/_"+e.role),t}static stringToContactType(e){let t=null;return r.trimToNull(e)&&(t=m.stringIsEmailAddress(e)?d.EmailAddress:null,t=!t&&m.stringIsPhoneNumber(e)?d.TextCapablePhoneNumber:t),t}static validContact(e){let t=!1;if(e?.type&&r.trimToNull(e?.value))switch(e.type){case d.EmailAddress:t=m.stringIsEmailAddress(e.value);break;case d.TextCapablePhoneNumber:t=m.stringIsPhoneNumber(e.value);break;default:t=!1}return t}static stringIsEmailAddress(e){return!!e.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)}static stringIsPhoneNumber(e){return!!e.match(/^[\\+]?[(]?[0-9]{3}[)]?[-\\s\\.]?[0-9]{3}[-\\s\\.]?[0-9]{4,6}$/im)}static stripWardenEntryToSummary(e){return e?{userId:e.userId,userLabel:e.userLabel,contactMethods:e.contactMethods,webAuthnAuthenticatorSummaries:(e.webAuthnAuthenticators||[]).map((e=>m.stripWardenWebAuthnEntryToSummary(e)))}:null}static stripWardenWebAuthnEntryToSummary(e){return e?{origin:e.origin,applicationName:e.applicationName,deviceLabel:e.deviceLabel,credentialIdBase64:e.credentialIdBase64}:null}static wrapperIsExpired(e){return e?.userObject?.exp&&e.expirationEpochSeconds<Date.now()/1e3}}class L{wrapped;serveExpiredCredentials;_currentUserSubject=new s(null);constructor(e,t=!1){this.wrapped=e,this.serveExpiredCredentials=t}fetchCurrentLoggedInJwtToken(){let e=this?._currentUserSubject?.getValue();return!this.serveExpiredCredentials&&e&&m.wrapperIsExpired(e)&&(n.info("Current wrapper in the subject is expired - autostripping"),this.currentUserSubject.next(null),e=null),e?.jwtToken}get currentUserSubject(){return this._currentUserSubject}onAutomaticLogout(){this.wrapped&&this.wrapped.onAutomaticLogout()}onAutomaticTokenRefresh(e){this?.wrapped?.onAutomaticTokenRefresh&&this.wrapped.onAutomaticTokenRefresh(e)}onLoginFailure(e){this?.wrapped?.onLoginFailure&&this.wrapped.onLoginFailure(e)}onLogout(){this?.wrapped?.onLogout&&this.wrapped.onLogout(),this.currentUserSubject.next(null)}onSuccessfulLogin(e){this?.wrapped?.onSuccessfulLogin&&this.wrapped.onSuccessfulLogin(e),this.currentUserSubject.next(e)}}class f{options;loggedInTimerSubscription;_autoRefreshEnabled=!1;constructor(e){this.options=e,n.info("Initializing user service");const t=this.options.loggedInUserProvider.fetchLoggedInUserWrapper();m.wrapperIsExpired(t)?(n.info("Stored token is expired, removing it"),this.options.loggedInUserProvider.logOutUser()):this.options.eventProcessor.onSuccessfulLogin(t);const r=this.options.loginCheckTimerPingSeconds||2.5;this.loggedInTimerSubscription=i(0,1e3*r).subscribe((e=>this.checkForAutoLogoutOrRefresh(e)))}cleanShutDown(){this.loggedInTimerSubscription&&this.loggedInTimerSubscription.unsubscribe()}get serviceOptions(){return this.options}async createAccount(e,t,n,o){const s=await this.options.wardenClient.createAccount(e,t,n,o);return this.options.recentLoginProvider&&r.trimToNull(s)&&this.options.recentLoginProvider.saveNewUser(s,n,e),s}async addContactToLoggedInUser(e){return this.options.wardenClient.addContactToLoggedInUser(e)}get autoRefreshEnabled(){return this._autoRefreshEnabled}set autoRefreshEnabled(e){if(e){if(!this.options.allowAutoRefresh)throw new Error("Cannot enable auto-refresh - this is disabled in the user service options");this._autoRefreshEnabled=!0}else this._autoRefreshEnabled=!1}async checkForAutoLogoutOrRefresh(e){n.debug("Checking for auto-logout or refresh : %s",e);const t=this.fetchLoggedInUserWrapper();if(t){const e=this.options.autoLoginHandlingThresholdSeconds||10;if(t.expirationEpochSeconds-Math.floor(Date.now()/1e3)<e)if(this.autoRefreshEnabled){n.info("Under threshold, initiating auto-refresh");const e=await this.refreshToken();this.options.eventProcessor.onAutomaticTokenRefresh(e)}else n.info("Under threshold, initiating auto-logout"),this.logout()}}logout(){this.options.loggedInUserProvider.logOutUser(),this.options.eventProcessor.onLogout()}fetchLoggedInUserWrapper(){let e=this.options.loggedInUserProvider.fetchLoggedInUserWrapper();return e&&m.wrapperIsExpired(e)&&(n.info("Token is expired - auto logout triggered"),this.logout(),e=null),e}loggedInUserHasRole(e){let t=!1;if(r.trimToNull(e)){const n=this.fetchLoggedInUserWrapper(),r=e.toLowerCase();t=n?.userObject?.roles&&!!n.userObject.roles.find((e=>e.toLowerCase()===r))}return t}isLoggedIn(){return!!this.fetchLoggedInUserWrapper()}fetchLoggedInUserJwtObject(){const e=this.fetchLoggedInUserWrapper();return e?e.userObject:null}fetchLoggedInUserJwtToken(){const e=this.fetchLoggedInUserWrapper();return e?e.jwtToken:null}fetchLoggedInUserObject(){const e=this.fetchLoggedInUserJwtObject();return e?e.user:null}fetchLoggedInUserExpirationEpochSeconds(){const e=this.fetchLoggedInUserJwtObject();return e?e.exp:null}fetchLoggedInUserRemainingSeconds(){const e=this.fetchLoggedInUserJwtObject();return e?e.exp-Math.floor(Date.now()/1e3):null}updateLoggedInUserFromTokenString(e){let t=null;if(r.trimToNull(e)){n.info("updateLoggedInUserFromTokenString : %s",e);const r=o.decodeTokenNoVerify(e);r?(t={userObject:r,jwtToken:e,expirationEpochSeconds:r.exp},this.options.loggedInUserProvider.setLoggedInUserWrapper(t),this.updateRecentLoginsFromWardenEntrySummary(r.loginData),this.options.eventProcessor.onSuccessfulLogin(t)):(n.warn("Failed to parse token %s - ignoring login and triggering failure"),this.options.eventProcessor.onLoginFailure("Could not parse token string"))}else n.info("Called updateLoggedInUserFromTokenString with empty string - logging out"),this.logout();return t}async refreshToken(){let e=null;const t=this.fetchLoggedInUserWrapper();if(t){const n=await this.options.wardenClient.refreshJwtToken(t.jwtToken);e=this.updateLoggedInUserFromTokenString(n)}else n.info("Could not refresh - no token available");return e}async sendExpiringCode(e){return this.options.wardenClient.sendExpiringValidationToken(e)}async processWardenLoginResults(e){let t=null;return e?(n.info("Warden: response : %j ",e),e.jwtToken?(n.info("Applying login"),t=this.updateLoggedInUserFromTokenString(e.jwtToken)):e.error?this.options.eventProcessor.onLoginFailure(e.error):(n.error("Response contained neither token nor error"),this.options.eventProcessor.onLoginFailure("Response contained neither token nor error"))):(n.error("Login call failed"),this.options.eventProcessor.onLoginFailure("Login call returned null")),t}updateRecentLoginsFromWardenEntrySummary(e){this.options.recentLoginProvider&&e?(n.info("UserService : Saving recent login %j",e),this.options.recentLoginProvider.saveRecentLogin(e)):n.info("Not saving recent login - no storage configured or no data passed")}updateRecentLoginsFromLoggedInUserWrapper(e){this.updateRecentLoginsFromWardenEntrySummary(e?.userObject?.loginData)}async executeWebAuthnBasedLogin(e){const t=await this.executeWebAuthnLoginToWardenLoginResults(e),n=await this.processWardenLoginResults(t);return this.updateRecentLoginsFromLoggedInUserWrapper(n),n}async removeWebAuthnRegistrationFromLoggedInUser(e){return await this.options.wardenClient.removeWebAuthnRegistrationFromLoggedInUser(e)}async removeContactFromLoggedInUser(e){return await this.options.wardenClient.removeContactFromLoggedInUser(e)}async executeValidationTokenBasedLogin(e,t,r){n.info("Warden: executeValidationTokenBasedLogin : %j : %s : %s",e,t,r);const o=await this.options.wardenClient.performLoginCmd({contact:e,expiringToken:t,createUserIfMissing:r}),s=await this.processWardenLoginResults(o);return this.updateRecentLoginsFromLoggedInUserWrapper(s),s}async saveCurrentDeviceAsWebAuthnForCurrentUser(){const e=await this.options.wardenClient.generateWebAuthnRegistrationChallengeForLoggedInUser(),t=await a(e),n=r.trimToEmpty(this.options?.deviceLabelGenerator?this.options.deviceLabelGenerator():this.defaultDeviceLabelGenerator()),o=await this.options.wardenClient.addWebAuthnRegistrationToLoggedInUser(this.options.applicationName,n,t);return this.updateRecentLoginsFromWardenEntrySummary(o),o}defaultDeviceLabelGenerator(){let e="";return navigator?(e=navigator.userAgentData&&navigator.userAgentData.brands&&navigator.userAgentData.brands[1]&&navigator.userAgentData.brands[1].brand?navigator.userAgentData.brands[1].brand:navigator.userAgent,navigator.platform&&(e+=" on "+navigator.platform)):e="Unknown device",e}async executeWebAuthnLoginToWardenLoginResults(e){let t=null;try{const r=await this.options.wardenClient.generateWebAuthnAuthenticationChallengeForUserId(e);n.info("Got login challenge : %s",r);const o=await c(r);n.info("Got creds: %j",o);const s={userId:e,webAuthn:o};t=await this.options.wardenClient.performLoginCmd(s)}catch(e){n.error("WebauthN Failed : %s",e)}return t}}class w{saveRecentLogin(e){if(e?.userId){n.info("Saving recent login : %j",e);let t=this.fetchCache();t=t.filter((t=>t.user.userId!==e.userId)),t.push({user:e,lastLoginEpochMS:Date.now()}),this.updateCache(t)}else n.warn("Cannot save recent login - no login provided : %s",e)}saveNewUser(e,t,o){r.trimToNull(e)&&m.validContact(o)?this.saveRecentLogin({userId:e,contactMethods:[o],webAuthnAuthenticatorSummaries:[],userLabel:t}):n.warn("Cannot save new user - invalid data : %s : %j",e,o)}removeUser(e){let t=this.fetchCache();t=t.filter((t=>t.user.userId!==e)),this.updateCache(t)}fetchAllLogins(){return Object.assign([],this.fetchCache())}clearAllLogins(){this.updateCache([])}}class b{localStorageKey;constructor(n){this.localStorageKey=n,e.notNullUndefinedOrOnlyWhitespaceString(this.localStorageKey,"localStorageKey"),localStorage||t.throwFormattedErr("Local storage not available on this platform")}fetchLoggedInUserWrapper(){const e=localStorage.getItem(this.localStorageKey);return r.trimToNull(e)?JSON.parse(e):null}logOutUser(){this.setLoggedInUserWrapper(null)}setLoggedInUserWrapper(e){e?localStorage.setItem(this.localStorageKey,JSON.stringify(e)):localStorage.removeItem(this.localStorageKey)}}class I extends w{localStorageKey;constructor(n){super(),this.localStorageKey=n,e.notNullUndefinedOrOnlyWhitespaceString(this.localStorageKey,"localStorageKey"),localStorage||t.throwFormattedErr("Local storage not available on this platform")}fetchCache(){const e=r.trimToNull(localStorage.getItem(r.trimToNull(this.localStorageKey)));return e?JSON.parse(e):[]}updateCache(e){const t=e?JSON.stringify(e):"[]";localStorage.setItem(r.trimToNull(this.localStorageKey),t)}}class C{wrapper;fetchLoggedInUserWrapper(){return this.wrapper}logOutUser(){this.wrapper=null}setLoggedInUserWrapper(e){this.wrapper=e}}class T extends w{_cache=[];fetchCache(){return this._cache}updateCache(e){this._cache=e}}!function(e){e.ExpiringCode="ExpiringCode",e.MagicLink="MagicLink",e.Custom="Custom"}(u||(u={})),function(e){e.Verified="Verified",e.Failed="Failed",e.Error="Error"}(h||(h={})),function(e){e.ble="ble",e.internal="internal",e.nfc="nfc",e.usb="usb",e.cable="cable",e.hybrid="hybrid"}(p||(p={}));export{l as RatchetWardenCommonInfo,g as WardenClient,w as WardenClientAbstractRecentLoginProvider,b as WardenClientLocalStorageLoggedInUserProvider,I as WardenClientLocalStorageRecentLoginProvider,C as WardenClientTransientMemoryLoggedInUserProvider,T as WardenClientTransientMemoryRecentLoginProvider,d as WardenContactType,u as WardenCustomerMessageType,L as WardenDelegatingCurrentUserProvidingUserServiceEventProcessingProvider,h as WardenStoreRegistrationResponseType,f as WardenUserService,m as WardenUtils,p as WardenWebAuthnTransportFutureType};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitblit/ratchet-warden-common",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.342-alpha",
|
|
4
4
|
"description": "Typescript library to simplify using simplewebauthn and secondary auth methods over GraphQL",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
},
|
|
48
48
|
"license": "Apache-2.0",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@bitblit/ratchet-common": "4.0.
|
|
50
|
+
"@bitblit/ratchet-common": "4.0.342-alpha",
|
|
51
51
|
"@simplewebauthn/browser": "10.0.0",
|
|
52
52
|
"jwt-decode": "4.0.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
|
-
"@bitblit/ratchet-common": "^4.0.
|
|
55
|
+
"@bitblit/ratchet-common": "^4.0.342-alpha",
|
|
56
56
|
"@simplewebauthn/browser": "^10.0.0",
|
|
57
57
|
"@simplewebauthn/types": "^10.0.0",
|
|
58
58
|
"jwt-decode": "^4.0.0"
|