Hello, the fix, made by an LLM, to the ProtonDrive backend, is around 100 LOC.
| Repo | Added | Removed | Net |
|---|---|---|---|
| go-proton-api | 93 | 8 | +85 |
| Proton-API-Bridge | 27 | 10 | +17 |
| rclone | 1 | 1 | 0 |
| Total | 121 | 19 | +102 |
_Clean Room_ Summary: Fixing Proton Drive File Uploads
Problem
All file uploads fail with HTTP 422 on POST /storage/blocks. Read operations work fine.
Root Cause
Proton's block upload API (POST /drive/blocks) now requires a per-block verification token. Without it, the server issues upload URLs that reject the actual block data.
Required Changes
1. Block Upload Request β New Fields
The block upload request (POST /drive/blocks) must include:
-
VolumeIDat the top level (alongside ShareID, LinkID, RevisionID) -
Verifier.Token(base64 string) per block entry in BlockList -
SizeandHashper block are no longer required (deprecated)
2. New API Endpoint β Verification Code
Before uploading blocks, the client must call:
GET /drive/v2/volumes/{volumeID}/links/{linkID}/revisions/{revisionID}/verification
This returns VerificationCode (base64) and ContentKeyPacket.
3. Token Computation
For each encrypted block:
-
Base64-decode the
VerificationCodeβ 32 bytes -
XOR the first 32 bytes of the encrypted block data with the verification code, byte by byte
-
Base64-encode the result β this is
Verifier.Token
If the encrypted block is shorter than 32 bytes, treat missing bytes as zero.
4. Storage Server Request
When uploading the actual block data to the storage server (POST <bareURL>):
-
Send only the
pm-storage-tokenheader β do not forward API auth headers (Authorization,x-pm-uid) -
Multipart form part should have field name
Block, filenameblob, and no Content-Type on the part
5. App Version String
The x-pm-appversion header must match: external-drive-{name}@{semver}-{channel}
Example: external-drive-rclone@1.0.0-beta+rclone
Upload Flow (Updated)
-
Create draft revision β get LinkID, RevisionID
-
Fetch verification code from the new endpoint using VolumeID, LinkID, RevisionID
-
Encrypt each block
-
Compute verification token per block (XOR first 32 bytes)
-
Request upload URLs via
POST /drive/blockswith VolumeID and Verifier.Token per block -
Upload block data to storage server (pm-storage-token only)
-
Commit revision