4tvhyd.com Ads.txt file

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2FA Authenticator</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: linear-gradient(135deg, #0f0f0f 0%, #1a1a1a 100%);
color: #e4e4e4;
min-height: 100vh;
display: flex;
flex-direction: column;
}

.header {
background: rgba(20, 20, 20, 0.9);
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
padding: 20px;
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.5);
}

.header-content {
max-width: 1400px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: space-between;
}

.logo {
display: flex;
align-items: center;
gap: 15px;
}

.logo-icon {
width: 40px;
height: 40px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}

h1 {
font-size: 24px;
font-weight: 600;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}

.container {
max-width: 1400px;
margin: 0 auto;
padding: 30px 20px;
flex: 1;
}

.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 25px;
margin-bottom: 30px;
}

.card {
background: rgba(30, 30, 30, 0.9);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
padding: 30px;
transition: transform 0.3s, box-shadow 0.3s;
}

.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 40px rgba(102, 126, 234, 0.1);
}

.card-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 25px;
padding-bottom: 15px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.card-icon {
width: 35px;
height: 35px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
}

.card-title {
font-size: 18px;
font-weight: 600;
color: #fff;
}

.form-group {
margin-bottom: 20px;
}

label {
display: block;
margin-bottom: 8px;
font-size: 13px;
color: #999;
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 600;
}

input, textarea, select {
width: 100%;
padding: 14px 16px;
background: rgba(20, 20, 20, 0.8);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
color: #fff;
font-size: 15px;
transition: all 0.3s;
font-family: 'Courier New', monospace;
}

input:focus, textarea:focus, select:focus {
outline: none;
border-color: #667eea;
background: rgba(30, 30, 30, 0.9);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

textarea {
resize: vertical;
min-height: 100px;
}

button {
width: 100%;
padding: 14px 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 12px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
text-transform: uppercase;
letter-spacing: 1px;
}

button:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
}

button:active {
transform: translateY(0);
}

.generate-btn {
background: linear-gradient(135deg, #00d2ff 0%, #3a7bd5 100%);
}

.copy-btn {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
margin-top: 10px;
}

.secret-display {
background: rgba(15, 15, 15, 0.9);
border: 1px solid rgba(102, 126, 234, 0.3);
border-radius: 12px;
padding: 20px;
margin: 20px 0;
word-break: break-all;
font-family: 'Courier New', monospace;
font-size: 16px;
color: #00ff88;
position: relative;
animation: glow 2s ease-in-out infinite;
}

@keyframes glow {
0%, 100% { box-shadow: 0 0 20px rgba(0, 255, 136, 0.1); }
50% { box-shadow: 0 0 30px rgba(0, 255, 136, 0.2); }
}

.qr-container {
display: flex;
flex-direction: column;
align-items: center;
margin: 20px 0;
padding: 20px;
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
}

.qr-code {
background: white;
padding: 15px;
border-radius: 12px;
margin-bottom: 15px;
}

.token-display {
text-align: center;
padding: 30px;
background: rgba(15, 15, 15, 0.9);
border-radius: 16px;
margin: 20px 0;
border: 2px solid rgba(0, 255, 136, 0.3);
position: relative;
overflow: hidden;
}

.token-display::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, #00ff88, #00d2ff, #667eea, #764ba2);
border-radius: 16px;
opacity: 0.3;
z-index: -1;
animation: rotate 3s linear infinite;
}

@keyframes rotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

.token-code {
font-size: 56px;
font-weight: 700;
color: #00ff88;
letter-spacing: 12px;
margin: 20px 0;
font-family: 'Courier New', monospace;
text-shadow: 0 0 20px rgba(0, 255, 136, 0.5);
}

.timer {
font-size: 18px;
color: #ffa500;
margin: 15px 0;
font-weight: 600;
}

.progress {
width: 100%;
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
overflow: hidden;
margin: 20px 0;
}

.progress-bar {
height: 100%;
background: linear-gradient(90deg, #ff3030, #ffa500, #00ff88);
transition: width 0.1s linear;
border-radius: 3px;
}

.verify-result {
margin-top: 20px;
padding: 15px;
border-radius: 12px;
text-align: center;
font-weight: 600;
animation: slideIn 0.3s ease;
}

@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

.success {
background: linear-gradient(135deg, #00d2ff 0%, #00ff88 100%);
color: #000;
}

.error {
background: linear-gradient(135deg, #f5576c 0%, #f093fb 100%);
color: #fff;
}

.info-box {
background: rgba(102, 126, 234, 0.1);
border: 1px solid rgba(102, 126, 234, 0.3);
border-radius: 12px;
padding: 15px;
margin: 20px 0;
font-size: 14px;
color: #aaa;
}

.supported-apps {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 10px;
}

.app-badge {
background: rgba(255, 255, 255, 0.05);
padding: 5px 12px;
border-radius: 20px;
font-size: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
}

@media (max-width: 768px) {
.grid {
grid-template-columns: 1fr;
}

.token-code {
font-size: 36px;
letter-spacing: 8px;
}
}
</style>
</head>
<body>
<div class="header">
<div class="header-content">
<div class="logo">
<div class="logo-icon">🔐</div>
<h1>2FA Authenticator</h1>
</div>
<div style="color: #666; font-size: 14px;">
Time-based One-Time Password Generator
</div>
</div>
</div>

<div class="container">
<div class="grid">
<!-- Generate New Secret -->
<div class="card">
<div class="card-header">
<div class="card-icon">🔑</div>
<div class="card-title">Generate New Secret</div>
</div>

<div class="form-group">
<label>Account Name (Optional)</label>
<input type="text" id="accountName" placeholder="e.g., john@example.com">
</div>

<div class="form-group">
<label>Issuer (Optional)</label>
<input type="text" id="issuer" placeholder="e.g., Google, GitHub, etc.">
</div>

<button class="generate-btn" onclick="generateNewSecret()">Generate New Secret</button>

<div id="generatedResult" style="display: none;">
<div class="secret-display" id="generatedSecret"></div>
<button class="copy-btn" onclick="copyToClipboard('generatedSecret')">Copy Secret</button>

<div class="qr-container">
<div class="qr-code">
<canvas id="qrCanvas"></canvas>
</div>
<div style="color: #999; font-size: 13px;">Scan with your authenticator app</div>
</div>

<div class="info-box">
<strong>Compatible with:</strong>
<div class="supported-apps">
<span class="app-badge">Google Authenticator</span>
<span class="app-badge">Microsoft Authenticator</span>
<span class="app-badge">Authy</span>
<span class="app-badge">1Password</span>
<span class="app-badge">LastPass</span>
</div>
</div>
</div>
</div>

<!-- Display Token -->
<div class="card">
<div class="card-header">
<div class="card-icon">📱</div>
<div class="card-title">Display 2FA Token</div>
</div>

<div class="form-group">
<label>Enter Secret Key</label>
<textarea id="displaySecret" placeholder="Paste your secret key here..."></textarea>
</div>

<button onclick="displayToken()">Generate Token</button>

<div id="tokenResult" style="display: none;">
<div class="token-display">
<label style="color: #999;">Current Token</label>
<div class="token-code" id="currentToken">000000</div>
<div class="timer" id="timer">Time remaining: 30s</div>
<div class="progress">
<div class="progress-bar" id="progressBar"></div>
</div>
</div>
</div>
</div>

<!-- Verify Code -->
<div class="card">
<div class="card-header">
<div class="card-icon">✓</div>
<div class="card-title">Verify 2FA Code</div>
</div>

<div class="form-group">
<label>Secret Key</label>
<textarea id="verifySecret" placeholder="Enter your secret key..."></textarea>
</div>

<div class="form-group">
<label>2FA Code</label>
<input type="text" id="verifyCode" placeholder="000000" maxlength="6" style="text-align: center; font-size: 24px;">
</div>

<button onclick="verifyCode()">Verify Code</button>

<div id="verifyResult"></div>
</div>
</div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
<script>
// Base32 encoding/decoding
const base32chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';

function base32encode(buffer) {
let result = '';
let bits = 0;
let value = 0;

for (let i = 0; i < buffer.length; i++) {
value = (value << 8) | buffer[i];
bits += 8;

while (bits >= 5) {
result += base32chars[(value >>> (bits - 5)) & 31];
bits -= 5;
}
}

if (bits > 0) {
result += base32chars[(value << (5 - bits)) & 31];
}

return result;
}

function base32decode(encoded) {
encoded = encoded.replace(/[=]/g, '').toUpperCase();
let bits = 0;
let value = 0;
let result = [];

for (let i = 0; i < encoded.length; i++) {
const idx = base32chars.indexOf(encoded[i]);
if (idx === -1) continue;

value = (value << 5) | idx;
bits += 5;

if (bits >= 8) {
result.push((value >>> (bits - 8)) & 255);
bits -= 8;
}
}

return new Uint8Array(result);
}

// TOTP generation
function generateTOTP(secret, timeStep = 30) {
const key = base32decode(secret);
const epoch = Math.floor(Date.now() / 1000);
const time = Math.floor(epoch / timeStep);

const timeBuffer = new ArrayBuffer(8);
const timeView = new DataView(timeBuffer);
timeView.setUint32(4, time, false);

return crypto.subtle.importKey(
'raw',
key,
{ name: 'HMAC', hash: 'SHA-1' },
false,
['sign']
).then(cryptoKey => {
return crypto.subtle.sign('HMAC', cryptoKey, timeBuffer);
}).then(signature => {
const signatureArray = new Uint8Array(signature);
const offset = signatureArray[signatureArray.length - 1] & 0x0f;
const binary = ((signatureArray[offset] & 0x7f) << 24) |
((signatureArray[offset + 1] & 0xff) << 16) |
((signatureArray[offset + 2] & 0xff) << 8) |
(signatureArray[offset + 3] & 0xff);
const otp = binary % 1000000;
return otp.toString().padStart(6, '0');
});
}

// Generate new secret
function generateNewSecret() {
const buffer = new Uint8Array(20);
crypto.getRandomValues(buffer);
const secret = base32encode(buffer);

document.getElementById('generatedSecret').textContent = secret;
document.getElementById('generatedResult').style.display = 'block';

// Generate QR code
const accountName = document.getElementById('accountName').value || 'user@example.com';
const issuer = document.getElementById('issuer').value || '2FA-Generator';
const otpUrl = `otpauth://totp/${encodeURIComponent(issuer)}:${encodeURIComponent(accountName)}?secret=${secret}&issuer=${encodeURIComponent(issuer)}`;

const canvas = document.getElementById('qrCanvas');
canvas.innerHTML = '';
new QRCode(canvas, {
text: otpUrl,
width: 200,
height: 200,
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
});
}

// Display token
let tokenInterval;
function displayToken() {
const secret = document.getElementById('displaySecret').value.trim();
if (!secret) {
alert('Please enter a secret key');
return;
}

document.getElementById('tokenResult').style.display = 'block';

if (tokenInterval) clearInterval(tokenInterval);

const updateToken = async () => {
try {
const token = await generateTOTP(secret);
document.getElementById('currentToken').textContent = token;

const timeRemaining = 30 - (Math.floor(Date.now() / 1000) % 30);
document.getElementById('timer').textContent = `Time remaining: ${timeRemaining}s`;
document.getElementById('progressBar').style.width = `${(timeRemaining / 30) * 100}%`;
} catch (error) {
document.getElementById('currentToken').textContent = 'ERROR';
console.error('Error generating token:', error);
}
};

updateToken();
tokenInterval = setInterval(updateToken, 1000);
}

// Verify code
async function verifyCode() {
const secret = document.getElementById('verifySecret').value.trim();
const code = document.getElementById('verifyCode').value.trim();

if (!secret || !code) {
alert('Please enter both secret and code');
return;
}

try {
const correctCode = await generateTOTP(secret);
const resultDiv = document.getElementById('verifyResult');

if (code === correctCode) {
resultDiv.className = 'verify-result success';
resultDiv.innerHTML = '✓ Code verified successfully!';
} else {
resultDiv.className = 'verify-result error';
resultDiv.innerHTML = '✗ Invalid code. Please try again.';
}

setTimeout(() => {
resultDiv.innerHTML = '';
}, 5000);
} catch (error) {
console.error('Error verifying code:', error);
document.getElementById('verifyResult').innerHTML = '<div class="verify-result error">Error processing secret key</div>';
}
}

// Copy to clipboard
function copyToClipboard(elementId) {
const text = document.getElementById(elementId).textContent;
navigator.clipboard.writeText(text).then(() => {
alert('Copied to clipboard!');
}).catch(err => {
console.error('Failed to copy:', err);
});
}
</script>
</body>
</html>

Ads.Txt Alerts - A trading name of Red Volcano Limited

Waterloo Buildings, Second Floor Rear, 53 London Road, Southampton, Hampshire, United Kingdom, SO15 2AD

© Red Volcano 2020. All Rights Reserved.