import { b64Decode, getQsParam } from "./common"; declare let hcaptcha: any; if (window.location.pathname.includes("mobile")) { require("./captcha-mobile.scss"); } else { require("./captcha.scss"); } document.addEventListener("DOMContentLoaded", () => { init(); }); (window as any).captchaSuccess = captchaSuccess; (window as any).captchaError = captchaError; let parentUrl: string = null; let parentOrigin: string = null; let mobileResponse: boolean = null; let sentSuccess = false; async function init() { await start(); onMessage(); } async function start() { sentSuccess = false; const data = getQsParam("data"); if (!data) { error("No data."); return; } parentUrl = getQsParam("parent"); if (!parentUrl) { error("No parent."); return; } else { parentUrl = decodeURIComponent(parentUrl); parentOrigin = new URL(parentUrl).origin; } let decodedData: any; try { decodedData = JSON.parse(b64Decode(data)); } catch (e) { error("Cannot parse data."); return; } mobileResponse = decodedData.callbackUri != null || decodedData.mobile === true; let src = "https://hcaptcha.com/1/api.js?render=explicit"; // Set language code if (decodedData.locale) { src += `&hl=${encodeURIComponent(decodedData.locale) ?? "en"}`; } // Set captchaRequired subtitle for mobile const subtitleEl = document.getElementById("captchaRequired"); if (decodedData.captchaRequiredText && subtitleEl) { subtitleEl.textContent = decodedData.captchaRequiredText; } const script = document.createElement("script"); script.src = src; script.async = true; script.defer = true; script.addEventListener("load", () => { hcaptcha.render("captcha", { sitekey: encodeURIComponent(decodedData.siteKey), callback: "captchaSuccess", "error-callback": "captchaError", }); watchHeight(); }); document.head.appendChild(script); } function captchaSuccess(response: string) { if (mobileResponse) { document.location.replace("bitwarden://captcha-callback?token=" + encodeURIComponent(response)); } else { success(response); } } function captchaError() { error("An error occurred with the captcha. Try again."); } function onMessage() { window.addEventListener( "message", (event) => { if (!event.origin || event.origin === "" || event.origin !== parentOrigin) { return; } if (event.data === "start") { start(); } }, false ); } function error(message: string) { parent.postMessage("error|" + message, parentUrl); } function success(data: string) { if (sentSuccess) { return; } parent.postMessage("success|" + data, parentUrl); sentSuccess = true; } function info(message: string | object) { parent.postMessage("info|" + JSON.stringify(message), parentUrl); } async function watchHeight() { const imagesDiv = document.body.lastChild as HTMLElement; // eslint-disable-next-line while (true) { info({ height: imagesDiv.style.visibility === "hidden" ? document.documentElement.offsetHeight : document.documentElement.scrollHeight, width: document.documentElement.scrollWidth, }); await sleep(100); } } async function sleep(ms: number) { await new Promise((r) => setTimeout(r, ms)); }