anti-brigading system - detection engine, phantom voting, ALTCHA adaptive difficulty, honeypot fields, admin security dashboard, auto-learning

This commit is contained in:
2026-03-22 08:35:26 +02:00
parent a530ce67b0
commit 14a605b3de
23 changed files with 3104 additions and 86 deletions

View File

@@ -7,6 +7,26 @@ import { cleanExpiredChallenges } from "../routes/passkey.js";
import { cleanupExpiredTokens } from "../lib/token-blocklist.js";
import { getPluginCronJobs } from "../plugins/loader.js";
import { cleanupViews } from "../lib/view-tracker.js";
import {
takeVoteSnapshots,
scanVoteVelocity,
scanPostVelocity,
scanIdentityClusters,
scanInflectionPoints,
scanCohortArrivals,
scanReferrerConcentration,
scanPostSimilarity,
recalculateBoardBaselines,
scanVoterOverlap,
scanOutboundLinks,
scanCommentVoteRatio,
scanVoteDistribution,
compareSeasonalBaseline,
pruneOldSnapshots,
pruneOldAnomalyEvents,
scanOffHoursActivity,
buildVoterGraph,
} from "../services/detection-engine.js";
export function startCronJobs() {
// prune old activity events - daily at 3am
@@ -108,6 +128,53 @@ export function startCronJobs() {
// clean expired view-tracker entries - every 5 minutes
cron.schedule("*/5 * * * *", () => { cleanupViews(); });
// --- anti-brigading detection jobs ---
// every 5 min: snapshots + velocity scans
cron.schedule("*/5 * * * *", async () => {
await takeVoteSnapshots().catch(() => {});
await scanVoteVelocity().catch(() => {});
await scanPostVelocity().catch(() => {});
});
// every 10 min: identity clustering
cron.schedule("*/10 * * * *", async () => {
await scanIdentityClusters().catch(() => {});
});
// every 15 min: inflection point detection
cron.schedule("*/15 * * * *", async () => {
await scanInflectionPoints().catch(() => {});
});
// every 30 min: cohort arrivals, referrer analysis, post similarity
cron.schedule("*/30 * * * *", async () => {
await scanCohortArrivals().catch(() => {});
await scanReferrerConcentration().catch(() => {});
await scanPostSimilarity().catch(() => {});
});
// hourly: baselines, overlap, links, comment ratio, off-hours, voter graph
cron.schedule("0 * * * *", async () => {
await recalculateBoardBaselines().catch(() => {});
await scanVoterOverlap().catch(() => {});
await scanOutboundLinks().catch(() => {});
await scanCommentVoteRatio().catch(() => {});
await scanOffHoursActivity().catch(() => {});
const boards = await prisma.board.findMany({ select: { id: true } }).catch(() => [] as { id: string }[]);
for (const b of boards) {
await buildVoterGraph(b.id).catch(() => {});
}
});
// daily at 3am: distribution, seasonal, pruning
cron.schedule("0 3 * * *", async () => {
await scanVoteDistribution().catch(() => {});
await compareSeasonalBaseline().catch(() => {});
await pruneOldSnapshots().catch(() => {});
await pruneOldAnomalyEvents().catch(() => {});
});
// register plugin-provided cron jobs (min interval: every minute, reject sub-minute)
for (const job of getPluginCronJobs()) {
if (!cron.validate(job.schedule)) {