All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 50s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
91 lines
2.7 KiB
TypeScript
91 lines
2.7 KiB
TypeScript
import {
|
|
count,
|
|
createUser,
|
|
db,
|
|
formWithFile,
|
|
get,
|
|
insertDump,
|
|
PNG,
|
|
post,
|
|
test,
|
|
} from "../helpers.ts";
|
|
import type { AttachmentResponse } from "../../../shared/dump.ts";
|
|
import type { Comment } from "../../../shared/comment.ts";
|
|
import { assertEquals } from "@std/assert";
|
|
|
|
test("attachments: upload an image, serve it back", async () => {
|
|
const user = await createUser();
|
|
const res = await post<AttachmentResponse>("/api/attachments", {
|
|
auth: user.auth,
|
|
form: formWithFile(PNG),
|
|
});
|
|
assertEquals(res.status, 201);
|
|
const id = res.data.id;
|
|
const served = await get(`/api/attachments/${id}`);
|
|
assertEquals(served.status, 200);
|
|
assertEquals(served.bytes, PNG);
|
|
assertEquals(served.headers.get("content-type"), "image/png");
|
|
assertEquals(served.headers.get("x-content-type-options"), "nosniff");
|
|
assertEquals(served.headers.get("cache-control"), "public, max-age=3600");
|
|
assertEquals(
|
|
(await get(`/api/attachments/${crypto.randomUUID()}`)).status,
|
|
404,
|
|
);
|
|
});
|
|
|
|
test("attachments: refuses non-images, non-multipart and anonymous uploads", async () => {
|
|
const user = await createUser();
|
|
assertEquals(
|
|
(await post("/api/attachments", {
|
|
auth: user.auth,
|
|
form: formWithFile(
|
|
new TextEncoder().encode("<script>"),
|
|
"x.png",
|
|
"image/png",
|
|
),
|
|
})).status,
|
|
400,
|
|
);
|
|
assertEquals(
|
|
(await post("/api/attachments", { auth: user.auth, json: {} })).status,
|
|
400,
|
|
);
|
|
const empty = new FormData();
|
|
empty.set("other", "x");
|
|
assertEquals(
|
|
(await post("/api/attachments", { auth: user.auth, form: empty })).status,
|
|
400,
|
|
);
|
|
assertEquals(
|
|
(await post("/api/attachments", { form: formWithFile(PNG) })).status,
|
|
401,
|
|
);
|
|
assertEquals(count(`SELECT COUNT(*) as n FROM attachments;`), 0);
|
|
});
|
|
|
|
test("attachments are claimed by the first text that links them", async () => {
|
|
const user = await createUser();
|
|
const { id: dumpId } = insertDump({ userId: user.id });
|
|
const up = await post<AttachmentResponse>("/api/attachments", {
|
|
auth: user.auth,
|
|
form: formWithFile(PNG),
|
|
});
|
|
const attachmentId = up.data.id;
|
|
const link = ``;
|
|
const comment = await post<Comment>(`/api/dumps/${dumpId}/comments`, {
|
|
auth: user.auth,
|
|
json: { body: link },
|
|
});
|
|
const owner = () =>
|
|
(db.prepare(`SELECT resource_id FROM attachments WHERE id = ?;`).get(
|
|
attachmentId,
|
|
) as { resource_id: string | null }).resource_id;
|
|
assertEquals(owner(), comment.data.id);
|
|
// A second text can't take it over.
|
|
await post(`/api/dumps/${dumpId}/comments`, {
|
|
auth: user.auth,
|
|
json: { body: link },
|
|
});
|
|
assertEquals(owner(), comment.data.id);
|
|
});
|