1
1
import argparse
2
2
import json
3
3
from datetime import datetime , timedelta
4
+ import time
4
5
from dateutil .parser import parse
5
6
from summarizer import summarize_vulnerabilities
6
7
import os
7
- from scrapers .sources import get_full_disclosure_latest , get_exploitdb_rss
8
- from scrapers . nist import get_nist_cves
9
- from scrapers . nist import Severity
8
+ from scrapers .sources import get_full_disclosure_latest , get_exploitdb_rss , get_nist_cves , Severity
9
+ from colorama import init , Fore , Style
10
+ import sys
10
11
11
12
def parse_args ():
12
13
parser = argparse .ArgumentParser (
@@ -50,8 +51,8 @@ def parse_args():
50
51
51
52
# Limit options
52
53
limit_group = parser .add_argument_group ('Limits' )
53
- limit_group .add_argument ('--max-items' , '-m' , type = int ,
54
- help = 'Maximum number of vulnerabilities to retrieve' )
54
+ limit_group .add_argument ('--max-items' , '-m' , type = int , default = 100 ,
55
+ help = 'Maximum number of vulnerabilities to retrieve per source ' )
55
56
limit_group .add_argument ('--min-severity' , '-M' ,
56
57
choices = ['LOW' , 'MEDIUM' , 'HIGH' , 'CRITICAL' ],
57
58
help = 'Minimum severity level for vulnerabilities' )
@@ -74,14 +75,11 @@ def parse_args():
74
75
args .type = 'all'
75
76
args .collect = True
76
77
args .summarize = True
77
- args .days = 30
78
- # Somente sobrescrever max_items se o usuário não tiver definido -m
79
- if not args .max_items :
80
- args .max_items = None
81
- args .include_unclassified = True
78
+ args .days = args .days or 30
79
+ args .include_unclassified = args .include_unclassified or False
82
80
83
81
if args .quick_scan :
84
- args .type = 'sources '
82
+ args .type = 'all '
85
83
args .collect = True
86
84
args .summarize = True
87
85
args .days = 7
@@ -125,28 +123,20 @@ def collect_vulnerabilities(args):
125
123
max_items = args .max_items
126
124
source_type = 'all' if args .type == 'all' else ('nist' if args .type == 'nist' else 'sources' )
127
125
128
- # Calculate max items per source
129
- if args .type == 'all' and max_items :
130
- active_sources = len (args .sources ) if 'nist' not in args .sources else len (args .sources ) + 1
131
- max_per_source = max_items // active_sources
132
- else :
133
- max_per_source = max_items
134
-
135
- print (f"Total limit: { max_items } , Per source limit: { max_per_source } " )
126
+ print (f"Total limit per source: { max_items } " )
136
127
137
128
if args .type in ['sources' , 'all' ]:
138
129
print (f"Collecting items from sources between { args .start_date .strftime ('%Y-%m-%d' )} and { args .end_date .strftime ('%Y-%m-%d' )} ..." )
139
130
140
131
if 'fulldisclosure' in args .sources :
141
132
fd_vulns = get_full_disclosure_latest (args .start_date , args .end_date , use_ai = not args .no_ai )
142
- fd_vulns = fd_vulns [:max_per_source ] if max_per_source else fd_vulns
133
+ fd_vulns = fd_vulns [:max_items ] if max_items else fd_vulns
143
134
vulns .extend (fd_vulns )
144
135
print (f"Full Disclosure results: { len (fd_vulns )} " )
145
136
146
137
if 'exploitdb' in args .sources :
147
- remaining = max_items - len (vulns ) if max_items else None
148
138
edb_vulns = get_exploitdb_rss (args .start_date , args .end_date )
149
- edb_vulns = edb_vulns [:max_per_source ] if max_per_source else edb_vulns
139
+ edb_vulns = edb_vulns [:max_items ] if max_items else edb_vulns
150
140
vulns .extend (edb_vulns )
151
141
print (f"Exploit-DB results: { len (edb_vulns )} " )
152
142
@@ -157,23 +147,30 @@ def collect_vulnerabilities(args):
157
147
start_date = args .start_date ,
158
148
end_date = args .end_date ,
159
149
classified_only = not args .include_unclassified ,
160
- max_cves = max_per_source , # Usa o mesmo limite por fonte
150
+ max_cves = max_items , # Apply the limit per source
161
151
min_severity = args .min_severity
162
152
)
163
153
vulns .extend (nist_vulns )
164
154
print (f"NIST CVE results: { len (nist_vulns )} " )
165
155
166
- # Aplica limite final ao total
167
- if max_items and len (vulns ) > max_items :
168
- vulns = vulns [:max_items ]
169
- print (f"Applied final limit: { len (vulns )} /{ max_items } vulnerabilities" )
170
-
171
156
output_file = f"{ args .output_dir } /{ source_type } _vulnerabilities.json"
172
157
save_to_json (vulns , output_file )
173
158
print (f"Data saved to { output_file } " )
174
159
return vulns , source_type
175
160
176
161
def main ():
162
+ init (autoreset = True )
163
+ print (Fore .GREEN + r"""
164
+ _ _ __ __ _ _
165
+ | | | | \ \ / / | | | |
166
+ | |_| |__ __\ \ /\ / /_ _| |_ ___| |__ ___ _ __
167
+ | __| '_ \ / _ \ \/ \/ / _` | __/ __| '_ \ / _ \ '__|
168
+ | |_| | | | __/\ /\ / (_| | || (__| | | | __/ |
169
+ \__|_| |_|\___| \/ \/ \__,_|\__\___|_| |_|\___|_|
170
+
171
+ """ , Style .RESET_ALL )
172
+ print (Fore .BLUE + "[theWatcher] Starting theWatcher..." + Style .RESET_ALL )
173
+
177
174
args = parse_args ()
178
175
179
176
if not args .collect and not args .summarize :
@@ -184,9 +181,11 @@ def main():
184
181
source_type = 'sources' # default
185
182
186
183
if args .collect :
184
+ print (Fore .CYAN + "[theWatcher] Collecting vulnerabilities..." + Style .RESET_ALL )
187
185
vulns , source_type = collect_vulnerabilities (args )
188
-
186
+
189
187
if args .summarize :
188
+ print (Fore .CYAN + "[theWatcher] Summarizing vulnerabilities..." + Style .RESET_ALL )
190
189
if not args .no_ai :
191
190
try :
192
191
input_file = f"{ args .output_dir } /{ source_type } _vulnerabilities.json"
@@ -197,6 +196,8 @@ def main():
197
196
print (f"Expected input file: { input_file } " )
198
197
else :
199
198
print ("Summarization skipped (AI disabled)" )
199
+
200
+ print (Fore .GREEN + "[theWatcher] Done." + Style .RESET_ALL )
200
201
201
202
if __name__ == "__main__" :
202
203
main ()
0 commit comments