Browse Source

Implementována validace tokenů

Implementoval jsem to od stolu, není to vyzkoušené.
export_seznamu_prednasek
Pavel "LEdoian" Turinsky 3 years ago
parent
commit
a11d7d011c
  1. 46
      seminar/views/doregistrace.py

46
seminar/views/doregistrace.py

@ -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: 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ů) #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 enum import Enum
from django import forms from django import forms
from django.contrib.auth.models import User, Permission from django.contrib.auth.models import User, Permission
@ -38,9 +39,11 @@ class DodatecnaRegistraceUzivateleView(TemplateResponseMixin, View):
status_code=400, 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í # Zkontrolovat, že to není moc staré poslání
now = datetime.now() now = datetime.now()
token_generation = datetime.fromisoformat(tok_data['timestamp']) token_generation = datetime.fromisoformat(tok_timestamp)
delta = now - token_generation delta = now - token_generation
if delta >= timedelta(weeks=10): if delta >= timedelta(weeks=10):
return render_to_response( return render_to_response(
@ -52,7 +55,6 @@ class DodatecnaRegistraceUzivateleView(TemplateResponseMixin, View):
# Najít osobu # 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) osoba = m.Osoba.objects.get(id=osoba_id)
if osoba.user is not None: if osoba.user is not None:
return render_to_response( return render_to_response(
@ -62,10 +64,7 @@ class DodatecnaRegistraceUzivateleView(TemplateResponseMixin, View):
status_code=400, status_code=400,
) )
# Vrátit view s formulářem a formulářovým tokenem # Vrátit view s formulářem a formulářovým tokenem
form_token = gen_token(UseCase.form, data={ form_token = gen_token(UseCase.form, osoba=osoba_id, timestamp=datetime.now())
'osoba': str(osoba_id),
'timestamp': datetime.now().isoformat(),
})
return render_to_response( return render_to_response(
context={ context={
'form': self.form(initial={ 'form': self.form(initial={
@ -151,15 +150,36 @@ class UseCase(Enum):
form = 'form' form = 'form'
# Token kóduje všechno v sobě # 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:
def verify_token(usecase: _UseCase, token: str) -> Optional[dict[str, 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 Inspirováno OSMO, je díky tomu jednoduché zároveň předat dekódovaná data a
výsledek ověření. 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…
Cancel
Save