Files
simkeep/server/auth.py
T
2026-10-06 15:49:27 +08:00

46 lines
1.3 KiB
Python

import hashlib
import hmac
import secrets
import threading
import time
from fastapi import HTTPException
def digest(value):
return hashlib.sha256(value.encode()).hexdigest()
def hash_password(password):
salt=secrets.token_bytes(16)
key=hashlib.scrypt(password.encode(),salt=salt,n=16384,r=8,p=1,dklen=32)
return f'scrypt${salt.hex()}${key.hex()}'
def verify_password(password,encoded):
try:
algorithm,salt,key=encoded.split('$')
if algorithm != 'scrypt':
return False
actual=hashlib.scrypt(password.encode(),salt=bytes.fromhex(salt),n=16384,r=8,p=1,dklen=32)
return hmac.compare_digest(actual,bytes.fromhex(key))
except (ValueError,TypeError):
return False
DUMMY_HASH=hash_password('never-a-real-account-password')
class RateLimit:
def __init__(self):
self.entries={}
self.lock=threading.Lock()
def check(self,key,limit=20,window=60):
now=time.monotonic()
with self.lock:
self.entries={k:v for k,v in self.entries.items() if now < v[0]}
expiry,count=self.entries.get(key,(now+window,0))
if count >= limit:
raise HTTPException(429,'操作过于频繁,请稍后重试')
self.entries[key]=(expiry,count+1)