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

non-malicious bots were catching strays over hashtags

+55 -5
+11 -3
src/rules/facets/facets.ts
··· 24 return; 25 } 26 27 - // Group facets by their byte position (byteStart:byteEnd) 28 const positionMap = new Map<string, number>(); 29 30 for (const facet of facets) { 31 - const key = `${facet.index.byteStart}:${facet.index.byteEnd}`; 32 - positionMap.set(key, (positionMap.get(key) || 0) + 1); 33 } 34 35 // Check if any position has more than the threshold
··· 24 return; 25 } 26 27 + // Group mention facets by their byte position (byteStart:byteEnd) 28 + // Only check mentions as duplicate tags/links are often bot bugs, not malicious 29 const positionMap = new Map<string, number>(); 30 31 for (const facet of facets) { 32 + // Only count mentions for spam detection 33 + const hasMention = facet.features.some( 34 + (feature) => feature.$type === "app.bsky.richtext.facet#mention" 35 + ); 36 + 37 + if (hasMention) { 38 + const key = `${facet.index.byteStart}:${facet.index.byteEnd}`; 39 + positionMap.set(key, (positionMap.get(key) || 0) + 1); 40 + } 41 } 42 43 // Check if any position has more than the threshold
+44 -2
src/rules/facets/tests/facets.test.ts
··· 92 93 expect(createAccountLabel).not.toHaveBeenCalled(); 94 }); 95 }); 96 97 describe("when spam is detected", () => { ··· 178 expect(createAccountLabel).toHaveBeenCalledOnce(); 179 }); 180 181 - it("should handle different feature types at same position", async () => { 182 const facets: Facet[] = [ 183 { 184 index: { byteStart: 0, byteEnd: 1 }, ··· 186 }, 187 { 188 index: { byteStart: 0, byteEnd: 1 }, 189 features: [{ $type: "app.bsky.richtext.facet#link", uri: "https://example.com" }], 190 }, 191 ]; 192 193 await checkFacetSpam(TEST_DID, TEST_TIME, TEST_URI, facets); 194 195 - // Should still detect as spam regardless of feature type 196 expect(createAccountLabel).toHaveBeenCalledOnce(); 197 }); 198 });
··· 92 93 expect(createAccountLabel).not.toHaveBeenCalled(); 94 }); 95 + 96 + it("should not label when duplicate tags/links at same position (bot bugs)", async () => { 97 + const facets: Facet[] = [ 98 + { 99 + index: { byteStart: 38, byteEnd: 43 }, 100 + features: [{ $type: "app.bsky.richtext.facet#tag", tag: "news" }], 101 + }, 102 + { 103 + index: { byteStart: 38, byteEnd: 43 }, 104 + features: [{ $type: "app.bsky.richtext.facet#tag", tag: "News" }], 105 + }, 106 + ]; 107 + 108 + await checkFacetSpam(TEST_DID, TEST_TIME, TEST_URI, facets); 109 + 110 + // Should not trigger - only mentions are checked 111 + expect(createAccountLabel).not.toHaveBeenCalled(); 112 + expect(logger.info).not.toHaveBeenCalled(); 113 + }); 114 + 115 + it("should not label when duplicate links at same position", async () => { 116 + const facets: Facet[] = [ 117 + { 118 + index: { byteStart: 0, byteEnd: 10 }, 119 + features: [{ $type: "app.bsky.richtext.facet#link", uri: "https://example.com" }], 120 + }, 121 + { 122 + index: { byteStart: 0, byteEnd: 10 }, 123 + features: [{ $type: "app.bsky.richtext.facet#link", uri: "https://example.org" }], 124 + }, 125 + ]; 126 + 127 + await checkFacetSpam(TEST_DID, TEST_TIME, TEST_URI, facets); 128 + 129 + // Should not trigger - only mentions are checked 130 + expect(createAccountLabel).not.toHaveBeenCalled(); 131 + expect(logger.info).not.toHaveBeenCalled(); 132 + }); 133 }); 134 135 describe("when spam is detected", () => { ··· 216 expect(createAccountLabel).toHaveBeenCalledOnce(); 217 }); 218 219 + it("should handle mixed feature types - only mentions at same position count", async () => { 220 const facets: Facet[] = [ 221 { 222 index: { byteStart: 0, byteEnd: 1 }, ··· 224 }, 225 { 226 index: { byteStart: 0, byteEnd: 1 }, 227 + features: [{ $type: "app.bsky.richtext.facet#mention", did: "did:plc:user2" }], 228 + }, 229 + { 230 + index: { byteStart: 0, byteEnd: 1 }, 231 features: [{ $type: "app.bsky.richtext.facet#link", uri: "https://example.com" }], 232 }, 233 ]; 234 235 await checkFacetSpam(TEST_DID, TEST_TIME, TEST_URI, facets); 236 237 + // Should detect spam (2 mentions at same position) 238 expect(createAccountLabel).toHaveBeenCalledOnce(); 239 }); 240 });