|
|
@ -10,6 +10,7 @@ Importovat prosím jen ty dva Views, ve výjimečných případech invite, nic d |
|
|
|
#TODO: Logování (tohle logovat chce skoro určitě) |
|
|
|
#TODO: Omezení počtu pokusů (per token -- města / údaje se bruteforcit dají, na rozdíl od tokenů) |
|
|
|
|
|
|
|
from datetime import datetime |
|
|
|
from enum import Enum |
|
|
|
from django import forms |
|
|
|
from django.contrib.auth.models import User, Permission |
|
|
@ -38,9 +39,11 @@ class DodatecnaRegistraceUzivateleView(TemplateResponseMixin, View): |
|
|
|
status_code=400, |
|
|
|
) |
|
|
|
|
|
|
|
osoba_id, tok_timestamp = tok_data # Token prostě vypadá takhle, je to zafixované. Pokud tak nevypadá, je něco moc špatně. |
|
|
|
|
|
|
|
# Zkontrolovat, že to není moc staré poslání |
|
|
|
now = datetime.now() |
|
|
|
token_generation = datetime.fromisoformat(tok_data['timestamp']) |
|
|
|
token_generation = datetime.fromisoformat(tok_timestamp) |
|
|
|
delta = now - token_generation |
|
|
|
if delta >= timedelta(weeks=10): |
|
|
|
return render_to_response( |
|
|
@ -52,7 +55,6 @@ class DodatecnaRegistraceUzivateleView(TemplateResponseMixin, View): |
|
|
|
|
|
|
|
|
|
|
|
# Najít osobu |
|
|
|
osoba_id = int(tok_data['osoba']) # Pokud tam není, tak jsme vygenerovali špatný token my (byl validní). |
|
|
|
osoba = m.Osoba.objects.get(id=osoba_id) |
|
|
|
if osoba.user is not None: |
|
|
|
return render_to_response( |
|
|
@ -62,10 +64,7 @@ class DodatecnaRegistraceUzivateleView(TemplateResponseMixin, View): |
|
|
|
status_code=400, |
|
|
|
) |
|
|
|
# Vrátit view s formulářem a formulářovým tokenem |
|
|
|
form_token = gen_token(UseCase.form, data={ |
|
|
|
'osoba': str(osoba_id), |
|
|
|
'timestamp': datetime.now().isoformat(), |
|
|
|
}) |
|
|
|
form_token = gen_token(UseCase.form, osoba=osoba_id, timestamp=datetime.now()) |
|
|
|
return render_to_response( |
|
|
|
context={ |
|
|
|
'form': self.form(initial={ |
|
|
@ -151,15 +150,36 @@ class UseCase(Enum): |
|
|
|
form = 'form' |
|
|
|
|
|
|
|
# Token kóduje všechno v sobě |
|
|
|
def gen_token(usecase: _UseCase, data: dict[str, str]) -> str: |
|
|
|
... |
|
|
|
|
|
|
|
def verify_token(usecase: _UseCase, token: str) -> Optional[dict[str, str]]: |
|
|
|
# Tokenové metody zároveň řeší konzistentní zakódování dat do tokenu, takže už to nemusí řešit nikdo jiný. |
|
|
|
HMAC_FUNCTION='sha-256' |
|
|
|
def gen_token(usecase: _UseCase, *, osoba_id: int, timestamp: datetime) -> str: |
|
|
|
strmsg = '@'.join([usecase.value, str(osoba_id), timestamp.isoformat()]) |
|
|
|
msg = bytes(strmsg, 'utf-8') |
|
|
|
key = bytes(SECRET_KEY, 'utf-8') |
|
|
|
mac = hmac.mac(key, msg, HMAC_FUNCTION).hexdigest() |
|
|
|
return mac+'@'+msg |
|
|
|
|
|
|
|
def verify_token(usecase: _UseCase, token: str) -> Optional[Tuple[int, datetime]]: |
|
|
|
""" |
|
|
|
Vrací slovník dat, pokud je token validní, jinak None. |
|
|
|
Vrací dvojici dat, pokud je token validní, jinak None. |
|
|
|
|
|
|
|
Inspirováno OSMO, je díky tomu jednoduché zároveň předat dekódovaná data a |
|
|
|
výsledek ověření. |
|
|
|
""" |
|
|
|
... |
|
|
|
|
|
|
|
try: |
|
|
|
tok_mac, uc, tok_osoba, tok_ts = token.split('@') |
|
|
|
except ValueError: |
|
|
|
# Nepodařilo se rozbít na právě čtyři části, takže je token špatně. |
|
|
|
return None |
|
|
|
strmsg = '@'.join([usecase.value, tok_osoba, tok_ts]) |
|
|
|
msg = bytes(strmsg, 'utf-8') |
|
|
|
key = bytes(SECRET_KEY, 'utf-8') |
|
|
|
valid_mac = hmac.mac(key, msg, HMAC_FUNCTION).hexdigest() |
|
|
|
|
|
|
|
if hmac.compare_digest(tok_mac, valid_mac): |
|
|
|
# HMAC sedí, takže data jsou v pořádku |
|
|
|
osoba_id = int(tok_osoba) |
|
|
|
ts = datetime.fromisoformat(tok_ts) |
|
|
|
return (osoba_id, ts) |
|
|
|
else: |
|
|
|
return None |
|
|
|