mirror of
https://github.com/PrivateCaptcha/PrivateCaptcha.git
synced 2026-04-27 16:30:30 -05:00
127 lines
3.4 KiB
JavaScript
127 lines
3.4 KiB
JavaScript
'use strict';
|
|
|
|
import { CaptchaWidget, RECAPTCHA_COMPAT } from './widget.js';
|
|
|
|
window.privateCaptcha = {
|
|
setup: setupPrivateCaptcha,
|
|
render: renderCaptchaWidget,
|
|
getResponse: getCaptchaResponse,
|
|
reset: resetCaptchaWidget,
|
|
};
|
|
|
|
const RENDER_EXPLICIT = "explicit";
|
|
|
|
/**
|
|
* Finds all captcha elements on the page
|
|
* @param {string} compatMode
|
|
*/
|
|
function findCaptchaElements(compatMode) {
|
|
const selector = (compatMode === RECAPTCHA_COMPAT) ? '.g-recaptcha' : '.private-captcha';
|
|
const elements = document.querySelectorAll(selector);
|
|
if (elements.length === 0) {
|
|
console.warn(`'PrivateCaptcha: No element was found with ${selector} class`);
|
|
}
|
|
return elements;
|
|
}
|
|
|
|
function getBaseOptions() {
|
|
let scriptTag;
|
|
const scripts = document.getElementsByTagName('script');
|
|
for (let script of scripts) {
|
|
if (script.src.includes('widget/js/privatecaptcha.js')) {
|
|
scriptTag = script;
|
|
break;
|
|
}
|
|
}
|
|
|
|
let options = {
|
|
compat: null,
|
|
render: null,
|
|
};
|
|
|
|
if (scriptTag) {
|
|
const scriptUrl = new URL(scriptTag.src);
|
|
const params = scriptUrl.searchParams;
|
|
|
|
const compatMode = params.get('compat');
|
|
if (compatMode && (typeof compatMode === 'string') && (compatMode.length > 0)) {
|
|
options.compat = compatMode;
|
|
}
|
|
|
|
const renderMode = params.get('render');
|
|
if (renderMode && (typeof renderMode === 'string') && (renderMode.length > 0)) {
|
|
options.render = renderMode;
|
|
}
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
function setupPrivateCaptcha() {
|
|
let options = getBaseOptions();
|
|
|
|
if (options.render !== RENDER_EXPLICIT) {
|
|
let autoWidget = window.privateCaptcha.autoWidget;
|
|
|
|
const elements = findCaptchaElements(options.compat);
|
|
for (let htmlElement of elements) {
|
|
autoWidget = renderCaptchaWidget(htmlElement, options);
|
|
}
|
|
|
|
window.privateCaptcha.autoWidget = autoWidget;
|
|
}
|
|
|
|
if (options.compat === RECAPTCHA_COMPAT) {
|
|
window.grecaptcha = window.privateCaptcha;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Google reCAPTCHA (and hCAPTCHA) compatibility layer: render
|
|
* @param {HTMLElement} element
|
|
* @param {Object} options
|
|
* @returns {CaptchaWidget} instance or null if already attached
|
|
*/
|
|
function renderCaptchaWidget(element, options) {
|
|
let widget = null;
|
|
|
|
if (element && !element.dataset['attached']) {
|
|
widget = new CaptchaWidget(element, options);
|
|
// We set the "data-attached" attribute so we don't attach to the same element twice.
|
|
element.dataset['attached'] = '1';
|
|
}
|
|
|
|
return widget;
|
|
}
|
|
|
|
/**
|
|
* Google reCAPTCHA compatibility layer: reset
|
|
* @param {CaptchaWidget} widget created with renderCaptchaWidget()
|
|
*/
|
|
function resetCaptchaWidget(widget) {
|
|
if (widget) {
|
|
widget.reset();
|
|
} else {
|
|
window.privateCaptcha.autoWidget.reset();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Google reCAPTCHA compatibility layer: getResponse
|
|
* @param {CaptchaWidget} widget created with renderCaptchaWidget()
|
|
* @returns {string} the response for the Private Captcha widget
|
|
*/
|
|
function getCaptchaResponse(widget) {
|
|
if (widget) {
|
|
return widget.solution();
|
|
} else {
|
|
return window.privateCaptcha.autoWidget.solution();
|
|
}
|
|
}
|
|
|
|
if (document.readyState !== 'loading') {
|
|
setupPrivateCaptcha();
|
|
} else {
|
|
document.addEventListener('DOMContentLoaded', setupPrivateCaptcha);
|
|
}
|