Files
OwnCord/Client/tauri-client/tests/unit/embeds.test.ts
T
jevb 2976863ad0 fix: atomic invite registration, fail-closed search, proxy-aware rate limiting
- Atomic CreateUserWithInvite prevents invite burn on failed registration
- Channel search fails closed on channel-type and override lookup errors
- Malformed FTS input returns 400 instead of 500
- Search rate limiting uses own namespace, respects trusted proxy IPs
- Login lockout keyed by forwarded client IP behind reverse proxy
- Trusted same-server OG previews re-enabled with self-signed cert support
- Normalized host matching for embeds/attachments
- Regression tests for all changes (auth, channel, embeds)
2026-03-29 19:39:22 +02:00

110 lines
3.2 KiB
TypeScript

import {
afterEach,
beforeEach,
describe,
expect,
it,
vi,
} from "vitest";
const { fetchMock } = vi.hoisted(() => ({
fetchMock: vi.fn(),
}));
vi.mock("@tauri-apps/plugin-http", () => ({
fetch: fetchMock,
}));
import { renderGenericLinkPreview } from "../../src/components/message-list/embeds";
import { setServerHost } from "../../src/components/message-list/attachments";
function mockHtmlResponse(html: string) {
return {
ok: true,
headers: {
get(name: string) {
return name.toLowerCase() === "content-type" ? "text/html; charset=utf-8" : null;
},
},
text: vi.fn().mockResolvedValue(html),
};
}
describe("renderGenericLinkPreview", () => {
beforeEach(() => {
document.body.innerHTML = "";
fetchMock.mockReset();
setServerHost("example.com");
});
afterEach(() => {
document.body.innerHTML = "";
});
it("fetches OG metadata for public domains that begin with fd", async () => {
fetchMock.mockResolvedValue(mockHtmlResponse("<html><head><title>F-Droid</title></head></html>"));
const card = renderGenericLinkPreview("https://fdroid.org/packages");
document.body.appendChild(card);
await vi.waitFor(() => {
expect(fetchMock).toHaveBeenCalledWith(
"https://fdroid.org/packages",
expect.objectContaining({
headers: expect.objectContaining({
"User-Agent": expect.stringContaining("facebookexternalhit"),
}),
}),
);
});
await vi.waitFor(() => {
expect(card.querySelector(".msg-embed-link-title")?.textContent).toBe("F-Droid");
});
});
it("blocks previews for private IPv6 literals", async () => {
for (const url of ["https://[fd00::1]/", "https://[fe80::1]/", "https://[::ffff:127.0.0.1]/"]) {
document.body.innerHTML = "";
const card = renderGenericLinkPreview(url);
document.body.appendChild(card);
await Promise.resolve();
expect(card.querySelector(".msg-embed-link-title")?.textContent).toBeTruthy();
}
expect(fetchMock).not.toHaveBeenCalled();
});
it("blocks previews for loopback IPv4 literals beyond 127.0.0.1", async () => {
const card = renderGenericLinkPreview("https://127.0.0.2/internal");
document.body.appendChild(card);
await Promise.resolve();
expect(fetchMock).not.toHaveBeenCalled();
expect(card.querySelector(".msg-embed-link-title")?.textContent).toBe("127.0.0.2");
});
it("allows previews for the configured OwnCord server even on private hosts", async () => {
setServerHost("LOCALHOST:8080");
fetchMock.mockResolvedValue(mockHtmlResponse("<html><head><title>OwnCord Local</title></head></html>"));
const card = renderGenericLinkPreview("https://localhost:8080/docs");
document.body.appendChild(card);
await vi.waitFor(() => {
expect(fetchMock).toHaveBeenCalledWith(
"https://localhost:8080/docs",
expect.objectContaining({
headers: expect.objectContaining({
"User-Agent": expect.stringContaining("facebookexternalhit"),
}),
}),
);
});
await vi.waitFor(() => {
expect(card.querySelector(".msg-embed-link-title")?.textContent).toBe("OwnCord Local");
});
});
});