|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Verification Required - TTS Arena</title> |
|
<link rel="preconnect" href="https://fonts.googleapis.com"> |
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> |
|
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit" async defer></script> |
|
<style> |
|
:root { |
|
--primary-color: #5046e5; |
|
--secondary-color: #f0f0f0; |
|
--text-color: #333; |
|
--light-gray: #f5f5f5; |
|
--border-color: #e0e0e0; |
|
--shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
|
--radius: 8px; |
|
} |
|
|
|
* { |
|
margin: 0; |
|
padding: 0; |
|
box-sizing: border-box; |
|
font-family: 'Inter', sans-serif; |
|
} |
|
|
|
body { |
|
color: var(--text-color); |
|
display: flex; |
|
min-height: 100vh; |
|
justify-content: center; |
|
align-items: center; |
|
background-color: var(--light-gray); |
|
} |
|
|
|
.verification-container { |
|
background-color: white; |
|
border-radius: var(--radius); |
|
box-shadow: var(--shadow); |
|
padding: 32px; |
|
width: 100%; |
|
max-width: 450px; |
|
text-align: center; |
|
} |
|
|
|
.logo { |
|
font-size: 24px; |
|
font-weight: 700; |
|
margin-bottom: 24px; |
|
color: var(--primary-color); |
|
} |
|
|
|
h1 { |
|
font-size: 20px; |
|
margin-bottom: 16px; |
|
color: var(--text-color); |
|
} |
|
|
|
p { |
|
margin-bottom: 24px; |
|
color: #666; |
|
line-height: 1.5; |
|
} |
|
|
|
.turnstile-container { |
|
display: flex; |
|
justify-content: center; |
|
margin-bottom: 24px; |
|
} |
|
|
|
.btn { |
|
background-color: var(--primary-color); |
|
color: white; |
|
border: none; |
|
border-radius: var(--radius); |
|
padding: 12px 24px; |
|
font-weight: 500; |
|
cursor: pointer; |
|
font-size: 1rem; |
|
transition: background-color 0.2s; |
|
width: 100%; |
|
} |
|
|
|
.btn:hover { |
|
background-color: #4038c7; |
|
} |
|
|
|
.btn:disabled { |
|
background-color: #a8a4e0; |
|
cursor: not-allowed; |
|
} |
|
|
|
.loader { |
|
display: none; |
|
width: 24px; |
|
height: 24px; |
|
border: 3px solid rgba(255, 255, 255, 0.3); |
|
border-radius: 50%; |
|
border-top-color: white; |
|
animation: spin 1s ease infinite; |
|
margin: 0 auto; |
|
} |
|
|
|
@keyframes spin { |
|
to { |
|
transform: rotate(360deg); |
|
} |
|
} |
|
|
|
.btn.loading .btn-text { |
|
display: none; |
|
font-size: 1rem; |
|
} |
|
|
|
.btn.loading .loader { |
|
display: inline-block; |
|
} |
|
|
|
.status-message { |
|
margin-top: 16px; |
|
font-size: 14px; |
|
color: #666; |
|
display: none; |
|
} |
|
|
|
|
|
@media (prefers-color-scheme: dark) { |
|
:root { |
|
--primary-color: #6c63ff; |
|
--secondary-color: #2d2b38; |
|
--text-color: #e0e0e0; |
|
--light-gray: #1e1e24; |
|
--border-color: #3a3a45; |
|
--shadow: 0 2px 8px rgba(0, 0, 0, 0.3); |
|
} |
|
|
|
body { |
|
background-color: #121218; |
|
} |
|
|
|
.verification-container { |
|
background-color: var(--light-gray); |
|
border: 1px solid var(--border-color); |
|
} |
|
|
|
p { |
|
color: #aaa; |
|
} |
|
|
|
.status-message { |
|
color: #aaa; |
|
} |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="verification-container"> |
|
<div class="logo">TTS Arena</div> |
|
<h1>Verification Required</h1> |
|
<p>Please complete the verification below to access TTS Arena.</p> |
|
|
|
<div id="turnstile-form"> |
|
<div class="turnstile-container"> |
|
<div id="cf-turnstile" class="cf-turnstile"></div> |
|
</div> |
|
<button type="button" class="btn" id="submit-btn" disabled onclick="submitVerification()"> |
|
<span class="btn-text">Continue to TTS Arena</span> |
|
<span class="loader"></span> |
|
</button> |
|
<div id="status-message" class="status-message"></div> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
|
|
let turnstileToken = ''; |
|
const redirectUrl = '{{ redirect_url }}'; |
|
|
|
const secureRedirectUrl = redirectUrl.replace(/^http:\/\//i, 'https://'); |
|
const verifyEndpoint = '{{ url_for("verify_turnstile") }}'; |
|
const statusMessage = document.getElementById('status-message'); |
|
const submitButton = document.getElementById('submit-btn'); |
|
|
|
|
|
function onTurnstileSuccess(token) { |
|
turnstileToken = token; |
|
submitButton.disabled = false; |
|
console.log("Turnstile verification successful"); |
|
} |
|
|
|
|
|
function onTurnstileError(error) { |
|
console.error("Turnstile error:", error); |
|
statusMessage.textContent = "Verification error. Please try again."; |
|
statusMessage.style.display = "block"; |
|
} |
|
|
|
|
|
function submitVerification() { |
|
if (!turnstileToken) { |
|
statusMessage.textContent = "Please complete the verification first."; |
|
statusMessage.style.display = "block"; |
|
return; |
|
} |
|
|
|
|
|
submitButton.classList.add('loading'); |
|
submitButton.disabled = true; |
|
|
|
|
|
const formData = new FormData(); |
|
formData.append('cf-turnstile-response', turnstileToken); |
|
formData.append('redirect_url', secureRedirectUrl); |
|
|
|
|
|
fetch(verifyEndpoint, { |
|
method: 'POST', |
|
body: formData, |
|
credentials: 'same-origin', |
|
headers: { |
|
'X-Requested-With': 'XMLHttpRequest', |
|
'Accept': 'application/json' |
|
} |
|
}) |
|
.then(response => { |
|
if (response.redirected) { |
|
|
|
window.location.href = response.url; |
|
} else { |
|
return response.json().then(data => { |
|
if (data.success) { |
|
|
|
window.location.href = secureRedirectUrl; |
|
} else { |
|
throw new Error("Verification failed"); |
|
} |
|
}); |
|
} |
|
}) |
|
.catch(error => { |
|
console.error("Verification error:", error); |
|
statusMessage.textContent = "Verification failed. Please try again."; |
|
statusMessage.style.display = "block"; |
|
submitButton.classList.remove('loading'); |
|
submitButton.disabled = false; |
|
|
|
|
|
if (typeof turnstile !== 'undefined') { |
|
turnstile.reset('#cf-turnstile'); |
|
} |
|
}); |
|
} |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
function waitForTurnstile() { |
|
if (typeof turnstile !== 'undefined') { |
|
|
|
turnstile.render('#cf-turnstile', { |
|
sitekey: '{{ turnstile_site_key }}', |
|
callback: onTurnstileSuccess, |
|
'error-callback': onTurnstileError |
|
}); |
|
} else { |
|
|
|
setTimeout(waitForTurnstile, 100); |
|
} |
|
} |
|
|
|
waitForTurnstile(); |
|
}); |
|
</script> |
|
</body> |
|
</html> |