Skip to content

Commit 23505eb

Browse files
committed
address PR comments
1 parent e99671a commit 23505eb

File tree

2 files changed

+61
-5
lines changed

2 files changed

+61
-5
lines changed

firebase_admin/app_check.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818
import jwt
1919
from jwt import PyJWKClient, ExpiredSignatureError, InvalidTokenError, DecodeError
2020
from jwt import InvalidAudienceError, InvalidIssuerError, InvalidSignatureError
21+
import requests
2122
from firebase_admin import _utils
2223
from firebase_admin import _http_client
23-
import requests
24+
from firebase_admin import exceptions
2425

2526
_APP_CHECK_ATTRIBUTE = '_app_check'
2627

@@ -106,9 +107,17 @@ def _verify_replay_protection(self, token: str) -> bool:
106107
body = {'app_check_token': token}
107108
try:
108109
response = self._http_client.body('post', path, json=body)
110+
if not isinstance(response, dict):
111+
raise exceptions.UnknownError(
112+
'Unexpected response from App Check service. '
113+
f'Expected a JSON object, but got {type(response).__name__}.')
109114
return response.get('alreadyConsumed', False)
110115
except requests.exceptions.RequestException as error:
111116
raise _utils.handle_platform_error_from_requests(error)
117+
except ValueError as error:
118+
raise exceptions.UnknownError(
119+
'Unexpected response from App Check service. '
120+
f'Error: {error}')
112121

113122
def _has_valid_token_headers(self, headers: Any) -> None:
114123
"""Checks whether the token has valid headers for App Check."""

tests/test_app_check.py

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,16 +264,63 @@ def test_verify_token_with_consume_network_error(self, mocker):
264264
mocker.patch("jwt.PyJWKClient.get_signing_key_from_jwt", return_value=PyJWK(signing_key))
265265
mocker.patch("jwt.get_unverified_header", return_value=JWT_PAYLOAD_SAMPLE.get("headers"))
266266
mock_http_client = mocker.patch("firebase_admin._http_client.JsonHttpClient")
267-
mock_http_client.return_value.body.side_effect = requests.exceptions.RequestException("Network error")
268-
267+
mock_http_client.return_value.body.side_effect = requests.exceptions.RequestException(
268+
"Network error")
269+
270+
# Use a fresh app to ensure _AppCheckService is re-initialized with the mock
271+
cred = testutils.MockCredential()
272+
app = firebase_admin.initialize_app(
273+
cred, {'projectId': PROJECT_ID}, name='test_consume_error')
274+
275+
try:
276+
with pytest.raises(exceptions.UnknownError) as excinfo:
277+
app_check.verify_token("encoded", app, consume=True)
278+
assert str(excinfo.value) == (
279+
"Unknown error while making a remote service call: Network error")
280+
finally:
281+
firebase_admin.delete_app(app)
282+
283+
def test_verify_token_with_consume_non_dict_response(self, mocker):
284+
"""Test verify_token with consume=True handles non-dict response."""
285+
mocker.patch("jwt.decode", return_value=JWT_PAYLOAD_SAMPLE)
286+
mocker.patch("jwt.PyJWKClient.get_signing_key_from_jwt", return_value=PyJWK(signing_key))
287+
mocker.patch("jwt.get_unverified_header", return_value=JWT_PAYLOAD_SAMPLE.get("headers"))
288+
mock_http_client = mocker.patch("firebase_admin._http_client.JsonHttpClient")
289+
mock_http_client.return_value.body.return_value = ["not", "a", "dict"]
290+
291+
# Use a fresh app to ensure _AppCheckService is re-initialized with the mock
292+
cred = testutils.MockCredential()
293+
app = firebase_admin.initialize_app(
294+
cred, {'projectId': PROJECT_ID}, name='test_consume_non_dict')
295+
296+
try:
297+
with pytest.raises(exceptions.UnknownError) as excinfo:
298+
app_check.verify_token("encoded", app, consume=True)
299+
assert str(excinfo.value) == (
300+
'Unexpected response from App Check service. '
301+
'Expected a JSON object, but got list.')
302+
finally:
303+
firebase_admin.delete_app(app)
304+
305+
def test_verify_token_with_consume_malformed_json(self, mocker):
306+
"""Test verify_token with consume=True handles malformed JSON response."""
307+
mocker.patch("jwt.decode", return_value=JWT_PAYLOAD_SAMPLE)
308+
mocker.patch("jwt.PyJWKClient.get_signing_key_from_jwt", return_value=PyJWK(signing_key))
309+
mocker.patch("jwt.get_unverified_header", return_value=JWT_PAYLOAD_SAMPLE.get("headers"))
310+
mock_http_client = mocker.patch("firebase_admin._http_client.JsonHttpClient")
311+
mock_http_client.return_value.body.side_effect = ValueError("Malformed JSON")
312+
269313
# Use a fresh app to ensure _AppCheckService is re-initialized with the mock
270314
cred = testutils.MockCredential()
271-
app = firebase_admin.initialize_app(cred, {'projectId': PROJECT_ID}, name='test_consume_error')
315+
app = firebase_admin.initialize_app(
316+
cred, {'projectId': PROJECT_ID}, name='test_consume_malformed_json')
272317

273318
try:
274319
with pytest.raises(exceptions.UnknownError) as excinfo:
275320
app_check.verify_token("encoded", app, consume=True)
276-
assert str(excinfo.value) == "Unknown error while making a remote service call: Network error"
321+
assert str(excinfo.value) == (
322+
'Unexpected response from App Check service. '
323+
'Error: Malformed JSON')
277324
finally:
278325
firebase_admin.delete_app(app)
279326

0 commit comments

Comments
 (0)