Skip to content

Read Grand Slam's hsc 409 with no au as a second factor - #9

Open
lazzurs wants to merge 1 commit into
parawanderer:mainfrom
lazzurs:fix/hsc-409-is-a-second-factor
Open

lazzurs wants to merge 1 commit into
parawanderer:mainfrom
lazzurs:fix/hsc-409-is-a-second-factor

Conversation

@lazzurs

@lazzurs lazzurs commented Nov 4, 2026

Copy link
Copy Markdown

Since 2026-10-12 a password Apple accepts but wants a code for is answered at the SRP complete step with hsc 409 and no au. au is what _gsa_authenticate reads to decide that a second factor is needed, so the sign-in is taken as finished, the code is never asked for, and the mobileme delegate login after it fails with status=1 (malmeloo#278, parawanderer/OpenTagViewer#248).

This adds _normalize_2fa_status, called on the complete response in _gsa_authenticate. A 409 with no au gets au = "trustedDeviceSecondaryAuth", which is how sacca97/os-findmy-e signs in. Anything else, including a 409 that does name au, is left as Apple sent it. The name and placement match malmeloo#279, so a later sync with upstream should be a no-op here.

Requested in the review of parawanderer/OpenTagViewer#274 (item 7). That PR currently does this by wrapping _gsa_request on each account at runtime. The wrapper already steps aside once the pinned FindMy.py has _normalize_2fa_status, so once this is merged the pin can move and the wrapper can go.

Tests

tests/test_hsc_409_second_factor.py runs the whole SRP exchange offline against a verifier built from the same password, so it exercises _gsa_authenticate's own decision rather than the helper alone. Without the call, the 409 test comes back AUTHENTICATED instead of asking for a code. The full suite passes, and so do OpenTagViewer's bridge tests against this branch, apart from the three tests of the wrapper itself.

🤖 Generated with Claude Code

https://claude.ai/code/session_015MJtmGkNZpfzFGSN1BZ82a

Since 2026-10-12 a password Apple accepts but wants a code for is
answered at the SRP complete step with hsc 409 and no au. au is what
_gsa_authenticate reads to decide that a code is needed, so the sign-in
was taken as finished, the code was never asked for, and the mobileme
delegate login after it failed with status=1 (malmeloo#278,
OpenTagViewer#248).

_normalize_2fa_status fills au in as trustedDeviceSecondaryAuth, which
is how sacca97/os-findmy-e signs in. Same name and placement as
malmeloo#279, so a later sync with upstream is a no-op here.
A 409 that does name au is left as Apple sent it.

OpenTagViewer did this by wrapping _gsa_request on each account at
runtime; with this it can drop that.

The tests run the whole SRP exchange offline against a verifier built
from the same password, so they exercise _gsa_authenticate's own
decision. Without the call, the 409 test fails with AUTHENTICATED.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015MJtmGkNZpfzFGSN1BZ82a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant