Fix decrypt failures, hanging waits, and a few listener crashes - #114
Open
P6g9YHK6 wants to merge 4 commits into
Open
Fix decrypt failures, hanging waits, and a few listener crashes#114P6g9YHK6 wants to merge 4 commits into
P6g9YHK6 wants to merge 4 commits into
Conversation
A failed request used to just print an error and return None. Every caller either discards that return value or waits on some other side effect of the request arriving (like an FCM push for a locate action), so a rejected request was indistinguishable from one that was accepted but never got a response - callers had to sit through a full timeout before finding out something had already failed immediately.
get_location_data_for_device() used to spin in a tight sleep loop with no way out if Google's push never arrived (device offline, no fresh fix available, etc.), hanging the script until it got killed by hand. Give it a 60s default timeout via threading.Event instead, and unregister the callback afterwards so repeated calls don't leak entries into FcmReceiver's callback list forever.
- fcmpushclient.py: per-message crypto-key/salt headers sometimes come without base64url padding, crashing the listener with a padding error; add the same padding fallback already used for der_data/secret. - fcmpushclient.py: those same headers can carry more than one ;-separated parameter, which used to decode into a garbage blob instead of raising, failing later with a confusing EC key error deep inside http_ece - split off the extra parameter instead. - fcmpushclient.py: a data message meant for a different app on the same Android ID used to be decrypted anyway (guaranteed to fail) and crash the whole listener - skip it instead. - auth_flow.py / shared_key_flow.py: Selenium's TimeoutException has no message, so a sign-in timeout showed up as a blank error with no indication of what happened - raise a descriptive TimeoutError instead. - auth_flow.py: overlapping sign-in flows would kill each other's Chrome process (create_driver() unconditionally pkills chrome before launching), so serialize them with a lock. - shared_key_flow.py: the alert-polling loop for the encryption confirmation step was unconditional (while True) with a bare except that swallowed everything, so it could hang forever with no way out if neither JS callback ever fired - bound it to the same sign-in timeout.
Two separate bugs combined to make trackers permanently undecryptable after an account's FMDN owner key was ever rotated (or on any account with more than one owner key generation in play), even when a working key was actually available: - response_parser.py: the vault can hold more than one key epoch for the finder_hw domain, but this always returned whichever entry the array happened to list first instead of comparing epochs - a stale/rotated-out epoch could win over the current one. - decrypt_locations.py: on a decrypt failure it went straight to telling the user to delete their credentials and sign in again, without ever retrying against the tracker's own required owner key version, or against any other key version the account might have. get_eid_info()/get_owner_key() now take an explicit owner_key_version. decrypt_locations.py retries with the tracker's own required version, then as a last resort against every owner key blob pulled from the real Find My Device web app's own internal API during sign-in (KeyBackup/vault_web_api.py, new - GetEidInfoForE2eeDevices always hands back only its own idea of 'current' no matter what version is actually requested, so this is the only way found so far to reach the others). Only falls through to the delete-and-resignin message if all of those fail too.
|
Thanks! this PR solved the issues I was having. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #22 & #67.
Raise on failed Nova API requests instead of returning None
A failed request used to just print an error and return
None. Every caller either discards that return value or waits on some other side effect of the request arriving (like an FCM push for a locate action), so a rejected request was indistinguishable from one that was accepted but never got a response - callers had to sit through a full timeout before finding out something had already failed immediately.Time out location requests instead of polling forever
get_location_data_for_device()used to spin in a tight sleep loop with no way out if Google's push never arrived (device offline, no fresh fix available, etc.), hanging the script until it got killed by hand. Gives it a 60s default timeout instead, and unregisters the callback afterwards so repeated calls don't leak entries intoFcmReceiver's callback list forever.Fix FCM push listener crashes and hanging sign-in waits
;-separated parameter, which used to decode into a garbage blob instead of raising, failing later with a confusing EC key error deep insidehttp_ece.TimeoutExceptionhas no message, so a sign-in timeout showed up as a blank error - both sign-in waits now raise a descriptiveTimeoutError.create_driver()unconditionally pkills chrome before launching) - serialized with a lock.while True) with a bareexceptthat swallowed everything, so it could hang forever if neither JS callback ever fired - bounded to the same sign-in timeout.Fix decrypt failures after an E2EE owner key rotation
This is the
cryptography.exceptions.InvalidTag/ "Failed to decrypt identity key encrypted with owner key version X, current owner key version is Y" failure. Two separate bugs combined to make trackers permanently undecryptable after an account's FMDN owner key was ever rotated (or on any account with more than one owner key generation in play), even when a working key was actually available:finder_hwdomain, but the parser always returned whichever entry the array happened to list first instead of comparing epochs.decrypt_locations.pywent straight to telling the user to delete their credentials and sign in again, without ever retrying against the tracker's own required owner key version, or against any other version the account might have.Now it retries with the tracker's own required version, then as a last resort against every owner key blob pulled from the real Find My Device web app's own internal API during sign-in (
KeyBackup/vault_web_api.py, new -GetEidInfoForE2eeDevicesalways hands back only its own idea of "current" no matter what version is actually requested, so this is the only way found so far to reach the others). Only falls through to the delete-and-resignin message if all of those fail too.