50 行
1.5 KiB
Python
50 行
1.5 KiB
Python
|
import secrets
|
||
|
|
||
|
from quart import current_app
|
||
|
|
||
|
from anonstream.helpers.captcha import generate_captcha_digest, generate_captcha_image
|
||
|
|
||
|
CONFIG = current_app.config
|
||
|
CAPTCHA_FACTORY = current_app.captcha_factory
|
||
|
CAPTCHA_SIGNER = current_app.captcha_signer
|
||
|
CAPTCHAS = current_app.captchas
|
||
|
|
||
|
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_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']
|