@bitblit/ratchet-warden-server 4.0.210-alpha → 4.0.211-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 CHANGED
@@ -1,2 +1,2 @@
1
- import{generateRegistrationOptions as e,verifyRegistrationResponse as t,generateAuthenticationOptions as r,verifyAuthenticationResponse as n}from"@simplewebauthn/server";import{WardenUtils as i,WardenCustomerMessageType as o,WardenStoreRegistrationResponseType as a,WardenContactType as s}from"@bitblit/ratchet-warden-common";import{ExpiringCodeRatchet as d,S3CacheRatchet as l}from"@bitblit/ratchet-aws";import{RequireRatchet as c,Logger as u,ErrorRatchet as h,StringRatchet as g,ExpiredJwtHandling as p,Base64Ratchet as m,TwilioRatchet as y}from"@bitblit/ratchet-common";class f{constructor(){}static buildInformation(){return{version:"210",hash:"8490a192d81de0ea00f88a5d60add399ed69aa8e",branch:"alpha-2023-08-30-3",tag:"alpha-2023-08-30-3",timeBuiltISO:"2023-08-30T11:18:27-0700",notes:"No notes"}}}class w{async fetchDecoration(e){return{userTokenData:i.stripWardenEntryToSummary(e),userTokenExpirationSeconds:3600,userTeamRoles:[{team:"WARDEN",role:"USER"}]}}}class v{async userCreated(e){}async userRemoved(e){}}class T{inOptions;opts;expiringCodeRatchet;constructor(e){this.inOptions=e,c.notNullOrUndefined(e,"options"),c.notNullOrUndefined(e.relyingPartyName,"options.relyingPartyName"),c.notNullUndefinedOrEmptyArray(e.allowedOrigins,"options.allowedOrigins"),c.notNullOrUndefined(e.storageProvider,"options.storageProvider"),c.notNullUndefinedOrEmptyArray(e.messageSendingProviders,"options.messageSendingProviders"),c.notNullOrUndefined(e.expiringCodeProvider,"options.expiringCodeProvider"),c.notNullOrUndefined(e.jwtRatchet,"options.jwtRatchet"),this.opts=Object.assign({userTokenDataProvider:new w,eventProcessor:new v},e),this.expiringCodeRatchet=new d(this.opts.expiringCodeProvider)}get options(){return Object.assign({},this.opts)}findEntryByContact(e){return this.opts.storageProvider.findEntryByContact(e)}findEntryById(e){return this.opts.storageProvider.findEntryById(e)}async processCommandStringToString(e,t,r){let n=null;try{const i=JSON.parse(e),o=await this.processCommandToResponse(i,t,r);null===o?u.warn("Response was null for %s %s %s",e,t,r):n=JSON.stringify(o)}catch(t){const r=h.safeStringifyErr(t);u.error("Failed %s : %j",r,e,t),n=JSON.stringify({error:r})}return n}async processCommandToResponse(e,t,r){let n=null;if(e){if(u.info("Processing command : UserID: %s Origin: %s Command: %j",r,t,e),e.sendExpiringValidationToken)n={sendExpiringValidationToken:await this.sendExpiringValidationToken(e.sendExpiringValidationToken)};else if(e.generateWebAuthnAuthenticationChallengeForUserId){const r=await this.generateWebAuthnAuthenticationChallengeForUserId(e.generateWebAuthnAuthenticationChallengeForUserId,t);n={generateWebAuthnAuthenticationChallengeForUserId:{dataAsJson:JSON.stringify(r)}}}else if(e.createAccount)n={createAccount:await this.createAccount(e.createAccount.contact,e.createAccount.sendCode,e.createAccount.label,e.createAccount.tags)};else if(e.sendMagicLink){let t=e.sendMagicLink.contact;if(!t&&e?.sendMagicLink?.userId){const r=await this.findEntryById(e.sendMagicLink.userId);r&&(t=e.sendMagicLink.contactType?(r.contactMethods||[]).find((t=>t.type===e.sendMagicLink.contactType)):(r.contactMethods||[]).length>0?r.contactMethods[0]:null)}if(!t)throw h.fErr("Could not find contract entry either directly or by lookup");n={sendMagicLink:await this.sendMagicLink(t,e.sendMagicLink.landingUrl,e.sendMagicLink.meta)}}else if(e.generateWebAuthnRegistrationChallengeForLoggedInUser){g.trimToNull(r)||h.throwFormattedErr("This requires a logged in user");const e=await this.generateWebAuthnRegistrationChallengeForLoggedInUser(r,t);n={generateWebAuthnRegistrationChallengeForLoggedInUser:{dataAsJson:JSON.stringify(e)}}}else if(e.addContactToLoggedInUser)if(i.validContact(e.addContactToLoggedInUser)){n={addContactToLoggedInUser:await this.addContactMethodToUser(r,e.addContactToLoggedInUser)}}else h.throwFormattedErr("Cannot add, invalid contact %j",e.addContactToLoggedInUser);else if(e.addWebAuthnRegistrationToLoggedInUser){g.trimToNull(r)||h.throwFormattedErr("This requires a logged in user");const o=JSON.parse(e.addWebAuthnRegistrationToLoggedInUser.dataAsJson),a=await this.storeAuthnRegistration(r,t,o);n=a.updatedEntry?{addWebAuthnRegistrationToLoggedInUser:i.stripWardenEntryToSummary(a.updatedEntry)}:a.error?{error:a.error}:{error:"Cannot happen - neither user nor error set"}}else if(e.removeWebAuthnRegistration){const t=await this.removeSingleWebAuthnRegistration(e.removeWebAuthnRegistration.userId,e.removeWebAuthnRegistration.credentialId);n={removeWebAuthnRegistration:i.stripWardenEntryToSummary(t)}}else if(e.removeWebAuthnRegistrationFromLoggedInUser){const t=await this.removeSingleWebAuthnRegistration(r,e.removeWebAuthnRegistrationFromLoggedInUser);n={removeWebAuthnRegistrationFromLoggedInUser:i.stripWardenEntryToSummary(t)}}else if(e.removeContactFromLoggedInUser){const t=await this.removeContactMethodFromUser(r,e.removeContactFromLoggedInUser);n={removeContactFromLoggedInUser:i.stripWardenEntryToSummary(t)}}else if(e.performLogin){const r=e.performLogin,o=await this.processLogin(r,t);if(u.info("Performing login - login auth check was : %s",o),o){const e=g.trimToNull(r.userId)?await this.opts.storageProvider.findEntryById(r.userId):await this.opts.storageProvider.findEntryByContact(r.contact),t=await this.opts.userDecorationProvider.fetchDecoration(e),o={loginData:i.stripWardenEntryToSummary(e),user:t.userTokenData,roles:i.teamRolesToRoles(t.userTeamRoles),proxy:null},a=await this.opts.jwtRatchet.createTokenString(o,t.userTokenExpirationSeconds);n={performLogin:{request:r,userId:e.userId,jwtToken:a}}}else n={error:"Login failed"}}else if(e.refreshJwtToken){const t=await this.opts.jwtRatchet.decodeToken(e.refreshJwtToken,p.THROW_EXCEPTION),r=await this.opts.storageProvider.findEntryById(t.loginData.userId),o=await this.opts.userDecorationProvider.fetchDecoration(r),a={loginData:i.stripWardenEntryToSummary(r),user:o.userTokenData,roles:i.teamRolesToRoles(o.userTeamRoles),proxy:null};n={refreshJwtToken:await this.opts.jwtRatchet.createTokenString(a,o.userTokenExpirationSeconds)}}}else n={error:"No command sent"};return n}urlIsOnAllowedOrigin(e){let t=!1;if(e){const r=new URL(e);for(let e=0;e<this.opts.allowedOrigins.length&&!t;e++){const n=new URL(this.opts.allowedOrigins[e]);t=n.origin===r.origin&&n.protocol===r.protocol&&n.port===r.port}}return t}async sendMagicLink(e,t,r){let n=!1;if(c.notNullOrUndefined(e,"contact"),c.notNullUndefinedOrOnlyWhitespaceString(t,"landingUrl"),c.true(this.urlIsOnAllowedOrigin(t),"landingUrl is not on an allowed origin for redirect"),e?.type&&g.trimToNull(e?.value)){const i=this.senderForContact(e);if(i){const a=await this.expiringCodeRatchet.createNewCode({context:e.value,length:36,alphabet:g.UPPER_CASE_LATIN,timeToLiveSeconds:300,tags:["MagicLink"]}),s=Object.assign({},r||{},{contact:e}),d=m.safeObjectToBase64JSON(s||{});let l=t;l=l.split("{CODE}").join(a.code),l=l.split("{META}").join(d);const c=Object.assign({},s||{},{landingUrl:l,code:a.code,relyingPartyName:this.opts.relyingPartyName}),u=await i.formatMessage(e,o.MagicLink,c);n=await i.sendMessage(e,u)}else h.throwFormattedErr("No provider found for contact type %s",e.type)}else h.throwFormattedErr("Cannot send - invalid contact %j",e);return n}async createAccount(e,t,r,n){let o=null;if(i.validContact(e)){await this.opts.storageProvider.findEntryByContact(e)&&h.throwFormattedErr("Cannot create - account already exists for %j",e);this.senderForContact(e)||h.throwFormattedErr("Cannot create - no sending provider for type %s",e.type);const i=g.createType4Guid(),a=Date.now(),s={userId:i,userLabel:r||"User "+i,contactMethods:[e],tags:n||[],webAuthnAuthenticators:[],createdEpochMS:a,updatedEpochMS:a},d=await this.opts.storageProvider.saveEntry(s);o=d.userId,this?.opts?.eventProcessor&&await this.opts.eventProcessor.userCreated(d),t&&(u.info("New user %j created and send requested - sending",d),await this.sendExpiringValidationToken(e))}else h.throwFormattedErr("Cannot create - invalid contact (missing or invalid fields)");return o}async addContactMethodToUser(e,t){let r=!1;if(g.trimToNull(e)&&i.validContact(t)){const n=await this.opts.storageProvider.findEntryByContact(t);n&&n.userId!==e&&h.throwFormattedErr("Cannot add contact to this user, another user already has that contact");const i=await this.opts.storageProvider.findEntryById(e);i||h.throwFormattedErr("Cannot add contact to this user, user does not exist"),i.contactMethods.push(t),await this.opts.storageProvider.saveEntry(i),r=!0}else h.throwFormattedErr("Cannot add - invalid config : %s %j",e,t);return r}async removeContactMethodFromUser(e,t){let r=null;if(g.trimToNull(e)&&i.validContact(t)){const n=await this.opts.storageProvider.findEntryById(e);n||h.throwFormattedErr("Cannot remove contact from this user, user does not exist"),n.contactMethods=(n.contactMethods||[]).filter((e=>e.type!==t.type||e.value!==t.value)),0===n.contactMethods.length&&h.throwFormattedErr("Cannot remove the last contact method from a user"),await this.opts.storageProvider.saveEntry(n),r=await this.opts.storageProvider.findEntryById(e)}else h.throwFormattedErr("Cannot add - invalid config : %s %j",e,t);return r}async generateWebAuthnRegistrationChallengeForLoggedInUser(t,r){if(!r||!this.opts.allowedOrigins.includes(r))throw new Error("Invalid origin : "+r);const n=new URL(r).hostname,i=await this.opts.storageProvider.findEntryById(t),o=await e({rpName:this.opts.relyingPartyName,rpID:n,userID:i.userId,userName:i.userLabel,attestationType:"none",excludeCredentials:i.webAuthnAuthenticators.map((e=>({id:m.base64StringToBuffer(e.credentialPublicKeyBase64),type:"public-key",transports:e.transports})))});return await this.opts.storageProvider.updateUserChallenge(i.userId,n,o.challenge),o}async storeAuthnRegistration(e,r,n){u.info("Store authn data : %j",n);let i=null;try{if(!r||!this.opts.allowedOrigins.includes(r))throw new Error("Invalid origin : "+r);const o=new URL(r).hostname,s=await this.opts.storageProvider.findEntryById(e),d={response:n,expectedChallenge:await this.opts.storageProvider.fetchCurrentUserChallenge(s.userId,o),expectedOrigin:r,expectedRPID:o};u.info("Calling verifyRegistrationResponse: %j",d);const l=await t(d);if(u.info("verifyRegistrationResponse Result : %j",l),i={updatedEntry:null,registrationResponseId:n.id,result:l.verified?a.Verified:a.Failed},i.result===a.Verified){u.info("Storing registration");const e={counter:l.registrationInfo.counter,credentialBackedUp:l.registrationInfo.credentialBackedUp,credentialDeviceType:l.registrationInfo.credentialDeviceType,credentialIdBase64:n.id,credentialPublicKeyBase64:m.generateBase64VersionOfBuffer(Buffer.from(l.registrationInfo.credentialPublicKey))};s.webAuthnAuthenticators=(s.webAuthnAuthenticators||[]).filter((t=>t.credentialIdBase64!==e.credentialIdBase64)),s.webAuthnAuthenticators.push(e);const t=await this.opts.storageProvider.saveEntry(s);i.updatedEntry=t,u.info("Stored auth : %j",t)}}catch(e){i={registrationResponseId:n.id,result:a.Error,error:h.safeStringifyErr(e)}}return i}async generateWebAuthnAuthenticationChallengeForUserId(e,t){const r=await this.opts.storageProvider.findEntryById(e);return await this.generateWebAuthnAuthenticationChallenge(r,t)}async generateWebAuthnAuthenticationChallenge(e,t){const n=e.webAuthnAuthenticators;if(!t||!this.opts.allowedOrigins.includes(t))throw new Error("Invalid origin : "+t);const i=new URL(t).hostname,o=n.map((e=>({id:Buffer.from(e.credentialIdBase64,"base64"),type:"public-key",transports:e.transports}))),a=await r({allowCredentials:o,userVerification:"preferred"});return await this.opts.storageProvider.updateUserChallenge(e.userId,i,a.challenge),a}senderForContact(e){let t=null;return e?.type&&(t=(this.opts.messageSendingProviders||[]).find((t=>t.handlesContactType(e.type)))),t}async sendExpiringValidationToken(e){let t=!1;if(e?.type&&g.trimToNull(e?.value)){const r=this.senderForContact(e);if(r){const n=await this.expiringCodeRatchet.createNewCode({context:e.value,length:6,alphabet:"0123456789",timeToLiveSeconds:300,tags:["Login"]}),i=await r.formatMessage(e,o.ExpiringCode,{code:n.code,relyingPartyName:this.opts.relyingPartyName});t=await r.sendMessage(e,i)}else h.throwFormattedErr("No provider found for contact type %s",e.type)}else h.throwFormattedErr("Cannot send - invalid request %j",e);return t}async processLogin(e,t){u.info("Processing login : %s : %j",t,e);let r=!1;c.notNullOrUndefined(e,"request"),c.true(!!g.trimToNull(e?.userId)||i.validContact(e?.contact),"Invalid contact and no userId"),c.true(!!e?.webAuthn||!!g.trimToNull(e?.expiringToken),"You must provide one of webAuthn or expiringToken"),c.true(!e?.webAuthn||!g.trimToNull(e?.expiringToken),"WebAuthn and ExpiringToken may not BOTH be set");const n=g.trimToNull(e?.userId)?await this.opts.storageProvider.findEntryById(e?.userId):await this.opts.storageProvider.findEntryByContact(e.contact);if(n||h.throwFormattedErr("No user found for %j / %s",e?.contact,e?.userId),e.webAuthn)r=await this.loginWithWebAuthnRequest(n,t,e.webAuthn);else if(g.trimToNull(e.expiringToken)){await this.expiringCodeRatchet.checkCode(g.trimToEmpty(e.expiringToken),g.trimToEmpty(e.contact.value),!0)?r=!0:h.throwFormattedErr("Cannot login - token is invalid for this user")}return r}async loginWithWebAuthnRequest(e,t,r){let i=!1;const o=new URL(t).hostname,a=await this.opts.storageProvider.fetchCurrentUserChallenge(e.userId,o),s=(e.webAuthnAuthenticators||[]).find((e=>e.credentialIdBase64===r.id));if(!s)throw new Error(`Could not find authenticator ${r.id} for user ${e.userId}`);const d={counter:s.counter,credentialID:m.base64StringToBuffer(s.credentialIdBase64),credentialPublicKey:m.base64StringToBuffer(s.credentialPublicKeyBase64)},l={response:r,expectedChallenge:a,expectedOrigin:t,expectedRPID:o,authenticator:d};return(await n(l)).verified&&(i=!0),i}async removeSingleWebAuthnRegistration(e,t){let r=await this.opts.storageProvider.findEntryById(e);return r?(r.webAuthnAuthenticators=(r.webAuthnAuthenticators||[]).filter((e=>e.credentialIdBase64!==t)),r=await this.opts.storageProvider.saveEntry(r)):u.info("Not removing - no such user as %s",e),r}async removeUser(e){let t=!1;if(g.trimToNull(e)){const r=await this.opts.storageProvider.findEntryById(e);r?(await this.opts.storageProvider.removeEntry(e),this?.opts?.eventProcessor&&await this.opts.eventProcessor.userRemoved(r),t=!0):u.warn("Cannot remove non-existent user : %s",e)}return t}}class C{mailer;options;static defaultOptions(){return{emailBaseLayoutName:void 0,expiringTokenHtmlTemplateName:"expiring-token-request-email",expiringTokenTxtTemplateName:void 0,magicLinkHtmlTemplateName:"magic-token-request-email",magicLinkTxtTemplateName:void 0}}constructor(e,t=C.defaultOptions()){this.mailer=e,this.options=t}async formatMessage(e,t,r){const n={destinationAddresses:[e.value],subject:"Your login token"};if(t===o.ExpiringCode)await this.mailer.fillEmailBody(n,r,this.options.expiringTokenHtmlTemplateName,this.options.expiringTokenTxtTemplateName,this.options.emailBaseLayoutName);else{if(t!==o.MagicLink)throw h.fErr("No such message type : %s",t);await this.mailer.fillEmailBody(n,r,this.options.magicLinkHtmlTemplateName,this.options.magicLinkTxtTemplateName,this.options.emailBaseLayoutName)}return n}handlesContactType(e){return e===s.EmailAddress}async sendMessage(e,t){const r=await this.mailer.sendEmail(t);return u.debug("SendRawEmailResponse was : %j",r),!!r}}class E{s3;options;ratchet;constructor(e,t){this.s3=e,this.options=t,this.ratchet=new l(this.s3,this.options.bucket)}async listUserSummaries(){return(await this.fetchDataFile()).entries.map((e=>i.stripWardenEntryToSummary(e)))}async fetchDataFile(){let e=await this.ratchet.fetchCacheFileAsObject(this.options.dataFileKey);return e=e||{entries:[],challenges:[]},e}async storeDataFile(e){let t=null;return e&&(t=await this.ratchet.writeObjectToCacheFile(this.options.dataFileKey,e)),t}async fetchCurrentUserChallenge(e,t){const r=((await this.fetchDataFile()).challenges||[]).find((r=>r.userId===e&&r.relyingPartyId===t));return r||h.throwFormattedErr("fetchCurrentUserChallenge: Could not find user %s",e),r.challenge}async findEntryByContact(e){let t=null;if(e?.type&&g.trimToNull(e?.value)){t=((await this.fetchDataFile()).entries||[]).find((t=>!!(t.contactMethods||[]).find((t=>t.type===e.type&&t.value===e.value))))}return t}async findEntryById(e){let t=null;if(g.trimToNull(e)){t=((await this.fetchDataFile()).entries||[]).find((t=>t.userId===e))}return t}async removeEntry(e){const t=await this.fetchDataFile();return t.entries=(t.entries||[]).filter((t=>t.userId!==e)),await this.storeDataFile(t),!0}async saveEntry(e){let t=null;if(e&&e.userId){const r=Date.now();e.createdEpochMS=e.createdEpochMS||r,e.updatedEpochMS=r;const n=await this.fetchDataFile();n.entries=(n.entries||[]).filter((t=>t.userId!==e.userId)),n.entries.push(e),await this.storeDataFile(n),t=await this.findEntryById(e.userId)}return t}async updateUserChallenge(e,t,r){const n=await this.fetchDataFile();return n.challenges=(n.challenges||[]).filter((r=>r.userId!==e||r.relyingPartyId!==t)),n.challenges.push({userId:e,relyingPartyId:t,challenge:r,updatedEpochMS:Date.now()}),await this.storeDataFile(n),!0}}class I{optsPromise;constructor(e){this.optsPromise=e}async formatMessage(e,t,r){let n=null;if(u.info("Creating text"),t===o.ExpiringCode)n=r.code+" is your "+r.relyingPartyName+" authentication code.\n@"+r.relyingPartyName+" #"+r.code;else{if(t!==o.MagicLink)throw h.fErr("No such message type : %s",t);n="Your magic link for "+r.relyingPartyName+" is "+r.landingUrl}return n}handlesContactType(e){return e===s.TextCapablePhoneNumber}async sendMessage(e,t){const r=await this.optsPromise,n=await y.sendMessageDirect(r.accountSID,r.authToken,r.outBoundNumber,[e.value],t);return u.debug("sendMessage was : %j",n),!!n&&n.length>0}}export{f as RatchetWardenServerInfo,w as WardenDefaultUserDecorationProvider,C as WardenMailerMessageSendingProvider,v as WardenNoOpEventProcessingProvider,E as WardenS3SingleFileStorageProvider,T as WardenService,I as WardenTwilioTextMessageSendingProvider};
1
+ import{generateRegistrationOptions as e,verifyRegistrationResponse as t,generateAuthenticationOptions as r,verifyAuthenticationResponse as n}from"@simplewebauthn/server";import{WardenUtils as i,WardenCustomerMessageType as o,WardenStoreRegistrationResponseType as a,WardenContactType as s}from"@bitblit/ratchet-warden-common";import{ExpiringCodeRatchet as d,S3CacheRatchet as l}from"@bitblit/ratchet-aws";import{RequireRatchet as c,Logger as u,ErrorRatchet as h,StringRatchet as g,ExpiredJwtHandling as p,Base64Ratchet as m,TwilioRatchet as y}from"@bitblit/ratchet-common";class f{constructor(){}static buildInformation(){return{version:"211",hash:"25cbad19c15c66817022ce9d416e28ce8c674da0",branch:"alpha-2023-09-01-2",tag:"alpha-2023-09-01-2",timeBuiltISO:"2023-09-01T12:59:56-0700",notes:"No notes"}}}class w{async fetchDecoration(e){return{userTokenData:i.stripWardenEntryToSummary(e),userTokenExpirationSeconds:3600,userTeamRoles:[{team:"WARDEN",role:"USER"}]}}}class v{async userCreated(e){}async userRemoved(e){}}class T{inOptions;opts;expiringCodeRatchet;constructor(e){this.inOptions=e,c.notNullOrUndefined(e,"options"),c.notNullOrUndefined(e.relyingPartyName,"options.relyingPartyName"),c.notNullUndefinedOrEmptyArray(e.allowedOrigins,"options.allowedOrigins"),c.notNullOrUndefined(e.storageProvider,"options.storageProvider"),c.notNullUndefinedOrEmptyArray(e.messageSendingProviders,"options.messageSendingProviders"),c.notNullOrUndefined(e.expiringCodeProvider,"options.expiringCodeProvider"),c.notNullOrUndefined(e.jwtRatchet,"options.jwtRatchet"),this.opts=Object.assign({userTokenDataProvider:new w,eventProcessor:new v},e),this.expiringCodeRatchet=new d(this.opts.expiringCodeProvider)}get options(){return Object.assign({},this.opts)}findEntryByContact(e){return this.opts.storageProvider.findEntryByContact(e)}findEntryById(e){return this.opts.storageProvider.findEntryById(e)}async processCommandStringToString(e,t,r){let n=null;try{const i=JSON.parse(e),o=await this.processCommandToResponse(i,t,r);null===o?u.warn("Response was null for %s %s %s",e,t,r):n=JSON.stringify(o)}catch(t){const r=h.safeStringifyErr(t);u.error("Failed %s : %j",r,e,t),n=JSON.stringify({error:r})}return n}async processCommandToResponse(e,t,r){let n=null;if(e){if(u.info("Processing command : UserID: %s Origin: %s Command: %j",r,t,e),e.sendExpiringValidationToken)n={sendExpiringValidationToken:await this.sendExpiringValidationToken(e.sendExpiringValidationToken)};else if(e.generateWebAuthnAuthenticationChallengeForUserId){const r=await this.generateWebAuthnAuthenticationChallengeForUserId(e.generateWebAuthnAuthenticationChallengeForUserId,t);n={generateWebAuthnAuthenticationChallengeForUserId:{dataAsJson:JSON.stringify(r)}}}else if(e.createAccount)n={createAccount:await this.createAccount(e.createAccount.contact,e.createAccount.sendCode,e.createAccount.label,e.createAccount.tags)};else if(e.sendMagicLink){let t=e.sendMagicLink.contact;if(!t&&e?.sendMagicLink?.userId){const r=await this.findEntryById(e.sendMagicLink.userId);r&&(t=e.sendMagicLink.contactType?(r.contactMethods||[]).find((t=>t.type===e.sendMagicLink.contactType)):(r.contactMethods||[]).length>0?r.contactMethods[0]:null)}if(!t)throw h.fErr("Could not find contract entry either directly or by lookup");n={sendMagicLink:await this.sendMagicLink(t,e.sendMagicLink.landingUrl,e.sendMagicLink.meta,e.sendMagicLink.ttlSeconds)}}else if(e.generateWebAuthnRegistrationChallengeForLoggedInUser){g.trimToNull(r)||h.throwFormattedErr("This requires a logged in user");const e=await this.generateWebAuthnRegistrationChallengeForLoggedInUser(r,t);n={generateWebAuthnRegistrationChallengeForLoggedInUser:{dataAsJson:JSON.stringify(e)}}}else if(e.addContactToLoggedInUser)if(i.validContact(e.addContactToLoggedInUser)){n={addContactToLoggedInUser:await this.addContactMethodToUser(r,e.addContactToLoggedInUser)}}else h.throwFormattedErr("Cannot add, invalid contact %j",e.addContactToLoggedInUser);else if(e.addWebAuthnRegistrationToLoggedInUser){g.trimToNull(r)||h.throwFormattedErr("This requires a logged in user");const o=JSON.parse(e.addWebAuthnRegistrationToLoggedInUser.dataAsJson),a=await this.storeAuthnRegistration(r,t,o);n=a.updatedEntry?{addWebAuthnRegistrationToLoggedInUser:i.stripWardenEntryToSummary(a.updatedEntry)}:a.error?{error:a.error}:{error:"Cannot happen - neither user nor error set"}}else if(e.removeWebAuthnRegistration){const t=await this.removeSingleWebAuthnRegistration(e.removeWebAuthnRegistration.userId,e.removeWebAuthnRegistration.credentialId);n={removeWebAuthnRegistration:i.stripWardenEntryToSummary(t)}}else if(e.removeWebAuthnRegistrationFromLoggedInUser){const t=await this.removeSingleWebAuthnRegistration(r,e.removeWebAuthnRegistrationFromLoggedInUser);n={removeWebAuthnRegistrationFromLoggedInUser:i.stripWardenEntryToSummary(t)}}else if(e.removeContactFromLoggedInUser){const t=await this.removeContactMethodFromUser(r,e.removeContactFromLoggedInUser);n={removeContactFromLoggedInUser:i.stripWardenEntryToSummary(t)}}else if(e.performLogin){const r=e.performLogin,o=await this.processLogin(r,t);if(u.info("Performing login - login auth check was : %s",o),o){const e=g.trimToNull(r.userId)?await this.opts.storageProvider.findEntryById(r.userId):await this.opts.storageProvider.findEntryByContact(r.contact),t=await this.opts.userDecorationProvider.fetchDecoration(e),o={loginData:i.stripWardenEntryToSummary(e),user:t.userTokenData,roles:i.teamRolesToRoles(t.userTeamRoles),proxy:null},a=await this.opts.jwtRatchet.createTokenString(o,t.userTokenExpirationSeconds);n={performLogin:{request:r,userId:e.userId,jwtToken:a}}}else n={error:"Login failed"}}else if(e.refreshJwtToken){const t=await this.opts.jwtRatchet.decodeToken(e.refreshJwtToken,p.THROW_EXCEPTION),r=await this.opts.storageProvider.findEntryById(t.loginData.userId),o=await this.opts.userDecorationProvider.fetchDecoration(r),a={loginData:i.stripWardenEntryToSummary(r),user:o.userTokenData,roles:i.teamRolesToRoles(o.userTeamRoles),proxy:null};n={refreshJwtToken:await this.opts.jwtRatchet.createTokenString(a,o.userTokenExpirationSeconds)}}}else n={error:"No command sent"};return n}urlIsOnAllowedOrigin(e){let t=!1;if(e){const r=new URL(e);for(let e=0;e<this.opts.allowedOrigins.length&&!t;e++){const n=new URL(this.opts.allowedOrigins[e]);t=n.origin===r.origin&&n.protocol===r.protocol&&n.port===r.port}}return t}async sendMagicLink(e,t,r,n=300){let i=!1;if(c.notNullOrUndefined(e,"contact"),c.notNullUndefinedOrOnlyWhitespaceString(t,"landingUrl"),c.true(this.urlIsOnAllowedOrigin(t),"landingUrl is not on an allowed origin for redirect"),e?.type&&g.trimToNull(e?.value)){const a=this.senderForContact(e);if(a){const s=await this.expiringCodeRatchet.createNewCode({context:e.value,length:36,alphabet:g.UPPER_CASE_LATIN,timeToLiveSeconds:n,tags:["MagicLink"]}),d=Object.assign({},r||{},{contact:e}),l=m.safeObjectToBase64JSON(d||{});let c=t;c=c.split("{CODE}").join(s.code),c=c.split("{META}").join(l);const u=Object.assign({},d||{},{landingUrl:c,code:s.code,relyingPartyName:this.opts.relyingPartyName}),h=await a.formatMessage(e,o.MagicLink,u);i=await a.sendMessage(e,h)}else h.throwFormattedErr("No provider found for contact type %s",e.type)}else h.throwFormattedErr("Cannot send - invalid contact %j",e);return i}async createAccount(e,t,r,n){let o=null;if(i.validContact(e)){await this.opts.storageProvider.findEntryByContact(e)&&h.throwFormattedErr("Cannot create - account already exists for %j",e);this.senderForContact(e)||h.throwFormattedErr("Cannot create - no sending provider for type %s",e.type);const i=g.createType4Guid(),a=Date.now(),s={userId:i,userLabel:r||"User "+i,contactMethods:[e],tags:n||[],webAuthnAuthenticators:[],createdEpochMS:a,updatedEpochMS:a},d=await this.opts.storageProvider.saveEntry(s);o=d.userId,this?.opts?.eventProcessor&&await this.opts.eventProcessor.userCreated(d),t&&(u.info("New user %j created and send requested - sending",d),await this.sendExpiringValidationToken(e))}else h.throwFormattedErr("Cannot create - invalid contact (missing or invalid fields)");return o}async addContactMethodToUser(e,t){let r=!1;if(g.trimToNull(e)&&i.validContact(t)){const n=await this.opts.storageProvider.findEntryByContact(t);n&&n.userId!==e&&h.throwFormattedErr("Cannot add contact to this user, another user already has that contact");const i=await this.opts.storageProvider.findEntryById(e);i||h.throwFormattedErr("Cannot add contact to this user, user does not exist"),i.contactMethods.push(t),await this.opts.storageProvider.saveEntry(i),r=!0}else h.throwFormattedErr("Cannot add - invalid config : %s %j",e,t);return r}async removeContactMethodFromUser(e,t){let r=null;if(g.trimToNull(e)&&i.validContact(t)){const n=await this.opts.storageProvider.findEntryById(e);n||h.throwFormattedErr("Cannot remove contact from this user, user does not exist"),n.contactMethods=(n.contactMethods||[]).filter((e=>e.type!==t.type||e.value!==t.value)),0===n.contactMethods.length&&h.throwFormattedErr("Cannot remove the last contact method from a user"),await this.opts.storageProvider.saveEntry(n),r=await this.opts.storageProvider.findEntryById(e)}else h.throwFormattedErr("Cannot add - invalid config : %s %j",e,t);return r}async generateWebAuthnRegistrationChallengeForLoggedInUser(t,r){if(!r||!this.opts.allowedOrigins.includes(r))throw new Error("Invalid origin : "+r);const n=new URL(r).hostname,i=await this.opts.storageProvider.findEntryById(t),o=await e({rpName:this.opts.relyingPartyName,rpID:n,userID:i.userId,userName:i.userLabel,attestationType:"none",excludeCredentials:i.webAuthnAuthenticators.map((e=>({id:m.base64StringToBuffer(e.credentialPublicKeyBase64),type:"public-key",transports:e.transports})))});return await this.opts.storageProvider.updateUserChallenge(i.userId,n,o.challenge),o}async storeAuthnRegistration(e,r,n){u.info("Store authn data : %j",n);let i=null;try{if(!r||!this.opts.allowedOrigins.includes(r))throw new Error("Invalid origin : "+r);const o=new URL(r).hostname,s=await this.opts.storageProvider.findEntryById(e),d={response:n,expectedChallenge:await this.opts.storageProvider.fetchCurrentUserChallenge(s.userId,o),expectedOrigin:r,expectedRPID:o};u.info("Calling verifyRegistrationResponse: %j",d);const l=await t(d);if(u.info("verifyRegistrationResponse Result : %j",l),i={updatedEntry:null,registrationResponseId:n.id,result:l.verified?a.Verified:a.Failed},i.result===a.Verified){u.info("Storing registration");const e={counter:l.registrationInfo.counter,credentialBackedUp:l.registrationInfo.credentialBackedUp,credentialDeviceType:l.registrationInfo.credentialDeviceType,credentialIdBase64:n.id,credentialPublicKeyBase64:m.generateBase64VersionOfBuffer(Buffer.from(l.registrationInfo.credentialPublicKey))};s.webAuthnAuthenticators=(s.webAuthnAuthenticators||[]).filter((t=>t.credentialIdBase64!==e.credentialIdBase64)),s.webAuthnAuthenticators.push(e);const t=await this.opts.storageProvider.saveEntry(s);i.updatedEntry=t,u.info("Stored auth : %j",t)}}catch(e){i={registrationResponseId:n.id,result:a.Error,error:h.safeStringifyErr(e)}}return i}async generateWebAuthnAuthenticationChallengeForUserId(e,t){const r=await this.opts.storageProvider.findEntryById(e);return await this.generateWebAuthnAuthenticationChallenge(r,t)}async generateWebAuthnAuthenticationChallenge(e,t){const n=e.webAuthnAuthenticators;if(!t||!this.opts.allowedOrigins.includes(t))throw new Error("Invalid origin : "+t);const i=new URL(t).hostname,o=n.map((e=>({id:Buffer.from(e.credentialIdBase64,"base64"),type:"public-key",transports:e.transports}))),a=await r({allowCredentials:o,userVerification:"preferred"});return await this.opts.storageProvider.updateUserChallenge(e.userId,i,a.challenge),a}senderForContact(e){let t=null;return e?.type&&(t=(this.opts.messageSendingProviders||[]).find((t=>t.handlesContactType(e.type)))),t}async sendExpiringValidationToken(e){let t=!1;if(e?.type&&g.trimToNull(e?.value)){const r=this.senderForContact(e);if(r){const n=await this.expiringCodeRatchet.createNewCode({context:e.value,length:6,alphabet:"0123456789",timeToLiveSeconds:300,tags:["Login"]}),i=await r.formatMessage(e,o.ExpiringCode,{code:n.code,relyingPartyName:this.opts.relyingPartyName});t=await r.sendMessage(e,i)}else h.throwFormattedErr("No provider found for contact type %s",e.type)}else h.throwFormattedErr("Cannot send - invalid request %j",e);return t}async processLogin(e,t){u.info("Processing login : %s : %j",t,e);let r=!1;c.notNullOrUndefined(e,"request"),c.true(!!g.trimToNull(e?.userId)||i.validContact(e?.contact),"Invalid contact and no userId"),c.true(!!e?.webAuthn||!!g.trimToNull(e?.expiringToken),"You must provide one of webAuthn or expiringToken"),c.true(!e?.webAuthn||!g.trimToNull(e?.expiringToken),"WebAuthn and ExpiringToken may not BOTH be set");const n=g.trimToNull(e?.userId)?await this.opts.storageProvider.findEntryById(e?.userId):await this.opts.storageProvider.findEntryByContact(e.contact);if(n||h.throwFormattedErr("No user found for %j / %s",e?.contact,e?.userId),e.webAuthn)r=await this.loginWithWebAuthnRequest(n,t,e.webAuthn);else if(g.trimToNull(e.expiringToken)){await this.expiringCodeRatchet.checkCode(g.trimToEmpty(e.expiringToken),g.trimToEmpty(e.contact.value),!0)?r=!0:h.throwFormattedErr("Cannot login - token is invalid for this user")}return r}async loginWithWebAuthnRequest(e,t,r){let i=!1;const o=new URL(t).hostname,a=await this.opts.storageProvider.fetchCurrentUserChallenge(e.userId,o),s=(e.webAuthnAuthenticators||[]).find((e=>e.credentialIdBase64===r.id));if(!s)throw new Error(`Could not find authenticator ${r.id} for user ${e.userId}`);const d={counter:s.counter,credentialID:m.base64StringToBuffer(s.credentialIdBase64),credentialPublicKey:m.base64StringToBuffer(s.credentialPublicKeyBase64)},l={response:r,expectedChallenge:a,expectedOrigin:t,expectedRPID:o,authenticator:d};return(await n(l)).verified&&(i=!0),i}async removeSingleWebAuthnRegistration(e,t){let r=await this.opts.storageProvider.findEntryById(e);return r?(r.webAuthnAuthenticators=(r.webAuthnAuthenticators||[]).filter((e=>e.credentialIdBase64!==t)),r=await this.opts.storageProvider.saveEntry(r)):u.info("Not removing - no such user as %s",e),r}async removeUser(e){let t=!1;if(g.trimToNull(e)){const r=await this.opts.storageProvider.findEntryById(e);r?(await this.opts.storageProvider.removeEntry(e),this?.opts?.eventProcessor&&await this.opts.eventProcessor.userRemoved(r),t=!0):u.warn("Cannot remove non-existent user : %s",e)}return t}}class C{mailer;options;static defaultOptions(){return{emailBaseLayoutName:void 0,expiringTokenHtmlTemplateName:"expiring-token-request-email",expiringTokenTxtTemplateName:void 0,magicLinkHtmlTemplateName:"magic-token-request-email",magicLinkTxtTemplateName:void 0}}constructor(e,t=C.defaultOptions()){this.mailer=e,this.options=t}async formatMessage(e,t,r){const n={destinationAddresses:[e.value],subject:"Your login token"};if(t===o.ExpiringCode)await this.mailer.fillEmailBody(n,r,this.options.expiringTokenHtmlTemplateName,this.options.expiringTokenTxtTemplateName,this.options.emailBaseLayoutName);else{if(t!==o.MagicLink)throw h.fErr("No such message type : %s",t);await this.mailer.fillEmailBody(n,r,this.options.magicLinkHtmlTemplateName,this.options.magicLinkTxtTemplateName,this.options.emailBaseLayoutName)}return n}handlesContactType(e){return e===s.EmailAddress}async sendMessage(e,t){const r=await this.mailer.sendEmail(t);return u.debug("SendRawEmailResponse was : %j",r),!!r}}class E{s3;options;ratchet;constructor(e,t){this.s3=e,this.options=t,this.ratchet=new l(this.s3,this.options.bucket)}async listUserSummaries(){return(await this.fetchDataFile()).entries.map((e=>i.stripWardenEntryToSummary(e)))}async fetchDataFile(){let e=await this.ratchet.fetchCacheFileAsObject(this.options.dataFileKey);return e=e||{entries:[],challenges:[]},e}async storeDataFile(e){let t=null;return e&&(t=await this.ratchet.writeObjectToCacheFile(this.options.dataFileKey,e)),t}async fetchCurrentUserChallenge(e,t){const r=((await this.fetchDataFile()).challenges||[]).find((r=>r.userId===e&&r.relyingPartyId===t));return r||h.throwFormattedErr("fetchCurrentUserChallenge: Could not find user %s",e),r.challenge}async findEntryByContact(e){let t=null;if(e?.type&&g.trimToNull(e?.value)){t=((await this.fetchDataFile()).entries||[]).find((t=>!!(t.contactMethods||[]).find((t=>t.type===e.type&&t.value===e.value))))}return t}async findEntryById(e){let t=null;if(g.trimToNull(e)){t=((await this.fetchDataFile()).entries||[]).find((t=>t.userId===e))}return t}async removeEntry(e){const t=await this.fetchDataFile();return t.entries=(t.entries||[]).filter((t=>t.userId!==e)),await this.storeDataFile(t),!0}async saveEntry(e){let t=null;if(e&&e.userId){const r=Date.now();e.createdEpochMS=e.createdEpochMS||r,e.updatedEpochMS=r;const n=await this.fetchDataFile();n.entries=(n.entries||[]).filter((t=>t.userId!==e.userId)),n.entries.push(e),await this.storeDataFile(n),t=await this.findEntryById(e.userId)}return t}async updateUserChallenge(e,t,r){const n=await this.fetchDataFile();return n.challenges=(n.challenges||[]).filter((r=>r.userId!==e||r.relyingPartyId!==t)),n.challenges.push({userId:e,relyingPartyId:t,challenge:r,updatedEpochMS:Date.now()}),await this.storeDataFile(n),!0}}class I{optsPromise;constructor(e){this.optsPromise=e}async formatMessage(e,t,r){let n=null;if(u.info("Creating text"),t===o.ExpiringCode)n=r.code+" is your "+r.relyingPartyName+" authentication code.\n@"+r.relyingPartyName+" #"+r.code;else{if(t!==o.MagicLink)throw h.fErr("No such message type : %s",t);n="Your magic link for "+r.relyingPartyName+" is "+r.landingUrl}return n}handlesContactType(e){return e===s.TextCapablePhoneNumber}async sendMessage(e,t){const r=await this.optsPromise,n=await y.sendMessageDirect(r.accountSID,r.authToken,r.outBoundNumber,[e.value],t);return u.debug("sendMessage was : %j",n),!!n&&n.length>0}}export{f as RatchetWardenServerInfo,w as WardenDefaultUserDecorationProvider,C as WardenMailerMessageSendingProvider,v as WardenNoOpEventProcessingProvider,E as WardenS3SingleFileStorageProvider,T as WardenService,I as WardenTwilioTextMessageSendingProvider};
2
2
  //# sourceMappingURL=index.mjs.map
