import * as plugins from '../../plugins.js'; import { CachedDocument, TTL } from '../classes.cached.document.js'; import { CacheDb } from '../classes.cachedb.js'; /** * Helper to get the smartdata database instance */ const getDb = () => CacheDb.getInstance().getDb(); /** * IP reputation result data */ export interface IIPReputationData { score: number; isSpam: boolean; isProxy: boolean; isTor: boolean; isVPN: boolean; country?: string; asn?: string; org?: string; blacklists?: string[]; } /** * CachedIPReputation - Stores IP reputation lookup results * * Caches the results of IP reputation checks to avoid repeated * external API calls. Default TTL is 24 hours. */ @plugins.smartdata.Collection(() => getDb()) export class CachedIPReputation extends CachedDocument { /** * IP address (unique identifier) */ @plugins.smartdata.unI() @plugins.smartdata.svDb() public ipAddress: string; /** * Reputation score (0-100, higher = better) */ @plugins.smartdata.svDb() public score: number; /** * Whether the IP is flagged as spam source */ @plugins.smartdata.svDb() public isSpam: boolean; /** * Whether the IP is a known proxy */ @plugins.smartdata.svDb() public isProxy: boolean; /** * Whether the IP is a Tor exit node */ @plugins.smartdata.svDb() public isTor: boolean; /** * Whether the IP is a VPN endpoint */ @plugins.smartdata.svDb() public isVPN: boolean; /** * Country code (ISO 3166-1 alpha-2) */ @plugins.smartdata.svDb() public country: string; /** * Autonomous System Number */ @plugins.smartdata.svDb() public asn: string; /** * Organization name */ @plugins.smartdata.svDb() public org: string; /** * List of blacklists the IP appears on */ @plugins.smartdata.svDb() public blacklists: string[]; /** * Number of times this IP has been checked */ @plugins.smartdata.svDb() public checkCount: number = 0; /** * Number of connections from this IP */ @plugins.smartdata.svDb() public connectionCount: number = 0; /** * Number of emails received from this IP */ @plugins.smartdata.svDb() public emailCount: number = 0; /** * Number of spam emails from this IP */ @plugins.smartdata.svDb() public spamCount: number = 0; constructor() { super(); this.setTTL(TTL.HOURS_24); // Default 24-hour TTL this.blacklists = []; this.score = 50; // Default neutral score this.isSpam = false; this.isProxy = false; this.isTor = false; this.isVPN = false; } /** * Create from reputation data */ public static fromReputationData(ipAddress: string, data: IIPReputationData): CachedIPReputation { const cached = new CachedIPReputation(); cached.ipAddress = ipAddress; cached.score = data.score; cached.isSpam = data.isSpam; cached.isProxy = data.isProxy; cached.isTor = data.isTor; cached.isVPN = data.isVPN; cached.country = data.country || ''; cached.asn = data.asn || ''; cached.org = data.org || ''; cached.blacklists = data.blacklists || []; cached.checkCount = 1; return cached; } /** * Convert to reputation data object */ public toReputationData(): IIPReputationData { this.touch(); return { score: this.score, isSpam: this.isSpam, isProxy: this.isProxy, isTor: this.isTor, isVPN: this.isVPN, country: this.country, asn: this.asn, org: this.org, blacklists: this.blacklists, }; } /** * Find by IP address */ public static async findByIP(ipAddress: string): Promise { return await CachedIPReputation.getInstance({ ipAddress, }); } /** * Find all IPs flagged as spam */ public static async findSpamIPs(): Promise { return await CachedIPReputation.getInstances({ isSpam: true, }); } /** * Find IPs with score below threshold */ public static async findLowScoreIPs(threshold: number): Promise { return await CachedIPReputation.getInstances({ score: { $lt: threshold }, }); } /** * Record a connection from this IP */ public recordConnection(): void { this.connectionCount++; this.touch(); } /** * Record an email from this IP */ public recordEmail(isSpam: boolean = false): void { this.emailCount++; if (isSpam) { this.spamCount++; } this.touch(); } /** * Update the reputation data */ public updateReputation(data: IIPReputationData): void { this.score = data.score; this.isSpam = data.isSpam; this.isProxy = data.isProxy; this.isTor = data.isTor; this.isVPN = data.isVPN; this.country = data.country || this.country; this.asn = data.asn || this.asn; this.org = data.org || this.org; this.blacklists = data.blacklists || this.blacklists; this.checkCount++; this.touch(); // Refresh TTL on update this.setTTL(TTL.HOURS_24); } /** * Check if this IP should be blocked */ public shouldBlock(): boolean { return this.isSpam || this.score < 20 || this.blacklists.length > 2; } }