wafaHell 0.2.0__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wafaHell/app.py +31 -0
- wafaHell/globals.py +5 -0
- wafaHell/logger.py +102 -14
- wafaHell/middleware.py +398 -81
- wafaHell/mock.py +53 -0
- wafaHell/model.py +98 -10
- wafaHell/panel.py +406 -0
- wafaHell/rateLimiter.py +0 -1
- wafaHell/utils.py +413 -7
- {wafahell-0.2.0.dist-info → wafahell-1.1.0.dist-info}/METADATA +5 -1
- wafahell-1.1.0.dist-info/RECORD +15 -0
- {wafahell-0.2.0.dist-info → wafahell-1.1.0.dist-info}/WHEEL +1 -1
- wafaHell/teste.py +0 -16
- wafahell-0.2.0.dist-info/RECORD +0 -12
- {wafahell-0.2.0.dist-info → wafahell-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {wafahell-0.2.0.dist-info → wafahell-1.1.0.dist-info}/top_level.txt +0 -0
wafaHell/utils.py
CHANGED
|
@@ -1,10 +1,416 @@
|
|
|
1
|
-
from
|
|
1
|
+
from .model import WafLog, Blocked, Whitelist, AdminUser, get_session
|
|
2
|
+
from .globals import waf_cache
|
|
3
|
+
from datetime import datetime, timedelta, timezone
|
|
4
|
+
import secrets
|
|
5
|
+
import socket
|
|
6
|
+
import string
|
|
7
|
+
import time
|
|
8
|
+
import tomllib
|
|
9
|
+
from werkzeug.security import generate_password_hash
|
|
10
|
+
from sqlalchemy.orm import Session
|
|
11
|
+
from sqlalchemy import text, func, case
|
|
12
|
+
from functools import wraps
|
|
13
|
+
from flask import session, redirect, url_for, request
|
|
14
|
+
import geoip2.database
|
|
15
|
+
import os
|
|
2
16
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
17
|
+
class Admin:
|
|
18
|
+
@staticmethod
|
|
19
|
+
def generate_secure_password(length=64):
|
|
20
|
+
alphabet = string.ascii_letters + string.digits + string.punctuation
|
|
21
|
+
return ''.join(secrets.choice(alphabet) for _ in range(length))
|
|
7
22
|
|
|
8
|
-
|
|
9
|
-
|
|
23
|
+
@staticmethod
|
|
24
|
+
def create_admin_user(session: Session):
|
|
25
|
+
admin = session.query(AdminUser).filter_by(login="admin").first()
|
|
26
|
+
if admin:
|
|
27
|
+
return
|
|
28
|
+
raw_password = "admin" #Admin.generate_secure_password(64)
|
|
29
|
+
hashed_password = generate_password_hash(raw_password)
|
|
10
30
|
|
|
31
|
+
admin = AdminUser(
|
|
32
|
+
login="admin",
|
|
33
|
+
password=hashed_password
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
session.add(admin)
|
|
37
|
+
session.commit()
|
|
38
|
+
|
|
39
|
+
print("* [WafaHell] Usuario admin criado com sucesso.")
|
|
40
|
+
print("* [WafaHell] Salve essa senha em um lugar seguro, não será mostrada novamente")
|
|
41
|
+
print("Senha: ", raw_password)
|
|
42
|
+
|
|
43
|
+
def admin(fn):
|
|
44
|
+
@wraps(fn)
|
|
45
|
+
def wrapper(*args, **kwargs):
|
|
46
|
+
if not session.get("logged_in"):
|
|
47
|
+
return redirect(url_for("login", next=request.path))
|
|
48
|
+
return fn(*args, **kwargs)
|
|
49
|
+
return wrapper
|
|
50
|
+
|
|
51
|
+
class Dashboard:
|
|
52
|
+
def __init__(self):
|
|
53
|
+
self.geo_db_path = os.path.join(os.path.dirname(__file__), 'GeoLite2-Country.mmdb')
|
|
54
|
+
|
|
55
|
+
def dashboard_setup(self):
|
|
56
|
+
json = {}
|
|
57
|
+
|
|
58
|
+
def get_waf_version():
|
|
59
|
+
base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
60
|
+
toml_path = os.path.join(base_path, "pyproject.toml")
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
with open(toml_path, "rb") as f:
|
|
64
|
+
data = tomllib.load(f)
|
|
65
|
+
return data["project"]["version"]
|
|
66
|
+
except FileNotFoundError:
|
|
67
|
+
return "v.0.0.0"
|
|
68
|
+
|
|
69
|
+
def get_server_info():
|
|
70
|
+
server_time = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z')
|
|
71
|
+
node_id = socket.gethostname()
|
|
72
|
+
avg_latency = waf_cache.get('latency_avg', default=0.0)
|
|
73
|
+
system_status = "critical" if avg_latency > 500 else "degraded" if avg_latency > 200 else "healthy"
|
|
74
|
+
return {
|
|
75
|
+
"server_time": server_time,
|
|
76
|
+
"node_id": node_id,
|
|
77
|
+
"average_latency_ms": round(float(avg_latency), 2),
|
|
78
|
+
"system_status": system_status,
|
|
79
|
+
"version": get_waf_version()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
def get_kpis():
|
|
83
|
+
now = datetime.now(timezone.utc)
|
|
84
|
+
last_24h = now - timedelta(hours=24)
|
|
85
|
+
prev_24h = now - timedelta(hours=48)
|
|
86
|
+
session = get_session()
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
# --- TOTAIS DE HOJE ---
|
|
90
|
+
total_today = session.query(func.count(WafLog.id)).filter(WafLog.timestamp >= last_24h).scalar() or 0
|
|
91
|
+
blocked_today = session.query(func.count(WafLog.id)).filter(
|
|
92
|
+
WafLog.timestamp >= last_24h,
|
|
93
|
+
WafLog.attack_type != 'INFO'
|
|
94
|
+
).scalar() or 0
|
|
95
|
+
|
|
96
|
+
# --- TOTAIS DE ONTEM (Para Tendência) ---
|
|
97
|
+
total_yesterday = session.query(func.count(WafLog.id)).filter(
|
|
98
|
+
WafLog.timestamp >= prev_24h,
|
|
99
|
+
WafLog.timestamp < last_24h
|
|
100
|
+
).scalar() or 0
|
|
101
|
+
|
|
102
|
+
blocked_yesterday = session.query(func.count(WafLog.id)).filter(
|
|
103
|
+
WafLog.timestamp >= prev_24h,
|
|
104
|
+
WafLog.timestamp < last_24h,
|
|
105
|
+
WafLog.attack_type != 'INFO'
|
|
106
|
+
).scalar() or 0
|
|
107
|
+
|
|
108
|
+
# --- CÁLCULO DE TENDÊNCIA (%) ---
|
|
109
|
+
def calc_trend(current, previous):
|
|
110
|
+
if previous == 0:
|
|
111
|
+
return 100.0 if current > 0 else 0.0
|
|
112
|
+
return round(((current - previous) / previous * 100), 1)
|
|
113
|
+
|
|
114
|
+
trend_total = calc_trend(total_today, total_yesterday)
|
|
115
|
+
trend_attacks = calc_trend(blocked_today, blocked_yesterday)
|
|
116
|
+
|
|
117
|
+
# --- INFOS COMPLEMENTARES ---
|
|
118
|
+
from globals import waf_cache
|
|
119
|
+
# Latência e RPS vindos do Cache Global
|
|
120
|
+
last_second_timestamp = int(time.time()) - 1
|
|
121
|
+
rps_key = f"rps_{last_second_timestamp}"
|
|
122
|
+
|
|
123
|
+
# 2. Lê o valor real do cache para esse segundo específico
|
|
124
|
+
current_rps = waf_cache.get(rps_key, default=0)
|
|
125
|
+
|
|
126
|
+
# 3. Lógica do Pico (Peak)
|
|
127
|
+
# Aqui continuamos usando uma chave fixa 'rps_peak_hour' para guardar o recorde
|
|
128
|
+
peak_rps = waf_cache.get('rps_peak_hour', default=0)
|
|
129
|
+
|
|
130
|
+
if current_rps > peak_rps:
|
|
131
|
+
peak_rps = current_rps
|
|
132
|
+
# Atualiza o recorde no cache por 1 hora
|
|
133
|
+
waf_cache.set('rps_peak_hour', peak_rps, expire=3600)
|
|
134
|
+
|
|
135
|
+
# Dados da Blacklist
|
|
136
|
+
total_blacklist = session.query(func.count(Blocked.id)).scalar() or 0
|
|
137
|
+
# Como blocked_at é String formatada no seu modelo, comparamos com o horário
|
|
138
|
+
added_today = session.query(func.count(Blocked.id)).filter(
|
|
139
|
+
Blocked.blocked_until >= now # Um IP "adicionado hoje" é tecnicamente um ainda bloqueado
|
|
140
|
+
).scalar() or 0
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
"total_requests_24h": {
|
|
144
|
+
"value": total_today,
|
|
145
|
+
"trend_percent": trend_total
|
|
146
|
+
},
|
|
147
|
+
"attacks_mitigated_24h": {
|
|
148
|
+
"value": blocked_today,
|
|
149
|
+
"trend_percent": trend_attacks # Adicionado aqui
|
|
150
|
+
},
|
|
151
|
+
"throughput": {
|
|
152
|
+
"current_req_per_sec": current_rps,
|
|
153
|
+
"peak_last_hour": peak_rps
|
|
154
|
+
},
|
|
155
|
+
"blacklist_count": {
|
|
156
|
+
"total_ips": total_blacklist,
|
|
157
|
+
"added_today": added_today
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
except Exception as e:
|
|
162
|
+
print(f"Erro no Dashboard: {e}")
|
|
163
|
+
finally:
|
|
164
|
+
session.close()
|
|
165
|
+
|
|
166
|
+
def get_traffic_chart():
|
|
167
|
+
now = datetime.now(timezone.utc)
|
|
168
|
+
start_time = now - timedelta(minutes=40)
|
|
169
|
+
session = get_session()
|
|
170
|
+
try:
|
|
171
|
+
# Query para agrupar por minuto
|
|
172
|
+
# No SQLite usamos strftime, no Postgres/MySQL seria date_format ou similar
|
|
173
|
+
query = session.query(
|
|
174
|
+
func.strftime('%H:%M', WafLog.timestamp).label('minute'),
|
|
175
|
+
func.count(WafLog.id).label('total'),
|
|
176
|
+
func.sum(case({WafLog.attack_type == 'INFO': 1}, else_=0)).label('legit'),
|
|
177
|
+
func.sum(case({WafLog.attack_type != 'INFO': 1}, else_=0)).label('attacks')
|
|
178
|
+
).filter(WafLog.timestamp >= start_time)\
|
|
179
|
+
.group_by('minute')\
|
|
180
|
+
.order_by('minute').all()
|
|
181
|
+
|
|
182
|
+
labels = []
|
|
183
|
+
series_legit = []
|
|
184
|
+
series_attacks = []
|
|
185
|
+
|
|
186
|
+
# Preenche os arrays para o gráfico
|
|
187
|
+
for row in query:
|
|
188
|
+
labels.append(row.minute)
|
|
189
|
+
series_legit.append(row.legit or 0)
|
|
190
|
+
series_attacks.append(row.attacks or 0)
|
|
191
|
+
|
|
192
|
+
# Caso não existam dados nos últimos 40 min, retorna arrays vazios para não quebrar o front
|
|
193
|
+
return {
|
|
194
|
+
"labels": labels,
|
|
195
|
+
"series_legit": series_legit,
|
|
196
|
+
"series_attacks": series_attacks
|
|
197
|
+
}
|
|
198
|
+
except Exception as e:
|
|
199
|
+
print(f"Erro no Dashboard: {e}")
|
|
200
|
+
finally:
|
|
201
|
+
session.close()
|
|
202
|
+
|
|
203
|
+
def get_distribution_vectors():
|
|
204
|
+
now = datetime.now(timezone.utc)
|
|
205
|
+
last_24h = now - timedelta(hours=24)
|
|
206
|
+
session = get_session()
|
|
207
|
+
try:
|
|
208
|
+
# 1. Buscamos a contagem agrupada por tipo de ataque
|
|
209
|
+
# Filtramos para não incluir tráfego legítimo (INFO)
|
|
210
|
+
query = session.query(
|
|
211
|
+
WafLog.attack_type,
|
|
212
|
+
func.count(WafLog.id).label('count')
|
|
213
|
+
).filter(
|
|
214
|
+
WafLog.timestamp >= last_24h,
|
|
215
|
+
WafLog.attack_type != 'INFO'
|
|
216
|
+
).group_by(WafLog.attack_type).all()
|
|
217
|
+
|
|
218
|
+
# 2. Calculamos o total de ataques para obter a porcentagem
|
|
219
|
+
total_attacks = sum(row.count for row in query)
|
|
220
|
+
|
|
221
|
+
distribution = []
|
|
222
|
+
|
|
223
|
+
for row in query:
|
|
224
|
+
percentage = round((row.count / total_attacks * 100), 1) if total_attacks > 0 else 0
|
|
225
|
+
distribution.append({
|
|
226
|
+
"label": row.attack_type,
|
|
227
|
+
"count": row.count,
|
|
228
|
+
"percentage": percentage
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
# Caso não haja ataques, retornamos uma lista vazia ou um placeholder
|
|
232
|
+
return distribution
|
|
233
|
+
except Exception as e:
|
|
234
|
+
print(f"Erro no Dashboard: {e}")
|
|
235
|
+
finally:
|
|
236
|
+
session.close()
|
|
237
|
+
|
|
238
|
+
def get_top_geo():
|
|
239
|
+
def resolve_ip(ip):
|
|
240
|
+
try:
|
|
241
|
+
if not os.path.exists(self.geo_db_path):
|
|
242
|
+
print("ERRO: Arquivo GeoLite2-Country.mmdb não encontrado!")
|
|
243
|
+
return "XX", "Unknown"
|
|
244
|
+
|
|
245
|
+
with geoip2.database.Reader(self.geo_db_path) as reader:
|
|
246
|
+
response = reader.country(ip)
|
|
247
|
+
return response.country.iso_code, response.country.name
|
|
248
|
+
except Exception as e:
|
|
249
|
+
print(f"Erro na consulta GeoIP: {e}") # Isso vai te dizer se o banco está corrompido ou o IP é inválido
|
|
250
|
+
return "XX", "Unknown"
|
|
251
|
+
|
|
252
|
+
now = datetime.now(timezone.utc)
|
|
253
|
+
last_24h = now - timedelta(hours=24)
|
|
254
|
+
session = get_session()
|
|
255
|
+
# 1. Busca todos os ataques agrupados por IP
|
|
256
|
+
try:
|
|
257
|
+
query = session.query(
|
|
258
|
+
WafLog.ip,
|
|
259
|
+
func.count(WafLog.id).label('count')
|
|
260
|
+
).filter(
|
|
261
|
+
WafLog.timestamp >= last_24h,
|
|
262
|
+
WafLog.attack_type != 'INFO'
|
|
263
|
+
).group_by(WafLog.ip).all()
|
|
264
|
+
|
|
265
|
+
geo_stats = {}
|
|
266
|
+
total_attacks = 0
|
|
267
|
+
|
|
268
|
+
# 2. Processa cada IP real usando o GeoIP2
|
|
269
|
+
for row in query:
|
|
270
|
+
code, name = resolve_ip(row.ip)
|
|
271
|
+
|
|
272
|
+
if code not in geo_stats:
|
|
273
|
+
geo_stats[code] = {"name": name, "count": 0}
|
|
274
|
+
|
|
275
|
+
geo_stats[code]["count"] += row.count
|
|
276
|
+
total_attacks += row.count
|
|
277
|
+
|
|
278
|
+
# 3. Formata o Top 5
|
|
279
|
+
top_geo = []
|
|
280
|
+
sorted_geo = sorted(geo_stats.items(), key=lambda x: x[1]['count'], reverse=True)[:5]
|
|
281
|
+
|
|
282
|
+
for code, data in sorted_geo:
|
|
283
|
+
percentage = round((data["count"] / total_attacks * 100), 1) if total_attacks > 0 else 0
|
|
284
|
+
top_geo.append({
|
|
285
|
+
"country_code": code,
|
|
286
|
+
"country_name": data["name"],
|
|
287
|
+
"count": data["count"],
|
|
288
|
+
"percentage": percentage
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
return top_geo
|
|
292
|
+
except Exception as e:
|
|
293
|
+
print(f"Erro no Dashboard: {e}")
|
|
294
|
+
finally:
|
|
295
|
+
session.close()
|
|
296
|
+
|
|
297
|
+
def get_top_offenders():
|
|
298
|
+
now = datetime.now(timezone.utc)
|
|
299
|
+
last_24h = now - timedelta(hours=24)
|
|
300
|
+
session = get_session()
|
|
301
|
+
# 1. Agrupamos por IP e contamos os hits e os tipos de ataques diferentes
|
|
302
|
+
# Ignoramos tráfego INFO
|
|
303
|
+
try:
|
|
304
|
+
query = session.query(
|
|
305
|
+
WafLog.ip,
|
|
306
|
+
func.count(WafLog.id).label('hits_count'),
|
|
307
|
+
func.count(func.distinct(WafLog.attack_type)).label('unique_vectors')
|
|
308
|
+
).filter(
|
|
309
|
+
WafLog.timestamp >= last_24h,
|
|
310
|
+
WafLog.attack_type != 'INFO'
|
|
311
|
+
).group_by(WafLog.ip).order_by(text('hits_count DESC')).limit(5).all()
|
|
312
|
+
|
|
313
|
+
offenders = []
|
|
314
|
+
for row in query:
|
|
315
|
+
# 2. Lógica de Risk Score (0 a 100)
|
|
316
|
+
# Baseada em volume e diversidade de ataques
|
|
317
|
+
# Ex: Cada vetor único vale 20 pontos + 1 ponto para cada 50 hits (até o teto de 100)
|
|
318
|
+
vector_points = row.unique_vectors * 20
|
|
319
|
+
hit_points = row.hits_count // 50
|
|
320
|
+
risk_score = min(100, vector_points + hit_points)
|
|
321
|
+
|
|
322
|
+
offenders.append({
|
|
323
|
+
"ip": row.ip,
|
|
324
|
+
"risk_score": int(risk_score),
|
|
325
|
+
"hits_count": row.hits_count
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
return offenders
|
|
329
|
+
except Exception as e:
|
|
330
|
+
print(f"Erro no Dashboard: {e}")
|
|
331
|
+
finally:
|
|
332
|
+
session.close()
|
|
333
|
+
|
|
334
|
+
try:
|
|
335
|
+
json['meta'] = get_server_info()
|
|
336
|
+
json['kpis'] = get_kpis()
|
|
337
|
+
json['traffic_chart'] = get_traffic_chart()
|
|
338
|
+
json['distribution_vectors'] = get_distribution_vectors()
|
|
339
|
+
json['top_geo'] = get_top_geo()
|
|
340
|
+
json['top_offenders'] = get_top_offenders()
|
|
341
|
+
|
|
342
|
+
return json
|
|
343
|
+
|
|
344
|
+
except Exception as e:
|
|
345
|
+
print(f"Erro no Dashboard: {e}")
|
|
346
|
+
return {"error": str(e)}
|
|
347
|
+
|
|
348
|
+
def seed_default_whitelist():
|
|
349
|
+
"""
|
|
350
|
+
Popula a Whitelist com IPs essenciais (Localhost, DNS públicos, etc)
|
|
351
|
+
Executar na inicialização do app.
|
|
352
|
+
"""
|
|
353
|
+
# Lista de IPs Padrão (Adicione aqui IPs unitários que confia)
|
|
354
|
+
DEFAULT_IPS = [
|
|
355
|
+
# --- Localhost / Loopback (Essencial) ---
|
|
356
|
+
"127.0.0.1",
|
|
357
|
+
"::1",
|
|
358
|
+
|
|
359
|
+
# Redes Privadas (As gigantes)
|
|
360
|
+
"10.0.0.0/8", # 16 milhões de IPs
|
|
361
|
+
"172.16.0.0/12", # 1 milhão de IPs
|
|
362
|
+
"192.168.0.0/16", # 65 mil IPs
|
|
363
|
+
|
|
364
|
+
# --- DNS Públicos (Google) ---
|
|
365
|
+
"8.8.8.8",
|
|
366
|
+
"8.8.4.4",
|
|
367
|
+
|
|
368
|
+
# --- DNS Públicos (Cloudflare) ---
|
|
369
|
+
"1.1.1.1",
|
|
370
|
+
"1.0.0.1",
|
|
371
|
+
|
|
372
|
+
# --- DNS Públicos (OpenDNS) ---
|
|
373
|
+
"208.67.222.222",
|
|
374
|
+
"208.67.220.220",
|
|
375
|
+
|
|
376
|
+
# --- DNS Públicos (Quad9) ---
|
|
377
|
+
"9.9.9.9",
|
|
378
|
+
"149.112.112.112"
|
|
379
|
+
]
|
|
380
|
+
|
|
381
|
+
session = get_session()
|
|
382
|
+
try:
|
|
383
|
+
# 1. Descobre o que já existe no banco para não duplicar
|
|
384
|
+
existing_query = session.query(Whitelist.ip).filter(Whitelist.ip.in_(DEFAULT_IPS)).all()
|
|
385
|
+
existing_ips = {row.ip for row in existing_query}
|
|
386
|
+
|
|
387
|
+
# 2. Filtra apenas os novos
|
|
388
|
+
ips_to_insert = set(DEFAULT_IPS) - existing_ips
|
|
389
|
+
|
|
390
|
+
if not ips_to_insert:
|
|
391
|
+
print(" * [WafaHell] Whitelist padrão já está atualizada.")
|
|
392
|
+
return
|
|
393
|
+
|
|
394
|
+
# 3. Prepara Bulk Insert e Cache
|
|
395
|
+
now_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
396
|
+
bulk_data = []
|
|
397
|
+
|
|
398
|
+
for ip in ips_to_insert:
|
|
399
|
+
bulk_data.append({
|
|
400
|
+
"ip": ip,
|
|
401
|
+
"added_at": now_str
|
|
402
|
+
})
|
|
403
|
+
# Já coloca no cache para funcionar imediatamente
|
|
404
|
+
waf_cache.set(f"whitelist_{ip}", True, expire=3600)
|
|
405
|
+
|
|
406
|
+
# 4. Grava no Banco
|
|
407
|
+
session.bulk_insert_mappings(Whitelist, bulk_data)
|
|
408
|
+
session.commit()
|
|
409
|
+
|
|
410
|
+
print(f" * [WafaHell] Seed Whitelist: {len(ips_to_insert)} IPs padrão adicionados.")
|
|
411
|
+
|
|
412
|
+
except Exception as e:
|
|
413
|
+
session.rollback()
|
|
414
|
+
print(f"Erro ao semear whitelist: {e}")
|
|
415
|
+
finally:
|
|
416
|
+
session.close()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wafaHell
|
|
3
|
-
Version:
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Middleware WAF to Flask
|
|
5
5
|
Author-email: Yago Martins <yagomartins30@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -33,6 +33,10 @@ Requires-Python: >=3.9
|
|
|
33
33
|
Description-Content-Type: text/markdown
|
|
34
34
|
License-File: LICENSE
|
|
35
35
|
Requires-Dist: Flask>=2.0
|
|
36
|
+
Requires-Dist: sqlalchemy>=2.0.0
|
|
37
|
+
Requires-Dist: requests
|
|
38
|
+
Requires-Dist: diskcache
|
|
39
|
+
Requires-Dist: geoip2
|
|
36
40
|
Dynamic: license-file
|
|
37
41
|
|
|
38
42
|
# WafHell
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
wafaHell/__init__.py,sha256=bdafr3LRK7_frr-V6umEJZUqt8RMrOiLJy72DSQfs2o,60
|
|
2
|
+
wafaHell/app.py,sha256=oZCqS6rwvm3vU1pc56yYiNc_Mh4DOI52H00qnVovt-o,986
|
|
3
|
+
wafaHell/globals.py,sha256=keIe0YCNsb5si0yUhUjd6nlk1s0YgfH5G7lH5-05Zws,160
|
|
4
|
+
wafaHell/logger.py,sha256=_h4ceGM2UYnEQ5SY7nbYtR0rZprCOC0rN1IehtkkM_o,5734
|
|
5
|
+
wafaHell/middleware.py,sha256=DlSGA-1YHaHG-iQ2lBIWJIuzQnxkRITBPMSQogM8hdA,19625
|
|
6
|
+
wafaHell/mock.py,sha256=EgfSCKYV3rUTerKoEyFQPSf47wrOo-E0yqe7JpQUe3w,2105
|
|
7
|
+
wafaHell/model.py,sha256=o3wrIp8H17vlIB1tW28ApYedXtJLIGTbtrB7zKjzbtE,2919
|
|
8
|
+
wafaHell/panel.py,sha256=mq_vUg4LWLaFEWLvXpuDB3_QUw46WHhw3ruKb6hc_Sc,15926
|
|
9
|
+
wafaHell/rateLimiter.py,sha256=p4IDxha-ZrRPROFf8Fa1gRTbbUTQdbD9TgBTmyMR2hQ,664
|
|
10
|
+
wafaHell/utils.py,sha256=nQk1A4J1OeuvDnX5lj8pIE8IyUF5f5wbtXt0XSdsF7A,16810
|
|
11
|
+
wafahell-1.1.0.dist-info/licenses/LICENSE,sha256=6bv9v4HamenV3rqm3mhaGOecwGFrgxtVTW7JPfFDmeY,1086
|
|
12
|
+
wafahell-1.1.0.dist-info/METADATA,sha256=8fF9VBaal86TMs5EwmntQeKPA7wY9bNbo-9VPvEWBEw,2087
|
|
13
|
+
wafahell-1.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
14
|
+
wafahell-1.1.0.dist-info/top_level.txt,sha256=VGBo2g3pOeTH2qIXfZDJCSblJgijemMHUHmI0bBgrls,9
|
|
15
|
+
wafahell-1.1.0.dist-info/RECORD,,
|
wafaHell/teste.py
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
from middleware import WafaHell
|
|
2
|
-
from flask import Flask
|
|
3
|
-
import logging
|
|
4
|
-
|
|
5
|
-
app = Flask(__name__)
|
|
6
|
-
waf = WafaHell(app, monitor_mode=True, block_ip=True, rate_limit=True)
|
|
7
|
-
|
|
8
|
-
# log = logging.getLogger('werkzeug')
|
|
9
|
-
# log.setLevel(logging.ERROR)
|
|
10
|
-
|
|
11
|
-
@app.route('/')
|
|
12
|
-
def home():
|
|
13
|
-
return "Bem-vindo ao site seguro!"
|
|
14
|
-
|
|
15
|
-
if __name__ == '__main__':
|
|
16
|
-
app.run(host='0.0.0.0', port=5000, debug=False)
|
wafahell-0.2.0.dist-info/RECORD
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
wafaHell/__init__.py,sha256=bdafr3LRK7_frr-V6umEJZUqt8RMrOiLJy72DSQfs2o,60
|
|
2
|
-
wafaHell/logger.py,sha256=yMEz5FY6RdNOzQ9RacAiKpfmwtGjnNVha5umeeSotAM,1354
|
|
3
|
-
wafaHell/middleware.py,sha256=nFhfrvoU3yNaS-_yKjAGbP7egdgG9gYwz5pxtFhVmTw,6052
|
|
4
|
-
wafaHell/model.py,sha256=QnnOOgsEvqs0tHWLN6SkxQlnWR6r4KYiutyMxQl1nDo,902
|
|
5
|
-
wafaHell/rateLimiter.py,sha256=_aU3ZORwpH2CCNpRWF44FyVM5slE3QvLyEgqWRcELr4,666
|
|
6
|
-
wafaHell/teste.py,sha256=rnO3lyYQ-d-fJvlX7EQ-qo2T3DkAM6VS_z897Hht77E,399
|
|
7
|
-
wafaHell/utils.py,sha256=htvGKGKY4VLsN8fcDOSQKDYqkTXbq8f3X29MQWq08P0,354
|
|
8
|
-
wafahell-0.2.0.dist-info/licenses/LICENSE,sha256=6bv9v4HamenV3rqm3mhaGOecwGFrgxtVTW7JPfFDmeY,1086
|
|
9
|
-
wafahell-0.2.0.dist-info/METADATA,sha256=v5yAr069OcRN4c3BxogmtQEAA-KKWr96a9ujgjuzbAc,1979
|
|
10
|
-
wafahell-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
-
wafahell-0.2.0.dist-info/top_level.txt,sha256=VGBo2g3pOeTH2qIXfZDJCSblJgijemMHUHmI0bBgrls,9
|
|
12
|
-
wafahell-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|