2021-07-23 21:30:04 +02:00
|
|
|
import { b64Decode, getQsParam } from "./common";
|
2021-06-22 21:35:33 +02:00
|
|
|
|
2022-02-24 12:10:07 +01:00
|
|
|
declare let hcaptcha: any;
|
2021-06-22 21:35:33 +02:00
|
|
|
|
2021-07-23 21:30:04 +02:00
|
|
|
if (window.location.pathname.includes("mobile")) {
|
|
|
|
require("./captcha-mobile.scss");
|
|
|
|
} else {
|
|
|
|
require("./captcha.scss");
|
|
|
|
}
|
2021-06-22 21:35:33 +02:00
|
|
|
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
|
|
init();
|
|
|
|
});
|
|
|
|
|
|
|
|
(window as any).captchaSuccess = captchaSuccess;
|
|
|
|
(window as any).captchaError = captchaError;
|
|
|
|
|
|
|
|
let parentUrl: string = null;
|
|
|
|
let parentOrigin: string = null;
|
2021-11-09 18:16:10 +01:00
|
|
|
let mobileResponse: boolean = null;
|
2021-06-22 21:35:33 +02:00
|
|
|
let sentSuccess = false;
|
|
|
|
|
2021-07-23 21:30:04 +02:00
|
|
|
async function init() {
|
|
|
|
await start();
|
2021-06-22 21:35:33 +02:00
|
|
|
onMessage();
|
|
|
|
}
|
|
|
|
|
2021-07-23 21:30:04 +02:00
|
|
|
async function start() {
|
2021-06-22 21:35:33 +02:00
|
|
|
sentSuccess = false;
|
2021-12-17 15:57:11 +01:00
|
|
|
|
2021-06-22 21:35:33 +02:00
|
|
|
const data = getQsParam("data");
|
|
|
|
if (!data) {
|
|
|
|
error("No data.");
|
|
|
|
return;
|
|
|
|
}
|
2021-12-17 15:57:11 +01:00
|
|
|
|
2021-06-22 21:35:33 +02:00
|
|
|
parentUrl = getQsParam("parent");
|
|
|
|
if (!parentUrl) {
|
|
|
|
error("No parent.");
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
parentUrl = decodeURIComponent(parentUrl);
|
|
|
|
parentOrigin = new URL(parentUrl).origin;
|
|
|
|
}
|
2021-12-17 15:57:11 +01:00
|
|
|
|
2021-07-23 21:30:04 +02:00
|
|
|
let decodedData: any;
|
|
|
|
try {
|
2022-03-02 21:49:35 +01:00
|
|
|
decodedData = JSON.parse(b64Decode(data, true));
|
2021-07-23 21:30:04 +02:00
|
|
|
} catch (e) {
|
|
|
|
error("Cannot parse data.");
|
|
|
|
return;
|
|
|
|
}
|
2021-11-09 18:16:10 +01:00
|
|
|
mobileResponse = decodedData.callbackUri != null || decodedData.mobile === true;
|
2021-12-17 15:57:11 +01:00
|
|
|
|
2021-07-23 21:30:04 +02:00
|
|
|
let src = "https://hcaptcha.com/1/api.js?render=explicit";
|
2021-12-17 15:57:11 +01:00
|
|
|
|
2021-07-23 21:30:04 +02:00
|
|
|
// Set language code
|
|
|
|
if (decodedData.locale) {
|
2021-11-09 18:16:10 +01:00
|
|
|
src += `&hl=${encodeURIComponent(decodedData.locale) ?? "en"}`;
|
2021-07-23 21:30:04 +02:00
|
|
|
}
|
2021-12-17 15:57:11 +01:00
|
|
|
|
2021-07-23 21:30:04 +02:00
|
|
|
// Set captchaRequired subtitle for mobile
|
|
|
|
const subtitleEl = document.getElementById("captchaRequired");
|
|
|
|
if (decodedData.captchaRequiredText && subtitleEl) {
|
|
|
|
subtitleEl.textContent = decodedData.captchaRequiredText;
|
|
|
|
}
|
2021-12-17 15:57:11 +01:00
|
|
|
|
2021-07-23 21:30:04 +02:00
|
|
|
const script = document.createElement("script");
|
|
|
|
script.src = src;
|
|
|
|
script.async = true;
|
|
|
|
script.defer = true;
|
2022-02-24 12:10:07 +01:00
|
|
|
script.addEventListener("load", () => {
|
2021-07-23 21:30:04 +02:00
|
|
|
hcaptcha.render("captcha", {
|
2021-11-09 18:16:10 +01:00
|
|
|
sitekey: encodeURIComponent(decodedData.siteKey),
|
2021-07-23 21:30:04 +02:00
|
|
|
callback: "captchaSuccess",
|
|
|
|
"error-callback": "captchaError",
|
2021-06-22 21:35:33 +02:00
|
|
|
});
|
2021-07-23 21:30:04 +02:00
|
|
|
watchHeight();
|
2021-12-17 15:57:11 +01:00
|
|
|
});
|
2021-07-23 21:30:04 +02:00
|
|
|
document.head.appendChild(script);
|
2021-06-22 21:35:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function captchaSuccess(response: string) {
|
2021-11-09 18:16:10 +01:00
|
|
|
if (mobileResponse) {
|
|
|
|
document.location.replace("bitwarden://captcha-callback?token=" + encodeURIComponent(response));
|
2021-08-13 00:01:18 +02:00
|
|
|
} else {
|
|
|
|
success(response);
|
2021-07-23 21:30:04 +02:00
|
|
|
}
|
2021-06-22 21:35:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2021-12-17 15:57:11 +01:00
|
|
|
|
2021-06-22 21:35:33 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-07-23 21:30:04 +02:00
|
|
|
function info(message: string | object) {
|
|
|
|
parent.postMessage("info|" + JSON.stringify(message), parentUrl);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function watchHeight() {
|
|
|
|
const imagesDiv = document.body.lastChild as HTMLElement;
|
2022-02-24 12:10:07 +01:00
|
|
|
// eslint-disable-next-line
|
2021-07-23 21:30:04 +02:00
|
|
|
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));
|
2021-06-22 21:35:33 +02:00
|
|
|
}
|