Add Proton Drive as a fully supported cloud provider#69
Open
Glitxhhh wants to merge 24 commits into
Open
Conversation
Implements end-to-end encrypted cloud saves via Proton Drive using the Proton SRP v4 auth protocol and OpenPGP key hierarchy decryption. - C++ backend: ProtonDriveProvider + ProtonPGP (Windows BCrypt / Linux OpenSSL) that handles SRP token refresh, E2E node key decryption/encryption, folder traversal, and file upload/download via the Proton Drive v2 API - C# auth UI: SRP v4 challenge-response flow, Argon2id key derivation, BouncyCastle PGP private key decryption, address key component extraction saved to token file; ProtonLoginWindow for credential entry - CMake: OpenSSL linkage for Linux, 32-bit support with lib32 path override - NuGet.Config: clears stale VS fallback folder to fix restore on machines where the old VS install path no longer exists - README: add Proton Drive to supported providers list
- Add ProtonAuthService (proton_auth.h/cpp): SRP v4 auth with BCrypt password expansion, Argon2id key derivation, PGP private key decryption (S2K type 3 SHA-1/SHA-256 + type 4 Argon2id), proper OpenPGP CFB decrypt with resync, RSA-OAEP session key decrypt, and atomic 0600 token write - Wire OAuthService.startProtonAuth() as Q_INVOKABLE wrapper - Add Proton Drive to CloudProviderPage with email/password Dialog - Link OpenSSL::Crypto, argon2, crypt in CMakeLists - Fix Windows ProtonSrpService: use TryAddWithoutValidation for x-pm-appversion and User-Agent headers
Remove User-Agent from HttpClient defaults — .NET 8 re-validates known headers at send time, and the @ in the app version string is invalid per RFC 7231 product token syntax. x-pm-appversion is the header Proton actually validates. Fix libargon2.so.1 not found at runtime by installing to /app/lib instead of /app/lib/x86_64-linux-gnu (flatpak LD_LIBRARY_PATH only covers /app/lib).
Revert SRP arithmetic to big-endian throughout (matches go-srp reference). Fix ParseSrpModulus/parseSrpModulus to split on \r\n|\n|\r so Proton's CRLF PGP messages are handled correctly on all platforms.
- All big integers are little-endian (reversed before/after BIGNUM ops in C++)
- expandHash = 4×SHA-512(data||i), 256 bytes (replaces SHA-512 64 bytes)
- Password hash: expandHash(bcrypt("$2y$10$"+bcryptB64(salt+"proton")[:22]) || modulus_LE)
- k multiplier: k = toNat(expandHash(g_LE || N_LE)) mod N
- S exponent: (u*x + a) mod (N-1)
- Proof: expandHash(A_LE || serverEph_LE || S_LE)
- Modulus PGP body is standard base64, not hex
- BCrypt salt fix in C#: replace BouncyCastle re-encoded salt chars with original saltStr22
…init reliability - app_state.cpp, manifest_store.cpp: heal CAS-key corruption from builds <=2.0.4 (strip 40-hex leaf from <name>/<sha40> paths), dedup by size - cloud_storage.cpp: TryReadCachedBlob detects legacy directory layout, uses file_size() to avoid bad_alloc on Linux when tellg() returns -1 - autocloud_bootstrap.cpp: wrap async blob fetch and future.get() in try/catch so one bad blob doesn't abort the entire prefetch - rpc_handlers.cpp: fall back to cloud state for file downloads when local manifest has zero size/sha (handles cold-start ordering race) - steam_kv_injector.cpp: add KvCrashGuard + sigsetjmp around all three Linux steamclient call sites; permanently disable injector on fault - http_server.cpp: wrap HandleConnection in try/catch so an unhandled exception in one connection doesn't take down the accept loop - init.cpp: extend steamclient poll from 10s to 120s with early-out on timeout; extract SpawnDeferredInit(); remove success notification popup
Proton's own Windows Drive client sends no Intent field in /auth/v4/info or /auth/v4 — sending it triggers a different server-side flow that returns Code 2028 / HTTP 422. Remove from both C# (Windows) and C++ (Linux) implementations. Also fix Qt HTTP error handling: postJson/getJson now read the response body even on 4xx so Proton's JSON error Code is surfaced instead of Qt's generic error string.
Use correct client identity strings matching Proton's format:
- Windows: windows-drive@2.1.0 (matches official windows-drive format)
- Linux: linux-drive-cloudredirect@1.0.0 (SDK format, no official linux client)
Add headers required by the Proton API:
- Accept: application/vnd.protonmail.api+json
- Accept-Language: en-US,en
- x-pm-locale: en_US
- User-Agent: ProtonDrive/{version} ({Platform})
- Log SRP version, modulus/salt/ephemeral byte lengths on Windows to diagnose Code 2028 - Change Linux appversion to linux-drive@2.1.0 (strip extra name segment causing Code 5002)
…Windows linux-drive@2.1.0 returns Code 5002 Invalid app version; linux-bridge is whitelisted. Log the Error string alongside Code from /auth/v4 response.
- Wire "proton" as alias in .so factory (cloud_storage.cpp) so the DLL recognises configs written by the QML UI - Linux backend: fetchProtonDriveApps() navigates the full Drive key chain (share key -> root node -> CloudRedirect -> account -> app folders) to list remote app IDs; wired into fetchRemoteApps() and deleteCloudAppData() - Linux auth: full SRP v4 flow in ProtonAuthService with TOTP 2FA support; needsTwoFactor signal emitted when TwoFactor.Enabled is set, forwarded through OAuthService to a new QML dialog (protonTwoFaDialog); resume via submitTwoFactor() -> POST /auth/v4/2fa - srpLog replaced with no-op stub to silence debug output for PR - Windows: ProtonSrpService gains step 3b 2FA check with ProtonTwoFaWindow dialog; OAuthService and UiCloudProviderFactory updated to accept both "protondrive" and "proton" provider strings
Navigate the PGP key chain to locate the target app ID folder
(CloudRedirect/<accountId>/<appId>) using HMAC-SHA256 hash lookup at each
level, then POST to /drive/v2/shares/{shareId}/links/trash to move it to
trash. Not-found at any level is treated as success (already deleted).
Refactors the duplicated token-file loading from listRemoteApps into a
shared loadTokenFile() helper used by both listing and delete. The delete
path reuses listFetchShare, listFetchRootLink, and listFindFolder with a
m_deleteMode flag that branches into delFindAppFolder at the account level
instead of enumerating all children.
If TwoFactor.Enabled has bit 2 set (FIDO2) but not bit 1 (TOTP), emit an error telling the user to switch to an authenticator app rather than silently proceeding with an unauthenticated session that fails later. Accounts with both TOTP and FIDO2 enabled still use the TOTP path.
- Add X25519 ECDH decrypt support to the shared Drive provider
(proton_pgp.cpp/.h) so accounts with a Proton ECC address key can
authenticate the Drive share, not just legacy RSA accounts. Implemented
for both BCrypt (Windows) and OpenSSL (Linux); proton_drive.cpp now
branches LoadProtonFields/EnsureKeysLoaded/GetRootFolderNode on
address_key_type. Node-key signing is skipped gracefully for ECC
accounts (Ed25519 signing not implemented), matching the existing
fallback for unloaded keys.
- Fix ApiHost/TokenEndpointHost: api.proton.me does not resolve in DNS.
The correct host is mail.proton.me, matching what both UI auth flows
already use. This was silently masked before because ECC accounts
never reached the network call in the first place.
- Fix TwoFactor response parsing on both platforms: it's a plain integer
bitmask, not a nested {"Enabled": N} object.
- Normalize ECC token field names between the Linux and Windows writers
(address_x25519_priv/_pub, address_key_fp) so the shared provider reads
consistent fields regardless of which UI authenticated; Linux now also
derives and stores the X25519 public key alongside the private scalar.
- Fix Proton sign-in/2FA dialog sizing: SizeToContent="Height" instead of
a fixed height that was a few pixels short of the actual content,
clipping the Sign In button at the bottom-right corner.
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.
Wires up Proton Drive as a complete third provider alongside Google Drive
and OneDrive on both Linux and Windows.
What's added
Authentication
Full SRP v4 login flow on both platforms. After the SRP exchange,
TwoFactor.Enabledis checked: TOTP triggers a second dialog for theauthenticator code (POST
/auth/v4/2fa); FIDO2-only accounts receive aclear error directing the user to switch to an authenticator app.
Remote app listing
fetchProtonDriveApps()walks the Proton Drive key chain to enumeratethe user's synced app IDs — decrypting the share key, root node, and each
folder level using OpenPGP, with HMAC-SHA256 name hashing for folder
lookup. Results are merged into the app list the same way GDrive and
OneDrive results are.
App folder deletion
Reuses the same key chain navigation to locate a specific app folder by
ID and moves it to trash via
POST /drive/v2/shares/{shareId}/links/trash.Cross-platform
ProtonAuthServicehandles auth and Drive API calls;OAuthServiceforwards theneedsTwoFactorsignal to a new QML dialogProtonSrpServiceand a newProtonTwoFaWindowdialogcover the same flow;
UiCloudProviderFactoryandOAuthServiceacceptboth
"proton"and"protondrive"provider strings for compatibility