From 9ce8858562ea8fcce687b8e410b9b68f86c08e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E6=BE=B3?= Date: Mon, 23 Mar 2026 14:32:15 +0800 Subject: [PATCH] first commit --- .env.example | 2 +- README.md | 6 +++--- app/main.py | 31 ++++++++++++++++++++++--------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/.env.example b/.env.example index ed053a6..6ce8d97 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ AUTH_DB_PATH=~/.nanobot/auth_service.sqlite3 AUTH_JWT_SECRET=change-this-secret AUTH_TOKEN_TTL_HOURS=24 AUTH_CORS_ORIGINS=* -AUTH_INVITE_CODES=invite-a,invite-b +AUTH_VERIFICATION_CODES=code-a,code-b AUTH_ADMIN_KEY=change-this-admin-key AUTH_HOST=0.0.0.0 AUTH_PORT=9100 diff --git a/README.md b/README.md index 5c499f1..4a1b0b2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Standalone phone/password auth service for nanobot web chat. ## Features -- `POST /auth/register` (phone + password + invite code; returns pending) +- `POST /auth/register` (phone + password + verification code; returns pending) - `POST /auth/login` - `GET /auth/me` (Bearer token) - `GET /auth/register/status/{request_id}` @@ -30,7 +30,7 @@ uvicorn app.main:app --host ${AUTH_HOST:-0.0.0.0} --port ${AUTH_PORT:-9100} - `AUTH_JWT_SECRET`: JWT signing secret - `AUTH_TOKEN_TTL_HOURS`: access token ttl - `AUTH_CORS_ORIGINS`: comma-separated origins or `*` -- `AUTH_INVITE_CODES`: comma-separated whitelist (empty means no whitelist check) +- `AUTH_VERIFICATION_CODES`: comma-separated whitelist (empty means no whitelist check) - `AUTH_ADMIN_KEY`: required by admin endpoints - `AUTH_HOST`: bind host (run command) - `AUTH_PORT`: bind port (run command) @@ -43,7 +43,7 @@ uvicorn app.main:app --host ${AUTH_HOST:-0.0.0.0} --port ${AUTH_PORT:-9100} { "phone": "13800000000", "password": "secret123", - "invite_code": "invite-a" + "verification_code": "code-a" } ``` diff --git a/app/main.py b/app/main.py index 0fe873f..8181b2f 100644 --- a/app/main.py +++ b/app/main.py @@ -27,6 +27,11 @@ AUTH_INVITE_CODES = { for item in os.getenv("AUTH_INVITE_CODES", "").split(",") if item.strip() } +AUTH_VERIFICATION_CODES = { + item.strip() + for item in os.getenv("AUTH_VERIFICATION_CODES", "").split(",") + if item.strip() +} AUTH_ADMIN_KEY = os.getenv("AUTH_ADMIN_KEY", "") @@ -74,7 +79,8 @@ class AuthPayload(BaseModel): class RegisterPayload(AuthPayload): - invite_code: str + invite_code: str = "" + verification_code: str = "" class TokenResponse(BaseModel): @@ -170,12 +176,17 @@ def _now_iso() -> str: return datetime.now(timezone.utc).isoformat() -def _require_invite_code(invite_code: str) -> str: - code = str(invite_code).strip() +def _allowed_verification_codes() -> set[str]: + return AUTH_VERIFICATION_CODES or AUTH_INVITE_CODES + + +def _require_verification_code(code_value: str) -> str: + code = str(code_value).strip() if not code: - raise HTTPException(status_code=400, detail="invite code is required") - if AUTH_INVITE_CODES and code not in AUTH_INVITE_CODES: - raise HTTPException(status_code=400, detail="invalid invite code") + raise HTTPException(status_code=400, detail="verification code is required") + allowed = _allowed_verification_codes() + if allowed and code not in allowed: + raise HTTPException(status_code=400, detail="invalid verification code") return code @@ -268,7 +279,7 @@ def health() -> dict: "ok": True, "service": "auth", "db": str(DB_PATH), - "invite_code_check": bool(AUTH_INVITE_CODES), + "verification_code_check": bool(_allowed_verification_codes()), } @@ -276,7 +287,9 @@ def health() -> dict: def register(payload: RegisterPayload): phone = _normalize_phone(payload.phone) _validate_password(payload.password) - invite_code = _require_invite_code(payload.invite_code) + verification_code = _require_verification_code( + payload.verification_code or payload.invite_code + ) salt = secrets.token_bytes(16) password_hash = _hash_password(payload.password, salt) @@ -308,7 +321,7 @@ def register(payload: RegisterPayload): INSERT INTO registration_requests(phone, password_hash, salt, invite_code, status, created_at) VALUES(?, ?, ?, ?, 'pending', ?) """, - (phone, password_hash, base64.b64encode(salt).decode("ascii"), invite_code, now), + (phone, password_hash, base64.b64encode(salt).decode("ascii"), verification_code, now), ) request_id = int(cur.lastrowid) conn.commit()