From 111c9e42f6b399bd9ec0da26b510a6ea4237f56b Mon Sep 17 00:00:00 2001 From: Ian K Smith Date: Thu, 28 Jan 2021 11:03:11 -0700 Subject: [PATCH 1/2] Support UTF-8 characters when encoding iframe options to Base64 --- packages/provider/src/util/base64-json.ts | 32 +++++++++++++++++-- .../src/react-native-webview-controller.tsx | 2 +- packages/web/src/iframe-controller.ts | 4 +-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/packages/provider/src/util/base64-json.ts b/packages/provider/src/util/base64-json.ts index b51b20b62..1dba03083 100644 --- a/packages/provider/src/util/base64-json.ts +++ b/packages/provider/src/util/base64-json.ts @@ -1,13 +1,41 @@ +function percentToByte(p: string) { + return String.fromCharCode(parseInt(p.slice(1), 16)); +} + +function byteToPercent(b: string) { + return `%${`00${b.charCodeAt(0).toString(16)}`.slice(-2)}`; +} + +/** + * Encodes a URI-safe Base64 string. Safe for UTF-8 characters. + * Original source is from the `universal-base64` NPM package. + * + * @source https://github.com/blakeembrey/universal-base64/blob/master/src/browser.ts + */ +function btoaUTF8(str: string): string { + return btoa(encodeURIComponent(str).replace(/%[0-9A-F]{2}/g, percentToByte)); +} + +/** + * Decodes a URI-safe Base64 string. Safe for UTF-8 characters. + * Original source is from the `universal-base64` NPM package. + * + * @source https://github.com/blakeembrey/universal-base64/blob/master/src/browser.ts + */ +function atobUTF8(str: string): string { + return decodeURIComponent(Array.from(atob(str), byteToPercent).join('')); +} + /** * Given a JSON-serializable object, encode as a Base64 string. */ export function encodeJSON(options: T): string { - return btoa(JSON.stringify(options)); + return btoaUTF8(JSON.stringify(options)); } /** * Given a Base64 JSON string, decode a JavaScript object. */ export function decodeJSON(queryString: string): T { - return JSON.parse(atob(queryString)); + return JSON.parse(atobUTF8(queryString)); } diff --git a/packages/react-native/src/react-native-webview-controller.tsx b/packages/react-native/src/react-native-webview-controller.tsx index 7fcc4c9a4..b3c0d3552 100644 --- a/packages/react-native/src/react-native-webview-controller.tsx +++ b/packages/react-native/src/react-native-webview-controller.tsx @@ -119,7 +119,7 @@ export class ReactNativeWebViewController extends ViewController diff --git a/packages/web/src/iframe-controller.ts b/packages/web/src/iframe-controller.ts index 4dec3ffde..d771dde18 100644 --- a/packages/web/src/iframe-controller.ts +++ b/packages/web/src/iframe-controller.ts @@ -52,12 +52,12 @@ export class IframeController extends ViewController { protected init() { this.iframe = new Promise((resolve) => { const onload = () => { - if (!checkForSameSrcInstances(encodeURIComponent(this.parameters))) { + if (!checkForSameSrcInstances(this.parameters)) { const iframe = document.createElement('iframe'); iframe.classList.add('magic-iframe'); iframe.dataset.magicIframeLabel = createURL(this.endpoint).host; iframe.title = 'Secure Modal'; - iframe.src = createURL(`/send?params=${encodeURIComponent(this.parameters)}`, this.endpoint).href; + iframe.src = createURL(`/send?params=${this.parameters}`, this.endpoint).href; applyOverlayStyles(iframe); document.body.appendChild(iframe); resolve(iframe); From 2076a0bbfd005f731de6ec3de4622eb78ddd7090 Mon Sep 17 00:00:00 2001 From: Ian K Smith Date: Thu, 28 Jan 2021 12:35:32 -0700 Subject: [PATCH 2/2] Update implementation to support changes in iframe --- packages/provider/src/util/base64-json.ts | 4 ++-- packages/react-native/src/react-native-webview-controller.tsx | 2 +- packages/web/src/iframe-controller.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/provider/src/util/base64-json.ts b/packages/provider/src/util/base64-json.ts index 1dba03083..8b8eb2ad5 100644 --- a/packages/provider/src/util/base64-json.ts +++ b/packages/provider/src/util/base64-json.ts @@ -7,7 +7,7 @@ function byteToPercent(b: string) { } /** - * Encodes a URI-safe Base64 string. Safe for UTF-8 characters. + * Encodes a Base64 string. Safe for UTF-8 characters. * Original source is from the `universal-base64` NPM package. * * @source https://github.com/blakeembrey/universal-base64/blob/master/src/browser.ts @@ -17,7 +17,7 @@ function btoaUTF8(str: string): string { } /** - * Decodes a URI-safe Base64 string. Safe for UTF-8 characters. + * Decodes a Base64 string. Safe for UTF-8 characters. * Original source is from the `universal-base64` NPM package. * * @source https://github.com/blakeembrey/universal-base64/blob/master/src/browser.ts diff --git a/packages/react-native/src/react-native-webview-controller.tsx b/packages/react-native/src/react-native-webview-controller.tsx index b3c0d3552..7fcc4c9a4 100644 --- a/packages/react-native/src/react-native-webview-controller.tsx +++ b/packages/react-native/src/react-native-webview-controller.tsx @@ -119,7 +119,7 @@ export class ReactNativeWebViewController extends ViewController diff --git a/packages/web/src/iframe-controller.ts b/packages/web/src/iframe-controller.ts index d771dde18..4dec3ffde 100644 --- a/packages/web/src/iframe-controller.ts +++ b/packages/web/src/iframe-controller.ts @@ -52,12 +52,12 @@ export class IframeController extends ViewController { protected init() { this.iframe = new Promise((resolve) => { const onload = () => { - if (!checkForSameSrcInstances(this.parameters)) { + if (!checkForSameSrcInstances(encodeURIComponent(this.parameters))) { const iframe = document.createElement('iframe'); iframe.classList.add('magic-iframe'); iframe.dataset.magicIframeLabel = createURL(this.endpoint).host; iframe.title = 'Secure Modal'; - iframe.src = createURL(`/send?params=${this.parameters}`, this.endpoint).href; + iframe.src = createURL(`/send?params=${encodeURIComponent(this.parameters)}`, this.endpoint).href; applyOverlayStyles(iframe); document.body.appendChild(iframe); resolve(iframe);