Private
Public Access
1
0
Files
MineSeeker/assets/js/mine-seeker/components/CaptchaOverlay.jsx
T

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,
};