Skip to content

Accept and diagnose escrow metadata variations - #1

Merged
gregakespret merged 2 commits into
findmy-export-supportfrom
fix/escrow-metadata-variations
Aug 29, 2026
Merged

Accept and diagnose escrow metadata variations#1
gregakespret merged 2 commits into
findmy-export-supportfrom
fix/escrow-metadata-variations

Conversation

@gregakespret

@gregakespret gregakespret commented Aug 28, 2026

Copy link
Copy Markdown
Owner

Builds on upstream stek29/rustpush@96c1228, cherry-picked onto findmy-export-support.

EscrowMetadata::passcode_generation is a required u32, so any escrow record Apple returns without passcodeGeneration fails to deserialize — and get_viable_bottles discarded those silently, via .ok()? inside a filter_map. The user saw "No escrow bottles found. Make sure you have another trusted device." with no way to tell that apart from an account that genuinely has no escrow. It is our single biggest connect failure: 22 sessions across four users in the six days Railway retains logs.

The field is now #[serde(default)], and bottle selection is an explicit loop that accounts for every record it drops:

  • info! with the record and viable-bottle counts — the discriminator for the failure, since our own count is taken after the discarding
  • warn! naming the serde error and the metadata's top-level key:type shape when a record does not fit the struct
  • warn! for metadata that is not valid base64, or that decodes but is not a valid plist
  • a summary warn! counting both kinds of discard

Every discard path is at warn! because every one of them costs the user a bottle; the shape dump is the only thing that says which key or type disagreed, so it has to survive default log levels. Decoding goes through a new base64_decode_checked, since the existing base64_decode unwraps internally and a malformed blob would abort the whole export ahead of any of this.

The diagnostics carry counts, key names and value types — never a metadata value and never key material.

Two adjacent papercuts on the same path:

  • login_apple_delegates discarded the error from generate_validation_data with .ok(). That call is a network POST, so a transient relay blip dropped X-Mme-Nas-Qualify and came back as UNAUTHORIZED, which callers read as bad credentials and answer with a full re-login and 2FA. The error is now logged.
  • KeychainClientState::new_with_host takes a full URL, not a bare host — a schemeless value only fails later, inside reqwest. The parameter is named and documented accordingly.

Cargo.lock is regenerated against the current submodule pin; it was stale enough that cargo check --locked refused to build and a plain build left every tree dirty.

Consuming this needs the matching export-findmy change: the info! is dropped by that repo's keychain redaction allowlist until its prefix is added (gregakespret/export-findmy#TBD).

cargo check --locked --lib passes, both with default features and with --no-default-features --features remote-anisette-v3.

🤖 Generated with Claude Code

https://claude.ai/code/session_017VmSAa6yRzmHW6kK55g57w

- login_apple_delegates no longer discards the validation-data error with
  `.ok()`. A transient relay/anisette failure omitted X-Mme-Nas-Qualify and
  came back as UNAUTHORIZED, which callers read as bad credentials and
  answered with a full re-login/2FA. Log the real cause at warn!.

- fetch_viable_bottles decoded escrow metadata with base64_decode, which
  unwraps internally: a blob using the URL-safe alphabet, embedded newlines
  or non-canonical padding panicked and aborted the whole export, ahead of
  the tolerant handling right below it. Added base64_decode_checked and
  count such a record as invalid_metadata instead.

- Raised the metadata shape diagnostic from debug! to warn!, matching the
  sibling "not a valid plist" arm and the summary counter. At default log
  levels an operator saw the count but never which keys or types mismatched.

- Renamed new_with_host's third parameter to escrow_proxy_url; it takes a
  full URL, and a bare host produced reqwest's RelativeUrlWithoutBase far
  from the constructor.

- Committed the regenerated Cargo.lock, stale since the submodule bump in
  e3d2ea4: `cargo check --locked` failed and a plain build dirtied the tree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017VmSAa6yRzmHW6kK55g57w
@gregakespret
gregakespret merged commit 317d605 into findmy-export-support Aug 29, 2026
@gregakespret
gregakespret deleted the fix/escrow-metadata-variations branch August 29, 2026 05:54
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.

2 participants