Skip to content

feat: OneDrive + Google Drive storage backends (OAuth2 device code)#13

Open
pszymkowiak wants to merge 1 commit into
mainfrom
feat/onedrive-gdrive-backends
Open

feat: OneDrive + Google Drive storage backends (OAuth2 device code)#13
pszymkowiak wants to merge 1 commit into
mainfrom
feat/onedrive-gdrive-backends

Conversation

@pszymkowiak

Copy link
Copy Markdown
Owner

Summary

  • Adds two new storage backends — OneDrive (Microsoft Graph) and Google Drive (Drive v3) — both authenticated via OAuth2 device code flow.
  • Targets the free tiers available with consumer cloud accounts (1 TB on OneDrive with O365, 15 GB on personal Google Drive) so personal backups don't require a paid object-storage subscription.
  • New `enigma auth` subcommand handles one-time browser login; refresh tokens are stored AES-256-GCM-encrypted at `<config_dir>/oauth_tokens.enc`.

What's in

Area Files
OAuth foundation `enigma-storage/src/oauth/{mod,device_flow,token_store,retry}.rs`
OneDrive backend `enigma-storage/src/onedrive.rs` (inline + upload session)
Google Drive backend `enigma-storage/src/gdrive.rs` (flat folder, file-id cache, multipart upload)
CLI `enigma-cli/src/commands/auth.rs` + new `Auth` subcommand in `main.rs`
Wiring New `ProviderType` variants; `init_providers` threads `base_dir` + passphrase through backup/restore/verify/gc
Docs OneDrive + Google Drive setup sections in `README.md` (English)

App scopes (least-privilege)

  • OneDrive: `Files.ReadWrite.AppFolder` + `offline_access` — Enigma can only see/touch `/Apps/Enigma/` in the user's OneDrive.
  • Google Drive: `drive.file` — Enigma can only see/modify files it creates itself.

Test plan

  • `cargo build --all-features` (compile not validated locally — dev env missing build-essential)
  • `cargo test -p enigma-storage --features oauth,onedrive,gdrive` (unit tests via wiremock)
  • Manual E2E:
    • Register an Entra ID app + Google Cloud app per README
    • `enigma auth login onedrive --client-id ` → browser code grant
    • `enigma auth login gdrive --client-id --client-secret `
    • Add `[[providers]]` entries with `type = "onedrive"` and `type = "gdrive"`
    • `enigma backup ./samples/image.jpg` → verify chunks land in `/Apps/Enigma/` and `enigma-chunks/`
    • Run backup a second time → confirm dedup (0 new chunks)
    • `enigma restore /tmp/restored` → `diff` original vs restored
    • `enigma auth status`, `enigma auth logout onedrive` round-trip

Out of scope (follow-ups)

  • `enigma-proxy` (S3 gateway) dispatch for OneDrive/GDrive — currently bails through the existing `_ => bail!` arm
  • 13 README translations
  • Multi-account-per-provider support
  • Auto-rotation of refresh tokens nearing expiry

Known limitations

This branch was committed without local compile validation (no build-essential on dev machine). Expect CI to catch any issues; follow-up fixes will land on this branch before merge.

🤖 Generated with Claude Code

Adds two new storage backends that target the substantial free tiers of
consumer cloud accounts (1 TB on OneDrive with O365, 15 GB on personal
Google Drive), making Enigma viable for personal backups without paying
for object storage.

Both providers authenticate via OAuth2 device code flow — the user enters
an 8-character code on microsoft.com/devicelogin or google.com/device once,
and refresh tokens stored AES-256-GCM-encrypted on disk handle every
subsequent operation transparently.

New module: enigma-storage/src/oauth/
  - device_flow.rs: hand-rolled OAuth2 device code + refresh implementation
    that handles both Microsoft Graph and Google identity endpoints
  - token_store.rs: encrypted token persistence at <config_dir>/oauth_tokens.enc
    (Argon2id + HKDF-SHA256(info="enigma-oauth-v1") + AES-256-GCM, same
    passphrase as the keystore)
  - retry.rs: with_retry helper honoring HTTP 429 + Retry-After

New backends:
  - onedrive.rs: Microsoft Graph /me/drive/special/approot endpoints with
    Files.ReadWrite.AppFolder scope (isolated to /Apps/Enigma/). Inline
    PUT for chunks ≤ 4 MiB; upload session for larger chunks (10 MiB
    segments) since FastCDC can produce ~8 MiB.
  - gdrive.rs: Drive v3 with drive.file scope (app sees only its own
    files). Flat folder strategy + in-memory chunk-key → file-id cache
    bulk-populated on first use.

New CLI subcommand:
  - enigma auth login {onedrive,gdrive} --client-id <id> [--client-secret <s>]
  - enigma auth status
  - enigma auth logout <provider>

Config: existing [[providers]] schema; type = "onedrive" or "gdrive";
bucket field unused (OneDrive uses approot, Drive uses fixed
"enigma-chunks" folder).

Wiring:
  - ProviderType::Onedrive, ProviderType::Gdrive added to enigma-core
  - enigma-cli/commands/providers.rs: lazy-open the encrypted token store
    only when an OAuth provider is configured; bubble a clear error if no
    passphrase is available
  - backup / restore / verify / gc updated to thread base_dir + passphrase
    through init_providers

Tests:
  - Unit tests for retry backoff, retry-after parsing, token store
    roundtrip + wrong-passphrase rejection, OneDrive URL path encoding,
    Drive name flattening, multipart boundary uniqueness

Out of scope (follow-ups):
  - enigma-proxy dispatch (S3 gateway) for OneDrive/GDrive — currently
    bails through the existing `_ => bail` arm
  - README translations (13 other languages)
  - Multi-account-per-provider support

Note: this commit was not validated locally because the dev environment
lacks build-essential / gcc. CI will catch any issues; follow-up commits
will fix compile errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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