Only wait out a refusal after a 2FA code, not every protocol error - #237
Merged
Merged
Conversation
code_was_already_spent accepted any UnhandledProtocolError raised after the submit, so every such failure got the #168 recovery: wait, send a new code, try again. That recovery is only right for Apple refusing the request. #236 is Apple taking the code and asking for verification again, identically each time, and the loop spent three codes per sign-in on it. It also swallowed MobileMeDelegateError, an UnhandledProtocolError subclass, so the terms handler both front ends put around log_in could not run after 2FA. Now only AppleServiceUnavailableError counts as a spent code; anything else propagates unchanged after one submit. Refs #236 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Refs #236 (fixes the second of the two faults reported there; the first is being tested on parawanderer/FindMy.py
experiment/236-akd-2fa-headers).code_was_already_spent(python/exporter/icloud.py) accepted anyUnhandledProtocolErrorraised bysubmit, so every such failure went through the #168 recovery: wait, send a new code, submit again, three times. On #236 the failure isUnexpected state after submitting 2FA: LoginState.REQUIRE_2FA, identical on every attempt, so each sign-in spent three codes for nothing.The same catch took
MobileMeDelegateError(anUnhandledProtocolErrorsubclass), so theexcept MobileMeDelegateErrorterms handler aroundlog_ininwizard.pyandcli.pynever ran after a 2FA submit.Changes:
code_was_already_spentnow returns true only forAppleServiceUnavailableError, which is what a refused Grand Slam call raises at the pinned FindMy.py._submit_code_with_retriesre-raises anything else unchanged after one submit, with no wait and no new code.test_retries.py: the spent-code fake now raisesAppleServiceUnavailableError; newTestAFailureThatIsNotWeathercovers the REQUIRE_2FA error, a non-refusal status, andMobileMeDelegateError, asserting one submit, zero code requests, and the original exception.Verified:
uv run pytest ./test ./opentagviewer_export(680 passed, 2 skipped) and flake8. With the old one-line classifier restored, all four new tests fail. Not run against Apple.🤖 Generated with Claude Code