Files
bitvid/docs/storage-r2.md
T

4.6 KiB

Cloudflare R2 integration (r2Service)

Purpose and scope

js/services/r2Service.js is the specialized provider handler for Cloudflare R2 uploads. While the new Storage Tab (powered by StorageService) manages the secure storage of credentials, 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.

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.