mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-28 16:32:28 +00:00
Audited the generic-S3 path: upload/thumbnail/.torrent, CORS guidance, and the delete/edit cleanup path-style (incl. the documented vhost bug) were already tested. The real gap was public-URL resolution — the upload tests mock buildS3ObjectUrl, so the actual path-style/vhost logic in js/storage/s3-url.js was unverified. Added tests/storage/s3-url.test.mjs (11 pure-function scenarios): path-style puts the bucket in the PATH; vhost puts it in the host subdomain (no double-prefix); endpoint path-prefix preserved; bare-endpoint https upgrade; key/slash normalization; explicit publicBaseUrl wins; missing inputs → "". Also covers s3Service.derivePublicBaseUrl / buildS3ObjectUrl. Closes #6. Co-Authored-By: Claude Opus 4.8 <[email protected]>
139 lines
4.5 KiB
JavaScript
139 lines
4.5 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import {
|
|
buildS3PublicUrl,
|
|
buildS3UrlFromBase,
|
|
normalizeS3PublicBaseUrl,
|
|
} from "../../js/storage/s3-url.js";
|
|
import {
|
|
derivePublicBaseUrl,
|
|
buildS3ObjectUrl,
|
|
} from "../../js/services/s3Service.js";
|
|
|
|
// #6: the generic-S3 path's public-URL resolution must honor forcePathStyle.
|
|
// Upload tests mock buildS3ObjectUrl, so the real path-style/vhost logic in
|
|
// s3-url.js is asserted here directly (pure functions, no mocking).
|
|
|
|
const ENDPOINT = "https://s3.example.com";
|
|
const BUCKET = "mybucket";
|
|
const KEY = "u/npub1abc/hash/clip.mp4";
|
|
|
|
test("forcePathStyle=true puts the bucket in the PATH (generic S3 / MinIO style)", () => {
|
|
const url = buildS3PublicUrl({
|
|
endpoint: ENDPOINT,
|
|
bucket: BUCKET,
|
|
key: KEY,
|
|
forcePathStyle: true,
|
|
});
|
|
assert.equal(url, `https://s3.example.com/mybucket/${KEY}`);
|
|
});
|
|
|
|
test("forcePathStyle=false puts the bucket in the HOST as a subdomain (virtual-hosted style)", () => {
|
|
const url = buildS3PublicUrl({
|
|
endpoint: ENDPOINT,
|
|
bucket: BUCKET,
|
|
key: KEY,
|
|
forcePathStyle: false,
|
|
});
|
|
assert.equal(url, `https://mybucket.s3.example.com/${KEY}`);
|
|
});
|
|
|
|
test("vhost style does not double-prefix a bucket already present in the hostname", () => {
|
|
const url = buildS3PublicUrl({
|
|
endpoint: "https://mybucket.s3.example.com",
|
|
bucket: BUCKET,
|
|
key: KEY,
|
|
forcePathStyle: false,
|
|
});
|
|
assert.equal(url, `https://mybucket.s3.example.com/${KEY}`);
|
|
});
|
|
|
|
test("path-style preserves an endpoint path prefix (e.g. self-hosted under /v1)", () => {
|
|
const url = buildS3PublicUrl({
|
|
endpoint: "https://host.internal/v1",
|
|
bucket: BUCKET,
|
|
key: KEY,
|
|
forcePathStyle: true,
|
|
});
|
|
assert.equal(url, `https://host.internal/v1/mybucket/${KEY}`);
|
|
});
|
|
|
|
test("a bare endpoint (no scheme) is upgraded to https and trailing slashes are trimmed", () => {
|
|
const url = buildS3PublicUrl({
|
|
endpoint: "s3.example.com/",
|
|
bucket: BUCKET,
|
|
key: "k.mp4",
|
|
forcePathStyle: true,
|
|
});
|
|
assert.equal(url, "https://s3.example.com/mybucket/k.mp4");
|
|
});
|
|
|
|
test("leading slashes on the key are normalized away (no //)", () => {
|
|
const url = buildS3PublicUrl({
|
|
endpoint: ENDPOINT,
|
|
bucket: BUCKET,
|
|
key: "///u/clip.mp4",
|
|
forcePathStyle: true,
|
|
});
|
|
assert.equal(url, "https://s3.example.com/mybucket/u/clip.mp4");
|
|
});
|
|
|
|
test("missing endpoint or bucket yields an empty string (no malformed URL)", () => {
|
|
assert.equal(buildS3PublicUrl({ bucket: BUCKET, key: KEY, forcePathStyle: true }), "");
|
|
assert.equal(buildS3PublicUrl({ endpoint: ENDPOINT, key: KEY, forcePathStyle: true }), "");
|
|
});
|
|
|
|
test("buildS3UrlFromBase joins a custom public base URL with the key", () => {
|
|
assert.equal(
|
|
buildS3UrlFromBase({ publicBaseUrl: "https://cdn.example.com", key: KEY }),
|
|
`https://cdn.example.com/${KEY}`,
|
|
);
|
|
// Trailing slash on the base is handled.
|
|
assert.equal(
|
|
buildS3UrlFromBase({ publicBaseUrl: "https://cdn.example.com/", key: "a/b.mp4" }),
|
|
"https://cdn.example.com/a/b.mp4",
|
|
);
|
|
// Missing pieces → empty.
|
|
assert.equal(buildS3UrlFromBase({ publicBaseUrl: "", key: KEY }), "");
|
|
assert.equal(buildS3UrlFromBase({ publicBaseUrl: "https://cdn.example.com", key: "" }), "");
|
|
});
|
|
|
|
test("normalizeS3PublicBaseUrl trims trailing slashes and whitespace", () => {
|
|
assert.equal(normalizeS3PublicBaseUrl(" https://cdn.example.com/// "), "https://cdn.example.com");
|
|
assert.equal(normalizeS3PublicBaseUrl(""), "");
|
|
});
|
|
|
|
test("s3Service.derivePublicBaseUrl returns the bucket root honoring forcePathStyle", () => {
|
|
assert.equal(
|
|
derivePublicBaseUrl({ endpoint: ENDPOINT, bucket: BUCKET, forcePathStyle: true }),
|
|
"https://s3.example.com/mybucket",
|
|
);
|
|
assert.equal(
|
|
derivePublicBaseUrl({ endpoint: ENDPOINT, bucket: BUCKET, forcePathStyle: false }),
|
|
"https://mybucket.s3.example.com",
|
|
);
|
|
});
|
|
|
|
test("s3Service.buildS3ObjectUrl prefers an explicit publicBaseUrl over endpoint derivation", () => {
|
|
// When a custom CDN/public base is configured, it wins — even if endpoint/bucket
|
|
// would derive something different.
|
|
const url = buildS3ObjectUrl({
|
|
publicBaseUrl: "https://cdn.example.com",
|
|
endpoint: ENDPOINT,
|
|
bucket: BUCKET,
|
|
key: KEY,
|
|
forcePathStyle: true,
|
|
});
|
|
assert.equal(url, `https://cdn.example.com/${KEY}`);
|
|
|
|
// Without a publicBaseUrl it falls back to endpoint derivation (path-style here).
|
|
const derived = buildS3ObjectUrl({
|
|
endpoint: ENDPOINT,
|
|
bucket: BUCKET,
|
|
key: KEY,
|
|
forcePathStyle: true,
|
|
});
|
|
assert.equal(derived, `https://s3.example.com/mybucket/${KEY}`);
|
|
});
|