use a kdf
This commit is contained in:
parent
2cfa671338
commit
e070a96fb6
1 changed files with 32 additions and 5 deletions
37
tresetter.py
37
tresetter.py
|
@ -6,10 +6,12 @@ import json
|
||||||
import uuid
|
import uuid
|
||||||
from subprocess import Popen, CalledProcessError, check_output
|
from subprocess import Popen, CalledProcessError, check_output
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
import hashlib
|
||||||
|
import base64
|
||||||
|
|
||||||
import redis
|
import redis
|
||||||
from fastapi import FastAPI, APIRouter, HTTPException, Cookie, Request
|
from fastapi import FastAPI, APIRouter, HTTPException, Cookie, Request
|
||||||
from fastapi.responses import Response, JSONResponse, RedirectResponse
|
from fastapi.responses import Response, RedirectResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from pydantic import BaseModel, BaseSettings
|
from pydantic import BaseModel, BaseSettings
|
||||||
|
|
||||||
|
@ -201,22 +203,47 @@ async def logout(session_id: str = Cookie(None)) -> BaseModel:
|
||||||
delete_session(session_id)
|
delete_session(session_id)
|
||||||
return BaseModel()
|
return BaseModel()
|
||||||
|
|
||||||
|
KDF_SALT_SIZE = 16
|
||||||
|
|
||||||
|
|
||||||
|
def kdf_gen(password, salt=None) -> str:
|
||||||
|
if salt is None:
|
||||||
|
salt = random.randbytes(KDF_SALT_SIZE)
|
||||||
|
if hasattr(password, 'encode'):
|
||||||
|
password = password.encode('utf8')
|
||||||
|
raw = hashlib.scrypt(password, n=2, r=1, p=1, salt=salt)
|
||||||
|
with_salt = salt + raw
|
||||||
|
return base64.b64encode(with_salt).decode('ascii')
|
||||||
|
|
||||||
|
def kdf_get_salt(hashed: str):
|
||||||
|
hashed_str = hashed.decode('ascii') if hasattr(hashed, 'decode') else hashed
|
||||||
|
with_salt = base64.b64decode(hashed_str)
|
||||||
|
salt = with_salt[:KDF_SALT_SIZE]
|
||||||
|
return salt
|
||||||
|
|
||||||
|
def kdf_verify(hashed: str, password: str) -> bool:
|
||||||
|
salt = kdf_get_salt(hashed)
|
||||||
|
hashed2 = kdf_gen(password, salt=salt)
|
||||||
|
return hashed == hashed2
|
||||||
|
|
||||||
|
|
||||||
@router.post("/generate", tags=["password"])
|
@router.post("/generate", tags=["password"])
|
||||||
async def generate(session_id: str = Cookie(None)):
|
async def generate(session_id: str = Cookie(None)):
|
||||||
session = get_session(session_id)
|
session = get_session(session_id)
|
||||||
session["proposed_password"] = password_generate()
|
proposed_password = password_generate()
|
||||||
|
session["proposed_password_hash"] = kdf_gen(proposed_password)
|
||||||
set_session(session_id, session)
|
set_session(session_id, session)
|
||||||
|
|
||||||
return ChangeData(password=session["proposed_password"])
|
return ChangeData(password=proposed_password)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/change", tags=["password"])
|
@router.post("/change", tags=["password"])
|
||||||
async def change(req: ChangeData, session_id: str = Cookie(None)) -> SuccessData:
|
async def change(req: ChangeData, session_id: str = Cookie(None)) -> SuccessData:
|
||||||
session = get_session(session_id)
|
session = get_session(session_id)
|
||||||
if "proposed_password" not in session:
|
if "proposed_password_hash" not in session:
|
||||||
raise HTTPException(status_code=400, detail="You must generate it first")
|
raise HTTPException(status_code=400, detail="You must generate it first")
|
||||||
if req.password != session["proposed_password"]:
|
hashed = session["proposed_password_hash"]
|
||||||
|
if not kdf_verify(hashed, req.password):
|
||||||
raise HTTPException(status_code=409)
|
raise HTTPException(status_code=409)
|
||||||
|
|
||||||
success = change_password(session["username"], req.password)
|
success = change_password(session["username"], req.password)
|
||||||
|
|
Loading…
Reference in a new issue