Script Basit 2FA Kod Üreticisi - Ücretsiz

Google Auth gibi uygulamalar kurmak zor geliyorsa secret kodunuzu girerek anlık tek kullanımlık şifre üreten basit bir araç oluşturabilirsiniz. <!DOCTYPE html> <html...

Google Auth gibi uygulamalar kurmak zor geliyorsa secret kodunuzu girerek anlık tek kullanımlık şifre üreten basit bir araç oluşturabilirsiniz.

<!DOCTYPE html> <html lang="tr"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>TOTP Kod Üretici</title> <style> :root { --bg: #0b1020; --panel: #131a2a; --panel-2: #1a2338; --text: #e8ecf3; --muted: #9aa4b2; --accent: #6ea8fe; --accent-2: #8b5cf6; --danger: #ef4444; --ok: #22c55e; --border: rgba(255,255,255,0.08); --shadow: 0 20px 60px rgba(0,0,0,0.35); } * { box-sizing: border-box; } body { margin: 0; min-height: 100vh; font-family: Inter, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; background: radial-gradient(circle at top right, rgba(110,168,254,0.16), transparent 28%), radial-gradient(circle at bottom left, rgba(139,92,246,0.12), transparent 24%), var(--bg); color: var(--text); display: grid; place-items: center; padding: 24px; } .card { width: 100%; max-width: 560px; background: linear-gradient(180deg, rgba(255,255,255,0.03), rgba(255,255,255,0.015)); border: 1px solid var(--border); border-radius: 24px; padding: 24px; box-shadow: var(--shadow); backdrop-filter: blur(8px); } h1 { margin: 0 0 8px; font-size: 28px; line-height: 1.15; } p.desc { margin: 0 0 20px; color: var(--muted); line-height: 1.55; } label { display: block; margin-bottom: 8px; font-size: 14px; color: var(--muted); } .row { display: grid; gap: 14px; grid-template-columns: 1fr; } input, select, button { width: 100%; border: 1px solid var(--border); background: var(--panel-2); color: var(--text); border-radius: 14px; padding: 14px 16px; font-size: 16px; outline: none; } input:focus, select:focus { border-color: rgba(110,168,254,0.55); box-shadow: 0 0 0 4px rgba(110,168,254,0.12); } .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 14px; } .actions { display: grid; grid-template-columns: 1fr auto; gap: 12px; margin-top: 14px; } button { cursor: pointer; background: linear-gradient(135deg, var(--accent), var(--accent-2)); border: 0; font-weight: 600; } button.secondary { background: var(--panel-2); border: 1px solid var(--border); min-width: 120px; } .result { margin-top: 20px; padding: 20px; border-radius: 20px; background: var(--panel); border: 1px solid var(--border); } .code { font-size: 52px; letter-spacing: 6px; font-weight: 800; text-align: center; margin: 8px 0 6px; font-variant-numeric: tabular-nums; } .meta { text-align: center; color: var(--muted); font-size: 14px; } .bar { margin-top: 14px; height: 10px; background: rgba(255,255,255,0.06); border-radius: 999px; overflow: hidden; } .bar > div { height: 100%; width: 0%; background: linear-gradient(90deg, var(--ok), #facc15, var(--danger)); transition: width 0.25s linear; } .error { margin-top: 14px; color: #fecaca; background: rgba(239,68,68,0.12); border: 1px solid rgba(239,68,68,0.24); border-radius: 14px; padding: 12px 14px; display: none; } .footer { margin-top: 16px; color: var(--muted); font-size: 13px; line-height: 1.5; } .hint { font-size: 13px; color: var(--muted); margin-top: 8px; } code.inline { background: rgba(255,255,255,0.06); padding: 2px 8px; border-radius: 999px; font-size: 12px; } @media (max-width: 560px) { .grid-2, .actions { grid-template-columns: 1fr; } .code { font-size: 40px; letter-spacing: 4px; } } </style> </head> <body> <main class="card"> <h1>TOTP Kod Üretici</h1> <p class="desc"> Google Authenticator uyumlu <strong>secret key</strong> gir, kod anında tarayıcıda üretilsin. Veri herhangi bir sunucuya gönderilmez. </p> <div class="row"> <div> <label for="secret">Secret / Anahtar</label> <input id="secret" type="text" placeholder="Örn: JBSWY3DPEHPK3PXP" autocomplete="off" spellcheck="false" /> <div class="hint">Base32 formatı desteklenir. Boşluk ve tireler otomatik temizlenir.</div> </div> </div> <div class="grid-2"> <div> <label for="digits">Hane</label> <select id="digits"> <option value="6" selected>6</option> </select> </div> <div> <label for="period">Süre (sn)</label> <select id="period"> <option value="30" selected>30</option> <option value="60">60</option> </select> </div> </div> <div class="actions"> <button id="generateBtn">Kodu Üret</button> <button id="copyBtn" class="secondary" type="button">Kopyala</button> </div> <div id="error" class="error"></div> <section class="result"> <div class="meta">Aktif tek kullanımlık kod</div> <div id="code" class="code">------</div> <div id="meta" class="meta">Secret girildiğinde otomatik güncellenir.</div> <div class="bar"><div id="progress"></div></div> </section> <div class="footer"> İstersen URL ile de kullanabilirsin: <code class="inline">?secret=JBSWY3DPEHPK3PXP</code> </div> </main> <script> const secretInput = document.getElementById('secret'); const digitsSelect = document.getElementById('digits'); const periodSelect = document.getElementById('period'); const codeEl = document.getElementById('code'); const metaEl = document.getElementById('meta'); const errorEl = document.getElementById('error'); const progressEl = document.getElementById('progress'); const generateBtn = document.getElementById('generateBtn'); const copyBtn = document.getElementById('copyBtn'); let timer = null; let lastCode = ''; function showError(message = '') { errorEl.textContent = message; errorEl.style.display = message ? 'block' : 'none'; } function normalizeSecret(secret) { return (secret || '').toUpperCase().replace(/[\s-]+/g, ''); } function base32ToBytes(base32) { const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; const cleaned = normalizeSecret(base32).replace(/=+$/g, ''); if (!cleaned) return new Uint8Array(); let bits = ''; for (const char of cleaned) { const val = alphabet.indexOf(char); if (val === -1) { throw new Error('Secret geçersiz görünüyor. Base32 karakterleri bekleniyor.'); } bits += val.toString(2).padStart(5, '0'); } const bytes = []; for (let i = 0; i + 8 <= bits.length; i += 8) { bytes.push(parseInt(bits.slice(i, i + 8), 2)); } return new Uint8Array(bytes); } async function hmacSha1(keyBytes, messageBytes) { const cryptoKey = await crypto.subtle.importKey( 'raw', keyBytes, { name: 'HMAC', hash: 'SHA-1' }, false, ['sign'] ); const signature = await crypto.subtle.sign('HMAC', cryptoKey, messageBytes); return new Uint8Array(signature); } function intToBytes(counter) { const bytes = new Uint8Array(8); let value = BigInt(counter); for (let i = 7; i >= 0; i--) { bytes[i] = Number(value & 0xffn); value >>= 8n; } return bytes; } async function generateTOTP(secret, digits = 6, period = 30, timestamp = Date.now()) { const key = base32ToBytes(secret); if (!key.length) { throw new Error('Lütfen bir secret key gir.'); } const counter = Math.floor(timestamp / 1000 / period); const counterBytes = intToBytes(counter); const hash = await hmacSha1(key, counterBytes); const offset = hash[hash.length - 1] & 0x0f; const binary = ((hash[offset] & 0x7f) << 24) | ((hash[offset + 1] & 0xff) << 16) | ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff); const otp = (binary % (10 ** digits)).toString().padStart(digits, '0'); const secondsRemaining = period - (Math.floor(timestamp / 1000) % period); return { otp, secondsRemaining, counter, }; } async function refreshCode() { const secret = secretInput.value; const digits = Number(digitsSelect.value); const period = Number(periodSelect.value); const now = Date.now(); if (!normalizeSecret(secret)) { codeEl.textContent = '-'.repeat(digits); metaEl.textContent = 'Secret girildiğinde otomatik güncellenir.'; progressEl.style.width = '0%'; showError(''); lastCode = ''; return; } try { const { otp, secondsRemaining } = await generateTOTP(secret, digits, period, now); lastCode = otp; codeEl.textContent = otp; metaEl.textContent = `${secondsRemaining} saniye sonra yenilenecek`; const elapsed = period - secondsRemaining; progressEl.style.width = `${(elapsed / period) * 100}%`; showError(''); } catch (err) { codeEl.textContent = '!'.repeat(digits); metaEl.textContent = 'Kod üretilemedi.'; progressEl.style.width = '0%'; showError(err.message || 'Beklenmeyen bir hata oluştu.'); lastCode = ''; } } function restartTimer() { if (timer) clearInterval(timer); refreshCode(); timer = setInterval(refreshCode, 250); } generateBtn.addEventListener('click', refreshCode); secretInput.addEventListener('input', restartTimer); digitsSelect.addEventListener('change', restartTimer); periodSelect.addEventListener('change', restartTimer); copyBtn.addEventListener('click', async () => { if (!lastCode) return; try { await navigator.clipboard.writeText(lastCode); const original = copyBtn.textContent; copyBtn.textContent = 'Kopyalandı'; setTimeout(() => { copyBtn.textContent = original; }, 1200); } catch { showError('Panoya kopyalama başarısız oldu.'); } }); function loadFromQuery() { const params = new URLSearchParams(location.search); const secret = params.get('secret') || ''; const digits = params.get('digits'); const period = params.get('period'); if (secret) secretInput.value = secret; if (digits && ['6', '8'].includes(digits)) digitsSelect.value = digits; if (period && ['30', '60'].includes(period)) periodSelect.value = period; } loadFromQuery(); restartTimer(); </script> </body> </html>


Demo : https://2fa.grandkingbet.com/
 
💬 SpyHackerz Telegram — Anlık tartışmalar ve duyurular için katıl
133,206Konular
3,281,343Mesajlar
318,731Kullanıcılar
REDWINGDEMONSon Üye
Üst Alt