Download app/auth.py from roz322/annotator: direct link, hf CLI and curl.
- Browser
- Download file 2.33 kB
-
https://huggingface.co/spaces/roz322/annotator/resolve/main/app/auth.py
- Command line
-
hf download hf://spaces/roz322/annotator/app/auth.py
-
curl -L -o auth.py https://huggingface.co/spaces/roz322/annotator/resolve/main/app/auth.py
2.33 kB
| """登录: 标注人账号在环境变量 ANNOTATORS_JSON 里配置(密码只存 PBKDF2 哈希), 会话用 HMAC 签名 cookie。 | |
| ANNOTATORS_JSON 示例(scripts/hash_password.py 生成哈希): | |
| { | |
| "Rong": {"role": "admin", "pw": "pbkdf2_sha256$..."}, | |
| "A": {"pw": "pbkdf2_sha256$...", "papers": ["MICCAI_3979_paper"]}, | |
| "B": {"pw": "pbkdf2_sha256$..."} | |
| } | |
| papers 可选: 给了就只能看到这些论文。repo 可选: 给了就把此人标注写进那个仓库(默认写 DATA_REPO 的 annotations/<ID>/)。未配置 ANNOTATORS_JSON 且为 local 后端时 = 开放模式(同 0817 本地版, 任填 ID)。 | |
| """ | |
| import base64 | |
| import hashlib | |
| import hmac | |
| import json | |
| import secrets | |
| import time | |
| from typing import Optional | |
| ITERATIONS = 200_000 | |
| COOKIE = "repl_sess" | |
| SESSION_TTL = 14 * 24 * 3600 | |
| def hash_password(pw: str, salt: Optional[str] = None) -> str: | |
| salt = salt or secrets.token_hex(16) | |
| dk = hashlib.pbkdf2_hmac("sha256", pw.encode(), salt.encode(), ITERATIONS) | |
| return f"pbkdf2_sha256${ITERATIONS}${salt}${dk.hex()}" | |
| def verify_password(pw: str, stored: str) -> bool: | |
| try: | |
| algo, it, salt, digest = stored.split("$") | |
| except ValueError: | |
| return False | |
| if algo != "pbkdf2_sha256": | |
| return False | |
| dk = hashlib.pbkdf2_hmac("sha256", pw.encode(), salt.encode(), int(it)) | |
| return hmac.compare_digest(dk.hex(), digest) | |
| def _b64(b: bytes) -> str: | |
| return base64.urlsafe_b64encode(b).decode().rstrip("=") | |
| def _unb64(s: str) -> bytes: | |
| return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4)) | |
| def sign_session(secret: str, annotator: str) -> str: | |
| body = _b64(json.dumps({"a": annotator, "exp": int(time.time()) + SESSION_TTL}).encode()) | |
| mac = _b64(hmac.new(secret.encode(), body.encode(), hashlib.sha256).digest()) | |
| return f"{body}.{mac}" | |
| def read_session(secret: str, token: Optional[str]) -> Optional[str]: | |
| if not token or "." not in token: | |
| return None | |
| body, mac = token.rsplit(".", 1) | |
| want = _b64(hmac.new(secret.encode(), body.encode(), hashlib.sha256).digest()) | |
| if not hmac.compare_digest(mac, want): | |
| return None | |
| try: | |
| data = json.loads(_unb64(body)) | |
| except (ValueError, json.JSONDecodeError): | |
| return None | |
| if data.get("exp", 0) < time.time(): | |
| return None | |
| return data.get("a") | |