A tool for parsing traffic on the jetstream and applying a moderation workstream based on regexp based rules

Refactor account age module

- Renamed files and directories to the `rules` structure. - Added global
allowlist check.

Changed files
+55 -12
src
+14 -4
src/account/age.ts src/rules/account/age.ts
··· 1 - import { agent, isLoggedIn } from "../agent.js"; 2 - import { logger } from "../logger.js"; 3 - import { createAccountLabel } from "../moderation.js"; 1 + import { agent, isLoggedIn } from "../../agent.js"; 2 + import { logger } from "../../logger.js"; 3 + import { createAccountLabel } from "../../moderation.js"; 4 4 import { ACCOUNT_AGE_CHECKS } from "./ageConstants.js"; 5 - import { PLC_URL } from "../config.js"; 5 + import { PLC_URL } from "../../config.js"; 6 + import { GLOBAL_ALLOW } from "../../constants.js"; 6 7 7 8 interface ReplyContext { 8 9 replyToDid: string; ··· 95 96 ): Promise<void> => { 96 97 // Skip if no checks configured 97 98 if (ACCOUNT_AGE_CHECKS.length === 0) { 99 + return; 100 + } 101 + 102 + // Skip if DID is globally allowlisted 103 + if (GLOBAL_ALLOW.includes(context.replyingDid)) { 104 + logger.debug( 105 + { process: "ACCOUNT_AGE", did: context.replyingDid, atURI: context.atURI }, 106 + "Global allowlisted DID", 107 + ); 98 108 return; 99 109 } 100 110
+1 -1
src/account/ageConstants.ts src/rules/account/ageConstants.ts
··· 1 - import { AccountAgeCheck } from "../types.js"; 1 + import { AccountAgeCheck } from "../../types.js"; 2 2 3 3 /** 4 4 * Account age monitoring configurations
+39 -6
src/account/tests/age.test.ts src/rules/account/tests/age.test.ts
··· 7 7 import { ACCOUNT_AGE_CHECKS } from "../ageConstants.js"; 8 8 9 9 // Mock dependencies 10 - vi.mock("../../agent.js", () => ({ 10 + vi.mock("../../../agent.js", () => ({ 11 11 agent: { 12 12 getProfile: vi.fn(), 13 13 }, 14 14 isLoggedIn: Promise.resolve(true), 15 15 })); 16 16 17 - vi.mock("../../logger.js", () => ({ 17 + vi.mock("../../../logger.js", () => ({ 18 18 logger: { 19 19 info: vi.fn(), 20 20 debug: vi.fn(), ··· 23 23 }, 24 24 })); 25 25 26 - vi.mock("../../moderation.js", () => ({ 26 + vi.mock("../../../moderation.js", () => ({ 27 27 createAccountLabel: vi.fn(), 28 28 })); 29 29 30 + vi.mock("../../../constants.js", () => ({ 31 + GLOBAL_ALLOW: [], 32 + })); 33 + 30 34 // Mock fetch for DID document lookups 31 35 global.fetch = vi.fn(); 32 36 33 - import { agent } from "../../agent.js"; 34 - import { logger } from "../../logger.js"; 35 - import { createAccountLabel } from "../../moderation.js"; 37 + import { agent } from "../../../agent.js"; 38 + import { logger } from "../../../logger.js"; 39 + import { createAccountLabel } from "../../../moderation.js"; 40 + import { GLOBAL_ALLOW } from "../../../constants.js"; 36 41 37 42 describe("Account Age Module", () => { 38 43 beforeEach(() => { ··· 150 155 beforeEach(() => { 151 156 // Clear the ACCOUNT_AGE_CHECKS array and add test config 152 157 ACCOUNT_AGE_CHECKS.length = 0; 158 + // Clear the GLOBAL_ALLOW array 159 + GLOBAL_ALLOW.length = 0; 153 160 }); 154 161 155 162 it("should skip if no checks configured", async () => { ··· 393 400 "did:plc:newaccount", 394 401 "label1", 395 402 expect.any(String), 403 + ); 404 + }); 405 + 406 + it("should skip if replying DID is globally allowlisted", async () => { 407 + ACCOUNT_AGE_CHECKS.push({ 408 + monitoredDIDs: ["did:plc:monitored"], 409 + anchorDate: "2025-01-15", 410 + maxAgeDays: 7, 411 + label: "new-account-reply", 412 + comment: "New account reply", 413 + }); 414 + 415 + // Add replying DID to global allowlist 416 + GLOBAL_ALLOW.push("did:plc:allowlisted"); 417 + 418 + await checkAccountAge({ 419 + replyToDid: "did:plc:monitored", 420 + replyingDid: "did:plc:allowlisted", 421 + atURI: TEST_REPLY_URI, 422 + time: TEST_TIME, 423 + }); 424 + 425 + expect(createAccountLabel).not.toHaveBeenCalled(); 426 + expect(logger.debug).toHaveBeenCalledWith( 427 + { process: "ACCOUNT_AGE", did: "did:plc:allowlisted", atURI: TEST_REPLY_URI }, 428 + "Global allowlisted DID", 396 429 ); 397 430 }); 398 431 });
+1 -1
src/main.ts
··· 19 19 import { checkHandle } from "./checkHandles.js"; 20 20 import { checkDescription, checkDisplayName } from "./checkProfiles.js"; 21 21 import { checkFacetSpam } from "./rules/facets/facets.js"; 22 - import { checkAccountAge } from "./account/age.js"; 22 + import { checkAccountAge } from "./rules/account/age.js"; 23 23 24 24 let cursor = 0; 25 25 let cursorUpdateInterval: NodeJS.Timeout;