From ccdf05a6357d9582bdb67e8de3f9ba7e819c034d Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Thu, 26 Aug 2021 17:39:52 +0200 Subject: [PATCH] Add connector for mobile webauthn (#1154) Adds a dedicated connector for handling WebAuthN for our mobile application. Which uses redirects instead of postMessage. --- src/connectors/webauthn-mobile.html | 19 +++++++++++++++++++ src/connectors/webauthn.ts | 24 ++++++++++++++++++++---- webpack.config.js | 5 +++++ 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 src/connectors/webauthn-mobile.html diff --git a/src/connectors/webauthn-mobile.html b/src/connectors/webauthn-mobile.html new file mode 100644 index 0000000000..c29d0ef8d9 --- /dev/null +++ b/src/connectors/webauthn-mobile.html @@ -0,0 +1,19 @@ + + + + + + + + + Bitwarden Mobile WebAuthn Connector + + + + +
+ +
+ + + diff --git a/src/connectors/webauthn.ts b/src/connectors/webauthn.ts index 2c1af50d33..692f321300 100644 --- a/src/connectors/webauthn.ts +++ b/src/connectors/webauthn.ts @@ -9,6 +9,7 @@ let webauthnJson: any; let btnText: string = null; let parentUrl: string = null; let parentOrigin: string = null; +let callbackUri: string = null; let stopWebAuthn = false; let sentSuccess = false; let obj: any = null; @@ -66,7 +67,7 @@ function parseParametersV1() { } function parseParametersV2() { - let dataObj: { data: any, btnText: string; } = null; + let dataObj: { data: any, btnText: string; callbackUri?: string } = null; try { dataObj = JSON.parse(b64Decode(getQsParam('data'))); } @@ -75,6 +76,7 @@ function parseParametersV2() { return; } + callbackUri = dataObj.callbackUri; webauthnJson = dataObj.data; btnText = dataObj.btnText; } @@ -104,7 +106,7 @@ function start() { stopWebAuthn = false; if (navigator.userAgent.indexOf(' Safari/') !== -1 && navigator.userAgent.indexOf('Chrome') === -1) { - // TODO: Hide image, show button + // Safari blocks non-user initiated WebAuthn requests. } else { executeWebAuthn(); } @@ -136,7 +138,11 @@ function onMessage() { } function error(message: string) { - parent.postMessage('error|' + message, parentUrl); + if (callbackUri) { + document.location.replace(callbackUri + '?error=' + encodeURIComponent(message)); + } else { + parent.postMessage('error|' + message, parentUrl); + } } function success(assertedCredential: PublicKeyCredential) { @@ -145,11 +151,21 @@ function success(assertedCredential: PublicKeyCredential) { } const dataString = buildDataString(assertedCredential); - parent.postMessage('success|' + dataString, parentUrl); + + if (callbackUri) { + document.location.replace(callbackUri + '?data=' + encodeURIComponent(dataString)); + } else { + parent.postMessage('success|' + dataString, parentUrl); + } + sentSuccess = true; } function info(message: string) { + if (callbackUri) { + return; + } + parent.postMessage('info|' + message, parentUrl); } diff --git a/webpack.config.js b/webpack.config.js index 0d5b88962e..2db0e87a90 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -97,6 +97,11 @@ const plugins = [ filename: 'webauthn-connector.html', chunks: ['connectors/webauthn'], }), + new HtmlWebpackPlugin({ + template: './src/connectors/webauthn-mobile.html', + filename: 'webauthn-mobile-connector.html', + chunks: ['connectors/webauthn'], + }), new HtmlWebpackPlugin({ template: './src/connectors/webauthn-fallback.html', filename: 'webauthn-fallback-connector.html',