// Provider-aware storage CORS setup helper. The helper must give the RIGHT rules + // apply-command for each provider: B2-native rules + the b2 CLI for Backblaze B2, and // standard S3 CORS + AWS CLI / dashboard guidance for Custom S3 and Cloudflare R2. // The invariant across all of them: the rules allow browser uploads (PUT/POST), which // is what makes uploads stop CORS-failing. import test, { beforeEach, afterEach } from "node:test"; import { strict as assert } from "node:assert"; import { JSDOM } from "jsdom"; import { buildBucketCorsRules, buildS3CorsConfig, buildB2CorsCommand, buildAwsCorsCommand, buildCorsHelpContent, StorageCorsHelp, } from "../js/ui/profileModal/storageCorsHelp.js"; test("B2-native rules include the upload operations the B2 presets omit", () => { const [rule] = buildBucketCorsRules(["https://bitvid.network"]); assert.ok(rule.allowedOperations.includes("s3_put")); assert.ok(rule.allowedOperations.includes("s3_post")); assert.ok(rule.allowedOperations.includes("s3_get")); }); test("standard S3 CORS config allows upload + ranged playback methods", () => { const cfg = buildS3CorsConfig(["https://bitvid.network"]); const rule = cfg.CORSRules[0]; assert.deepEqual(rule.AllowedMethods, ["GET", "HEAD", "PUT", "POST", "DELETE"]); // OPTIONS is not a valid S3 AllowedMethod and must not be present. assert.ok(!rule.AllowedMethods.includes("OPTIONS")); assert.deepEqual(rule.ExposeHeaders, [ "ETag", "Content-Length", "Content-Range", "Accept-Ranges", ]); }); test("origins fall back to every-origin when none are provided", () => { assert.deepEqual(buildBucketCorsRules([])[0].allowedOrigins, ["*"]); assert.deepEqual(buildS3CorsConfig(undefined).CORSRules[0].AllowedOrigins, ["*"]); }); test("B2 command targets the bucket allPublic with compact one-line JSON", () => { const cmd = buildB2CorsCommand("bitvid", buildBucketCorsRules(["https://x"])); assert.match(cmd, /^b2 update-bucket --corsRules '.*' bitvid allPublic$/); assert.ok(!cmd.includes("\n")); }); test("AWS command includes the endpoint + bucket, one line", () => { const cmd = buildAwsCorsCommand( "vids", "https://s3.example.com", buildS3CorsConfig(["https://x"]), ); assert.match( cmd, /^aws s3api put-bucket-cors --bucket vids --endpoint-url https:\/\/s3\.example\.com --cors-configuration '.*'$/, ); }); test("content for Backblaze B2 uses B2-native rules + the b2 CLI", () => { const c = buildCorsHelpContent({ provider: "backblaze_b2", origins: ["https://bitvid.network"], bucket: "bitvid", endpoint: "https://s3.us-west-004.backblazeb2.com", }); assert.match(c.cmd, /^b2 update-bucket /); assert.match(c.cmdLabel, /B2 command-line/i); assert.ok(JSON.parse(c.json)[0].allowedOperations.includes("s3_put")); assert.match(c.notes, /pipx install b2/i); }); test("content for Custom S3 uses standard S3 CORS + the AWS CLI", () => { const c = buildCorsHelpContent({ provider: "generic_s3", origins: ["https://bitvid.network"], bucket: "vids", endpoint: "https://s3.example.com", }); assert.match(c.cmd, /^aws s3api put-bucket-cors /); assert.match(c.cmd, /--endpoint-url https:\/\/s3\.example\.com/); assert.ok(JSON.parse(c.json).CORSRules[0].AllowedMethods.includes("PUT")); assert.doesNotMatch(c.cmd, /backblaze|b2 update-bucket/i); }); test("content for Cloudflare R2 uses S3 CORS and points at the R2 dashboard", () => { const c = buildCorsHelpContent({ provider: "cloudflare_r2", origins: ["https://bitvid.network"], bucket: "vids", endpoint: "https://acct.r2.cloudflarestorage.com", }); assert.match(c.cmd, /^aws s3api put-bucket-cors /); assert.match(c.notes, /Cloudflare dashboard/i); assert.match(c.cmdLabel, /Cloudflare/i); assert.ok(JSON.parse(c.json).CORSRules); }); // --- DOM behavior (provider switch reflected in the modal) --- let dom; beforeEach(() => { dom = new JSDOM( `