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: 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: | ||||||
|  | 	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 | 	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…
	
		Reference in a new issue
	
	 Pavel "LEdoian" Turinsky
						Pavel "LEdoian" Turinsky