Read-only iCloud Drive client prototype with change feed and protocol note #1

Merged
HoroTW merged 4 commits from hakalya/feature/fox-58-protocol-prototype into main 2026-10-12 05:53:37 +00:00 AGit
Collaborator

Read-only iCloud Drive client for Linux in standard-library Python, plus the protocol research behind it (FOX-58). Not for merge without review.

What it does

  • login: Apple ID web sign-in (SRP, human second factor), resumable, session in a 0700/0600 state directory. The password is never sent or stored.
  • ls, cat: list one folder, read one file.
  • changes, watch: Drive change feed through CloudKit Web Services (changes/zone with a sync token). An idle poll is one request.
  • No write, rename or delete code. No FUSE.

Verified against the real service (one human sign-in, read-only)

  • App-specific password does not open iCloud setup (CalDAV 207, setup 401).
  • Sign-in with texted code, session setup, root listing, one file read (bytes received = listed size).
  • Change feed: full zone history paged in 5 requests, deletions included; follow-up call with the last token returned 0 records and the same token.

Not verified

  • A change made after the baseline showing up in the next changes call (nothing changed on the account while measuring; the project is read-only).
  • Push notifications (not probed; watch polls).
  • Sign-in with a code from a trusted Apple device, s2k_fo accounts, packages, session lifetime, Advanced Data Protection accounts.

Tests

PYTHONPATH=src python3 -m unittest discover -s tests -t . -> Ran 65 tests / OK. No network, no account: an in-process fake keeps the server half of SRP; the HTTP transport runs against a local server.

Secret scan and provenance

  • All 24 tracked files were checked against the test credentials and against every value in the private session and capture files (including decoded names): no credential, token, cookie, signed URL, identifier or account-specific name. Overlaps are protocol constants and a few ordinary English words.
  • No Apple binaries or decompiled code. The Windows installer was only unpacked and searched for strings.
  • No third-party run-time dependencies. See docs/PROVENANCE.md; this is not a strict clean room.

🤖 Generated with Claude Code

Read-only iCloud Drive client for Linux in standard-library Python, plus the protocol research behind it (FOX-58). Not for merge without review. ## What it does - `login`: Apple ID web sign-in (SRP, human second factor), resumable, session in a 0700/0600 state directory. The password is never sent or stored. - `ls`, `cat`: list one folder, read one file. - `changes`, `watch`: Drive change feed through CloudKit Web Services (`changes/zone` with a sync token). An idle poll is one request. - No write, rename or delete code. No FUSE. ## Verified against the real service (one human sign-in, read-only) - App-specific password does not open iCloud setup (CalDAV 207, setup 401). - Sign-in with texted code, session setup, root listing, one file read (bytes received = listed size). - Change feed: full zone history paged in 5 requests, deletions included; follow-up call with the last token returned 0 records and the same token. ## Not verified - A change made after the baseline showing up in the next `changes` call (nothing changed on the account while measuring; the project is read-only). - Push notifications (not probed; `watch` polls). - Sign-in with a code from a trusted Apple device, `s2k_fo` accounts, packages, session lifetime, Advanced Data Protection accounts. ## Tests `PYTHONPATH=src python3 -m unittest discover -s tests -t .` -> `Ran 65 tests` / `OK`. No network, no account: an in-process fake keeps the server half of SRP; the HTTP transport runs against a local server. ## Secret scan and provenance - All 24 tracked files were checked against the test credentials and against every value in the private session and capture files (including decoded names): no credential, token, cookie, signed URL, identifier or account-specific name. Overlaps are protocol constants and a few ordinary English words. - No Apple binaries or decompiled code. The Windows installer was only unpacked and searched for strings. - No third-party run-time dependencies. See `docs/PROVENANCE.md`; this is **not** a strict clean room. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Standard-library Python client: SRP web sign-in with human second
factor, private session store (0700/0600), folder listing, single-file
read, bounded retry, and three read-only probes for the open
change-detection question. Tests run against an in-process fake that
keeps the server half of SRP, and against a local HTTP server.

docs/PROTOCOL.md records what the official Windows client's interface
metadata shows (CloudKit change tokens and APNs do apply to Drive),
the measured result that an app-specific password does not open
iCloud setup, and what is still unverified on the web path.

Refs FOX-58

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A real sign-in on an account without trusted devices showed that the
second-factor options request answers 201 with mode "sms" and makes
Apple text the code. The client only understood 200, fell back to the
trusted-device endpoint and got 400 / -21669 for a correct code.

- read mode and phone id from the options answer (200 or 201) and
  submit texted codes to verify/phone/securitycode
- a later `login` continues an accepted password at the code step, or
  after it when the code was already accepted; `--restart` starts over
- never fetch the options twice in one run (each fetch is a text)
- fake server models the text-only account; regression tests added
- protocol note: proof and 409 answer now confirmed on the wire

Refs FOX-58

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With one human sign-in the whole web path was exercised on a real
account: session setup, folder listing, a single-file read, and the
question the research was about. The web session can read the Drive
container through CloudKit Web Services, and changes/zone returns the
records changed since a syncToken, deletions included. An idle poll is
one request with an unchanged token.

- changes.py: zones/list + changes/zone, paging with a request cap,
  record parsing (folder, file, content, deletion), read-only
- cli: `changes` (baseline, then delta; position in a 0600 file) and
  `watch` (polling, 30 s floor)
- fake server follows the observed record shapes with invented data
- protocol note: evidence levels raised to "seen on the wire" where
  that is true, and the open points listed: a change made after the
  baseline has not been observed, push is untested

Refs FOX-58

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Write tests on a real account were approved for a throwaway folder
(/Hakalya-Sora-Tests/<run-id>). They showed what the web API enforces:
create can be exclusive (409), move-to-trash is a compare-and-swap on
the etag, but content overwrite and rename check no version at all.
Two simultaneous overwrites were both accepted and one was lost.

- writer.py: mkdir, create (exclusive), replace (new document, then
  version-checked trash of the old one, then rename; conflict copy on
  mismatch), overwrite_in_place (documented as unsafe), rename, trash,
  journal and recover. No permanent delete. Optional sandbox folder.
- drive.py: a listing whose entry count differs from the announced
  count raises IncompleteListing instead of being used.
- cli: `cat -o` replaces the local file only after a full download.
- tools/live_write_test.py: 13 live checks incl. races and client-side
  fault injection; content-free report.
- docs/SAFETY.md: the contract, its tests, and what is not guaranteed.
- docs/PROTOCOL.md: write requests and measured server behaviour; a
  change made after the baseline is now observed in the change feed.

Refs FOX-58

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HoroTW merged commit 376de5e497 into main 2026-10-12 05:53:37 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
HoroTW/icloud-drive-linux!1
No description provided.