1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-07 20:24:01 +00:00

fix(redirect): [PM-26578] Https Redirection for Cloud Users - Made redirect uri not required for mobile webauthn

This commit is contained in:
Patrick Pimentel
2026-01-09 14:05:41 -05:00
parent c6b7177886
commit ce0e7884b4
3 changed files with 29 additions and 36 deletions

View File

@@ -40,7 +40,7 @@ function appLinkHost(): string {
return "bitwarden.com";
}
export function buildMobileCallbackUriFromParam(kind: "duo" | "webauthn"): string {
export function buildMobileDeeplinkUriFromParam(kind: "duo" | "webauthn"): string {
const scheme = (getQsParam("deeplinkScheme") || "").toLowerCase();
const path = `${kind}-callback`;
if (scheme === "https") {

View File

@@ -1,4 +1,4 @@
import { buildMobileCallbackUriFromParam, getQsParam } from "./common";
import { buildMobileDeeplinkUriFromParam, getQsParam } from "./common";
import { TranslationService } from "./translation.service";
const mobileDesktopCallback = "bitwarden://duo-callback";
@@ -40,7 +40,7 @@ window.addEventListener("load", async () => {
displayHandoffMessage(client);
} else if (client === "mobile") {
document.location.replace(
buildMobileCallbackUriFromParam("duo") +
buildMobileDeeplinkUriFromParam("duo") +
"?code=" +
encodeURIComponent(code) +
"&state=" +

View File

@@ -1,6 +1,6 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { b64Decode, buildMobileCallbackUriFromParam, getQsParam } from "./common";
import { b64Decode, getQsParam } from "./common";
import { buildDataString, parseWebauthnJson } from "./common-webauthn";
let parsed = false;
@@ -11,7 +11,7 @@ let btnAwaitingInteractionText: string = null;
let btnReturnText: string = null;
let parentUrl: string = null;
let parentOrigin: string = null;
let mobileResponse = false;
let callbackUri: string = null;
let stopWebAuthn = false;
let sentSuccess = false;
let obj: any = null;
@@ -81,21 +81,8 @@ function parseParameters() {
return;
}
// Determine if this is a mobile-initiated flow via query param
const client: string | null = getQsParam("client");
if (client === "mobile") {
mobileResponse = true;
}
parentUrl = getQsParam("parent");
if (!parentUrl) {
// In non-mobile flows we must have a parent for postMessage handoff
if (!mobileResponse) {
error("No parent.");
return;
}
} else {
if (parentUrl) {
parentUrl = decodeURIComponent(parentUrl);
parentOrigin = new URL(parentUrl).origin;
}
@@ -107,6 +94,13 @@ function parseParameters() {
} else {
parseParametersV2();
}
// Require at least one return mechanism
if (!parentUrl && !callbackUri) {
error("No return target provided.");
return;
}
parsed = true;
}
@@ -131,7 +125,6 @@ function parseParametersV2() {
btnText: string;
btnReturnText: string;
callbackUri?: string;
mobile?: boolean;
} = null;
try {
dataObj = JSON.parse(b64Decode(getQsParam("data")));
@@ -142,8 +135,8 @@ function parseParametersV2() {
return;
}
// Treat presence of callbackUri/mobile in payload as mobile, or preserve existing mobileResponse (e.g., set by client=mobile)
mobileResponse = mobileResponse || dataObj.callbackUri != null || dataObj.mobile === true;
// Use optional callbackUri to indicate deep-link return; otherwise we will use postMessage to parent
callbackUri = dataObj.callbackUri ?? null;
webauthnJson = dataObj.data;
headerText = dataObj.headerText;
btnText = dataObj.btnText;
@@ -184,8 +177,8 @@ function start() {
stopWebAuthn = false;
if (
mobileResponse ||
(navigator.userAgent.indexOf(" Safari/") !== -1 && navigator.userAgent.indexOf("Chrome") === -1)
navigator.userAgent.indexOf(" Safari/") !== -1 &&
navigator.userAgent.indexOf("Chrome") === -1
) {
// Safari and mobile chrome blocks non-user initiated WebAuthn requests.
} else {
@@ -208,7 +201,7 @@ function onMessage() {
window.addEventListener(
"message",
(event) => {
if (!event.origin || event.origin === "" || event.origin !== parentOrigin) {
if (parentOrigin && (!event.origin || event.origin === "" || event.origin !== parentOrigin)) {
return;
}
@@ -224,11 +217,11 @@ function onMessage() {
}
function error(message: string) {
if (mobileResponse) {
const callbackUri = buildMobileCallbackUriFromParam("webauthn");
document.location.replace(callbackUri + "?error=" + encodeURIComponent(message));
returnButton(callbackUri + "?error=" + encodeURIComponent(message));
} else {
if (callbackUri) {
const uri = callbackUri + "?error=" + encodeURIComponent(message);
document.location.replace(uri);
returnButton(uri);
} else if (parentUrl) {
parent.postMessage("error|" + message, parentUrl);
setDefaultWebAuthnButtonState();
}
@@ -241,18 +234,18 @@ function success(assertedCredential: PublicKeyCredential) {
const dataString = buildDataString(assertedCredential);
if (mobileResponse) {
const callbackUri = buildMobileCallbackUriFromParam("webauthn");
document.location.replace(callbackUri + "?data=" + encodeURIComponent(dataString));
returnButton(callbackUri + "?data=" + encodeURIComponent(dataString));
} else {
if (callbackUri) {
const uri = callbackUri + "?data=" + encodeURIComponent(dataString);
document.location.replace(uri);
returnButton(uri);
} else if (parentUrl) {
parent.postMessage("success|" + dataString, parentUrl);
sentSuccess = true;
}
}
function info(message: string) {
if (mobileResponse) {
if (!parentUrl) {
return;
}