anonstream/anonstream/captcha.py

59 行
1.7 KiB
Python

# SPDX-FileCopyrightText: 2022 n9k [https://git.076.ne.jp/ninya9k]
# SPDX-License-Identifier: AGPL-3.0-or-later
import secrets
from quart import current_app
from anonstream.helpers.captcha import generate_captcha_digest, generate_captcha_image
CONFIG = current_app.config
CAPTCHAS = current_app.captchas
CAPTCHA_FACTORY = current_app.captcha_factory
CAPTCHA_SIGNER = current_app.captcha_signer
def generate_random_captcha_solution():
return ''.join(
secrets.choice(CONFIG['CAPTCHA_ALPHABET'])
for _ in range(CONFIG['CAPTCHA_LENGTH'])
)
def _get_random_cached_captcha_digest():
chosen_index = secrets.randbelow(len(CAPTCHAS))
for index, digest in enumerate(CAPTCHAS):
if index == chosen_index:
break
return digest
def get_random_captcha_digest():
if len(CAPTCHAS) >= CONFIG['MAX_CAPTCHAS']:
digest = _get_random_cached_captcha_digest()
else:
salt = secrets.token_bytes(16)
solution = generate_random_captcha_solution()
digest = generate_captcha_digest(CAPTCHA_SIGNER, salt, solution)
CAPTCHAS[digest] = {'solution': solution}
while len(CAPTCHAS) >= CONFIG['MAX_CAPTCHAS']:
CAPTCHAS.popitem(last=False)
return digest
def get_random_captcha_digest_for(user):
if user['verified']:
return None
else:
return get_random_captcha_digest()
def get_captcha_image(digest):
try:
captcha = CAPTCHAS[digest]
except KeyError:
return None
else:
if 'image' not in captcha:
captcha['image'] = generate_captcha_image(
factory=CAPTCHA_FACTORY,
solution=captcha.pop('solution'),
)
return captcha['image']