A tool for parsing traffic on the jetstream and applying a moderation workstream based on regexp based rules
at main 4.5 kB view raw
1import { STARTER_PACK_THRESHOLD_CONFIGS } from "../rules/starterPackThreshold.js"; 2import { 3 createAccountComment, 4 createAccountLabel, 5 createAccountReport, 6} from "./accountModeration.js"; 7import { logger } from "./logger.js"; 8import { 9 starterPackLabelsThresholdAppliedCounter, 10 starterPackThresholdChecksCounter, 11 starterPackThresholdMetCounter, 12} from "./metrics.js"; 13import { 14 getStarterPackCountInWindow, 15 trackStarterPackForAccount, 16} from "./redis.js"; 17import type { StarterPackThresholdConfig } from "./types.js"; 18 19function validateAndLoadConfigs(): StarterPackThresholdConfig[] { 20 if (STARTER_PACK_THRESHOLD_CONFIGS.length === 0) { 21 logger.warn( 22 { process: "STARTER_PACK_THRESHOLD" }, 23 "No starter pack threshold configs found", 24 ); 25 return []; 26 } 27 28 for (const config of STARTER_PACK_THRESHOLD_CONFIGS) { 29 if (config.threshold <= 0) { 30 throw new Error( 31 `Invalid starter pack threshold config: threshold must be positive`, 32 ); 33 } 34 if (config.window <= 0) { 35 throw new Error( 36 `Invalid starter pack threshold config: window must be positive`, 37 ); 38 } 39 } 40 41 logger.info( 42 { process: "STARTER_PACK_THRESHOLD", count: STARTER_PACK_THRESHOLD_CONFIGS.length }, 43 "Loaded starter pack threshold configs", 44 ); 45 46 return STARTER_PACK_THRESHOLD_CONFIGS; 47} 48 49const cachedConfigs = validateAndLoadConfigs(); 50 51export function loadStarterPackThresholdConfigs(): StarterPackThresholdConfig[] { 52 return cachedConfigs; 53} 54 55export async function checkStarterPackThreshold( 56 did: string, 57 starterPackUri: string, 58 timestamp: number, 59): Promise<void> { 60 try { 61 const configs = loadStarterPackThresholdConfigs(); 62 63 if (configs.length === 0) { 64 return; 65 } 66 67 starterPackThresholdChecksCounter.inc(); 68 69 for (const config of configs) { 70 // Check allowlist 71 if (config.allowlist?.includes(did)) { 72 logger.debug( 73 { process: "STARTER_PACK_THRESHOLD", did, starterPackUri }, 74 "Account is in allowlist, skipping threshold check", 75 ); 76 continue; 77 } 78 79 await trackStarterPackForAccount( 80 did, 81 starterPackUri, 82 timestamp, 83 config.window, 84 config.windowUnit, 85 ); 86 87 const count = await getStarterPackCountInWindow( 88 did, 89 config.window, 90 config.windowUnit, 91 timestamp, 92 ); 93 94 logger.debug( 95 { 96 process: "STARTER_PACK_THRESHOLD", 97 did, 98 count, 99 threshold: config.threshold, 100 window: config.window, 101 windowUnit: config.windowUnit, 102 }, 103 "Checked starter pack threshold", 104 ); 105 106 if (count >= config.threshold) { 107 starterPackThresholdMetCounter.inc({ account_label: config.accountLabel }); 108 109 logger.info( 110 { 111 process: "STARTER_PACK_THRESHOLD", 112 did, 113 starterPackUri, 114 accountLabel: config.accountLabel, 115 count, 116 threshold: config.threshold, 117 }, 118 "Starter pack threshold met", 119 ); 120 121 const shouldLabel = config.toLabel !== false; 122 123 const formattedComment = `${config.accountComment}\n\nThreshold: ${count.toString()}/${config.threshold.toString()} in ${config.window.toString()} ${config.windowUnit}\n\nStarter Pack: ${starterPackUri}`; 124 125 if (shouldLabel) { 126 await createAccountLabel(did, config.accountLabel, formattedComment); 127 starterPackLabelsThresholdAppliedCounter.inc({ 128 account_label: config.accountLabel, 129 action: "label", 130 }); 131 } 132 133 if (config.reportAcct) { 134 await createAccountReport(did, formattedComment); 135 starterPackLabelsThresholdAppliedCounter.inc({ 136 account_label: config.accountLabel, 137 action: "report", 138 }); 139 } 140 141 if (config.commentAcct) { 142 const atURI = `starterpack-threshold-comment:${config.accountLabel}:${timestamp.toString()}`; 143 await createAccountComment(did, formattedComment, atURI); 144 starterPackLabelsThresholdAppliedCounter.inc({ 145 account_label: config.accountLabel, 146 action: "comment", 147 }); 148 } 149 } 150 } 151 } catch (error) { 152 logger.error( 153 { process: "STARTER_PACK_THRESHOLD", did, starterPackUri, error }, 154 "Error checking starter pack threshold", 155 ); 156 throw error; 157 } 158}