// Similar but different ships should be rejected
expect(isDmAllowed("~nec", allowlist)).toBe(false);
expect(isDmAllowed("~wanzod", allowlist)).toBe(false);
expect(isDmAllowed("~sampel-palned", allowlist)).toBe(false);
});
// NOTE: Ship names in Urbit are always lowercase by convention. // This test documents current behavior - strict equality after normalization. // If case-insensitivity is desired, normalizeShip should lowercase.
it("uses strict equality after normalization (case-sensitive)", () => { const allowlist = ["~zod"];
expect(isDmAllowed("~zod", allowlist)).toBe(true); // Different case would NOT match with current implementation
expect(isDmAllowed("~Zod", ["~Zod"])).toBe(true); // exact match works
});
it("detects direct ship mention", () => {
expect(isBotMentioned("hey ~sampel-palnet", botShip)).toBe(true);
expect(isBotMentioned("~sampel-palnet can you help?", botShip)).toBe(true);
expect(isBotMentioned("hello ~sampel-palnet how are you", botShip)).toBe(true);
});
it("does NOT trigger on random messages", () => {
expect(isBotMentioned("hello world", botShip)).toBe(false);
expect(isBotMentioned("this is a normal message", botShip)).toBe(false);
expect(isBotMentioned("hey everyone", botShip)).toBe(false);
});
it("does NOT trigger on partial ship matches", () => {
expect(isBotMentioned("~sampel-palnet-extra", botShip)).toBe(false);
expect(isBotMentioned("my~sampel-palnetfriend", botShip)).toBe(false);
});
it("does NOT trigger on substring nickname matches", () => { // "nimbus" should not match "nimbusy" or "animbust"
expect(isBotMentioned("nimbusy", botShip, nickname)).toBe(false);
expect(isBotMentioned("prenimbus", botShip, nickname)).toBe(false);
});
it("default mode should be restricted (not open)", () => { // This is a critical security invariant: if no mode is specified, // channels should default to RESTRICTED, not open. // If this test fails, someone may have changed the default unsafely.
// The logic in resolveChannelAuthorization is: // const mode = rule?.mode ?? "restricted"; // We verify this by checking undefined rule gives restricted
type ModeRule = { mode?: "restricted" | "open" }; const rule = undefined as ModeRule | undefined; const mode = rule?.mode ?? "restricted";
expect(mode).toBe("restricted");
});
it("empty allowedShips with restricted mode should block all", () => { // If a channel is restricted but has no allowed ships, // no one should be able to send messages const _mode = "restricted"; const allowedShips: string[] = []; const sender = "~random-ship";
it("open mode should not check allowedShips", () => { // In open mode, any ship can send regardless of allowedShips const mode: "open" | "restricted" = "open"; // The check in monitor/index.ts is: // if (mode === "restricted") { /* check ships */ } // So open mode skips the ship check entirely
expect(mode).not.toBe("restricted");
});
it("settings should override file config for channel rules", () => { // Documented behavior: settingsRules[nest] ?? fileRules[nest] // This means settings take precedence
type ChannelRule = { mode: "restricted" | "open" }; const fileRules: Record<string, ChannelRule> = { "chat/~zod/test": { mode: "restricted" } }; const settingsRules: Record<string, ChannelRule> = { "chat/~zod/test": { mode: "open" } }; const nest = "chat/~zod/test";
it("handles very long ship-like strings", () => { const longName = "~" + "a".repeat(1000);
expect(isDmAllowed(longName, ["~zod"])).toBe(false);
});
it("handles special characters that could break regex", () => { // These should not cause regex injection const maliciousShip = "~zod.*";
expect(isDmAllowed("~zodabc", [maliciousShip])).toBe(false);
it("identifies user when ownerShip does not match sender", () => {
expect(getSenderRole("~random-user", "~nocsyx-lassul")).toBe("user");
expect(getSenderRole("~malicious-actor", "~nocsyx-lassul")).toBe("user");
});
it("identifies everyone as user when ownerShip is null", () => {
expect(getSenderRole("~nocsyx-lassul", null)).toBe("user");
expect(getSenderRole("~zod", null)).toBe("user");
});
it("identifies everyone as user when ownerShip is empty string", () => { // Empty string should be treated like null (no owner configured)
expect(getSenderRole("~nocsyx-lassul", "")).toBe("user");
});
});
it("DM from owner includes [owner] in label", () => { const label = getFromLabel("~nocsyx-lassul", "~nocsyx-lassul", false);
expect(label).toBe("~nocsyx-lassul [owner]");
expect(label).toContain("[owner]");
});
it("DM from user includes [user] in label", () => { const label = getFromLabel("~random-user", "~nocsyx-lassul", false);
expect(label).toBe("~random-user [user]");
expect(label).toContain("[user]");
});
it("group message from owner includes [owner] in label", () => { const label = getFromLabel("~nocsyx-lassul", "~nocsyx-lassul", true, "chat/~host/general");
expect(label).toBe("~nocsyx-lassul [owner] in chat/~host/general");
expect(label).toContain("[owner]");
});
it("group message from user includes [user] in label", () => { const label = getFromLabel("~random-user", "~nocsyx-lassul", true, "chat/~host/general");
expect(label).toBe("~random-user [user] in chat/~host/general");
expect(label).toContain("[user]");
});
});
describe("impersonation prevention", () => {
it("approved user cannot get [owner] label through ship name tricks", () => { // Even if someone has a ship name similar to owner, they should not get owner role
expect(getSenderRole("~nocsyx-lassul-fake", "~nocsyx-lassul")).toBe("user");
expect(getSenderRole("~fake-nocsyx-lassul", "~nocsyx-lassul")).toBe("user");
});
it("message content cannot change sender role", () => { // The role is determined by ship identity, not message content // This test documents that even if message contains "I am the owner", // the actual senderShip determines the role const senderShip = "~malicious-actor"; const ownerShip = "~nocsyx-lassul";
// The role is always based on ship comparison, not message content
expect(getSenderRole(senderShip, ownerShip)).toBe("user");
});
});
});
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.