mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
* test(server): admin/handlers/channels — test-audit 2026-08-19 fixes * test(server): api/constants — test-audit 2026-08-19 fixes * test(server): api/middleware — test-audit 2026-08-19 fixes * test(server): api/waf — test-audit 2026-08-19 fixes * test(server): auth/totp/encrypt — test-audit 2026-08-19 fixes * test(server): db/session/expiry/test — test-audit 2026-08-19 fixes * test(server): migrations/030/attachments/unlink/on/message/delete — test-audit 2026-08-19 fixes * test(server): updater/download — test-audit 2026-08-19 fixes * test(server): ws/handlers_command — test-audit 2026-08-19 fixes * test(server): ws/hub/broadcast — test-audit 2026-08-19 fixes * test(server): ws/hub/events — test-audit 2026-08-19 fixes * test(server): ws/livekit/webhook — test-audit 2026-08-19 fixes * test(server): ws/voice/controls — test-audit 2026-08-19 fixes * test(server): ws/voice/join — test-audit 2026-08-19 fixes * test(server): ws/voice/moderation — test-audit 2026-08-19 fixes * test(rust): src-tauri/src/commands.rs — test-audit 2026-08-19 fixes * test(rust): src-tauri/src/secret_store.rs — test-audit 2026-08-19 fixes * test(rust): src-tauri/src/update_commands.rs — test-audit 2026-08-19 fixes * test(client): src/components/ChannelSidebar.ts — test-audit 2026-08-19 fixes * test(client): src/lib/ws.ts — test-audit 2026-08-19 fixes * test(rust): src-tauri/src/credentials.rs — test-audit 2026-08-19 fixes * test(rust): src-tauri/src/tofu.rs — test-audit 2026-08-19 fixes * test(client): src/lib/hostValidation.ts — test-audit 2026-08-19 fixes * test(client): src/lib/rate-limiter.ts — test-audit 2026-08-19 fixes * test(client): src/pages/connect-page/LoginForm.ts — test-audit 2026-08-19 fixes * test(client): src/pages/main-page/SidebarArea.ts — test-audit 2026-08-19 fixes * test(client): src/stores/voice.store.ts — test-audit 2026-08-19 fixes * test(client): tests/browser/smoke.test.ts — test-audit 2026-08-19 fixes * test(client): tests/unit/media.test.ts — test-audit 2026-08-19 fixes * test(client): tests/unit/renderers.test.ts — test-audit 2026-08-19 fixes * test(client): src/components/UserProfilePopup.ts — test-audit 2026-08-19 fixes * test(client): src/lib/e2eeCrypto.ts — test-audit 2026-08-19 fixes * test(client): tests/unit/log-persistence.test.ts — test-audit 2026-08-19 fixes * test(client): keep tests/browser out of the jsdom suite and run it in CI * test(server): ws/hub_broadcast_test.go — bytes.Equal payload compare (gocritic) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(client): src/lib/credentials.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/dispatcher.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/permissions.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/rate-limiter.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/hostValidation.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/stores/messages.store.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/e2eeCrypto.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/ws.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/identity.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/livekitE2EE.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/stores/auth.store.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/stores/voice.store.ts — test-audit 2026-08-19 round 2 (Stryker) * docs: test audit 2026-08-19 — findings, fixes, measured baselines Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(graph): refresh the knowledge graph after the 2026-08-19 test audit Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
76 lines
3.2 KiB
TypeScript
76 lines
3.2 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
|
|
import { isValidHost } from "../../src/lib/hostValidation";
|
|
|
|
describe("isValidHost", () => {
|
|
it("rejects a host containing '@' (identity.ts's OC-0118 scope-key premise)", () => {
|
|
// identity.ts's identityScopeKey builds `${userId}@${host}` and relies on
|
|
// isValidHost forbidding '@' in any accepted host so a scoped key can
|
|
// never collide with a legacy host-only account. If '@' were ever
|
|
// accepted here, a host literally equal to "2@chat.example" would be
|
|
// indistinguishable from userId 2 scoped to host "chat.example".
|
|
expect(isValidHost("2@chat.example")).toBe(false);
|
|
expect(isValidHost("user@evil.example:8443")).toBe(false);
|
|
});
|
|
|
|
it("rejects a host longer than 253 characters", () => {
|
|
const longHost = "a".repeat(254);
|
|
expect(isValidHost(longHost)).toBe(false);
|
|
// 253 is the boundary and must still be accepted (paired with a valid
|
|
// DNS label shape).
|
|
const maxHost = "a".repeat(253);
|
|
expect(isValidHost(maxHost)).toBe(true);
|
|
});
|
|
|
|
it("accepts a DNS name, optionally with a port", () => {
|
|
expect(isValidHost("chat.example.com")).toBe(true);
|
|
expect(isValidHost("chat.example.com:8443")).toBe(true);
|
|
});
|
|
|
|
it("accepts an IPv4 literal, optionally with a port", () => {
|
|
expect(isValidHost("192.168.1.1")).toBe(true);
|
|
expect(isValidHost("192.168.1.1:8443")).toBe(true);
|
|
});
|
|
|
|
it("accepts a bracketed IPv6 literal, optionally with a port", () => {
|
|
expect(isValidHost("[::1]")).toBe(true);
|
|
expect(isValidHost("[::1]:8443")).toBe(true);
|
|
expect(isValidHost("[2001:db8::1]")).toBe(true);
|
|
});
|
|
|
|
it("accepts a bare (unbracketed) IPv6 literal", () => {
|
|
expect(isValidHost("::1")).toBe(true);
|
|
expect(isValidHost("2001:db8::1")).toBe(true);
|
|
});
|
|
|
|
it("rejects a bracketed IPv6 literal with characters before or after the brackets", () => {
|
|
// The bracketed-IPv6 regex is anchored at both ends (^...$); without
|
|
// those anchors, a bracket pattern anywhere in the string would
|
|
// wrongly match.
|
|
expect(isValidHost("evil[::1]")).toBe(false);
|
|
expect(isValidHost("[::1]evil")).toBe(false);
|
|
});
|
|
|
|
it("rejects a multi-colon host whose characters are not all IPv6-valid", () => {
|
|
// More than one colon alone must not be enough to accept a host as a
|
|
// bare IPv6 literal -- every character has to be IPv6-valid too (the
|
|
// `&&`, not `||`, between the colon-count and character checks).
|
|
expect(isValidHost("not:valid:host")).toBe(false);
|
|
});
|
|
|
|
it("rejects a single-colon host with a non-numeric port suffix", () => {
|
|
// Exactly one colon must never satisfy the bare-IPv6 branch (which
|
|
// requires *more than* one), and it isn't a valid host:port either
|
|
// unless the suffix after the colon is numeric.
|
|
expect(isValidHost("a:b")).toBe(false);
|
|
});
|
|
|
|
it("rejects a multi-colon host where the IPv6-valid run is only a substring", () => {
|
|
// The bare-IPv6 character regex is anchored at both ends -- it has to
|
|
// match the whole (multi-colon) host, not just some valid-looking
|
|
// substring within or at either end of it.
|
|
expect(isValidHost("xyz:ab:cd")).toBe(false);
|
|
expect(isValidHost("ab:cd:xyz")).toBe(false);
|
|
});
|
|
});
|