1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-10-10 06:08:34 +02:00
bitwarden-browser/src/connectors/captcha.ts

143 lines
3.4 KiB
TypeScript
Raw Normal View History

import { b64Decode, getQsParam } from './common';
declare var hcaptcha: any;
if (window.location.pathname.includes('mobile')) {
// tslint:disable-next-line
require('./captcha-mobile.scss');
} else {
// tslint:disable-next-line
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 callbackUri: string = 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;
}
callbackUri = decodedData.callbackUri;
let src = 'https://hcaptcha.com/1/api.js?render=explicit';
// Set language code
if (decodedData.locale) {
src += `&hl=${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', e => {
hcaptcha.render('captcha', {
sitekey: decodedData.siteKey,
callback: 'captchaSuccess',
'error-callback': 'captchaError',
});
watchHeight();
});
document.head.appendChild(script);
}
function captchaSuccess(response: string) {
if (callbackUri) {
document.location.replace(callbackUri + '?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;
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));
}