diff --git a/examples/email-recovery/.env.local.example b/examples/email-recovery/.env.local.example index 010c8ff31..0cc922464 100644 --- a/examples/email-recovery/.env.local.example +++ b/examples/email-recovery/.env.local.example @@ -4,4 +4,4 @@ NEXT_PUBLIC_ORGANIZATION_ID="" NEXT_PUBLIC_BASE_URL="https://api.turnkey.com" # Can be changed to a localhost iframe if you're modifying the recovery flow # For production, the URL should not be changed and point to the primary Turnkey domain. -NEXT_PUBLIC_RECOVERY_IFRAME_URL="https://recovery.turnkey.com" \ No newline at end of file +NEXT_PUBLIC_RECOVERY_IFRAME_URL="https://recovery.turnkey.com" diff --git a/examples/email-recovery/README.md b/examples/email-recovery/README.md index b3a8c0454..2b5273e4d 100644 --- a/examples/email-recovery/README.md +++ b/examples/email-recovery/README.md @@ -8,7 +8,7 @@ This example shows a complete email recovery flow. It contains a NextJS app with The overall flow for email recovery is outlined below: ![Email recovery flow diagram](./email_recovery_steps.png) -This example contains an example recovery page as well as a stub API endpoint for "your business" (where the email is resolved into an organization ID). The creation of the hidden iframe is abstracted by our `@turnkey/iframe-stamper` package. +This example contains an example recovery page as well as a stub API endpoint for "your business" (where the email is resolved into an organization ID). The creation of the hidden iframe is abstracted by our `@turnkey/iframe-stamper` package. For more information on email recovery, [check out our documentation](https://docs.turnkey.com/getting-started/email-recovery). ## Getting started diff --git a/examples/email-recovery/src/pages/index.tsx b/examples/email-recovery/src/pages/index.tsx index 09bb1e3f3..be7105e58 100644 --- a/examples/email-recovery/src/pages/index.tsx +++ b/examples/email-recovery/src/pages/index.tsx @@ -86,11 +86,13 @@ export default function RecoveryPage() { throw new Error("initRecoveryResponse is null"); } - let injected = await iframeStamper.injectRecoveryBundle( - data.recoveryBundle - ); - if (injected !== true) { - throw new Error("unexpected error while injecting recovery bundle"); + try { + await iframeStamper.injectRecoveryBundle(data.recoveryBundle); + } catch (e) { + const msg = `error while injecting bundle: ${e}`; + console.error(msg); + alert(msg); + return; } const challenge = generateRandomBuffer(); diff --git a/packages/iframe-stamper/src/index.ts b/packages/iframe-stamper/src/index.ts index d9adcb974..3b2403e37 100644 --- a/packages/iframe-stamper/src/index.ts +++ b/packages/iframe-stamper/src/index.ts @@ -26,6 +26,9 @@ export enum IframeEventType { // Event sent by the iframe to communicate the result of a stamp operation. // Value: signed payload Stamp = "STAMP", + // Event sent by the iframe to communicate an error + // Value: serialized error + Error = "ERROR", } type TStamp = { @@ -129,15 +132,15 @@ export class IframeStamper { * This is used during recovery flows. */ async injectRecoveryBundle(bundle: string): Promise { - this.iframe.contentWindow?.postMessage( - { - type: IframeEventType.InjectRecoveryBundle, - value: bundle, - }, - "*" - ); + return new Promise((resolve, reject) => { + this.iframe.contentWindow?.postMessage( + { + type: IframeEventType.InjectRecoveryBundle, + value: bundle, + }, + "*" + ); - return new Promise((resolve, _reject) => { window.addEventListener( "message", (event) => { @@ -149,6 +152,9 @@ export class IframeStamper { if (event.data?.type === IframeEventType.BundleInjected) { resolve(event.data["value"]); } + if (event.data?.type === IframeEventType.Error) { + reject(event.data["value"]); + } }, false ); @@ -170,7 +176,7 @@ export class IframeStamper { "*" ); - return new Promise((resolve, _reject) => { + return new Promise((resolve, reject) => { window.addEventListener( "message", (event) => { @@ -182,6 +188,9 @@ export class IframeStamper { if (event.data?.type === IframeEventType.BundleInjected) { resolve(event.data["value"]); } + if (event.data?.type === IframeEventType.Error) { + reject(event.data["value"]); + } }, false ); @@ -203,7 +212,7 @@ export class IframeStamper { "*" ); - return new Promise((resolve, _reject) => { + return new Promise((resolve, reject) => { window.addEventListener( "message", (event) => { @@ -215,6 +224,9 @@ export class IframeStamper { if (event.data?.type === IframeEventType.BundleInjected) { resolve(event.data["value"]); } + if (event.data?.type === IframeEventType.Error) { + reject(event.data["value"]); + } }, false ); @@ -241,7 +253,7 @@ export class IframeStamper { "*" ); - return new Promise(function (resolve, _reject) { + return new Promise(function (resolve, reject) { window.addEventListener( "message", (event) => { @@ -256,6 +268,9 @@ export class IframeStamper { stampHeaderValue: event.data["value"], }); } + if (event.data?.type === IframeEventType.Error) { + reject(event.data["value"]); + } }, false );