From 6fd96fea0c54d8987c679fe9ddc3f6c80be5e710 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Mon, 9 Oct 2023 14:17:53 +0530 Subject: [PATCH 1/8] fix: crash with InvalidAuthBlockingTokenError (wrong audience) --- src/firebase_functions/private/_identity_fn.py | 8 ++++---- src/firebase_functions/private/token_verifier.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/firebase_functions/private/_identity_fn.py b/src/firebase_functions/private/_identity_fn.py index e301141..55db63f 100644 --- a/src/firebase_functions/private/_identity_fn.py +++ b/src/firebase_functions/private/_identity_fn.py @@ -64,11 +64,11 @@ def _auth_user_info_from_token_data(token_data: dict[str, _typing.Any]): def _auth_user_metadata_from_token_data(token_data: dict[str, _typing.Any]): from firebase_functions.identity_fn import AuthUserMetadata + creation_time = int(token_data["creation_time"]) / 1000.0 + last_sign_in_time = int(token_data["last_sign_in_time"]) / 1000.0 return AuthUserMetadata( - creation_time=_dt.datetime.utcfromtimestamp( - token_data["creation_time"] / 1000.0), - last_sign_in_time=_dt.datetime.utcfromtimestamp( - token_data["last_sign_in_time"] / 1000.0), + creation_time=_dt.datetime.utcfromtimestamp(creation_time), + last_sign_in_time=_dt.datetime.utcfromtimestamp(last_sign_in_time), ) diff --git a/src/firebase_functions/private/token_verifier.py b/src/firebase_functions/private/token_verifier.py index 300da43..a986ec4 100644 --- a/src/firebase_functions/private/token_verifier.py +++ b/src/firebase_functions/private/token_verifier.py @@ -95,14 +95,14 @@ def verify(self, token, request): 'Firebase {0} has incorrect algorithm. Expected "RS256" but got ' '"{1}". {2}'.format(self.short_name, header.get('alg'), verify_id_token_msg)) - elif self.expected_audience and self.expected_audience not in audience: + elif not emulated and self.expected_audience and self.expected_audience not in audience: error_message = ( 'Firebase {0} has incorrect "aud" (audience) claim. Expected "{1}" but ' 'got "{2}". {3} {4}'.format(self.short_name, self.expected_audience, audience, project_id_match_msg, verify_id_token_msg)) - elif not self.expected_audience and audience != self.project_id: + elif not emulated and not self.expected_audience and audience != self.project_id: error_message = ( 'Firebase {0} has incorrect "aud" (audience) claim. Expected "{1}" but ' 'got "{2}". {3} {4}'.format(self.short_name, self.project_id, From b56f46ca2020cb4684a5c3419fa2d4c805d9e7f8 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Mon, 9 Oct 2023 14:38:03 +0530 Subject: [PATCH 2/8] fix: KeyError when last_sign_in_time does not exist in token_data --- .../private/_identity_fn.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/firebase_functions/private/_identity_fn.py b/src/firebase_functions/private/_identity_fn.py index 55db63f..e0e34ae 100644 --- a/src/firebase_functions/private/_identity_fn.py +++ b/src/firebase_functions/private/_identity_fn.py @@ -65,10 +65,12 @@ def _auth_user_info_from_token_data(token_data: dict[str, _typing.Any]): def _auth_user_metadata_from_token_data(token_data: dict[str, _typing.Any]): from firebase_functions.identity_fn import AuthUserMetadata creation_time = int(token_data["creation_time"]) / 1000.0 - last_sign_in_time = int(token_data["last_sign_in_time"]) / 1000.0 + last_sign_in_time = None + if "last_sign_in_time" in token_data: + last_sign_in_time = int(token_data["last_sign_in_time"]) / 1000.0 return AuthUserMetadata( creation_time=_dt.datetime.utcfromtimestamp(creation_time), - last_sign_in_time=_dt.datetime.utcfromtimestamp(last_sign_in_time), + last_sign_in_time=_dt.datetime.utcfromtimestamp(last_sign_in_time) if last_sign_in_time else None, ) @@ -89,7 +91,7 @@ def _auth_multi_factor_info_from_token_data(token_data: dict[str, _typing.Any]): def _auth_multi_factor_settings_from_token_data(token_data: dict[str, - _typing.Any]): +_typing.Any]): if not token_data: return None @@ -214,14 +216,14 @@ def _auth_blocking_event_from_token_data(token_data: dict[str, _typing.Any]): def _validate_auth_response( - event_type: str, - auth_response, + event_type: str, + auth_response, ) -> dict[str, _typing.Any]: if auth_response is None: auth_response = {} custom_claims: dict[str, - _typing.Any] | None = auth_response.get("custom_claims") + _typing.Any] | None = auth_response.get("custom_claims") session_claims: dict[str, _typing.Any] | None = auth_response.get( "session_claims") @@ -303,9 +305,9 @@ def _validate_auth_response( def before_operation_handler( - func: _typing.Callable, - event_type: str, - request: _Request, + func: _typing.Callable, + event_type: str, + request: _Request, ) -> _Response: from firebase_functions.identity_fn import BeforeCreateResponse, BeforeSignInResponse try: From 8a9c376ff5700069c920107e75592d4d7efcb0f9 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Mon, 9 Oct 2023 15:23:50 +0530 Subject: [PATCH 3/8] refactor: creation_time and last_sign_in_time parsing --- src/firebase_functions/private/_identity_fn.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/firebase_functions/private/_identity_fn.py b/src/firebase_functions/private/_identity_fn.py index e0e34ae..cfc409d 100644 --- a/src/firebase_functions/private/_identity_fn.py +++ b/src/firebase_functions/private/_identity_fn.py @@ -64,13 +64,14 @@ def _auth_user_info_from_token_data(token_data: dict[str, _typing.Any]): def _auth_user_metadata_from_token_data(token_data: dict[str, _typing.Any]): from firebase_functions.identity_fn import AuthUserMetadata - creation_time = int(token_data["creation_time"]) / 1000.0 + creation_time = _dt.datetime.utcfromtimestamp(int(token_data["creation_time"]) / 1000.0) last_sign_in_time = None if "last_sign_in_time" in token_data: - last_sign_in_time = int(token_data["last_sign_in_time"]) / 1000.0 + last_sign_in_time = _dt.datetime.utcfromtimestamp(int(token_data["last_sign_in_time"]) / 1000.0) + return AuthUserMetadata( - creation_time=_dt.datetime.utcfromtimestamp(creation_time), - last_sign_in_time=_dt.datetime.utcfromtimestamp(last_sign_in_time) if last_sign_in_time else None, + creation_time=creation_time, + last_sign_in_time=last_sign_in_time ) From ccc4d7e3b32b19383acf7862e4179e78856a42a0 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Mon, 9 Oct 2023 14:17:53 +0530 Subject: [PATCH 4/8] fix: crash with InvalidAuthBlockingTokenError (wrong audience) --- src/firebase_functions/private/_identity_fn.py | 8 ++++---- src/firebase_functions/private/token_verifier.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/firebase_functions/private/_identity_fn.py b/src/firebase_functions/private/_identity_fn.py index e301141..55db63f 100644 --- a/src/firebase_functions/private/_identity_fn.py +++ b/src/firebase_functions/private/_identity_fn.py @@ -64,11 +64,11 @@ def _auth_user_info_from_token_data(token_data: dict[str, _typing.Any]): def _auth_user_metadata_from_token_data(token_data: dict[str, _typing.Any]): from firebase_functions.identity_fn import AuthUserMetadata + creation_time = int(token_data["creation_time"]) / 1000.0 + last_sign_in_time = int(token_data["last_sign_in_time"]) / 1000.0 return AuthUserMetadata( - creation_time=_dt.datetime.utcfromtimestamp( - token_data["creation_time"] / 1000.0), - last_sign_in_time=_dt.datetime.utcfromtimestamp( - token_data["last_sign_in_time"] / 1000.0), + creation_time=_dt.datetime.utcfromtimestamp(creation_time), + last_sign_in_time=_dt.datetime.utcfromtimestamp(last_sign_in_time), ) diff --git a/src/firebase_functions/private/token_verifier.py b/src/firebase_functions/private/token_verifier.py index 300da43..a986ec4 100644 --- a/src/firebase_functions/private/token_verifier.py +++ b/src/firebase_functions/private/token_verifier.py @@ -95,14 +95,14 @@ def verify(self, token, request): 'Firebase {0} has incorrect algorithm. Expected "RS256" but got ' '"{1}". {2}'.format(self.short_name, header.get('alg'), verify_id_token_msg)) - elif self.expected_audience and self.expected_audience not in audience: + elif not emulated and self.expected_audience and self.expected_audience not in audience: error_message = ( 'Firebase {0} has incorrect "aud" (audience) claim. Expected "{1}" but ' 'got "{2}". {3} {4}'.format(self.short_name, self.expected_audience, audience, project_id_match_msg, verify_id_token_msg)) - elif not self.expected_audience and audience != self.project_id: + elif not emulated and not self.expected_audience and audience != self.project_id: error_message = ( 'Firebase {0} has incorrect "aud" (audience) claim. Expected "{1}" but ' 'got "{2}". {3} {4}'.format(self.short_name, self.project_id, From 0d84189d1c0b5fa9662ff4bc6b12f7576b2b235a Mon Sep 17 00:00:00 2001 From: exaby73 Date: Mon, 9 Oct 2023 14:38:03 +0530 Subject: [PATCH 5/8] fix: KeyError when last_sign_in_time does not exist in token_data --- .../private/_identity_fn.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/firebase_functions/private/_identity_fn.py b/src/firebase_functions/private/_identity_fn.py index 55db63f..e0e34ae 100644 --- a/src/firebase_functions/private/_identity_fn.py +++ b/src/firebase_functions/private/_identity_fn.py @@ -65,10 +65,12 @@ def _auth_user_info_from_token_data(token_data: dict[str, _typing.Any]): def _auth_user_metadata_from_token_data(token_data: dict[str, _typing.Any]): from firebase_functions.identity_fn import AuthUserMetadata creation_time = int(token_data["creation_time"]) / 1000.0 - last_sign_in_time = int(token_data["last_sign_in_time"]) / 1000.0 + last_sign_in_time = None + if "last_sign_in_time" in token_data: + last_sign_in_time = int(token_data["last_sign_in_time"]) / 1000.0 return AuthUserMetadata( creation_time=_dt.datetime.utcfromtimestamp(creation_time), - last_sign_in_time=_dt.datetime.utcfromtimestamp(last_sign_in_time), + last_sign_in_time=_dt.datetime.utcfromtimestamp(last_sign_in_time) if last_sign_in_time else None, ) @@ -89,7 +91,7 @@ def _auth_multi_factor_info_from_token_data(token_data: dict[str, _typing.Any]): def _auth_multi_factor_settings_from_token_data(token_data: dict[str, - _typing.Any]): +_typing.Any]): if not token_data: return None @@ -214,14 +216,14 @@ def _auth_blocking_event_from_token_data(token_data: dict[str, _typing.Any]): def _validate_auth_response( - event_type: str, - auth_response, + event_type: str, + auth_response, ) -> dict[str, _typing.Any]: if auth_response is None: auth_response = {} custom_claims: dict[str, - _typing.Any] | None = auth_response.get("custom_claims") + _typing.Any] | None = auth_response.get("custom_claims") session_claims: dict[str, _typing.Any] | None = auth_response.get( "session_claims") @@ -303,9 +305,9 @@ def _validate_auth_response( def before_operation_handler( - func: _typing.Callable, - event_type: str, - request: _Request, + func: _typing.Callable, + event_type: str, + request: _Request, ) -> _Response: from firebase_functions.identity_fn import BeforeCreateResponse, BeforeSignInResponse try: From 4d93b43270df2293576059d907c5ff3dcfd2b98c Mon Sep 17 00:00:00 2001 From: exaby73 Date: Mon, 9 Oct 2023 15:23:50 +0530 Subject: [PATCH 6/8] refactor: creation_time and last_sign_in_time parsing --- src/firebase_functions/private/_identity_fn.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/firebase_functions/private/_identity_fn.py b/src/firebase_functions/private/_identity_fn.py index e0e34ae..cfc409d 100644 --- a/src/firebase_functions/private/_identity_fn.py +++ b/src/firebase_functions/private/_identity_fn.py @@ -64,13 +64,14 @@ def _auth_user_info_from_token_data(token_data: dict[str, _typing.Any]): def _auth_user_metadata_from_token_data(token_data: dict[str, _typing.Any]): from firebase_functions.identity_fn import AuthUserMetadata - creation_time = int(token_data["creation_time"]) / 1000.0 + creation_time = _dt.datetime.utcfromtimestamp(int(token_data["creation_time"]) / 1000.0) last_sign_in_time = None if "last_sign_in_time" in token_data: - last_sign_in_time = int(token_data["last_sign_in_time"]) / 1000.0 + last_sign_in_time = _dt.datetime.utcfromtimestamp(int(token_data["last_sign_in_time"]) / 1000.0) + return AuthUserMetadata( - creation_time=_dt.datetime.utcfromtimestamp(creation_time), - last_sign_in_time=_dt.datetime.utcfromtimestamp(last_sign_in_time) if last_sign_in_time else None, + creation_time=creation_time, + last_sign_in_time=last_sign_in_time ) From 424fb08ed6614c4fd27cc3cbc01aab65a577da95 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Wed, 11 Oct 2023 12:07:35 +0530 Subject: [PATCH 7/8] fix: line too long lint --- src/firebase_functions/private/_identity_fn.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/firebase_functions/private/_identity_fn.py b/src/firebase_functions/private/_identity_fn.py index cfc409d..7a8eda1 100644 --- a/src/firebase_functions/private/_identity_fn.py +++ b/src/firebase_functions/private/_identity_fn.py @@ -67,7 +67,8 @@ def _auth_user_metadata_from_token_data(token_data: dict[str, _typing.Any]): creation_time = _dt.datetime.utcfromtimestamp(int(token_data["creation_time"]) / 1000.0) last_sign_in_time = None if "last_sign_in_time" in token_data: - last_sign_in_time = _dt.datetime.utcfromtimestamp(int(token_data["last_sign_in_time"]) / 1000.0) + last_sign_in_time = _dt.datetime.utcfromtimestamp( + int(token_data["last_sign_in_time"]) / 1000.0) return AuthUserMetadata( creation_time=creation_time, From e759b1e6bc054ee4525c6ced78157dbebe9a8543 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Wed, 11 Oct 2023 12:10:25 +0530 Subject: [PATCH 8/8] fix: type checks and formatting --- src/firebase_functions/identity_fn.py | 2 +- .../private/_identity_fn.py | 23 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/firebase_functions/identity_fn.py b/src/firebase_functions/identity_fn.py index 9a8d18f..8e84c73 100644 --- a/src/firebase_functions/identity_fn.py +++ b/src/firebase_functions/identity_fn.py @@ -59,7 +59,7 @@ class AuthUserMetadata: creation_time: _dt.datetime """The date the user was created.""" - last_sign_in_time: _dt.datetime + last_sign_in_time: _typing.Optional[_dt.datetime] """The date the user last signed in.""" diff --git a/src/firebase_functions/private/_identity_fn.py b/src/firebase_functions/private/_identity_fn.py index 7a8eda1..dc7d169 100644 --- a/src/firebase_functions/private/_identity_fn.py +++ b/src/firebase_functions/private/_identity_fn.py @@ -64,16 +64,15 @@ def _auth_user_info_from_token_data(token_data: dict[str, _typing.Any]): def _auth_user_metadata_from_token_data(token_data: dict[str, _typing.Any]): from firebase_functions.identity_fn import AuthUserMetadata - creation_time = _dt.datetime.utcfromtimestamp(int(token_data["creation_time"]) / 1000.0) + creation_time = _dt.datetime.utcfromtimestamp( + int(token_data["creation_time"]) / 1000.0) last_sign_in_time = None if "last_sign_in_time" in token_data: last_sign_in_time = _dt.datetime.utcfromtimestamp( int(token_data["last_sign_in_time"]) / 1000.0) - return AuthUserMetadata( - creation_time=creation_time, - last_sign_in_time=last_sign_in_time - ) + return AuthUserMetadata(creation_time=creation_time, + last_sign_in_time=last_sign_in_time) def _auth_multi_factor_info_from_token_data(token_data: dict[str, _typing.Any]): @@ -93,7 +92,7 @@ def _auth_multi_factor_info_from_token_data(token_data: dict[str, _typing.Any]): def _auth_multi_factor_settings_from_token_data(token_data: dict[str, -_typing.Any]): + _typing.Any]): if not token_data: return None @@ -218,14 +217,14 @@ def _auth_blocking_event_from_token_data(token_data: dict[str, _typing.Any]): def _validate_auth_response( - event_type: str, - auth_response, + event_type: str, + auth_response, ) -> dict[str, _typing.Any]: if auth_response is None: auth_response = {} custom_claims: dict[str, - _typing.Any] | None = auth_response.get("custom_claims") + _typing.Any] | None = auth_response.get("custom_claims") session_claims: dict[str, _typing.Any] | None = auth_response.get( "session_claims") @@ -307,9 +306,9 @@ def _validate_auth_response( def before_operation_handler( - func: _typing.Callable, - event_type: str, - request: _Request, + func: _typing.Callable, + event_type: str, + request: _Request, ) -> _Response: from firebase_functions.identity_fn import BeforeCreateResponse, BeforeSignInResponse try: