66import secrets
77import uuid
88import zipfile
9+ from collections .abc import Mapping
910from http import HTTPStatus
10- from typing import Any , Protocol , runtime_checkable
11+ from typing import Any , Protocol , TypeGuard , runtime_checkable
1112from urllib .parse import parse_qs
1213
1314from beartype import beartype
@@ -88,6 +89,13 @@ def remove_oauth2_client_credential(self, client_id: str) -> None:
8889)
8990_CLIENT_CREDENTIALS_SCOPE = "oauth2.clientcredentials.all"
9091_MAX_CLIENT_CREDENTIALS = 100
92+
93+
94+ def _is_object_mapping (value : object , / ) -> TypeGuard [Mapping [object , object ]]:
95+ """Return whether a value is a mapping with unchecked entries."""
96+ return isinstance (value , Mapping )
97+
98+
9199# A stable mock value standing in for the user-id segment that real
92100# Vuforia embeds in some Model Target error targets such as
93101# ``userId:7635391``. The numeric portion is per-account in real Vuforia;
@@ -290,8 +298,10 @@ def _jwt_header_error(*, bearer_token: str) -> str | None:
290298
291299
292300@beartype
293- def _jwt_payload_error (* , bearer_token : str ) -> str | None :
294- """Return the Vuforia error for an invalid JSON Web Token payload."""
301+ def _jwt_payload (* , bearer_token : str ) -> tuple [Mapping [object , object ], bool ]:
302+ """Decode a JSON Web Token payload and report whether it is an
303+ object.
304+ """
295305 encoded_payload = bearer_token .split (sep = "." )[1 ]
296306 try :
297307 padding = "=" * (- len (encoded_payload ) % 4 )
@@ -300,11 +310,20 @@ def _jwt_payload_error(*, bearer_token: str) -> str | None:
300310 altchars = b"-_" ,
301311 validate = True ,
302312 )
303- payload = json .loads (s = decoded_payload )
313+ payload : object = json .loads (s = decoded_payload )
304314 except ValueError :
305315 payload = None
306316
307- if not isinstance (payload , dict ):
317+ if not _is_object_mapping (payload ):
318+ return dict [object , object ](), False
319+ return payload , True
320+
321+
322+ @beartype
323+ def _jwt_payload_error (* , bearer_token : str ) -> str | None :
324+ """Return the Vuforia error for an invalid JSON Web Token payload."""
325+ _ , is_object = _jwt_payload (bearer_token = bearer_token )
326+ if not is_object :
308327 return "Payload of JWS object is not a valid JSON object"
309328 return None
310329
@@ -334,19 +353,12 @@ def _jwt_signature_error(*, bearer_token: str) -> str | None:
334353@beartype
335354def _jwt_scopes (* , bearer_token : str ) -> frozenset [str ]:
336355 """Return scopes from a valid mock JSON Web Token."""
337- encoded_payload = bearer_token .split (sep = "." )[1 ]
338- padding = "=" * (- len (encoded_payload ) % 4 )
339- payload = json .loads (
340- s = base64 .b64decode (
341- s = encoded_payload + padding ,
342- altchars = b"-_" ,
343- validate = True ,
344- ),
345- )
346- scope = payload .get ("scope" , "" ) # pyrefly: ignore [unknown-variable-type]
356+ empty_scopes = frozenset [str ]()
357+ payload , _ = _jwt_payload (bearer_token = bearer_token )
358+ scope : object = payload .get ("scope" , "" )
347359 if not isinstance (scope , str ):
348- return frozenset () # ty: ignore[unsound-return-statement]
349- return frozenset (scope .split ()) # ty: ignore[unsound-return-statement]
360+ return empty_scopes
361+ return frozenset (scope .split ())
350362
351363
352364@beartype
0 commit comments