111 lines
2.9 KiB
React
111 lines
2.9 KiB
React
/**
|
|
* This file is part of the SplendidBear Websites' projects.
|
|
*
|
|
* Copyright (c) 2026 @ www.splendidbear.org
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
import 'cap-widget';
|
|
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react';
|
|
import { func, node, string } from 'prop-types';
|
|
|
|
const CAPTCHA_STORAGE_KEY = 'mineseeker_captcha_verified';
|
|
const CAPTCHA_TOKEN_KEY = 'mineseeker_captcha_token';
|
|
|
|
const CaptchaOverlay = ({ apiEndpoint, onVerified, children }) => {
|
|
const [verified, setVerified] = useState(false);
|
|
const capRef = useRef(null);
|
|
|
|
const handleToken = useCallback(token => {
|
|
const wrapper = document.getElementById('mine-wrapper');
|
|
if (wrapper) {
|
|
wrapper.dataset.captchaToken = token;
|
|
}
|
|
sessionStorage.setItem(CAPTCHA_TOKEN_KEY, token);
|
|
sessionStorage.setItem(CAPTCHA_STORAGE_KEY, Date.now().toString());
|
|
setVerified(true);
|
|
onVerified?.();
|
|
}, [onVerified]);
|
|
|
|
useEffect(() => {
|
|
const storedToken = sessionStorage.getItem(CAPTCHA_TOKEN_KEY);
|
|
const storedTime = sessionStorage.getItem(CAPTCHA_STORAGE_KEY);
|
|
|
|
if (storedToken && storedTime) {
|
|
const elapsed = (Date.now() - parseInt(storedTime)) / 1000;
|
|
if (110 > elapsed) {
|
|
const wrapper = document.getElementById('mine-wrapper');
|
|
if (wrapper) {
|
|
wrapper.dataset.captchaToken = storedToken;
|
|
}
|
|
setVerified(true);
|
|
onVerified?.();
|
|
return;
|
|
}
|
|
}
|
|
}, [onVerified]);
|
|
|
|
useEffect(() => {
|
|
const widget = document.createElement('cap-widget');
|
|
widget.style.display = 'none';
|
|
capRef.current = widget;
|
|
document.body.appendChild(widget);
|
|
|
|
const cap = new window.Cap({ apiEndpoint }, widget);
|
|
let cancelled = false;
|
|
|
|
const run = async () => {
|
|
try {
|
|
const result = await cap.solve();
|
|
if (!cancelled && result?.token) {
|
|
handleToken(result.token);
|
|
}
|
|
} catch (_) {
|
|
if (!cancelled) {
|
|
setTimeout(() => {
|
|
if (!cancelled) {
|
|
run();
|
|
}
|
|
}, 1200);
|
|
}
|
|
}
|
|
};
|
|
|
|
run();
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
widget.remove();
|
|
capRef.current = null;
|
|
};
|
|
}, [apiEndpoint, handleToken]);
|
|
|
|
if (verified) {
|
|
return <Fragment>{children}</Fragment>;
|
|
}
|
|
|
|
return (
|
|
<div className="captcha-overlay">
|
|
<div className="captcha-content">
|
|
<div className="captcha-icon">
|
|
<i className="fa fa-shield-halved" />
|
|
</div>
|
|
<h1 className="captcha-title">Ready to Play?</h1>
|
|
<p className="captcha-description">
|
|
Verifying your session...
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default CaptchaOverlay;
|
|
|
|
CaptchaOverlay.propTypes = {
|
|
apiEndpoint: string.isRequired,
|
|
onVerified: func,
|
|
children: node,
|
|
};
|