Implementována validace tokenů
Implementoval jsem to od stolu, není to vyzkoušené.
This commit is contained in:
parent
1d19f48ac7
commit
a11d7d011c
1 changed files with 31 additions and 11 deletions
|
@ -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:
|
||||
...
|
||||
# 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[dict[str, str]]:
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue