Skip to content

Commit 3ab1df8

Browse files
committed
fix(api): resolve mypy type errors; fix invalid jwt exception
- cast Any-returning calls (resp.json/json.loads/scalar_one) to declared types - cast redis smembers/ping awaitables (redis-py async stub returns Awaitable|T) - fix bug: jwt.InvalidClaimError does not exist (would AttributeError on nonce mismatch) -> jwt.InvalidTokenError
1 parent a4fccba commit 3ab1df8

4 files changed

Lines changed: 14 additions & 12 deletions

File tree

‎apps/api/src/auth/oauth.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import hashlib
99
import os
1010
import time
11-
from typing import Any
11+
from typing import Any, cast
1212

1313
import httpx
1414
import jwt
@@ -185,7 +185,7 @@ async def exchange_code_for_tokens(
185185
async with httpx.AsyncClient(timeout=10.0) as client:
186186
resp = await client.post(cfg["token_endpoint"], data=data, headers=headers)
187187
resp.raise_for_status()
188-
return resp.json()
188+
return cast(dict[str, Any], resp.json())
189189

190190

191191
# ---------------------------------------------------------------------------
@@ -200,7 +200,7 @@ async def _fetch_jwks(jwks_uri: str) -> dict[str, Any]:
200200
async with httpx.AsyncClient(timeout=10.0) as client:
201201
resp = await client.get(jwks_uri)
202202
resp.raise_for_status()
203-
return resp.json()
203+
return cast(dict[str, Any], resp.json())
204204

205205

206206
async def verify_google_id_token(
@@ -245,7 +245,7 @@ async def verify_google_id_token(
245245
)
246246

247247
if claims.get("nonce") != nonce:
248-
raise jwt.InvalidClaimError("nonce mismatch — possible replay attack")
248+
raise jwt.InvalidTokenError("nonce mismatch — possible replay attack")
249249

250250
return claims
251251

@@ -318,7 +318,7 @@ async def _fetch_apple_jwks() -> dict[str, Any]:
318318
async with httpx.AsyncClient(timeout=10.0) as client:
319319
resp = await client.get(APPLE_JWKS_URI)
320320
resp.raise_for_status()
321-
return resp.json()
321+
return cast(dict[str, Any], resp.json())
322322

323323

324324
def _find_apple_jwk(jwks: dict[str, Any], kid: str | None) -> Any:
@@ -395,4 +395,4 @@ async def exchange_apple_code_for_tokens(
395395
async with httpx.AsyncClient(timeout=10.0) as client:
396396
resp = await client.post(APPLE_TOKEN_ENDPOINT, data=data)
397397
resp.raise_for_status()
398-
return resp.json()
398+
return cast(dict[str, Any], resp.json())

‎apps/api/src/auth/tokens.py‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
import os
1010
import secrets
1111
import time
12-
from typing import Any
12+
from collections.abc import Awaitable
13+
from typing import Any, cast
1314

1415
import jwt
1516
from redis.asyncio import Redis
@@ -199,7 +200,7 @@ async def rotate_refresh(
199200
async def invalidate_family(redis: Redis, family_id: str) -> None:
200201
"""Delete all refresh tokens belonging to a family."""
201202
fkey = _family_key(family_id)
202-
token_hashes = await redis.smembers(fkey)
203+
token_hashes = await cast(Awaitable[set[str]], redis.smembers(fkey))
203204

204205
if token_hashes:
205206
pipe = redis.pipeline()
@@ -217,4 +218,4 @@ async def get_refresh_record(redis: Redis, raw_token: str) -> dict[str, Any] | N
217218
raw = await redis.get(_refresh_key(token_hash))
218219
if raw is None:
219220
return None
220-
return json.loads(raw)
221+
return cast(dict[str, Any], json.loads(raw))

‎apps/api/src/contacts/repository.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ async def count(
112112
stmt, user_id=user_id, q=q, tag=tag, country=country, city=city
113113
)
114114
result = await self.session.execute(stmt)
115-
return result.scalar_one()
115+
return int(result.scalar_one())
116116

117117
async def find_by_id(self, contact_id: int, user_id: str) -> Contact | None:
118118
stmt = select(Contact).where(

‎apps/api/src/main.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
2-
from collections.abc import AsyncGenerator
2+
from collections.abc import AsyncGenerator, Awaitable
33
from contextlib import asynccontextmanager
4+
from typing import cast
45

56
from fastapi import FastAPI, Request
67
from fastapi.middleware.cors import CORSMiddleware
@@ -99,7 +100,7 @@ async def health() -> JSONResponse:
99100
except Exception:
100101
db_ok = False
101102
try:
102-
await redis.ping()
103+
await cast(Awaitable[bool], redis.ping())
103104
redis_ok = True
104105
except Exception:
105106
redis_ok = False

0 commit comments

Comments
 (0)