Ransomware.live integration, 48h window, CISA feeds, validation updates, README
This commit is contained in:
+31
-11
@@ -24,8 +24,10 @@ from telegram.ext import (
|
||||
from telegram.constants import ParseMode
|
||||
from telegram.error import TelegramError
|
||||
|
||||
import aiohttp
|
||||
from rss_manager import RSSFeedManager
|
||||
from content_classifier import ContentClassifier
|
||||
from ransomware_fetcher import RansomwareFetcher
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
@@ -54,6 +56,8 @@ class ThreatIntelBot:
|
||||
self.classifier = ContentClassifier()
|
||||
self.application = None
|
||||
self.monitoring_task = None
|
||||
ransomware_key = os.getenv("RANSOMWARE_LIVE_API_KEY", "")
|
||||
self.ransomware_fetcher = RansomwareFetcher(ransomware_key) if ransomware_key else None
|
||||
self.load_subscribers()
|
||||
|
||||
def load_subscribers(self):
|
||||
@@ -393,19 +397,23 @@ class ThreatIntelBot:
|
||||
"""Background task to monitor RSS feeds by category."""
|
||||
logger.info("Starting RSS feed monitoring for category feeds...")
|
||||
|
||||
# First run - just mark existing articles as seen, don't send alerts
|
||||
# First run - mark existing articles and victims as seen, don't send alerts
|
||||
try:
|
||||
for category, cfg in CATEGORY_CONFIG.items():
|
||||
async with RSSFeedManager(feeds_file=cfg["feeds_file"], feed_type=category) as manager:
|
||||
logger.info(f"Initial {category.upper()} feed scan - marking existing articles as seen...")
|
||||
existing_articles = await manager.fetch_all_feeds(initial_run=True)
|
||||
logger.info(
|
||||
f"Completed initial {category.upper()} scan. "
|
||||
f"Found {len(existing_articles)} existing articles (no alerts sent)"
|
||||
)
|
||||
await manager.fetch_all_feeds(initial_run=True)
|
||||
except Exception as e:
|
||||
logger.error(f"Error in initial feed scan: {e}")
|
||||
|
||||
if self.ransomware_fetcher:
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
await self.ransomware_fetcher.fetch_new_victims(session, initial_run=True)
|
||||
logger.info("Initial ransomware scan complete — existing victims marked as seen")
|
||||
except Exception as e:
|
||||
logger.error(f"Error in initial ransomware scan: {e}")
|
||||
|
||||
while True:
|
||||
try:
|
||||
all_articles = []
|
||||
@@ -417,7 +425,7 @@ class ThreatIntelBot:
|
||||
if category_articles:
|
||||
logger.info(f"Found {len(category_articles)} new {category.upper()} articles")
|
||||
|
||||
# Deduplicate within this polling batch (cross-feed/source duplicates).
|
||||
# Deduplicate within this polling batch
|
||||
unique_articles = []
|
||||
batch_seen_url = set()
|
||||
batch_seen_content = set()
|
||||
@@ -425,16 +433,14 @@ class ThreatIntelBot:
|
||||
fp = RSSFeedManager.get_article_fingerprints(article)
|
||||
url_key = fp['url_key']
|
||||
content_key = fp['content_key']
|
||||
|
||||
if (url_key and url_key in batch_seen_url) or (content_key in batch_seen_content):
|
||||
continue
|
||||
|
||||
if url_key:
|
||||
batch_seen_url.add(url_key)
|
||||
batch_seen_content.add(content_key)
|
||||
unique_articles.append(article)
|
||||
|
||||
# Classify and send all unique articles
|
||||
# Classify and send RSS articles
|
||||
sent_count = 0
|
||||
for article in unique_articles:
|
||||
classified = self.classifier.classify_article(article)
|
||||
@@ -448,10 +454,24 @@ class ThreatIntelBot:
|
||||
else:
|
||||
logger.info("No new articles found")
|
||||
|
||||
# Poll ransomware.live for new victims
|
||||
if self.ransomware_fetcher:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
new_victims = await self.ransomware_fetcher.fetch_new_victims(session)
|
||||
victim_count = 0
|
||||
for victim in new_victims:
|
||||
article = RansomwareFetcher.to_article(victim)
|
||||
sent = await self.send_alert(article)
|
||||
if sent:
|
||||
self.ransomware_fetcher.mark_seen(victim.get("id", ""))
|
||||
victim_count += 1
|
||||
await asyncio.sleep(1)
|
||||
if new_victims:
|
||||
logger.info(f"Ransomware victims: {len(new_victims)} new, {victim_count} delivered")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in feed monitoring: {e}")
|
||||
|
||||
# Wait 5 minutes before next check
|
||||
await asyncio.sleep(300)
|
||||
|
||||
def build_application(self):
|
||||
|
||||
Reference in New Issue
Block a user