package/lib/index.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/build/ratchet-warden-server-info.ts","../src/server/provider/warden-default-user-decoration-provider.ts","../src/server/provider/warden-no-op-event-processing-provider.ts","../src/server/warden-service.ts","../src/server/provider/warden-mailer-message-sending-provider.ts","../src/server/provider/warden-s3-single-file-storage-provider.ts","../src/server/provider/warden-twilio-text-message-sending-provider.ts"],"sourcesContent":["export class RatchetWardenServerInfo {\n constructor() { }\n static buildInformation() {\n const val = {\n version: 'LOCAL-SNAPSHOT',\n hash: 'LOCAL-HASH',\n branch: 'LOCAL-BRANCH',\n tag: 'LOCAL-TAG',\n timeBuiltISO: 'LOCAL-TIME-ISO',\n notes: 'LOCAL-NOTES',\n };\n return val;\n }\n}\n//# sourceMappingURL=ratchet-warden-server-info.js.map","import { WardenUtils } from '@bitblit/ratchet-warden-common';\nexport class WardenDefaultUserDecorationProvider {\n async fetchDecoration(wardenUser) {\n const rval = {\n userTokenData: WardenUtils.stripWardenEntryToSummary(wardenUser),\n userTokenExpirationSeconds: 3600,\n userTeamRoles: [{ team: 'WARDEN', role: 'USER' }],\n };\n return rval;\n }\n}\n//# sourceMappingURL=warden-default-user-decoration-provider.js.map","export class WardenNoOpEventProcessingProvider {\n async userCreated(entry) { }\n async userRemoved(entry) { }\n}\n//# sourceMappingURL=warden-no-op-event-processing-provider.js.map","import { generateAuthenticationOptions, generateRegistrationOptions, verifyAuthenticationResponse, verifyRegistrationResponse, } from '@simplewebauthn/server';\nimport { WardenUtils } from '@bitblit/ratchet-warden-common';\nimport { ExpiringCodeRatchet } from '@bitblit/ratchet-aws';\nimport { Logger } from '@bitblit/ratchet-common';\nimport { StringRatchet } from '@bitblit/ratchet-common';\nimport { ErrorRatchet } from '@bitblit/ratchet-common';\nimport { RequireRatchet } from '@bitblit/ratchet-common';\nimport { ExpiredJwtHandling } from '@bitblit/ratchet-common';\nimport { Base64Ratchet } from '@bitblit/ratchet-common';\nimport { WardenDefaultUserDecorationProvider } from './provider/warden-default-user-decoration-provider.js';\nimport { WardenNoOpEventProcessingProvider } from './provider/warden-no-op-event-processing-provider.js';\nimport { WardenStoreRegistrationResponseType } from '@bitblit/ratchet-warden-common';\nimport { WardenCustomerMessageType } from '@bitblit/ratchet-warden-common';\nexport class WardenService {\n inOptions;\n opts;\n expiringCodeRatchet;\n constructor(inOptions) {\n this.inOptions = inOptions;\n RequireRatchet.notNullOrUndefined(inOptions, 'options');\n RequireRatchet.notNullOrUndefined(inOptions.relyingPartyName, 'options.relyingPartyName');\n RequireRatchet.notNullUndefinedOrEmptyArray(inOptions.allowedOrigins, 'options.allowedOrigins');\n RequireRatchet.notNullOrUndefined(inOptions.storageProvider, 'options.storageProvider');\n RequireRatchet.notNullUndefinedOrEmptyArray(inOptions.messageSendingProviders, 'options.messageSendingProviders');\n RequireRatchet.notNullOrUndefined(inOptions.expiringCodeProvider, 'options.expiringCodeProvider');\n RequireRatchet.notNullOrUndefined(inOptions.jwtRatchet, 'options.jwtRatchet');\n this.opts = Object.assign({ userTokenDataProvider: new WardenDefaultUserDecorationProvider(), eventProcessor: new WardenNoOpEventProcessingProvider() }, inOptions);\n this.expiringCodeRatchet = new ExpiringCodeRatchet(this.opts.expiringCodeProvider);\n }\n get options() {\n return Object.assign({}, this.opts);\n }\n findEntryByContact(contact) {\n return this.opts.storageProvider.findEntryByContact(contact);\n }\n findEntryById(userId) {\n return this.opts.storageProvider.findEntryById(userId);\n }\n async processCommandStringToString(cmdString, origin, loggedInUserId) {\n let rval = null;\n try {\n const cmd = JSON.parse(cmdString);\n const resp = await this.processCommandToResponse(cmd, origin, loggedInUserId);\n if (resp === null) {\n Logger.warn('Response was null for %s %s %s', cmdString, origin, loggedInUserId);\n }\n else {\n rval = JSON.stringify(resp);\n }\n }\n catch (err) {\n const errString = ErrorRatchet.safeStringifyErr(err);\n Logger.error('Failed %s : %j', errString, cmdString, err);\n rval = JSON.stringify({ error: errString });\n }\n return rval;\n }\n async processCommandToResponse(cmd, origin, loggedInUserId) {\n let rval = null;\n if (cmd) {\n Logger.info('Processing command : UserID: %s Origin: %s Command: %j', loggedInUserId, origin, cmd);\n if (cmd.sendExpiringValidationToken) {\n rval = { sendExpiringValidationToken: await this.sendExpiringValidationToken(cmd.sendExpiringValidationToken) };\n }\n else if (cmd.generateWebAuthnAuthenticationChallengeForUserId) {\n const tmp = await this.generateWebAuthnAuthenticationChallengeForUserId(cmd.generateWebAuthnAuthenticationChallengeForUserId, origin);\n rval = { generateWebAuthnAuthenticationChallengeForUserId: { dataAsJson: JSON.stringify(tmp) } };\n }\n else if (cmd.createAccount) {\n rval = {\n createAccount: await this.createAccount(cmd.createAccount.contact, cmd.createAccount.sendCode, cmd.createAccount.label, cmd.createAccount.tags),\n };\n }\n else if (cmd.sendMagicLink) {\n let contact = cmd.sendMagicLink.contact;\n if (!contact && cmd?.sendMagicLink?.userId) {\n const entry = await this.findEntryById(cmd.sendMagicLink.userId);\n if (entry) {\n if (cmd.sendMagicLink.contactType) {\n contact = (entry.contactMethods || []).find((cm) => cm.type === cmd.sendMagicLink.contactType);\n }\n else {\n contact = (entry.contactMethods || []).length > 0 ? entry.contactMethods[0] : null;\n }\n }\n }\n if (!contact) {\n throw ErrorRatchet.fErr('Could not find contract entry either directly or by lookup');\n }\n rval = {\n sendMagicLink: await this.sendMagicLink(contact, cmd.sendMagicLink.landingUrl, cmd.sendMagicLink.meta),\n };\n }\n else if (cmd.generateWebAuthnRegistrationChallengeForLoggedInUser) {\n if (!StringRatchet.trimToNull(loggedInUserId)) {\n ErrorRatchet.throwFormattedErr('This requires a logged in user');\n }\n const tmp = await this.generateWebAuthnRegistrationChallengeForLoggedInUser(loggedInUserId, origin);\n rval = { generateWebAuthnRegistrationChallengeForLoggedInUser: { dataAsJson: JSON.stringify(tmp) } };\n }\n else if (cmd.addContactToLoggedInUser) {\n if (!WardenUtils.validContact(cmd.addContactToLoggedInUser)) {\n ErrorRatchet.throwFormattedErr('Cannot add, invalid contact %j', cmd.addContactToLoggedInUser);\n }\n else {\n const out = await this.addContactMethodToUser(loggedInUserId, cmd.addContactToLoggedInUser);\n rval = { addContactToLoggedInUser: out };\n }\n }\n else if (cmd.addWebAuthnRegistrationToLoggedInUser) {\n if (!StringRatchet.trimToNull(loggedInUserId)) {\n ErrorRatchet.throwFormattedErr('This requires a logged in user');\n }\n const data = JSON.parse(cmd.addWebAuthnRegistrationToLoggedInUser.dataAsJson);\n const out = await this.storeAuthnRegistration(loggedInUserId, origin, data);\n if (out.updatedEntry) {\n rval = { addWebAuthnRegistrationToLoggedInUser: WardenUtils.stripWardenEntryToSummary(out.updatedEntry) };\n }\n else if (out.error) {\n rval = { error: out.error };\n }\n else {\n rval = { error: 'Cannot happen - neither user nor error set' };\n }\n }\n else if (cmd.removeWebAuthnRegistration) {\n const modified = await this.removeSingleWebAuthnRegistration(cmd.removeWebAuthnRegistration.userId, cmd.removeWebAuthnRegistration.credentialId);\n rval = {\n removeWebAuthnRegistration: WardenUtils.stripWardenEntryToSummary(modified),\n };\n }\n else if (cmd.removeWebAuthnRegistrationFromLoggedInUser) {\n const modified = await this.removeSingleWebAuthnRegistration(loggedInUserId, cmd.removeWebAuthnRegistrationFromLoggedInUser);\n rval = {\n removeWebAuthnRegistrationFromLoggedInUser: WardenUtils.stripWardenEntryToSummary(modified),\n };\n }\n else if (cmd.removeContactFromLoggedInUser) {\n const output = await this.removeContactMethodFromUser(loggedInUserId, cmd.removeContactFromLoggedInUser);\n rval = {\n removeContactFromLoggedInUser: WardenUtils.stripWardenEntryToSummary(output),\n };\n }\n else if (cmd.performLogin) {\n const loginData = cmd.performLogin;\n const loginOk = await this.processLogin(loginData, origin);\n Logger.info('Performing login - login auth check was : %s', loginOk);\n if (loginOk) {\n const user = StringRatchet.trimToNull(loginData.userId)\n ? await this.opts.storageProvider.findEntryById(loginData.userId)\n : await this.opts.storageProvider.findEntryByContact(loginData.contact);\n const decoration = await this.opts.userDecorationProvider.fetchDecoration(user);\n const wardenToken = {\n loginData: WardenUtils.stripWardenEntryToSummary(user),\n user: decoration.userTokenData,\n roles: WardenUtils.teamRolesToRoles(decoration.userTeamRoles),\n proxy: null,\n };\n const jwtToken = await this.opts.jwtRatchet.createTokenString(wardenToken, decoration.userTokenExpirationSeconds);\n const output = {\n request: loginData,\n userId: user.userId,\n jwtToken: jwtToken,\n };\n rval = { performLogin: output };\n }\n else {\n rval = { error: 'Login failed' };\n }\n }\n else if (cmd.refreshJwtToken) {\n const parsed = await this.opts.jwtRatchet.decodeToken(cmd.refreshJwtToken, ExpiredJwtHandling.THROW_EXCEPTION);\n const user = await this.opts.storageProvider.findEntryById(parsed.loginData.userId);\n const decoration = await this.opts.userDecorationProvider.fetchDecoration(user);\n const wardenToken = {\n loginData: WardenUtils.stripWardenEntryToSummary(user),\n user: decoration.userTokenData,\n roles: WardenUtils.teamRolesToRoles(decoration.userTeamRoles),\n proxy: null,\n };\n const newToken = await this.opts.jwtRatchet.createTokenString(wardenToken, decoration.userTokenExpirationSeconds);\n rval = {\n refreshJwtToken: newToken,\n };\n }\n }\n else {\n rval = { error: 'No command sent' };\n }\n return rval;\n }\n urlIsOnAllowedOrigin(url) {\n let rval = false;\n if (url) {\n const u = new URL(url);\n for (let i = 0; i < this.opts.allowedOrigins.length && !rval; i++) {\n const test = new URL(this.opts.allowedOrigins[i]);\n rval = test.origin === u.origin && test.protocol === u.protocol && test.port === u.port;\n }\n }\n return rval;\n }\n async sendMagicLink(contact, landingUrl, metaIn) {\n let rval = false;\n RequireRatchet.notNullOrUndefined(contact, 'contact');\n RequireRatchet.notNullUndefinedOrOnlyWhitespaceString(landingUrl, 'landingUrl');\n RequireRatchet.true(this.urlIsOnAllowedOrigin(landingUrl), 'landingUrl is not on an allowed origin for redirect');\n if (contact?.type && StringRatchet.trimToNull(contact?.value)) {\n const prov = this.senderForContact(contact);\n if (prov) {\n const token = await this.expiringCodeRatchet.createNewCode({\n context: contact.value,\n length: 36,\n alphabet: StringRatchet.UPPER_CASE_LATIN,\n timeToLiveSeconds: 300,\n tags: ['MagicLink'],\n });\n const meta = Object.assign({}, metaIn || {}, { contact: contact });\n const encodedMeta = Base64Ratchet.safeObjectToBase64JSON(meta || {});\n let landingUrlFilled = landingUrl;\n landingUrlFilled = landingUrlFilled.split('{CODE}').join(token.code);\n landingUrlFilled = landingUrlFilled.split('{META}').join(encodedMeta);\n const context = Object.assign({}, meta || {}, {\n landingUrl: landingUrlFilled,\n code: token.code,\n relyingPartyName: this.opts.relyingPartyName,\n });\n const msg = await prov.formatMessage(contact, WardenCustomerMessageType.MagicLink, context);\n rval = await prov.sendMessage(contact, msg);\n }\n else {\n ErrorRatchet.throwFormattedErr('No provider found for contact type %s', contact.type);\n }\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot send - invalid contact %j', contact);\n }\n return rval;\n }\n async createAccount(contact, sendCode, label, tags) {\n let rval = null;\n if (WardenUtils.validContact(contact)) {\n const old = await this.opts.storageProvider.findEntryByContact(contact);\n if (!!old) {\n ErrorRatchet.throwFormattedErr('Cannot create - account already exists for %j', contact);\n }\n const prov = this.senderForContact(contact);\n if (!prov) {\n ErrorRatchet.throwFormattedErr('Cannot create - no sending provider for type %s', contact.type);\n }\n const guid = StringRatchet.createType4Guid();\n const now = Date.now();\n const newUser = {\n userId: guid,\n userLabel: label || 'User ' + guid,\n contactMethods: [contact],\n tags: tags || [],\n webAuthnAuthenticators: [],\n createdEpochMS: now,\n updatedEpochMS: now,\n };\n const next = await this.opts.storageProvider.saveEntry(newUser);\n rval = next.userId;\n if (this?.opts?.eventProcessor) {\n await this.opts.eventProcessor.userCreated(next);\n }\n if (sendCode) {\n Logger.info('New user %j created and send requested - sending', next);\n await this.sendExpiringValidationToken(contact);\n }\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot create - invalid contact (missing or invalid fields)');\n }\n return rval;\n }\n async addContactMethodToUser(userId, contact) {\n let rval = false;\n if (StringRatchet.trimToNull(userId) && WardenUtils.validContact(contact)) {\n const otherUser = await this.opts.storageProvider.findEntryByContact(contact);\n if (otherUser && otherUser.userId !== userId) {\n ErrorRatchet.throwFormattedErr('Cannot add contact to this user, another user already has that contact');\n }\n const curUser = await this.opts.storageProvider.findEntryById(userId);\n if (!curUser) {\n ErrorRatchet.throwFormattedErr('Cannot add contact to this user, user does not exist');\n }\n curUser.contactMethods.push(contact);\n await this.opts.storageProvider.saveEntry(curUser);\n rval = true;\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot add - invalid config : %s %j', userId, contact);\n }\n return rval;\n }\n async removeContactMethodFromUser(userId, contact) {\n let rval = null;\n if (StringRatchet.trimToNull(userId) && WardenUtils.validContact(contact)) {\n const curUser = await this.opts.storageProvider.findEntryById(userId);\n if (!curUser) {\n ErrorRatchet.throwFormattedErr('Cannot remove contact from this user, user does not exist');\n }\n curUser.contactMethods = (curUser.contactMethods || []).filter((s) => s.type !== contact.type || s.value !== contact.value);\n if (curUser.contactMethods.length === 0) {\n ErrorRatchet.throwFormattedErr('Cannot remove the last contact method from a user');\n }\n await this.opts.storageProvider.saveEntry(curUser);\n rval = await this.opts.storageProvider.findEntryById(userId);\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot add - invalid config : %s %j', userId, contact);\n }\n return rval;\n }\n async generateWebAuthnRegistrationChallengeForLoggedInUser(userId, origin) {\n if (!origin || !this.opts.allowedOrigins.includes(origin)) {\n throw new Error('Invalid origin : ' + origin);\n }\n const asUrl = new URL(origin);\n const rpID = asUrl.hostname;\n const entry = await this.opts.storageProvider.findEntryById(userId);\n const options = await generateRegistrationOptions({\n rpName: this.opts.relyingPartyName,\n rpID: rpID,\n userID: entry.userId,\n userName: entry.userLabel,\n attestationType: 'none',\n excludeCredentials: entry.webAuthnAuthenticators.map((authenticator) => ({\n id: Base64Ratchet.base64StringToBuffer(authenticator.credentialPublicKeyBase64),\n type: 'public-key',\n transports: authenticator.transports,\n })),\n });\n await this.opts.storageProvider.updateUserChallenge(entry.userId, rpID, options.challenge);\n return options;\n }\n async storeAuthnRegistration(userId, origin, data) {\n Logger.info('Store authn data : %j', data);\n let rval = null;\n try {\n if (!origin || !this.opts.allowedOrigins.includes(origin)) {\n throw new Error('Invalid origin : ' + origin);\n }\n const asUrl = new URL(origin);\n const rpID = asUrl.hostname;\n const user = await this.opts.storageProvider.findEntryById(userId);\n const expectedChallenge = await this.opts.storageProvider.fetchCurrentUserChallenge(user.userId, rpID);\n const vrOpts = {\n response: data,\n expectedChallenge: expectedChallenge,\n expectedOrigin: origin,\n expectedRPID: rpID,\n };\n Logger.info('Calling verifyRegistrationResponse: %j', vrOpts);\n const verification = await verifyRegistrationResponse(vrOpts);\n Logger.info('verifyRegistrationResponse Result : %j', verification);\n rval = {\n updatedEntry: null,\n registrationResponseId: data.id,\n result: verification.verified ? WardenStoreRegistrationResponseType.Verified : WardenStoreRegistrationResponseType.Failed,\n };\n if (rval.result === WardenStoreRegistrationResponseType.Verified) {\n Logger.info('Storing registration');\n const newAuth = {\n counter: verification.registrationInfo.counter,\n credentialBackedUp: verification.registrationInfo.credentialBackedUp,\n credentialDeviceType: verification.registrationInfo.credentialDeviceType,\n credentialIdBase64: data.id,\n credentialPublicKeyBase64: Base64Ratchet.generateBase64VersionOfBuffer(Buffer.from(verification.registrationInfo.credentialPublicKey)),\n };\n user.webAuthnAuthenticators = (user.webAuthnAuthenticators || []).filter((wa) => wa.credentialIdBase64 !== newAuth.credentialIdBase64);\n user.webAuthnAuthenticators.push(newAuth);\n const storedUser = await this.opts.storageProvider.saveEntry(user);\n rval.updatedEntry = storedUser;\n Logger.info('Stored auth : %j', storedUser);\n }\n }\n catch (err) {\n rval = {\n registrationResponseId: data.id,\n result: WardenStoreRegistrationResponseType.Error,\n error: ErrorRatchet.safeStringifyErr(err),\n };\n }\n return rval;\n }\n async generateWebAuthnAuthenticationChallengeForUserId(userId, origin) {\n const user = await this.opts.storageProvider.findEntryById(userId);\n const rval = await this.generateWebAuthnAuthenticationChallenge(user, origin);\n return rval;\n }\n async generateWebAuthnAuthenticationChallenge(user, origin) {\n const userAuthenticators = user.webAuthnAuthenticators;\n if (!origin || !this.opts.allowedOrigins.includes(origin)) {\n throw new Error('Invalid origin : ' + origin);\n }\n const asUrl = new URL(origin);\n const rpID = asUrl.hostname;\n const out = userAuthenticators.map((authenticator) => {\n const next = {\n id: Buffer.from(authenticator.credentialIdBase64, 'base64'),\n type: 'public-key',\n transports: authenticator.transports,\n };\n return next;\n });\n const options = await generateAuthenticationOptions({\n allowCredentials: out,\n userVerification: 'preferred',\n });\n await this.opts.storageProvider.updateUserChallenge(user.userId, rpID, options.challenge);\n return options;\n }\n senderForContact(contact) {\n let rval = null;\n if (contact?.type) {\n rval = (this.opts.messageSendingProviders || []).find((p) => p.handlesContactType(contact.type));\n }\n return rval;\n }\n async sendExpiringValidationToken(request) {\n let rval = false;\n if (request?.type && StringRatchet.trimToNull(request?.value)) {\n const prov = this.senderForContact(request);\n if (prov) {\n const token = await this.expiringCodeRatchet.createNewCode({\n context: request.value,\n length: 6,\n alphabet: '0123456789',\n timeToLiveSeconds: 300,\n tags: ['Login'],\n });\n const msg = await prov.formatMessage(request, WardenCustomerMessageType.ExpiringCode, {\n code: token.code,\n relyingPartyName: this.opts.relyingPartyName,\n });\n rval = await prov.sendMessage(request, msg);\n }\n else {\n ErrorRatchet.throwFormattedErr('No provider found for contact type %s', request.type);\n }\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot send - invalid request %j', request);\n }\n return rval;\n }\n async processLogin(request, origin) {\n Logger.info('Processing login : %s : %j', origin, request);\n let rval = false;\n RequireRatchet.notNullOrUndefined(request, 'request');\n RequireRatchet.true(!!StringRatchet.trimToNull(request?.userId) || WardenUtils.validContact(request?.contact), 'Invalid contact and no userId');\n RequireRatchet.true(!!request?.webAuthn || !!StringRatchet.trimToNull(request?.expiringToken), 'You must provide one of webAuthn or expiringToken');\n RequireRatchet.true(!request?.webAuthn || !StringRatchet.trimToNull(request?.expiringToken), 'WebAuthn and ExpiringToken may not BOTH be set');\n const user = StringRatchet.trimToNull(request?.userId)\n ? await this.opts.storageProvider.findEntryById(request?.userId)\n : await this.opts.storageProvider.findEntryByContact(request.contact);\n if (!user) {\n ErrorRatchet.throwFormattedErr('No user found for %j / %s', request?.contact, request?.userId);\n }\n if (request.webAuthn) {\n rval = await this.loginWithWebAuthnRequest(user, origin, request.webAuthn);\n }\n else if (StringRatchet.trimToNull(request.expiringToken)) {\n const lookup = await this.expiringCodeRatchet.checkCode(StringRatchet.trimToEmpty(request.expiringToken), StringRatchet.trimToEmpty(request.contact.value), true);\n if (lookup) {\n rval = true;\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot login - token is invalid for this user');\n }\n }\n return rval;\n }\n async loginWithWebAuthnRequest(user, origin, data) {\n let rval = false;\n const asUrl = new URL(origin);\n const rpID = asUrl.hostname;\n const expectedChallenge = await this.opts.storageProvider.fetchCurrentUserChallenge(user.userId, rpID);\n const auth = (user.webAuthnAuthenticators || []).find((s) => s.credentialIdBase64 === data.id);\n if (!auth) {\n throw new Error(`Could not find authenticator ${data.id} for user ${user.userId}`);\n }\n const authenticator = {\n counter: auth.counter,\n credentialID: Base64Ratchet.base64StringToBuffer(auth.credentialIdBase64),\n credentialPublicKey: Base64Ratchet.base64StringToBuffer(auth.credentialPublicKeyBase64),\n };\n const vrOpts = {\n response: data,\n expectedChallenge,\n expectedOrigin: origin,\n expectedRPID: rpID,\n authenticator,\n };\n const verification = await verifyAuthenticationResponse(vrOpts);\n if (verification.verified) {\n rval = true;\n }\n return rval;\n }\n async removeSingleWebAuthnRegistration(userId, key) {\n let ent = await this.opts.storageProvider.findEntryById(userId);\n if (ent) {\n ent.webAuthnAuthenticators = (ent.webAuthnAuthenticators || []).filter((s) => s.credentialIdBase64 !== key);\n ent = await this.opts.storageProvider.saveEntry(ent);\n }\n else {\n Logger.info('Not removing - no such user as %s', userId);\n }\n return ent;\n }\n async removeUser(userId) {\n let rval = false;\n if (StringRatchet.trimToNull(userId)) {\n const oldUser = await this.opts.storageProvider.findEntryById(userId);\n if (oldUser) {\n await this.opts.storageProvider.removeEntry(userId);\n if (this?.opts?.eventProcessor) {\n await this.opts.eventProcessor.userRemoved(oldUser);\n }\n rval = true;\n }\n else {\n Logger.warn('Cannot remove non-existent user : %s', userId);\n }\n }\n return rval;\n }\n}\n//# sourceMappingURL=warden-service.js.map","import { ErrorRatchet, Logger } from '@bitblit/ratchet-common';\nimport { WardenContactType } from '@bitblit/ratchet-warden-common';\nimport { WardenCustomerMessageType } from '@bitblit/ratchet-warden-common';\nexport class WardenMailerMessageSendingProvider {\n mailer;\n options;\n static defaultOptions() {\n const rval = {\n emailBaseLayoutName: undefined,\n expiringTokenHtmlTemplateName: 'expiring-token-request-email',\n expiringTokenTxtTemplateName: undefined,\n magicLinkHtmlTemplateName: 'magic-token-request-email',\n magicLinkTxtTemplateName: undefined,\n };\n return rval;\n }\n constructor(mailer, options = WardenMailerMessageSendingProvider.defaultOptions()) {\n this.mailer = mailer;\n this.options = options;\n }\n async formatMessage(contact, messageType, context) {\n const rts = {\n destinationAddresses: [contact.value],\n subject: 'Your login token',\n };\n if (messageType === WardenCustomerMessageType.ExpiringCode) {\n await this.mailer.fillEmailBody(rts, context, this.options.expiringTokenHtmlTemplateName, this.options.expiringTokenTxtTemplateName, this.options.emailBaseLayoutName);\n }\n else if (messageType === WardenCustomerMessageType.MagicLink) {\n await this.mailer.fillEmailBody(rts, context, this.options.magicLinkHtmlTemplateName, this.options.magicLinkTxtTemplateName, this.options.emailBaseLayoutName);\n }\n else {\n throw ErrorRatchet.fErr('No such message type : %s', messageType);\n }\n return rts;\n }\n handlesContactType(type) {\n return type === WardenContactType.EmailAddress;\n }\n async sendMessage(contact, message) {\n const rval = await this.mailer.sendEmail(message);\n Logger.debug('SendRawEmailResponse was : %j', rval);\n return !!rval;\n }\n}\n//# sourceMappingURL=warden-mailer-message-sending-provider.js.map","import { WardenUtils } from '@bitblit/ratchet-warden-common';\nimport { S3CacheRatchet } from '@bitblit/ratchet-aws';\nimport { StringRatchet } from '@bitblit/ratchet-common';\nimport { ErrorRatchet } from '@bitblit/ratchet-common';\nexport class WardenS3SingleFileStorageProvider {\n s3;\n options;\n ratchet;\n constructor(s3, options) {\n this.s3 = s3;\n this.options = options;\n this.ratchet = new S3CacheRatchet(this.s3, this.options.bucket);\n }\n async listUserSummaries() {\n const allData = (await this.fetchDataFile()).entries;\n const rval = allData.map((d) => WardenUtils.stripWardenEntryToSummary(d));\n return rval;\n }\n async fetchDataFile() {\n let data = await this.ratchet.fetchCacheFileAsObject(this.options.dataFileKey);\n data = data || {\n entries: [],\n challenges: [],\n };\n return data;\n }\n async storeDataFile(file) {\n let rval = null;\n if (file) {\n rval = await this.ratchet.writeObjectToCacheFile(this.options.dataFileKey, file);\n }\n return rval;\n }\n async fetchCurrentUserChallenge(userId, relyingPartyId) {\n const data = await this.fetchDataFile();\n const entry = (data.challenges || []).find((d) => d.userId === userId && d.relyingPartyId === relyingPartyId);\n if (!entry) {\n ErrorRatchet.throwFormattedErr('fetchCurrentUserChallenge: Could not find user %s', userId);\n }\n return entry.challenge;\n }\n async findEntryByContact(contact) {\n let rval = null;\n if (contact?.type && StringRatchet.trimToNull(contact?.value)) {\n const data = await this.fetchDataFile();\n rval = (data.entries || []).find((d) => !!(d.contactMethods || []).find((x) => x.type === contact.type && x.value === contact.value));\n }\n return rval;\n }\n async findEntryById(userId) {\n let rval = null;\n if (StringRatchet.trimToNull(userId)) {\n const data = await this.fetchDataFile();\n rval = (data.entries || []).find((d) => d.userId === userId);\n }\n return rval;\n }\n async removeEntry(userId) {\n const data = await this.fetchDataFile();\n data.entries = (data.entries || []).filter((d) => d.userId !== userId);\n await this.storeDataFile(data);\n return true;\n }\n async saveEntry(entry) {\n let rval = null;\n if (entry && entry.userId) {\n const now = Date.now();\n entry.createdEpochMS = entry.createdEpochMS || now;\n entry.updatedEpochMS = now;\n const data = await this.fetchDataFile();\n data.entries = (data.entries || []).filter((d) => d.userId !== entry.userId);\n data.entries.push(entry);\n await this.storeDataFile(data);\n rval = await this.findEntryById(entry.userId);\n }\n return rval;\n }\n async updateUserChallenge(userId, relyingPartyId, challenge) {\n const data = await this.fetchDataFile();\n data.challenges = (data.challenges || []).filter((d) => d.userId !== userId || d.relyingPartyId !== relyingPartyId);\n data.challenges.push({\n userId: userId,\n relyingPartyId: relyingPartyId,\n challenge: challenge,\n updatedEpochMS: Date.now(),\n });\n await this.storeDataFile(data);\n return true;\n }\n}\n//# sourceMappingURL=warden-s3-single-file-storage-provider.js.map","import { ErrorRatchet, Logger } from '@bitblit/ratchet-common';\nimport { TwilioRatchet } from '@bitblit/ratchet-common';\nimport { WardenCustomerMessageType } from '@bitblit/ratchet-warden-common';\nimport { WardenContactType } from '@bitblit/ratchet-warden-common';\nexport class WardenTwilioTextMessageSendingProvider {\n optsPromise;\n constructor(optsPromise) {\n this.optsPromise = optsPromise;\n }\n async formatMessage(contact, messageType, context) {\n let msg = null;\n Logger.info('Creating text');\n if (messageType === WardenCustomerMessageType.ExpiringCode) {\n msg =\n context['code'] +\n ' is your ' +\n context['relyingPartyName'] +\n ' authentication code.\\n@' +\n context['relyingPartyName'] +\n ' #' +\n context['code'];\n }\n else if (messageType === WardenCustomerMessageType.MagicLink) {\n msg = 'Your magic link for ' + context['relyingPartyName'] + ' is ' + context['landingUrl'];\n }\n else {\n throw ErrorRatchet.fErr('No such message type : %s', messageType);\n }\n return msg;\n }\n handlesContactType(type) {\n return type === WardenContactType.TextCapablePhoneNumber;\n }\n async sendMessage(contact, message) {\n const opts = await this.optsPromise;\n const rval = await TwilioRatchet.sendMessageDirect(opts.accountSID, opts.authToken, opts.outBoundNumber, [contact.value], message);\n Logger.debug('sendMessage was : %j', rval);\n return !!rval && rval.length > 0;\n }\n}\n//# sourceMappingURL=warden-twilio-text-message-sending-provider.js.map"],"names":["RatchetWardenServerInfo","constructor","static","version","hash","branch","tag","timeBuiltISO","notes","WardenDefaultUserDecorationProvider","async","wardenUser","userTokenData","WardenUtils","stripWardenEntryToSummary","userTokenExpirationSeconds","userTeamRoles","team","role","WardenNoOpEventProcessingProvider","entry","WardenService","inOptions","opts","expiringCodeRatchet","this","RequireRatchet","notNullOrUndefined","relyingPartyName","notNullUndefinedOrEmptyArray","allowedOrigins","storageProvider","messageSendingProviders","expiringCodeProvider","jwtRatchet","Object","assign","userTokenDataProvider","eventProcessor","ExpiringCodeRatchet","options","findEntryByContact","contact","findEntryById","userId","cmdString","origin","loggedInUserId","rval","cmd","JSON","parse","resp","processCommandToResponse","Logger","warn","stringify","err","errString","ErrorRatchet","safeStringifyErr","error","info","sendExpiringValidationToken","generateWebAuthnAuthenticationChallengeForUserId","tmp","dataAsJson","createAccount","sendCode","label","tags","sendMagicLink","contactType","contactMethods","find","cm","type","length","fErr","landingUrl","meta","generateWebAuthnRegistrationChallengeForLoggedInUser","StringRatchet","trimToNull","throwFormattedErr","addContactToLoggedInUser","validContact","addContactMethodToUser","addWebAuthnRegistrationToLoggedInUser","data","out","storeAuthnRegistration","updatedEntry","removeWebAuthnRegistration","modified","removeSingleWebAuthnRegistration","credentialId","removeWebAuthnRegistrationFromLoggedInUser","removeContactFromLoggedInUser","output","removeContactMethodFromUser","performLogin","loginData","loginOk","processLogin","user","decoration","userDecorationProvider","fetchDecoration","wardenToken","roles","teamRolesToRoles","proxy","jwtToken","createTokenString","request","refreshJwtToken","parsed","decodeToken","ExpiredJwtHandling","THROW_EXCEPTION","urlIsOnAllowedOrigin","url","u","URL","i","test","protocol","port","metaIn","notNullUndefinedOrOnlyWhitespaceString","true","value","prov","senderForContact","token","createNewCode","context","alphabet","UPPER_CASE_LATIN","timeToLiveSeconds","encodedMeta","Base64Ratchet","safeObjectToBase64JSON","landingUrlFilled","split","join","code","msg","formatMessage","WardenCustomerMessageType","MagicLink","sendMessage","guid","createType4Guid","now","Date","newUser","userLabel","webAuthnAuthenticators","createdEpochMS","updatedEpochMS","next","saveEntry","userCreated","otherUser","curUser","push","filter","s","includes","Error","rpID","hostname","generateRegistrationOptions","rpName","userID","userName","attestationType","excludeCredentials","map","authenticator","id","base64StringToBuffer","credentialPublicKeyBase64","transports","updateUserChallenge","challenge","vrOpts","response","expectedChallenge","fetchCurrentUserChallenge","expectedOrigin","expectedRPID","verification","verifyRegistrationResponse","registrationResponseId","result","verified","WardenStoreRegistrationResponseType","Verified","Failed","newAuth","counter","registrationInfo","credentialBackedUp","credentialDeviceType","credentialIdBase64","generateBase64VersionOfBuffer","Buffer","from","credentialPublicKey","wa","storedUser","generateWebAuthnAuthenticationChallenge","userAuthenticators","generateAuthenticationOptions","allowCredentials","userVerification","p","handlesContactType","ExpiringCode","webAuthn","expiringToken","loginWithWebAuthnRequest","checkCode","trimToEmpty","auth","credentialID","verifyAuthenticationResponse","key","ent","oldUser","removeEntry","userRemoved","WardenMailerMessageSendingProvider","mailer","emailBaseLayoutName","undefined","expiringTokenHtmlTemplateName","expiringTokenTxtTemplateName","magicLinkHtmlTemplateName","magicLinkTxtTemplateName","defaultOptions","messageType","rts","destinationAddresses","subject","fillEmailBody","WardenContactType","EmailAddress","message","sendEmail","debug","WardenS3SingleFileStorageProvider","s3","ratchet","S3CacheRatchet","bucket","fetchDataFile","entries","d","fetchCacheFileAsObject","dataFileKey","challenges","file","writeObjectToCacheFile","relyingPartyId","x","storeDataFile","WardenTwilioTextMessageSendingProvider","optsPromise","TextCapablePhoneNumber","TwilioRatchet","sendMessageDirect","accountSID","authToken","outBoundNumber"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/build/ratchet-warden-server-info.ts","../src/server/provider/warden-default-user-decoration-provider.ts","../src/server/provider/warden-no-op-event-processing-provider.ts","../src/server/warden-service.ts","../src/server/provider/warden-mailer-message-sending-provider.ts","../src/server/provider/warden-s3-single-file-storage-provider.ts","../src/server/provider/warden-twilio-text-message-sending-provider.ts"],"sourcesContent":["export class RatchetWardenServerInfo {\n constructor() { }\n static buildInformation() {\n const val = {\n version: 'LOCAL-SNAPSHOT',\n hash: 'LOCAL-HASH',\n branch: 'LOCAL-BRANCH',\n tag: 'LOCAL-TAG',\n timeBuiltISO: 'LOCAL-TIME-ISO',\n notes: 'LOCAL-NOTES',\n };\n return val;\n }\n}\n//# sourceMappingURL=ratchet-warden-server-info.js.map","import { WardenUtils } from '@bitblit/ratchet-warden-common';\nexport class WardenDefaultUserDecorationProvider {\n async fetchDecoration(wardenUser) {\n const rval = {\n userTokenData: WardenUtils.stripWardenEntryToSummary(wardenUser),\n userTokenExpirationSeconds: 3600,\n userTeamRoles: [{ team: 'WARDEN', role: 'USER' }],\n };\n return rval;\n }\n}\n//# sourceMappingURL=warden-default-user-decoration-provider.js.map","export class WardenNoOpEventProcessingProvider {\n async userCreated(entry) { }\n async userRemoved(entry) { }\n}\n//# sourceMappingURL=warden-no-op-event-processing-provider.js.map","import { generateAuthenticationOptions, generateRegistrationOptions, verifyAuthenticationResponse, verifyRegistrationResponse, } from '@simplewebauthn/server';\nimport { WardenUtils } from '@bitblit/ratchet-warden-common';\nimport { ExpiringCodeRatchet } from '@bitblit/ratchet-aws';\nimport { Logger } from '@bitblit/ratchet-common';\nimport { StringRatchet } from '@bitblit/ratchet-common';\nimport { ErrorRatchet } from '@bitblit/ratchet-common';\nimport { RequireRatchet } from '@bitblit/ratchet-common';\nimport { ExpiredJwtHandling } from '@bitblit/ratchet-common';\nimport { Base64Ratchet } from '@bitblit/ratchet-common';\nimport { WardenDefaultUserDecorationProvider } from './provider/warden-default-user-decoration-provider.js';\nimport { WardenNoOpEventProcessingProvider } from './provider/warden-no-op-event-processing-provider.js';\nimport { WardenStoreRegistrationResponseType } from '@bitblit/ratchet-warden-common';\nimport { WardenCustomerMessageType } from '@bitblit/ratchet-warden-common';\nexport class WardenService {\n inOptions;\n opts;\n expiringCodeRatchet;\n constructor(inOptions) {\n this.inOptions = inOptions;\n RequireRatchet.notNullOrUndefined(inOptions, 'options');\n RequireRatchet.notNullOrUndefined(inOptions.relyingPartyName, 'options.relyingPartyName');\n RequireRatchet.notNullUndefinedOrEmptyArray(inOptions.allowedOrigins, 'options.allowedOrigins');\n RequireRatchet.notNullOrUndefined(inOptions.storageProvider, 'options.storageProvider');\n RequireRatchet.notNullUndefinedOrEmptyArray(inOptions.messageSendingProviders, 'options.messageSendingProviders');\n RequireRatchet.notNullOrUndefined(inOptions.expiringCodeProvider, 'options.expiringCodeProvider');\n RequireRatchet.notNullOrUndefined(inOptions.jwtRatchet, 'options.jwtRatchet');\n this.opts = Object.assign({ userTokenDataProvider: new WardenDefaultUserDecorationProvider(), eventProcessor: new WardenNoOpEventProcessingProvider() }, inOptions);\n this.expiringCodeRatchet = new ExpiringCodeRatchet(this.opts.expiringCodeProvider);\n }\n get options() {\n return Object.assign({}, this.opts);\n }\n findEntryByContact(contact) {\n return this.opts.storageProvider.findEntryByContact(contact);\n }\n findEntryById(userId) {\n return this.opts.storageProvider.findEntryById(userId);\n }\n async processCommandStringToString(cmdString, origin, loggedInUserId) {\n let rval = null;\n try {\n const cmd = JSON.parse(cmdString);\n const resp = await this.processCommandToResponse(cmd, origin, loggedInUserId);\n if (resp === null) {\n Logger.warn('Response was null for %s %s %s', cmdString, origin, loggedInUserId);\n }\n else {\n rval = JSON.stringify(resp);\n }\n }\n catch (err) {\n const errString = ErrorRatchet.safeStringifyErr(err);\n Logger.error('Failed %s : %j', errString, cmdString, err);\n rval = JSON.stringify({ error: errString });\n }\n return rval;\n }\n async processCommandToResponse(cmd, origin, loggedInUserId) {\n let rval = null;\n if (cmd) {\n Logger.info('Processing command : UserID: %s Origin: %s Command: %j', loggedInUserId, origin, cmd);\n if (cmd.sendExpiringValidationToken) {\n rval = { sendExpiringValidationToken: await this.sendExpiringValidationToken(cmd.sendExpiringValidationToken) };\n }\n else if (cmd.generateWebAuthnAuthenticationChallengeForUserId) {\n const tmp = await this.generateWebAuthnAuthenticationChallengeForUserId(cmd.generateWebAuthnAuthenticationChallengeForUserId, origin);\n rval = { generateWebAuthnAuthenticationChallengeForUserId: { dataAsJson: JSON.stringify(tmp) } };\n }\n else if (cmd.createAccount) {\n rval = {\n createAccount: await this.createAccount(cmd.createAccount.contact, cmd.createAccount.sendCode, cmd.createAccount.label, cmd.createAccount.tags),\n };\n }\n else if (cmd.sendMagicLink) {\n let contact = cmd.sendMagicLink.contact;\n if (!contact && cmd?.sendMagicLink?.userId) {\n const entry = await this.findEntryById(cmd.sendMagicLink.userId);\n if (entry) {\n if (cmd.sendMagicLink.contactType) {\n contact = (entry.contactMethods || []).find((cm) => cm.type === cmd.sendMagicLink.contactType);\n }\n else {\n contact = (entry.contactMethods || []).length > 0 ? entry.contactMethods[0] : null;\n }\n }\n }\n if (!contact) {\n throw ErrorRatchet.fErr('Could not find contract entry either directly or by lookup');\n }\n rval = {\n sendMagicLink: await this.sendMagicLink(contact, cmd.sendMagicLink.landingUrl, cmd.sendMagicLink.meta, cmd.sendMagicLink.ttlSeconds),\n };\n }\n else if (cmd.generateWebAuthnRegistrationChallengeForLoggedInUser) {\n if (!StringRatchet.trimToNull(loggedInUserId)) {\n ErrorRatchet.throwFormattedErr('This requires a logged in user');\n }\n const tmp = await this.generateWebAuthnRegistrationChallengeForLoggedInUser(loggedInUserId, origin);\n rval = { generateWebAuthnRegistrationChallengeForLoggedInUser: { dataAsJson: JSON.stringify(tmp) } };\n }\n else if (cmd.addContactToLoggedInUser) {\n if (!WardenUtils.validContact(cmd.addContactToLoggedInUser)) {\n ErrorRatchet.throwFormattedErr('Cannot add, invalid contact %j', cmd.addContactToLoggedInUser);\n }\n else {\n const out = await this.addContactMethodToUser(loggedInUserId, cmd.addContactToLoggedInUser);\n rval = { addContactToLoggedInUser: out };\n }\n }\n else if (cmd.addWebAuthnRegistrationToLoggedInUser) {\n if (!StringRatchet.trimToNull(loggedInUserId)) {\n ErrorRatchet.throwFormattedErr('This requires a logged in user');\n }\n const data = JSON.parse(cmd.addWebAuthnRegistrationToLoggedInUser.dataAsJson);\n const out = await this.storeAuthnRegistration(loggedInUserId, origin, data);\n if (out.updatedEntry) {\n rval = { addWebAuthnRegistrationToLoggedInUser: WardenUtils.stripWardenEntryToSummary(out.updatedEntry) };\n }\n else if (out.error) {\n rval = { error: out.error };\n }\n else {\n rval = { error: 'Cannot happen - neither user nor error set' };\n }\n }\n else if (cmd.removeWebAuthnRegistration) {\n const modified = await this.removeSingleWebAuthnRegistration(cmd.removeWebAuthnRegistration.userId, cmd.removeWebAuthnRegistration.credentialId);\n rval = {\n removeWebAuthnRegistration: WardenUtils.stripWardenEntryToSummary(modified),\n };\n }\n else if (cmd.removeWebAuthnRegistrationFromLoggedInUser) {\n const modified = await this.removeSingleWebAuthnRegistration(loggedInUserId, cmd.removeWebAuthnRegistrationFromLoggedInUser);\n rval = {\n removeWebAuthnRegistrationFromLoggedInUser: WardenUtils.stripWardenEntryToSummary(modified),\n };\n }\n else if (cmd.removeContactFromLoggedInUser) {\n const output = await this.removeContactMethodFromUser(loggedInUserId, cmd.removeContactFromLoggedInUser);\n rval = {\n removeContactFromLoggedInUser: WardenUtils.stripWardenEntryToSummary(output),\n };\n }\n else if (cmd.performLogin) {\n const loginData = cmd.performLogin;\n const loginOk = await this.processLogin(loginData, origin);\n Logger.info('Performing login - login auth check was : %s', loginOk);\n if (loginOk) {\n const user = StringRatchet.trimToNull(loginData.userId)\n ? await this.opts.storageProvider.findEntryById(loginData.userId)\n : await this.opts.storageProvider.findEntryByContact(loginData.contact);\n const decoration = await this.opts.userDecorationProvider.fetchDecoration(user);\n const wardenToken = {\n loginData: WardenUtils.stripWardenEntryToSummary(user),\n user: decoration.userTokenData,\n roles: WardenUtils.teamRolesToRoles(decoration.userTeamRoles),\n proxy: null,\n };\n const jwtToken = await this.opts.jwtRatchet.createTokenString(wardenToken, decoration.userTokenExpirationSeconds);\n const output = {\n request: loginData,\n userId: user.userId,\n jwtToken: jwtToken,\n };\n rval = { performLogin: output };\n }\n else {\n rval = { error: 'Login failed' };\n }\n }\n else if (cmd.refreshJwtToken) {\n const parsed = await this.opts.jwtRatchet.decodeToken(cmd.refreshJwtToken, ExpiredJwtHandling.THROW_EXCEPTION);\n const user = await this.opts.storageProvider.findEntryById(parsed.loginData.userId);\n const decoration = await this.opts.userDecorationProvider.fetchDecoration(user);\n const wardenToken = {\n loginData: WardenUtils.stripWardenEntryToSummary(user),\n user: decoration.userTokenData,\n roles: WardenUtils.teamRolesToRoles(decoration.userTeamRoles),\n proxy: null,\n };\n const newToken = await this.opts.jwtRatchet.createTokenString(wardenToken, decoration.userTokenExpirationSeconds);\n rval = {\n refreshJwtToken: newToken,\n };\n }\n }\n else {\n rval = { error: 'No command sent' };\n }\n return rval;\n }\n urlIsOnAllowedOrigin(url) {\n let rval = false;\n if (url) {\n const u = new URL(url);\n for (let i = 0; i < this.opts.allowedOrigins.length && !rval; i++) {\n const test = new URL(this.opts.allowedOrigins[i]);\n rval = test.origin === u.origin && test.protocol === u.protocol && test.port === u.port;\n }\n }\n return rval;\n }\n async sendMagicLink(contact, landingUrl, metaIn, ttlSeconds = 300) {\n let rval = false;\n RequireRatchet.notNullOrUndefined(contact, 'contact');\n RequireRatchet.notNullUndefinedOrOnlyWhitespaceString(landingUrl, 'landingUrl');\n RequireRatchet.true(this.urlIsOnAllowedOrigin(landingUrl), 'landingUrl is not on an allowed origin for redirect');\n if (contact?.type && StringRatchet.trimToNull(contact?.value)) {\n const prov = this.senderForContact(contact);\n if (prov) {\n const token = await this.expiringCodeRatchet.createNewCode({\n context: contact.value,\n length: 36,\n alphabet: StringRatchet.UPPER_CASE_LATIN,\n timeToLiveSeconds: ttlSeconds,\n tags: ['MagicLink'],\n });\n const meta = Object.assign({}, metaIn || {}, { contact: contact });\n const encodedMeta = Base64Ratchet.safeObjectToBase64JSON(meta || {});\n let landingUrlFilled = landingUrl;\n landingUrlFilled = landingUrlFilled.split('{CODE}').join(token.code);\n landingUrlFilled = landingUrlFilled.split('{META}').join(encodedMeta);\n const context = Object.assign({}, meta || {}, {\n landingUrl: landingUrlFilled,\n code: token.code,\n relyingPartyName: this.opts.relyingPartyName,\n });\n const msg = await prov.formatMessage(contact, WardenCustomerMessageType.MagicLink, context);\n rval = await prov.sendMessage(contact, msg);\n }\n else {\n ErrorRatchet.throwFormattedErr('No provider found for contact type %s', contact.type);\n }\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot send - invalid contact %j', contact);\n }\n return rval;\n }\n async createAccount(contact, sendCode, label, tags) {\n let rval = null;\n if (WardenUtils.validContact(contact)) {\n const old = await this.opts.storageProvider.findEntryByContact(contact);\n if (!!old) {\n ErrorRatchet.throwFormattedErr('Cannot create - account already exists for %j', contact);\n }\n const prov = this.senderForContact(contact);\n if (!prov) {\n ErrorRatchet.throwFormattedErr('Cannot create - no sending provider for type %s', contact.type);\n }\n const guid = StringRatchet.createType4Guid();\n const now = Date.now();\n const newUser = {\n userId: guid,\n userLabel: label || 'User ' + guid,\n contactMethods: [contact],\n tags: tags || [],\n webAuthnAuthenticators: [],\n createdEpochMS: now,\n updatedEpochMS: now,\n };\n const next = await this.opts.storageProvider.saveEntry(newUser);\n rval = next.userId;\n if (this?.opts?.eventProcessor) {\n await this.opts.eventProcessor.userCreated(next);\n }\n if (sendCode) {\n Logger.info('New user %j created and send requested - sending', next);\n await this.sendExpiringValidationToken(contact);\n }\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot create - invalid contact (missing or invalid fields)');\n }\n return rval;\n }\n async addContactMethodToUser(userId, contact) {\n let rval = false;\n if (StringRatchet.trimToNull(userId) && WardenUtils.validContact(contact)) {\n const otherUser = await this.opts.storageProvider.findEntryByContact(contact);\n if (otherUser && otherUser.userId !== userId) {\n ErrorRatchet.throwFormattedErr('Cannot add contact to this user, another user already has that contact');\n }\n const curUser = await this.opts.storageProvider.findEntryById(userId);\n if (!curUser) {\n ErrorRatchet.throwFormattedErr('Cannot add contact to this user, user does not exist');\n }\n curUser.contactMethods.push(contact);\n await this.opts.storageProvider.saveEntry(curUser);\n rval = true;\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot add - invalid config : %s %j', userId, contact);\n }\n return rval;\n }\n async removeContactMethodFromUser(userId, contact) {\n let rval = null;\n if (StringRatchet.trimToNull(userId) && WardenUtils.validContact(contact)) {\n const curUser = await this.opts.storageProvider.findEntryById(userId);\n if (!curUser) {\n ErrorRatchet.throwFormattedErr('Cannot remove contact from this user, user does not exist');\n }\n curUser.contactMethods = (curUser.contactMethods || []).filter((s) => s.type !== contact.type || s.value !== contact.value);\n if (curUser.contactMethods.length === 0) {\n ErrorRatchet.throwFormattedErr('Cannot remove the last contact method from a user');\n }\n await this.opts.storageProvider.saveEntry(curUser);\n rval = await this.opts.storageProvider.findEntryById(userId);\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot add - invalid config : %s %j', userId, contact);\n }\n return rval;\n }\n async generateWebAuthnRegistrationChallengeForLoggedInUser(userId, origin) {\n if (!origin || !this.opts.allowedOrigins.includes(origin)) {\n throw new Error('Invalid origin : ' + origin);\n }\n const asUrl = new URL(origin);\n const rpID = asUrl.hostname;\n const entry = await this.opts.storageProvider.findEntryById(userId);\n const options = await generateRegistrationOptions({\n rpName: this.opts.relyingPartyName,\n rpID: rpID,\n userID: entry.userId,\n userName: entry.userLabel,\n attestationType: 'none',\n excludeCredentials: entry.webAuthnAuthenticators.map((authenticator) => ({\n id: Base64Ratchet.base64StringToBuffer(authenticator.credentialPublicKeyBase64),\n type: 'public-key',\n transports: authenticator.transports,\n })),\n });\n await this.opts.storageProvider.updateUserChallenge(entry.userId, rpID, options.challenge);\n return options;\n }\n async storeAuthnRegistration(userId, origin, data) {\n Logger.info('Store authn data : %j', data);\n let rval = null;\n try {\n if (!origin || !this.opts.allowedOrigins.includes(origin)) {\n throw new Error('Invalid origin : ' + origin);\n }\n const asUrl = new URL(origin);\n const rpID = asUrl.hostname;\n const user = await this.opts.storageProvider.findEntryById(userId);\n const expectedChallenge = await this.opts.storageProvider.fetchCurrentUserChallenge(user.userId, rpID);\n const vrOpts = {\n response: data,\n expectedChallenge: expectedChallenge,\n expectedOrigin: origin,\n expectedRPID: rpID,\n };\n Logger.info('Calling verifyRegistrationResponse: %j', vrOpts);\n const verification = await verifyRegistrationResponse(vrOpts);\n Logger.info('verifyRegistrationResponse Result : %j', verification);\n rval = {\n updatedEntry: null,\n registrationResponseId: data.id,\n result: verification.verified ? WardenStoreRegistrationResponseType.Verified : WardenStoreRegistrationResponseType.Failed,\n };\n if (rval.result === WardenStoreRegistrationResponseType.Verified) {\n Logger.info('Storing registration');\n const newAuth = {\n counter: verification.registrationInfo.counter,\n credentialBackedUp: verification.registrationInfo.credentialBackedUp,\n credentialDeviceType: verification.registrationInfo.credentialDeviceType,\n credentialIdBase64: data.id,\n credentialPublicKeyBase64: Base64Ratchet.generateBase64VersionOfBuffer(Buffer.from(verification.registrationInfo.credentialPublicKey)),\n };\n user.webAuthnAuthenticators = (user.webAuthnAuthenticators || []).filter((wa) => wa.credentialIdBase64 !== newAuth.credentialIdBase64);\n user.webAuthnAuthenticators.push(newAuth);\n const storedUser = await this.opts.storageProvider.saveEntry(user);\n rval.updatedEntry = storedUser;\n Logger.info('Stored auth : %j', storedUser);\n }\n }\n catch (err) {\n rval = {\n registrationResponseId: data.id,\n result: WardenStoreRegistrationResponseType.Error,\n error: ErrorRatchet.safeStringifyErr(err),\n };\n }\n return rval;\n }\n async generateWebAuthnAuthenticationChallengeForUserId(userId, origin) {\n const user = await this.opts.storageProvider.findEntryById(userId);\n const rval = await this.generateWebAuthnAuthenticationChallenge(user, origin);\n return rval;\n }\n async generateWebAuthnAuthenticationChallenge(user, origin) {\n const userAuthenticators = user.webAuthnAuthenticators;\n if (!origin || !this.opts.allowedOrigins.includes(origin)) {\n throw new Error('Invalid origin : ' + origin);\n }\n const asUrl = new URL(origin);\n const rpID = asUrl.hostname;\n const out = userAuthenticators.map((authenticator) => {\n const next = {\n id: Buffer.from(authenticator.credentialIdBase64, 'base64'),\n type: 'public-key',\n transports: authenticator.transports,\n };\n return next;\n });\n const options = await generateAuthenticationOptions({\n allowCredentials: out,\n userVerification: 'preferred',\n });\n await this.opts.storageProvider.updateUserChallenge(user.userId, rpID, options.challenge);\n return options;\n }\n senderForContact(contact) {\n let rval = null;\n if (contact?.type) {\n rval = (this.opts.messageSendingProviders || []).find((p) => p.handlesContactType(contact.type));\n }\n return rval;\n }\n async sendExpiringValidationToken(request) {\n let rval = false;\n if (request?.type && StringRatchet.trimToNull(request?.value)) {\n const prov = this.senderForContact(request);\n if (prov) {\n const token = await this.expiringCodeRatchet.createNewCode({\n context: request.value,\n length: 6,\n alphabet: '0123456789',\n timeToLiveSeconds: 300,\n tags: ['Login'],\n });\n const msg = await prov.formatMessage(request, WardenCustomerMessageType.ExpiringCode, {\n code: token.code,\n relyingPartyName: this.opts.relyingPartyName,\n });\n rval = await prov.sendMessage(request, msg);\n }\n else {\n ErrorRatchet.throwFormattedErr('No provider found for contact type %s', request.type);\n }\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot send - invalid request %j', request);\n }\n return rval;\n }\n async processLogin(request, origin) {\n Logger.info('Processing login : %s : %j', origin, request);\n let rval = false;\n RequireRatchet.notNullOrUndefined(request, 'request');\n RequireRatchet.true(!!StringRatchet.trimToNull(request?.userId) || WardenUtils.validContact(request?.contact), 'Invalid contact and no userId');\n RequireRatchet.true(!!request?.webAuthn || !!StringRatchet.trimToNull(request?.expiringToken), 'You must provide one of webAuthn or expiringToken');\n RequireRatchet.true(!request?.webAuthn || !StringRatchet.trimToNull(request?.expiringToken), 'WebAuthn and ExpiringToken may not BOTH be set');\n const user = StringRatchet.trimToNull(request?.userId)\n ? await this.opts.storageProvider.findEntryById(request?.userId)\n : await this.opts.storageProvider.findEntryByContact(request.contact);\n if (!user) {\n ErrorRatchet.throwFormattedErr('No user found for %j / %s', request?.contact, request?.userId);\n }\n if (request.webAuthn) {\n rval = await this.loginWithWebAuthnRequest(user, origin, request.webAuthn);\n }\n else if (StringRatchet.trimToNull(request.expiringToken)) {\n const lookup = await this.expiringCodeRatchet.checkCode(StringRatchet.trimToEmpty(request.expiringToken), StringRatchet.trimToEmpty(request.contact.value), true);\n if (lookup) {\n rval = true;\n }\n else {\n ErrorRatchet.throwFormattedErr('Cannot login - token is invalid for this user');\n }\n }\n return rval;\n }\n async loginWithWebAuthnRequest(user, origin, data) {\n let rval = false;\n const asUrl = new URL(origin);\n const rpID = asUrl.hostname;\n const expectedChallenge = await this.opts.storageProvider.fetchCurrentUserChallenge(user.userId, rpID);\n const auth = (user.webAuthnAuthenticators || []).find((s) => s.credentialIdBase64 === data.id);\n if (!auth) {\n throw new Error(`Could not find authenticator ${data.id} for user ${user.userId}`);\n }\n const authenticator = {\n counter: auth.counter,\n credentialID: Base64Ratchet.base64StringToBuffer(auth.credentialIdBase64),\n credentialPublicKey: Base64Ratchet.base64StringToBuffer(auth.credentialPublicKeyBase64),\n };\n const vrOpts = {\n response: data,\n expectedChallenge,\n expectedOrigin: origin,\n expectedRPID: rpID,\n authenticator,\n };\n const verification = await verifyAuthenticationResponse(vrOpts);\n if (verification.verified) {\n rval = true;\n }\n return rval;\n }\n async removeSingleWebAuthnRegistration(userId, key) {\n let ent = await this.opts.storageProvider.findEntryById(userId);\n if (ent) {\n ent.webAuthnAuthenticators = (ent.webAuthnAuthenticators || []).filter((s) => s.credentialIdBase64 !== key);\n ent = await this.opts.storageProvider.saveEntry(ent);\n }\n else {\n Logger.info('Not removing - no such user as %s', userId);\n }\n return ent;\n }\n async removeUser(userId) {\n let rval = false;\n if (StringRatchet.trimToNull(userId)) {\n const oldUser = await this.opts.storageProvider.findEntryById(userId);\n if (oldUser) {\n await this.opts.storageProvider.removeEntry(userId);\n if (this?.opts?.eventProcessor) {\n await this.opts.eventProcessor.userRemoved(oldUser);\n }\n rval = true;\n }\n else {\n Logger.warn('Cannot remove non-existent user : %s', userId);\n }\n }\n return rval;\n }\n}\n//# sourceMappingURL=warden-service.js.map","import { ErrorRatchet, Logger } from '@bitblit/ratchet-common';\nimport { WardenContactType } from '@bitblit/ratchet-warden-common';\nimport { WardenCustomerMessageType } from '@bitblit/ratchet-warden-common';\nexport class WardenMailerMessageSendingProvider {\n mailer;\n options;\n static defaultOptions() {\n const rval = {\n emailBaseLayoutName: undefined,\n expiringTokenHtmlTemplateName: 'expiring-token-request-email',\n expiringTokenTxtTemplateName: undefined,\n magicLinkHtmlTemplateName: 'magic-token-request-email',\n magicLinkTxtTemplateName: undefined,\n };\n return rval;\n }\n constructor(mailer, options = WardenMailerMessageSendingProvider.defaultOptions()) {\n this.mailer = mailer;\n this.options = options;\n }\n async formatMessage(contact, messageType, context) {\n const rts = {\n destinationAddresses: [contact.value],\n subject: 'Your login token',\n };\n if (messageType === WardenCustomerMessageType.ExpiringCode) {\n await this.mailer.fillEmailBody(rts, context, this.options.expiringTokenHtmlTemplateName, this.options.expiringTokenTxtTemplateName, this.options.emailBaseLayoutName);\n }\n else if (messageType === WardenCustomerMessageType.MagicLink) {\n await this.mailer.fillEmailBody(rts, context, this.options.magicLinkHtmlTemplateName, this.options.magicLinkTxtTemplateName, this.options.emailBaseLayoutName);\n }\n else {\n throw ErrorRatchet.fErr('No such message type : %s', messageType);\n }\n return rts;\n }\n handlesContactType(type) {\n return type === WardenContactType.EmailAddress;\n }\n async sendMessage(contact, message) {\n const rval = await this.mailer.sendEmail(message);\n Logger.debug('SendRawEmailResponse was : %j', rval);\n return !!rval;\n }\n}\n//# sourceMappingURL=warden-mailer-message-sending-provider.js.map","import { WardenUtils } from '@bitblit/ratchet-warden-common';\nimport { S3CacheRatchet } from '@bitblit/ratchet-aws';\nimport { StringRatchet } from '@bitblit/ratchet-common';\nimport { ErrorRatchet } from '@bitblit/ratchet-common';\nexport class WardenS3SingleFileStorageProvider {\n s3;\n options;\n ratchet;\n constructor(s3, options) {\n this.s3 = s3;\n this.options = options;\n this.ratchet = new S3CacheRatchet(this.s3, this.options.bucket);\n }\n async listUserSummaries() {\n const allData = (await this.fetchDataFile()).entries;\n const rval = allData.map((d) => WardenUtils.stripWardenEntryToSummary(d));\n return rval;\n }\n async fetchDataFile() {\n let data = await this.ratchet.fetchCacheFileAsObject(this.options.dataFileKey);\n data = data || {\n entries: [],\n challenges: [],\n };\n return data;\n }\n async storeDataFile(file) {\n let rval = null;\n if (file) {\n rval = await this.ratchet.writeObjectToCacheFile(this.options.dataFileKey, file);\n }\n return rval;\n }\n async fetchCurrentUserChallenge(userId, relyingPartyId) {\n const data = await this.fetchDataFile();\n const entry = (data.challenges || []).find((d) => d.userId === userId && d.relyingPartyId === relyingPartyId);\n if (!entry) {\n ErrorRatchet.throwFormattedErr('fetchCurrentUserChallenge: Could not find user %s', userId);\n }\n return entry.challenge;\n }\n async findEntryByContact(contact) {\n let rval = null;\n if (contact?.type && StringRatchet.trimToNull(contact?.value)) {\n const data = await this.fetchDataFile();\n rval = (data.entries || []).find((d) => !!(d.contactMethods || []).find((x) => x.type === contact.type && x.value === contact.value));\n }\n return rval;\n }\n async findEntryById(userId) {\n let rval = null;\n if (StringRatchet.trimToNull(userId)) {\n const data = await this.fetchDataFile();\n rval = (data.entries || []).find((d) => d.userId === userId);\n }\n return rval;\n }\n async removeEntry(userId) {\n const data = await this.fetchDataFile();\n data.entries = (data.entries || []).filter((d) => d.userId !== userId);\n await this.storeDataFile(data);\n return true;\n }\n async saveEntry(entry) {\n let rval = null;\n if (entry && entry.userId) {\n const now = Date.now();\n entry.createdEpochMS = entry.createdEpochMS || now;\n entry.updatedEpochMS = now;\n const data = await this.fetchDataFile();\n data.entries = (data.entries || []).filter((d) => d.userId !== entry.userId);\n data.entries.push(entry);\n await this.storeDataFile(data);\n rval = await this.findEntryById(entry.userId);\n }\n return rval;\n }\n async updateUserChallenge(userId, relyingPartyId, challenge) {\n const data = await this.fetchDataFile();\n data.challenges = (data.challenges || []).filter((d) => d.userId !== userId || d.relyingPartyId !== relyingPartyId);\n data.challenges.push({\n userId: userId,\n relyingPartyId: relyingPartyId,\n challenge: challenge,\n updatedEpochMS: Date.now(),\n });\n await this.storeDataFile(data);\n return true;\n }\n}\n//# sourceMappingURL=warden-s3-single-file-storage-provider.js.map","import { ErrorRatchet, Logger } from '@bitblit/ratchet-common';\nimport { TwilioRatchet } from '@bitblit/ratchet-common';\nimport { WardenCustomerMessageType } from '@bitblit/ratchet-warden-common';\nimport { WardenContactType } from '@bitblit/ratchet-warden-common';\nexport class WardenTwilioTextMessageSendingProvider {\n optsPromise;\n constructor(optsPromise) {\n this.optsPromise = optsPromise;\n }\n async formatMessage(contact, messageType, context) {\n let msg = null;\n Logger.info('Creating text');\n if (messageType === WardenCustomerMessageType.ExpiringCode) {\n msg =\n context['code'] +\n ' is your ' +\n context['relyingPartyName'] +\n ' authentication code.\\n@' +\n context['relyingPartyName'] +\n ' #' +\n context['code'];\n }\n else if (messageType === WardenCustomerMessageType.MagicLink) {\n msg = 'Your magic link for ' + context['relyingPartyName'] + ' is ' + context['landingUrl'];\n }\n else {\n throw ErrorRatchet.fErr('No such message type : %s', messageType);\n }\n return msg;\n }\n handlesContactType(type) {\n return type === WardenContactType.TextCapablePhoneNumber;\n }\n async sendMessage(contact, message) {\n const opts = await this.optsPromise;\n const rval = await TwilioRatchet.sendMessageDirect(opts.accountSID, opts.authToken, opts.outBoundNumber, [contact.value], message);\n Logger.debug('sendMessage was : %j', rval);\n return !!rval && rval.length > 0;\n }\n}\n//# sourceMappingURL=warden-twilio-text-message-sending-provider.js.map"],"names":["RatchetWardenServerInfo","constructor","static","version","hash","branch","tag","timeBuiltISO","notes","WardenDefaultUserDecorationProvider","async","wardenUser","userTokenData","WardenUtils","stripWardenEntryToSummary","userTokenExpirationSeconds","userTeamRoles","team","role","WardenNoOpEventProcessingProvider","entry","WardenService","inOptions","opts","expiringCodeRatchet","this","RequireRatchet","notNullOrUndefined","relyingPartyName","notNullUndefinedOrEmptyArray","allowedOrigins","storageProvider","messageSendingProviders","expiringCodeProvider","jwtRatchet","Object","assign","userTokenDataProvider","eventProcessor","ExpiringCodeRatchet","options","findEntryByContact","contact","findEntryById","userId","cmdString","origin","loggedInUserId","rval","cmd","JSON","parse","resp","processCommandToResponse","Logger","warn","stringify","err","errString","ErrorRatchet","safeStringifyErr","error","info","sendExpiringValidationToken","generateWebAuthnAuthenticationChallengeForUserId","tmp","dataAsJson","createAccount","sendCode","label","tags","sendMagicLink","contactType","contactMethods","find","cm","type","length","fErr","landingUrl","meta","ttlSeconds","generateWebAuthnRegistrationChallengeForLoggedInUser","StringRatchet","trimToNull","throwFormattedErr","addContactToLoggedInUser","validContact","addContactMethodToUser","addWebAuthnRegistrationToLoggedInUser","data","out","storeAuthnRegistration","updatedEntry","removeWebAuthnRegistration","modified","removeSingleWebAuthnRegistration","credentialId","removeWebAuthnRegistrationFromLoggedInUser","removeContactFromLoggedInUser","output","removeContactMethodFromUser","performLogin","loginData","loginOk","processLogin","user","decoration","userDecorationProvider","fetchDecoration","wardenToken","roles","teamRolesToRoles","proxy","jwtToken","createTokenString","request","refreshJwtToken","parsed","decodeToken","ExpiredJwtHandling","THROW_EXCEPTION","urlIsOnAllowedOrigin","url","u","URL","i","test","protocol","port","metaIn","notNullUndefinedOrOnlyWhitespaceString","true","value","prov","senderForContact","token","createNewCode","context","alphabet","UPPER_CASE_LATIN","timeToLiveSeconds","encodedMeta","Base64Ratchet","safeObjectToBase64JSON","landingUrlFilled","split","join","code","msg","formatMessage","WardenCustomerMessageType","MagicLink","sendMessage","guid","createType4Guid","now","Date","newUser","userLabel","webAuthnAuthenticators","createdEpochMS","updatedEpochMS","next","saveEntry","userCreated","otherUser","curUser","push","filter","s","includes","Error","rpID","hostname","generateRegistrationOptions","rpName","userID","userName","attestationType","excludeCredentials","map","authenticator","id","base64StringToBuffer","credentialPublicKeyBase64","transports","updateUserChallenge","challenge","vrOpts","response","expectedChallenge","fetchCurrentUserChallenge","expectedOrigin","expectedRPID","verification","verifyRegistrationResponse","registrationResponseId","result","verified","WardenStoreRegistrationResponseType","Verified","Failed","newAuth","counter","registrationInfo","credentialBackedUp","credentialDeviceType","credentialIdBase64","generateBase64VersionOfBuffer","Buffer","from","credentialPublicKey","wa","storedUser","generateWebAuthnAuthenticationChallenge","userAuthenticators","generateAuthenticationOptions","allowCredentials","userVerification","p","handlesContactType","ExpiringCode","webAuthn","expiringToken","loginWithWebAuthnRequest","checkCode","trimToEmpty","auth","credentialID","verifyAuthenticationResponse","key","ent","oldUser","removeEntry","userRemoved","WardenMailerMessageSendingProvider","mailer","emailBaseLayoutName","undefined","expiringTokenHtmlTemplateName","expiringTokenTxtTemplateName","magicLinkHtmlTemplateName","magicLinkTxtTemplateName","defaultOptions","messageType","rts","destinationAddresses","subject","fillEmailBody","WardenContactType","EmailAddress","message","sendEmail","debug","WardenS3SingleFileStorageProvider","s3","ratchet","S3CacheRatchet","bucket","fetchDataFile","entries","d","fetchCacheFileAsObject","dataFileKey","challenges","file","writeObjectToCacheFile","relyingPartyId","x","storeDataFile","WardenTwilioTextMessageSendingProvider","optsPromise","TextCapablePhoneNumber","TwilioRatchet","sendMessageDirect","accountSID","authToken","outBoundNumber"],"mappings":"6jBAAO,MAAMA,EACTC,cAAiB,CACjBC,0BASI,MARY,CACRC,QAAS,iBACTC,KAAM,aACNC,OAAQ,eACRC,IAAK,YACLC,aAAc,iBACdC,MAAO,cAGd,ECXE,MAAMC,EACTC,sBAAsBC,GAMlB,MALa,CACTC,cAAeC,EAAYC,0BAA0BH,GACrDI,2BAA4B,KAC5BC,cAAe,CAAC,CAAEC,KAAM,SAAUC,KAAM,SAG/C,ECTE,MAAMC,EACTT,kBAAkBU,GAAU,CAC5BV,kBAAkBU,GAAU,ECWzB,MAAMC,EACTC,UACAC,KACAC,oBACAvB,YAAYqB,GACRG,KAAKH,UAAYA,EACjBI,EAAeC,mBAAmBL,EAAW,WAC7CI,EAAeC,mBAAmBL,EAAUM,iBAAkB,4BAC9DF,EAAeG,6BAA6BP,EAAUQ,eAAgB,0BACtEJ,EAAeC,mBAAmBL,EAAUS,gBAAiB,2BAC7DL,EAAeG,6BAA6BP,EAAUU,wBAAyB,mCAC/EN,EAAeC,mBAAmBL,EAAUW,qBAAsB,gCAClEP,EAAeC,mBAAmBL,EAAUY,WAAY,sBACxDT,KAAKF,KAAOY,OAAOC,OAAO,CAAEC,sBAAuB,IAAI5B,EAAuC6B,eAAgB,IAAInB,GAAuCG,GACzJG,KAAKD,oBAAsB,IAAIe,EAAoBd,KAAKF,KAAKU,qBAChE,CACGO,cACA,OAAOL,OAAOC,OAAO,CAAE,EAAEX,KAAKF,KACjC,CACDkB,mBAAmBC,GACf,OAAOjB,KAAKF,KAAKQ,gBAAgBU,mBAAmBC,EACvD,CACDC,cAAcC,GACV,OAAOnB,KAAKF,KAAKQ,gBAAgBY,cAAcC,EAClD,CACDlC,mCAAmCmC,EAAWC,EAAQC,GAClD,IAAIC,EAAO,KACX,IACI,MAAMC,EAAMC,KAAKC,MAAMN,GACjBO,QAAa3B,KAAK4B,yBAAyBJ,EAAKH,EAAQC,GACjD,OAATK,EACAE,EAAOC,KAAK,iCAAkCV,EAAWC,EAAQC,GAGjEC,EAAOE,KAAKM,UAAUJ,EAE7B,CACD,MAAOK,GACH,MAAMC,EAAYC,EAAaC,iBAAiBH,GAChDH,EAAOO,MAAM,iBAAkBH,EAAWb,EAAWY,GACrDT,EAAOE,KAAKM,UAAU,CAAEK,MAAOH,GAClC,CACD,OAAOV,CACV,CACDtC,+BAA+BuC,EAAKH,EAAQC,GACxC,IAAIC,EAAO,KACX,GAAIC,GAEA,GADAK,EAAOQ,KAAK,0DAA2Df,EAAgBD,EAAQG,GAC3FA,EAAIc,4BACJf,EAAO,CAAEe,kCAAmCtC,KAAKsC,4BAA4Bd,EAAIc,mCAEhF,GAAId,EAAIe,iDAAkD,CAC3D,MAAMC,QAAYxC,KAAKuC,iDAAiDf,EAAIe,iDAAkDlB,GAC9HE,EAAO,CAAEgB,iDAAkD,CAAEE,WAAYhB,KAAKM,UAAUS,IAC3F,MACI,GAAIhB,EAAIkB,cACTnB,EAAO,CACHmB,oBAAqB1C,KAAK0C,cAAclB,EAAIkB,cAAczB,QAASO,EAAIkB,cAAcC,SAAUnB,EAAIkB,cAAcE,MAAOpB,EAAIkB,cAAcG,YAG7I,GAAIrB,EAAIsB,cAAe,CACxB,IAAI7B,EAAUO,EAAIsB,cAAc7B,QAChC,IAAKA,GAAWO,GAAKsB,eAAe3B,OAAQ,CACxC,MAAMxB,QAAcK,KAAKkB,cAAcM,EAAIsB,cAAc3B,QACrDxB,IAEIsB,EADAO,EAAIsB,cAAcC,aACPpD,EAAMqD,gBAAkB,IAAIC,MAAMC,GAAOA,EAAGC,OAAS3B,EAAIsB,cAAcC,eAGvEpD,EAAMqD,gBAAkB,IAAII,OAAS,EAAIzD,EAAMqD,eAAe,GAAK,KAGzF,CACD,IAAK/B,EACD,MAAMiB,EAAamB,KAAK,8DAE5B9B,EAAO,CACHuB,oBAAqB9C,KAAK8C,cAAc7B,EAASO,EAAIsB,cAAcQ,WAAY9B,EAAIsB,cAAcS,KAAM/B,EAAIsB,cAAcU,YAEhI,MACI,GAAIhC,EAAIiC,qDAAsD,CAC1DC,EAAcC,WAAWrC,IAC1BY,EAAa0B,kBAAkB,kCAEnC,MAAMpB,QAAYxC,KAAKyD,qDAAqDnC,EAAgBD,GAC5FE,EAAO,CAAEkC,qDAAsD,CAAEhB,WAAYhB,KAAKM,UAAUS,IAC/F,MACI,GAAIhB,EAAIqC,yBACT,GAAKzE,EAAY0E,aAAatC,EAAIqC,0BAG7B,CAEDtC,EAAO,CAAEsC,+BADS7D,KAAK+D,uBAAuBzC,EAAgBE,EAAIqC,0BAErE,MALG3B,EAAa0B,kBAAkB,iCAAkCpC,EAAIqC,+BAOxE,GAAIrC,EAAIwC,sCAAuC,CAC3CN,EAAcC,WAAWrC,IAC1BY,EAAa0B,kBAAkB,kCAEnC,MAAMK,EAAOxC,KAAKC,MAAMF,EAAIwC,sCAAsCvB,YAC5DyB,QAAYlE,KAAKmE,uBAAuB7C,EAAgBD,EAAQ4C,GAElE1C,EADA2C,EAAIE,aACG,CAAEJ,sCAAuC5E,EAAYC,0BAA0B6E,EAAIE,eAErFF,EAAI9B,MACF,CAAEA,MAAO8B,EAAI9B,OAGb,CAAEA,MAAO,6CAEvB,MACI,GAAIZ,EAAI6C,2BAA4B,CACrC,MAAMC,QAAiBtE,KAAKuE,iCAAiC/C,EAAI6C,2BAA2BlD,OAAQK,EAAI6C,2BAA2BG,cACnIjD,EAAO,CACH8C,2BAA4BjF,EAAYC,0BAA0BiF,GAEzE,MACI,GAAI9C,EAAIiD,2CAA4C,CACrD,MAAMH,QAAiBtE,KAAKuE,iCAAiCjD,EAAgBE,EAAIiD,4CACjFlD,EAAO,CACHkD,2CAA4CrF,EAAYC,0BAA0BiF,GAEzF,MACI,GAAI9C,EAAIkD,8BAA+B,CACxC,MAAMC,QAAe3E,KAAK4E,4BAA4BtD,EAAgBE,EAAIkD,+BAC1EnD,EAAO,CACHmD,8BAA+BtF,EAAYC,0BAA0BsF,GAE5E,MACI,GAAInD,EAAIqD,aAAc,CACvB,MAAMC,EAAYtD,EAAIqD,aAChBE,QAAgB/E,KAAKgF,aAAaF,EAAWzD,GAEnD,GADAQ,EAAOQ,KAAK,+CAAgD0C,GACxDA,EAAS,CACT,MAAME,EAAOvB,EAAcC,WAAWmB,EAAU3D,cACpCnB,KAAKF,KAAKQ,gBAAgBY,cAAc4D,EAAU3D,cAClDnB,KAAKF,KAAKQ,gBAAgBU,mBAAmB8D,EAAU7D,SAC7DiE,QAAmBlF,KAAKF,KAAKqF,uBAAuBC,gBAAgBH,GACpEI,EAAc,CAChBP,UAAW1F,EAAYC,0BAA0B4F,GACjDA,KAAMC,EAAW/F,cACjBmG,MAAOlG,EAAYmG,iBAAiBL,EAAW3F,eAC/CiG,MAAO,MAELC,QAAiBzF,KAAKF,KAAKW,WAAWiF,kBAAkBL,EAAaH,EAAW5F,4BAMtFiC,EAAO,CAAEsD,aALM,CACXc,QAASb,EACT3D,OAAQ8D,EAAK9D,OACbsE,SAAUA,GAGjB,MAEGlE,EAAO,CAAEa,MAAO,eAEvB,MACI,GAAIZ,EAAIoE,gBAAiB,CAC1B,MAAMC,QAAe7F,KAAKF,KAAKW,WAAWqF,YAAYtE,EAAIoE,gBAAiBG,EAAmBC,iBACxFf,QAAajF,KAAKF,KAAKQ,gBAAgBY,cAAc2E,EAAOf,UAAU3D,QACtE+D,QAAmBlF,KAAKF,KAAKqF,uBAAuBC,gBAAgBH,GACpEI,EAAc,CAChBP,UAAW1F,EAAYC,0BAA0B4F,GACjDA,KAAMC,EAAW/F,cACjBmG,MAAOlG,EAAYmG,iBAAiBL,EAAW3F,eAC/CiG,MAAO,MAGXjE,EAAO,CACHqE,sBAFmB5F,KAAKF,KAAKW,WAAWiF,kBAAkBL,EAAaH,EAAW5F,4BAIzF,OAGDiC,EAAO,CAAEa,MAAO,mBAEpB,OAAOb,CACV,CACD0E,qBAAqBC,GACjB,IAAI3E,GAAO,EACX,GAAI2E,EAAK,CACL,MAAMC,EAAI,IAAIC,IAAIF,GAClB,IAAK,IAAIG,EAAI,EAAGA,EAAIrG,KAAKF,KAAKO,eAAe+C,SAAW7B,EAAM8E,IAAK,CAC/D,MAAMC,EAAO,IAAIF,IAAIpG,KAAKF,KAAKO,eAAegG,IAC9C9E,EAAO+E,EAAKjF,SAAW8E,EAAE9E,QAAUiF,EAAKC,WAAaJ,EAAEI,UAAYD,EAAKE,OAASL,EAAEK,IACtF,CACJ,CACD,OAAOjF,CACV,CACDtC,oBAAoBgC,EAASqC,EAAYmD,EAAQjD,EAAa,KAC1D,IAAIjC,GAAO,EAIX,GAHAtB,EAAeC,mBAAmBe,EAAS,WAC3ChB,EAAeyG,uCAAuCpD,EAAY,cAClErD,EAAe0G,KAAK3G,KAAKiG,qBAAqB3C,GAAa,uDACvDrC,GAASkC,MAAQO,EAAcC,WAAW1C,GAAS2F,OAAQ,CAC3D,MAAMC,EAAO7G,KAAK8G,iBAAiB7F,GACnC,GAAI4F,EAAM,CACN,MAAME,QAAc/G,KAAKD,oBAAoBiH,cAAc,CACvDC,QAAShG,EAAQ2F,MACjBxD,OAAQ,GACR8D,SAAUxD,EAAcyD,iBACxBC,kBAAmB5D,EACnBX,KAAM,CAAC,eAELU,EAAO7C,OAAOC,OAAO,CAAE,EAAE8F,GAAU,CAAA,EAAI,CAAExF,QAASA,IAClDoG,EAAcC,EAAcC,uBAAuBhE,GAAQ,CAAE,GACnE,IAAIiE,EAAmBlE,EACvBkE,EAAmBA,EAAiBC,MAAM,UAAUC,KAAKX,EAAMY,MAC/DH,EAAmBA,EAAiBC,MAAM,UAAUC,KAAKL,GACzD,MAAMJ,EAAUvG,OAAOC,OAAO,CAAA,EAAI4C,GAAQ,CAAA,EAAI,CAC1CD,WAAYkE,EACZG,KAAMZ,EAAMY,KACZxH,iBAAkBH,KAAKF,KAAKK,mBAE1ByH,QAAYf,EAAKgB,cAAc5G,EAAS6G,EAA0BC,UAAWd,GACnF1F,QAAasF,EAAKmB,YAAY/G,EAAS2G,EAC1C,MAEG1F,EAAa0B,kBAAkB,wCAAyC3C,EAAQkC,KAEvF,MAEGjB,EAAa0B,kBAAkB,mCAAoC3C,GAEvE,OAAOM,CACV,CACDtC,oBAAoBgC,EAAS0B,EAAUC,EAAOC,GAC1C,IAAItB,EAAO,KACX,GAAInC,EAAY0E,aAAa7C,GAAU,OACjBjB,KAAKF,KAAKQ,gBAAgBU,mBAAmBC,IAE3DiB,EAAa0B,kBAAkB,gDAAiD3C,GAEvEjB,KAAK8G,iBAAiB7F,IAE/BiB,EAAa0B,kBAAkB,kDAAmD3C,EAAQkC,MAE9F,MAAM8E,EAAOvE,EAAcwE,kBACrBC,EAAMC,KAAKD,MACXE,EAAU,CACZlH,OAAQ8G,EACRK,UAAW1F,GAAS,QAAUqF,EAC9BjF,eAAgB,CAAC/B,GACjB4B,KAAMA,GAAQ,GACd0F,uBAAwB,GACxBC,eAAgBL,EAChBM,eAAgBN,GAEdO,QAAa1I,KAAKF,KAAKQ,gBAAgBqI,UAAUN,GACvD9G,EAAOmH,EAAKvH,OACRnB,MAAMF,MAAMe,sBACNb,KAAKF,KAAKe,eAAe+H,YAAYF,GAE3C/F,IACAd,EAAOQ,KAAK,mDAAoDqG,SAC1D1I,KAAKsC,4BAA4BrB,GAE9C,MAEGiB,EAAa0B,kBAAkB,+DAEnC,OAAOrC,CACV,CACDtC,6BAA6BkC,EAAQF,GACjC,IAAIM,GAAO,EACX,GAAImC,EAAcC,WAAWxC,IAAW/B,EAAY0E,aAAa7C,GAAU,CACvE,MAAM4H,QAAkB7I,KAAKF,KAAKQ,gBAAgBU,mBAAmBC,GACjE4H,GAAaA,EAAU1H,SAAWA,GAClCe,EAAa0B,kBAAkB,0EAEnC,MAAMkF,QAAgB9I,KAAKF,KAAKQ,gBAAgBY,cAAcC,GACzD2H,GACD5G,EAAa0B,kBAAkB,wDAEnCkF,EAAQ9F,eAAe+F,KAAK9H,SACtBjB,KAAKF,KAAKQ,gBAAgBqI,UAAUG,GAC1CvH,GAAO,CACV,MAEGW,EAAa0B,kBAAkB,sCAAuCzC,EAAQF,GAElF,OAAOM,CACV,CACDtC,kCAAkCkC,EAAQF,GACtC,IAAIM,EAAO,KACX,GAAImC,EAAcC,WAAWxC,IAAW/B,EAAY0E,aAAa7C,GAAU,CACvE,MAAM6H,QAAgB9I,KAAKF,KAAKQ,gBAAgBY,cAAcC,GACzD2H,GACD5G,EAAa0B,kBAAkB,6DAEnCkF,EAAQ9F,gBAAkB8F,EAAQ9F,gBAAkB,IAAIgG,QAAQC,GAAMA,EAAE9F,OAASlC,EAAQkC,MAAQ8F,EAAErC,QAAU3F,EAAQ2F,QAC/E,IAAlCkC,EAAQ9F,eAAeI,QACvBlB,EAAa0B,kBAAkB,2DAE7B5D,KAAKF,KAAKQ,gBAAgBqI,UAAUG,GAC1CvH,QAAavB,KAAKF,KAAKQ,gBAAgBY,cAAcC,EACxD,MAEGe,EAAa0B,kBAAkB,sCAAuCzC,EAAQF,GAElF,OAAOM,CACV,CACDtC,2DAA2DkC,EAAQE,GAC/D,IAAKA,IAAWrB,KAAKF,KAAKO,eAAe6I,SAAS7H,GAC9C,MAAM,IAAI8H,MAAM,oBAAsB9H,GAE1C,MACM+H,EADQ,IAAIhD,IAAI/E,GACHgI,SACb1J,QAAcK,KAAKF,KAAKQ,gBAAgBY,cAAcC,GACtDJ,QAAgBuI,EAA4B,CAC9CC,OAAQvJ,KAAKF,KAAKK,iBAClBiJ,KAAMA,EACNI,OAAQ7J,EAAMwB,OACdsI,SAAU9J,EAAM2I,UAChBoB,gBAAiB,OACjBC,mBAAoBhK,EAAM4I,uBAAuBqB,KAAKC,IAAmB,CACrEC,GAAIxC,EAAcyC,qBAAqBF,EAAcG,2BACrD7G,KAAM,aACN8G,WAAYJ,EAAcI,iBAIlC,aADMjK,KAAKF,KAAKQ,gBAAgB4J,oBAAoBvK,EAAMwB,OAAQiI,EAAMrI,EAAQoJ,WACzEpJ,CACV,CACD9B,6BAA6BkC,EAAQE,EAAQ4C,GACzCpC,EAAOQ,KAAK,wBAAyB4B,GACrC,IAAI1C,EAAO,KACX,IACI,IAAKF,IAAWrB,KAAKF,KAAKO,eAAe6I,SAAS7H,GAC9C,MAAM,IAAI8H,MAAM,oBAAsB9H,GAE1C,MACM+H,EADQ,IAAIhD,IAAI/E,GACHgI,SACbpE,QAAajF,KAAKF,KAAKQ,gBAAgBY,cAAcC,GAErDiJ,EAAS,CACXC,SAAUpG,EACVqG,wBAH4BtK,KAAKF,KAAKQ,gBAAgBiK,0BAA0BtF,EAAK9D,OAAQiI,GAI7FoB,eAAgBnJ,EAChBoJ,aAAcrB,GAElBvH,EAAOQ,KAAK,yCAA0C+H,GACtD,MAAMM,QAAqBC,EAA2BP,GAOtD,GANAvI,EAAOQ,KAAK,yCAA0CqI,GACtDnJ,EAAO,CACH6C,aAAc,KACdwG,uBAAwB3G,EAAK6F,GAC7Be,OAAQH,EAAaI,SAAWC,EAAoCC,SAAWD,EAAoCE,QAEnH1J,EAAKsJ,SAAWE,EAAoCC,SAAU,CAC9DnJ,EAAOQ,KAAK,wBACZ,MAAM6I,EAAU,CACZC,QAAST,EAAaU,iBAAiBD,QACvCE,mBAAoBX,EAAaU,iBAAiBC,mBAClDC,qBAAsBZ,EAAaU,iBAAiBE,qBACpDC,mBAAoBtH,EAAK6F,GACzBE,0BAA2B1C,EAAckE,8BAA8BC,OAAOC,KAAKhB,EAAaU,iBAAiBO,uBAErH1G,EAAKsD,wBAA0BtD,EAAKsD,wBAA0B,IAAIS,QAAQ4C,GAAOA,EAAGL,qBAAuBL,EAAQK,qBACnHtG,EAAKsD,uBAAuBQ,KAAKmC,GACjC,MAAMW,QAAmB7L,KAAKF,KAAKQ,gBAAgBqI,UAAU1D,GAC7D1D,EAAK6C,aAAeyH,EACpBhK,EAAOQ,KAAK,mBAAoBwJ,EACnC,CACJ,CACD,MAAO7J,GACHT,EAAO,CACHqJ,uBAAwB3G,EAAK6F,GAC7Be,OAAQE,EAAoC5B,MAC5C/G,MAAOF,EAAaC,iBAAiBH,GAE5C,CACD,OAAOT,CACV,CACDtC,uDAAuDkC,EAAQE,GAC3D,MAAM4D,QAAajF,KAAKF,KAAKQ,gBAAgBY,cAAcC,GAE3D,aADmBnB,KAAK8L,wCAAwC7G,EAAM5D,EAEzE,CACDpC,8CAA8CgG,EAAM5D,GAChD,MAAM0K,EAAqB9G,EAAKsD,uBAChC,IAAKlH,IAAWrB,KAAKF,KAAKO,eAAe6I,SAAS7H,GAC9C,MAAM,IAAI8H,MAAM,oBAAsB9H,GAE1C,MACM+H,EADQ,IAAIhD,IAAI/E,GACHgI,SACbnF,EAAM6H,EAAmBnC,KAAKC,IACnB,CACTC,GAAI2B,OAAOC,KAAK7B,EAAc0B,mBAAoB,UAClDpI,KAAM,aACN8G,WAAYJ,EAAcI,eAI5BlJ,QAAgBiL,EAA8B,CAChDC,iBAAkB/H,EAClBgI,iBAAkB,cAGtB,aADMlM,KAAKF,KAAKQ,gBAAgB4J,oBAAoBjF,EAAK9D,OAAQiI,EAAMrI,EAAQoJ,WACxEpJ,CACV,CACD+F,iBAAiB7F,GACb,IAAIM,EAAO,KAIX,OAHIN,GAASkC,OACT5B,GAAQvB,KAAKF,KAAKS,yBAA2B,IAAI0C,MAAMkJ,GAAMA,EAAEC,mBAAmBnL,EAAQkC,SAEvF5B,CACV,CACDtC,kCAAkC0G,GAC9B,IAAIpE,GAAO,EACX,GAAIoE,GAASxC,MAAQO,EAAcC,WAAWgC,GAASiB,OAAQ,CAC3D,MAAMC,EAAO7G,KAAK8G,iBAAiBnB,GACnC,GAAIkB,EAAM,CACN,MAAME,QAAc/G,KAAKD,oBAAoBiH,cAAc,CACvDC,QAAStB,EAAQiB,MACjBxD,OAAQ,EACR8D,SAAU,aACVE,kBAAmB,IACnBvE,KAAM,CAAC,WAEL+E,QAAYf,EAAKgB,cAAclC,EAASmC,EAA0BuE,aAAc,CAClF1E,KAAMZ,EAAMY,KACZxH,iBAAkBH,KAAKF,KAAKK,mBAEhCoB,QAAasF,EAAKmB,YAAYrC,EAASiC,EAC1C,MAEG1F,EAAa0B,kBAAkB,wCAAyC+B,EAAQxC,KAEvF,MAEGjB,EAAa0B,kBAAkB,mCAAoC+B,GAEvE,OAAOpE,CACV,CACDtC,mBAAmB0G,EAAStE,GACxBQ,EAAOQ,KAAK,6BAA8BhB,EAAQsE,GAClD,IAAIpE,GAAO,EACXtB,EAAeC,mBAAmByF,EAAS,WAC3C1F,EAAe0G,OAAOjD,EAAcC,WAAWgC,GAASxE,SAAW/B,EAAY0E,aAAa6B,GAAS1E,SAAU,iCAC/GhB,EAAe0G,OAAOhB,GAAS2G,YAAc5I,EAAcC,WAAWgC,GAAS4G,eAAgB,qDAC/FtM,EAAe0G,MAAMhB,GAAS2G,WAAa5I,EAAcC,WAAWgC,GAAS4G,eAAgB,kDAC7F,MAAMtH,EAAOvB,EAAcC,WAAWgC,GAASxE,cACnCnB,KAAKF,KAAKQ,gBAAgBY,cAAcyE,GAASxE,cACjDnB,KAAKF,KAAKQ,gBAAgBU,mBAAmB2E,EAAQ1E,SAIjE,GAHKgE,GACD/C,EAAa0B,kBAAkB,4BAA6B+B,GAAS1E,QAAS0E,GAASxE,QAEvFwE,EAAQ2G,SACR/K,QAAavB,KAAKwM,yBAAyBvH,EAAM5D,EAAQsE,EAAQ2G,eAEhE,GAAI5I,EAAcC,WAAWgC,EAAQ4G,eAAgB,OACjCvM,KAAKD,oBAAoB0M,UAAU/I,EAAcgJ,YAAY/G,EAAQ4G,eAAgB7I,EAAcgJ,YAAY/G,EAAQ1E,QAAQ2F,QAAQ,GAExJrF,GAAO,EAGPW,EAAa0B,kBAAkB,gDAEtC,CACD,OAAOrC,CACV,CACDtC,+BAA+BgG,EAAM5D,EAAQ4C,GACzC,IAAI1C,GAAO,EACX,MACM6H,EADQ,IAAIhD,IAAI/E,GACHgI,SACbiB,QAA0BtK,KAAKF,KAAKQ,gBAAgBiK,0BAA0BtF,EAAK9D,OAAQiI,GAC3FuD,GAAQ1H,EAAKsD,wBAA0B,IAAItF,MAAMgG,GAAMA,EAAEsC,qBAAuBtH,EAAK6F,KAC3F,IAAK6C,EACD,MAAM,IAAIxD,MAAM,gCAAgClF,EAAK6F,eAAe7E,EAAK9D,UAE7E,MAAM0I,EAAgB,CAClBsB,QAASwB,EAAKxB,QACdyB,aAActF,EAAcyC,qBAAqB4C,EAAKpB,oBACtDI,oBAAqBrE,EAAcyC,qBAAqB4C,EAAK3C,4BAE3DI,EAAS,CACXC,SAAUpG,EACVqG,oBACAE,eAAgBnJ,EAChBoJ,aAAcrB,EACdS,iBAMJ,aAJ2BgD,EAA6BzC,IACvCU,WACbvJ,GAAO,GAEJA,CACV,CACDtC,uCAAuCkC,EAAQ2L,GAC3C,IAAIC,QAAY/M,KAAKF,KAAKQ,gBAAgBY,cAAcC,GAQxD,OAPI4L,GACAA,EAAIxE,wBAA0BwE,EAAIxE,wBAA0B,IAAIS,QAAQC,GAAMA,EAAEsC,qBAAuBuB,IACvGC,QAAY/M,KAAKF,KAAKQ,gBAAgBqI,UAAUoE,IAGhDlL,EAAOQ,KAAK,oCAAqClB,GAE9C4L,CACV,CACD9N,iBAAiBkC,GACb,IAAII,GAAO,EACX,GAAImC,EAAcC,WAAWxC,GAAS,CAClC,MAAM6L,QAAgBhN,KAAKF,KAAKQ,gBAAgBY,cAAcC,GAC1D6L,SACMhN,KAAKF,KAAKQ,gBAAgB2M,YAAY9L,GACxCnB,MAAMF,MAAMe,sBACNb,KAAKF,KAAKe,eAAeqM,YAAYF,GAE/CzL,GAAO,GAGPM,EAAOC,KAAK,uCAAwCX,EAE3D,CACD,OAAOI,CACV,EC9gBE,MAAM4L,EACTC,OACArM,QACAtC,wBAQI,MAPa,CACT4O,yBAAqBC,EACrBC,8BAA+B,+BAC/BC,kCAA8BF,EAC9BG,0BAA2B,4BAC3BC,8BAA0BJ,EAGjC,CACD9O,YAAY4O,EAAQrM,EAAUoM,EAAmCQ,kBAC7D3N,KAAKoN,OAASA,EACdpN,KAAKe,QAAUA,CAClB,CACD9B,oBAAoBgC,EAAS2M,EAAa3G,GACtC,MAAM4G,EAAM,CACRC,qBAAsB,CAAC7M,EAAQ2F,OAC/BmH,QAAS,oBAEb,GAAIH,IAAgB9F,EAA0BuE,mBACpCrM,KAAKoN,OAAOY,cAAcH,EAAK5G,EAASjH,KAAKe,QAAQwM,8BAA+BvN,KAAKe,QAAQyM,6BAA8BxN,KAAKe,QAAQsM,yBAEjJ,IAAIO,IAAgB9F,EAA0BC,UAI/C,MAAM7F,EAAamB,KAAK,4BAA6BuK,SAH/C5N,KAAKoN,OAAOY,cAAcH,EAAK5G,EAASjH,KAAKe,QAAQ0M,0BAA2BzN,KAAKe,QAAQ2M,yBAA0B1N,KAAKe,QAAQsM,oBAI7I,CACD,OAAOQ,CACV,CACDzB,mBAAmBjJ,GACf,OAAOA,IAAS8K,EAAkBC,YACrC,CACDjP,kBAAkBgC,EAASkN,GACvB,MAAM5M,QAAavB,KAAKoN,OAAOgB,UAAUD,GAEzC,OADAtM,EAAOwM,MAAM,gCAAiC9M,KACrCA,CACZ,ECvCE,MAAM+M,EACTC,GACAxN,QACAyN,QACAhQ,YAAY+P,EAAIxN,GACZf,KAAKuO,GAAKA,EACVvO,KAAKe,QAAUA,EACff,KAAKwO,QAAU,IAAIC,EAAezO,KAAKuO,GAAIvO,KAAKe,QAAQ2N,OAC3D,CACDzP,0BAGI,aAFuBe,KAAK2O,iBAAiBC,QACxBhF,KAAKiF,GAAMzP,EAAYC,0BAA0BwP,IAEzE,CACD5P,sBACI,IAAIgF,QAAajE,KAAKwO,QAAQM,uBAAuB9O,KAAKe,QAAQgO,aAKlE,OAJA9K,EAAOA,GAAQ,CACX2K,QAAS,GACTI,WAAY,IAET/K,CACV,CACDhF,oBAAoBgQ,GAChB,IAAI1N,EAAO,KAIX,OAHI0N,IACA1N,QAAavB,KAAKwO,QAAQU,uBAAuBlP,KAAKe,QAAQgO,YAAaE,IAExE1N,CACV,CACDtC,gCAAgCkC,EAAQgO,GACpC,MACMxP,UADaK,KAAK2O,iBACJK,YAAc,IAAI/L,MAAM4L,GAAMA,EAAE1N,SAAWA,GAAU0N,EAAEM,iBAAmBA,IAI9F,OAHKxP,GACDuC,EAAa0B,kBAAkB,oDAAqDzC,GAEjFxB,EAAMwK,SAChB,CACDlL,yBAAyBgC,GACrB,IAAIM,EAAO,KACX,GAAIN,GAASkC,MAAQO,EAAcC,WAAW1C,GAAS2F,OAAQ,CAE3DrF,UADmBvB,KAAK2O,iBACXC,SAAW,IAAI3L,MAAM4L,MAASA,EAAE7L,gBAAkB,IAAIC,MAAMmM,GAAMA,EAAEjM,OAASlC,EAAQkC,MAAQiM,EAAExI,QAAU3F,EAAQ2F,SACjI,CACD,OAAOrF,CACV,CACDtC,oBAAoBkC,GAChB,IAAII,EAAO,KACX,GAAImC,EAAcC,WAAWxC,GAAS,CAElCI,UADmBvB,KAAK2O,iBACXC,SAAW,IAAI3L,MAAM4L,GAAMA,EAAE1N,SAAWA,GACxD,CACD,OAAOI,CACV,CACDtC,kBAAkBkC,GACd,MAAM8C,QAAajE,KAAK2O,gBAGxB,OAFA1K,EAAK2K,SAAW3K,EAAK2K,SAAW,IAAI5F,QAAQ6F,GAAMA,EAAE1N,SAAWA,UACzDnB,KAAKqP,cAAcpL,IAClB,CACV,CACDhF,gBAAgBU,GACZ,IAAI4B,EAAO,KACX,GAAI5B,GAASA,EAAMwB,OAAQ,CACvB,MAAMgH,EAAMC,KAAKD,MACjBxI,EAAM6I,eAAiB7I,EAAM6I,gBAAkBL,EAC/CxI,EAAM8I,eAAiBN,EACvB,MAAMlE,QAAajE,KAAK2O,gBACxB1K,EAAK2K,SAAW3K,EAAK2K,SAAW,IAAI5F,QAAQ6F,GAAMA,EAAE1N,SAAWxB,EAAMwB,SACrE8C,EAAK2K,QAAQ7F,KAAKpJ,SACZK,KAAKqP,cAAcpL,GACzB1C,QAAavB,KAAKkB,cAAcvB,EAAMwB,OACzC,CACD,OAAOI,CACV,CACDtC,0BAA0BkC,EAAQgO,EAAgBhF,GAC9C,MAAMlG,QAAajE,KAAK2O,gBASxB,OARA1K,EAAK+K,YAAc/K,EAAK+K,YAAc,IAAIhG,QAAQ6F,GAAMA,EAAE1N,SAAWA,GAAU0N,EAAEM,iBAAmBA,IACpGlL,EAAK+K,WAAWjG,KAAK,CACjB5H,OAAQA,EACRgO,eAAgBA,EAChBhF,UAAWA,EACX1B,eAAgBL,KAAKD,cAEnBnI,KAAKqP,cAAcpL,IAClB,CACV,ECpFE,MAAMqL,EACTC,YACA/Q,YAAY+Q,GACRvP,KAAKuP,YAAcA,CACtB,CACDtQ,oBAAoBgC,EAAS2M,EAAa3G,GACtC,IAAIW,EAAM,KAEV,GADA/F,EAAOQ,KAAK,iBACRuL,IAAgB9F,EAA0BuE,aAC1CzE,EACIX,EAAc,KACV,YACAA,EAA0B,iBAC1B,2BACAA,EAA0B,iBAC1B,KACAA,EAAc,SAErB,IAAI2G,IAAgB9F,EAA0BC,UAI/C,MAAM7F,EAAamB,KAAK,4BAA6BuK,GAHrDhG,EAAM,uBAAyBX,EAA0B,iBAAI,OAASA,EAAoB,UAI7F,CACD,OAAOW,CACV,CACDwE,mBAAmBjJ,GACf,OAAOA,IAAS8K,EAAkBuB,sBACrC,CACDvQ,kBAAkBgC,EAASkN,GACvB,MAAMrO,QAAaE,KAAKuP,YAClBhO,QAAakO,EAAcC,kBAAkB5P,EAAK6P,WAAY7P,EAAK8P,UAAW9P,EAAK+P,eAAgB,CAAC5O,EAAQ2F,OAAQuH,GAE1H,OADAtM,EAAOwM,MAAM,uBAAwB9M,KAC5BA,GAAQA,EAAK6B,OAAS,CAClC"}
@@ -18,7 +18,7 @@ export declare class WardenService {
18
18
  processCommandStringToString(cmdString: string, origin: string, loggedInUserId: string): Promise<string>;
19
19
  processCommandToResponse(cmd: WardenCommand, origin: string, loggedInUserId: string): Promise<WardenCommandResponse>;
20
20
  urlIsOnAllowedOrigin(url: string): boolean;
21
- sendMagicLink(contact: WardenContact, landingUrl: string, metaIn?: Record<string, string>): Promise<boolean>;
21
+ sendMagicLink(contact: WardenContact, landingUrl: string, metaIn?: Record<string, string>, ttlSeconds?: number): Promise<boolean>;
22
22
  createAccount(contact: WardenContact, sendCode?: boolean, label?: string, tags?: string[]): Promise<string>;
23
23
  addContactMethodToUser(userId: string, contact: WardenContact): Promise<boolean>;
24
24
  removeContactMethodFromUser(userId: string, contact: WardenContact): Promise<WardenEntry>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitblit/ratchet-warden-server",
3
- "version": "4.0.210-alpha",
3
+ "version": "4.0.211-alpha",
4
4
  "description": "Typescript library to simplify using simplewebauthn and secondary auth methods over GraphQL",
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -49,9 +49,9 @@
49
49
  "dependencies": {
50
50
  "@aws-sdk/client-s3": "3.370.0",
51
51
  "@aws-sdk/client-ses": "3.370.0",
52
- "@bitblit/ratchet-aws": "4.0.210-alpha",
53
- "@bitblit/ratchet-common": "4.0.210-alpha",
54
- "@bitblit/ratchet-warden-common": "4.0.210-alpha",
52
+ "@bitblit/ratchet-aws": "4.0.211-alpha",
53
+ "@bitblit/ratchet-common": "4.0.211-alpha",
54
+ "@bitblit/ratchet-warden-common": "4.0.211-alpha",
55
55
  "@simplewebauthn/browser": "8.0.2",
56
56
  "@simplewebauthn/iso-webcrypto": "7.4.0",
57
57
  "@simplewebauthn/server": "8.0.1",