1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-07 11:03:30 +00:00

Feature/use hcaptcha if bot (#1089)

* Add captcha to login page

* pull out shared method

* Update parse parameter logic

* Load captcha

* responsive iframe height
* correct i18n
* site key provided by server

* Fix locale parsing

* Add optional success callbackUri

* Make captcha connector responsive

* Handle parameter versions in webauthn

* Move variables to top of script

* Add captcha to registration

* Move captcha above `<hr>` div to be part of input form

* Add styled mobile captcha connector

* Linter Fixes

* Remove duplicate import

* Use listener to load captcha

* PR review
This commit is contained in:
Matt Gibson
2021-07-23 14:30:04 -05:00
committed by GitHub
parent 2b5f61cadd
commit a73cbbb672
14 changed files with 247 additions and 66 deletions

View File

@@ -1,9 +1,14 @@
import { getQsParam } from './common';
import { b64Decode, getQsParam } from './common';
declare var hcaptcha: any;
// tslint:disable-next-line
require('./captcha.scss');
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();
@@ -14,15 +19,15 @@ document.addEventListener('DOMContentLoaded', () => {
let parentUrl: string = null;
let parentOrigin: string = null;
let callbackUri: string = null;
let sentSuccess = false;
function init() {
start();
async function init() {
await start();
onMessage();
info('ready');
}
function start() {
async function start() {
sentSuccess = false;
const data = getQsParam('data');
@@ -40,15 +45,49 @@ function start() {
parentOrigin = new URL(parentUrl).origin;
}
hcaptcha.render('captcha', {
sitekey: 'bc38c8a2-5311-4e8c-9dfc-49e99f6df417',
callback: 'captchaSuccess',
'error-callback': 'captchaError',
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) {
success(response);
if (callbackUri) {
document.location.replace(callbackUri + '?token=' + encodeURIComponent(response));
}
}
function captchaError() {
@@ -79,7 +118,24 @@ function success(data: string) {
sentSuccess = true;
}
function info(message: string) {
parent.postMessage('info|' + message, parentUrl);
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));
}