57 Zeilen
1.4 KiB
Python
57 Zeilen
1.4 KiB
Python
import pyotp
|
|
import qrcode
|
|
import random
|
|
import string
|
|
import hashlib
|
|
from io import BytesIO
|
|
import base64
|
|
|
|
|
|
def generate_totp_secret():
|
|
"""Generate a new TOTP secret"""
|
|
return pyotp.random_base32()
|
|
|
|
|
|
def generate_qr_code(username, totp_secret):
|
|
"""Generate QR code for TOTP setup"""
|
|
totp_uri = pyotp.totp.TOTP(totp_secret).provisioning_uri(
|
|
name=username,
|
|
issuer_name='V2 Admin Panel'
|
|
)
|
|
|
|
qr = qrcode.QRCode(version=1, box_size=10, border=5)
|
|
qr.add_data(totp_uri)
|
|
qr.make(fit=True)
|
|
|
|
img = qr.make_image(fill_color="black", back_color="white")
|
|
buf = BytesIO()
|
|
img.save(buf, format='PNG')
|
|
buf.seek(0)
|
|
|
|
return base64.b64encode(buf.getvalue()).decode()
|
|
|
|
|
|
def verify_totp(totp_secret, token):
|
|
"""Verify a TOTP token"""
|
|
totp = pyotp.TOTP(totp_secret)
|
|
return totp.verify(token, valid_window=1)
|
|
|
|
|
|
def generate_backup_codes(count=8):
|
|
"""Generate backup codes for 2FA recovery"""
|
|
codes = []
|
|
for _ in range(count):
|
|
code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
|
|
codes.append(code)
|
|
return codes
|
|
|
|
|
|
def hash_backup_code(code):
|
|
"""Hash a backup code for storage"""
|
|
return hashlib.sha256(code.encode()).hexdigest()
|
|
|
|
|
|
def verify_backup_code(code, hashed_codes):
|
|
"""Verify a backup code against stored hashes"""
|
|
code_hash = hashlib.sha256(code.encode()).hexdigest()
|
|
return code_hash in hashed_codes |