Files
bitvid/docs/storage-r2.md
T

5.2 KiB

Cloudflare R2 integration (r2Service)

Purpose and scope

js/services/r2Service.js is the specialized provider handler for Cloudflare R2 uploads. It implements one of the supported S3 Upload Modes (specifically Mode 1: Browser-held keys).

Security Note: This integration requires storing encrypted credentials in the browser. See README.md and docs/storage-tab-design.md for security warnings and alternative upload modes for untrusted environments.

The Storage Tab (powered by StorageService) is the single supported configuration path for R2 credentials. The deprecated quick-upload panel (quickR2Section / js/r2-quick.js) has been removed to avoid conflicting credential sources. r2Service is responsible for:

  • Uploading the selected video/HLS asset via multipart S3 uploads.
  • Verifying public access via the configured Public Bucket URL.
  • Publishing the resulting public URL into the video note payload.

Architecture Note: For the high-level design of credential storage, encryption, and the provider adapter pattern, please refer to docs/storage-tab-design.md.

Assets stored in R2

R2 is used as the URL-first playback source. The upload path supports a single file per upload, but file types include:

  • Video files (MP4/WebM/MOV/MKV/MPG/MPEG).
  • HLS/DASH assets (manifest .m3u8/.mpd and segment files like .ts/.m4s).
  • Related static media if the operator chooses to upload them separately (images, subtitles such as .vtt/.srt), which benefit from cache-friendly headers set in the upload flow.

The object key format is generated by buildR2Key() in js/r2.js and looks like: u/<npub>/<YYYY>/<MM>/<slug>.<ext>, which keeps uploads scoped by user and month.

Setup Guide: Getting your Cloudflare Credentials

To enable R2 uploads, you must provide Cloudflare S3-compatible credentials and configure your bucket for public access and CORS.

Step 1: Create Bucket & Enable Public Access

  1. Log in to the Cloudflare Dashboard.
  2. Navigate to R2 -> Create Bucket.
  3. In the bucket settings, enable Public Access (R2.dev subdomain) or connect a custom domain.
  4. Copy the Public Bucket URL (e.g., https://pub-xxxxxx.r2.dev).

Step 2: Configure CORS

Manually add a CORS policy in the bucket settings to allow uploads from your app's origin (or *). (See content/upload-content.md for the recommended JSON configuration).

Step 3: Create S3 Credentials

  1. In the R2 dashboard, click Manage R2 API Tokens.
  2. Click Create API Token.
  3. Select Object Read & Write permissions (Minimal).
  4. Copy the Account ID, Access Key ID, and Secret Access Key.

Step 4: Configure the App

  1. Open the Storage Tab (in Profile or Upload modal).
  2. Add a new connection and select Cloudflare R2.
  3. Enter the Account ID, Access Key ID, Secret Access Key, and Public Bucket URL.
  4. Click Verify & Save.

The app will attempt to upload a small test file to verify the credentials and public access configuration.

Upload lifecycle

  1. Credential Retrieval:

    • When an upload starts, UploadModal retrieves the decrypted credentials from StorageService.
    • StorageService handles the NIP-44/04 decryption of the Master Key and subsequent decryption of the R2 connection payload.
  2. Upload Execution:

    • r2Service.multipartUpload() uses the standard AWS SDK commands (CreateMultipartUpload, UploadPart, etc.) via js/storage/s3-multipart.js and the makeR2Client adapter.
    • The adapter automatically constructs the R2 endpoint (https://<accountId>.r2.cloudflarestorage.com) using the stored accountId.
  3. Publish:

    • On success, publishVideoNote() is called with the hosted URL, enabling URL-first playback.

Configuration keys

R2 credentials are no longer stored in plain bitvidSettings. They are encapsulated within the StorageService data model. Legacy r2Settings are migrated into StorageService on first unlock and then cleared.

R2 Connection Profile (Encrypted):

  • provider: cloudflare_r2
  • accountId: Cloudflare account ID.
  • accessKeyId: S3 access key ID.
  • secretAccessKey: S3 secret access key.
  • bucket: The target bucket name.

Metadata (Plaintext):

  • baseDomain: The Public Bucket URL (e.g., https://pub-xxxx.r2.dev).
  • defaultForUploads: Boolean flag indicating if this is the active upload target.

Environment / global flags

  • globalThis.__BITVID_DISABLE_NETWORK_IMPORTS__: disables the AWS SDK network import used by the R2 S3 client loader (js/storage/r2-s3.js). When true, uploads will fail with a load error until the SDK is bundled or otherwise provided. Multipart helpers live in js/storage/s3-multipart.js and rely on the same SDK import.

Security considerations

  • Encrypted Storage: All sensitive keys (accessKeyId, secretAccessKey) are encrypted at rest using the user's Nostr signer.
  • Session Security: Decrypted keys exist in memory only during the active session.
  • Public Exposure: The generated playback URLs are public. Ensure your bucket permissions match your intent.
  • Least Privilege: Always use "Object Read & Write" tokens rather than Admin tokens.