aiwaf 0.1.9.0.9__tar.gz → 0.1.9.1.1__tar.gz
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.
Potentially problematic release.
This version of aiwaf might be problematic. Click here for more details.
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/PKG-INFO +1 -1
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/__init__.py +1 -1
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/storage.py +21 -2
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/trainer.py +5 -6
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf.egg-info/PKG-INFO +1 -1
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/pyproject.toml +1 -1
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/setup.py +1 -1
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/LICENSE +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/README.md +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/apps.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/blacklist_manager.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/decorators.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/__init__.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/__init__.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/add_exemption.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/add_ipexemption.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/aiwaf_diagnose.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/aiwaf_logging.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/aiwaf_reset.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/clear_cache.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/debug_csv.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/detect_and_train.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/diagnose_blocking.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/regenerate_model.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/setup_models.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/test_exemption.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/management/commands/test_exemption_fix.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/middleware.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/middleware_logger.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/models.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/resources/model.pkl +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/templatetags/__init__.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/templatetags/aiwaf_tags.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf/utils.py +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf.egg-info/SOURCES.txt +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf.egg-info/dependency_links.txt +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf.egg-info/requires.txt +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/aiwaf.egg-info/top_level.txt +0 -0
- {aiwaf-0.1.9.0.9 → aiwaf-0.1.9.1.1}/setup.cfg +0 -0
|
@@ -116,6 +116,11 @@ class ModelBlacklistStore:
|
|
|
116
116
|
"""Remove IP from blacklist (alias for unblock_ip)"""
|
|
117
117
|
ModelBlacklistStore.unblock_ip(ip)
|
|
118
118
|
|
|
119
|
+
@staticmethod
|
|
120
|
+
def add_ip(ip, reason="Automated block"):
|
|
121
|
+
"""Add IP to blacklist (alias for block_ip)"""
|
|
122
|
+
ModelBlacklistStore.block_ip(ip, reason)
|
|
123
|
+
|
|
119
124
|
@staticmethod
|
|
120
125
|
def get_all_blocked_ips():
|
|
121
126
|
"""Get all blocked IPs"""
|
|
@@ -189,7 +194,7 @@ class ModelExemptionStore:
|
|
|
189
194
|
|
|
190
195
|
class ModelKeywordStore:
|
|
191
196
|
@staticmethod
|
|
192
|
-
def add_keyword(keyword):
|
|
197
|
+
def add_keyword(keyword, count=1):
|
|
193
198
|
"""Add a keyword to the dynamic keyword list"""
|
|
194
199
|
_import_models()
|
|
195
200
|
if DynamicKeyword is None:
|
|
@@ -197,11 +202,25 @@ class ModelKeywordStore:
|
|
|
197
202
|
try:
|
|
198
203
|
obj, created = DynamicKeyword.objects.get_or_create(keyword=keyword)
|
|
199
204
|
if not created:
|
|
200
|
-
obj.count +=
|
|
205
|
+
obj.count += count
|
|
206
|
+
obj.save()
|
|
207
|
+
else:
|
|
208
|
+
obj.count = count
|
|
201
209
|
obj.save()
|
|
202
210
|
except Exception as e:
|
|
203
211
|
print(f"Error adding keyword {keyword}: {e}")
|
|
204
212
|
|
|
213
|
+
@staticmethod
|
|
214
|
+
def remove_keyword(keyword):
|
|
215
|
+
"""Remove a keyword from the dynamic keyword list"""
|
|
216
|
+
_import_models()
|
|
217
|
+
if DynamicKeyword is None:
|
|
218
|
+
return
|
|
219
|
+
try:
|
|
220
|
+
DynamicKeyword.objects.filter(keyword=keyword).delete()
|
|
221
|
+
except Exception as e:
|
|
222
|
+
print(f"Error removing keyword {keyword}: {e}")
|
|
223
|
+
|
|
205
224
|
@staticmethod
|
|
206
225
|
def get_top_keywords(n=10):
|
|
207
226
|
"""Get top N keywords by count"""
|
|
@@ -15,6 +15,7 @@ from django.apps import apps
|
|
|
15
15
|
from django.db.models import F
|
|
16
16
|
from .utils import is_exempt_path
|
|
17
17
|
from .storage import get_blacklist_store, get_exemption_store, get_keyword_store
|
|
18
|
+
from .blacklist_manager import BlacklistManager
|
|
18
19
|
|
|
19
20
|
# ─────────── Configuration ───────────
|
|
20
21
|
LOG_PATH = getattr(settings, 'AIWAF_ACCESS_LOG', None)
|
|
@@ -102,13 +103,12 @@ def _parse(line: str) -> dict | None:
|
|
|
102
103
|
def train() -> None:
|
|
103
104
|
remove_exempt_keywords()
|
|
104
105
|
|
|
105
|
-
# Remove any IPs in IPExemption from the blacklist using
|
|
106
|
+
# Remove any IPs in IPExemption from the blacklist using BlacklistManager
|
|
106
107
|
exemption_store = get_exemption_store()
|
|
107
|
-
blacklist_store = get_blacklist_store()
|
|
108
108
|
|
|
109
109
|
exempted_ips = [entry['ip_address'] for entry in exemption_store.get_all()]
|
|
110
110
|
for ip in exempted_ips:
|
|
111
|
-
|
|
111
|
+
BlacklistManager.unblock(ip)
|
|
112
112
|
|
|
113
113
|
raw_lines = _read_all_logs()
|
|
114
114
|
if not raw_lines:
|
|
@@ -141,8 +141,7 @@ def train() -> None:
|
|
|
141
141
|
|
|
142
142
|
# Don't block if majority of 404s are on login paths
|
|
143
143
|
if count > login_404s: # More non-login 404s than login 404s
|
|
144
|
-
|
|
145
|
-
blacklist_store.add_ip(ip, f"Excessive 404s (≥6 non-login, {count}/{total_404s})")
|
|
144
|
+
BlacklistManager.block(ip, f"Excessive 404s (≥6 non-login, {count}/{total_404s})")
|
|
146
145
|
|
|
147
146
|
feature_dicts = []
|
|
148
147
|
for r in parsed:
|
|
@@ -239,7 +238,7 @@ def train() -> None:
|
|
|
239
238
|
continue
|
|
240
239
|
|
|
241
240
|
# Block if it shows clear signs of malicious behavior
|
|
242
|
-
|
|
241
|
+
BlacklistManager.block(ip, f"AI anomaly + suspicious patterns (kw:{avg_kw_hits:.1f}, 404s:{max_404s}, burst:{avg_burst:.1f})")
|
|
243
242
|
blocked_count += 1
|
|
244
243
|
print(f" - {ip}: Blocked for suspicious behavior (kw:{avg_kw_hits:.1f}, 404s:{max_404s}, burst:{avg_burst:.1f})")
|
|
245
244
|
|
|
@@ -9,7 +9,7 @@ long_description = (HERE / "README.md").read_text(encoding="utf-8")
|
|
|
9
9
|
|
|
10
10
|
setup(
|
|
11
11
|
name="aiwaf",
|
|
12
|
-
version="0.1.9.
|
|
12
|
+
version="0.1.9.1.1",
|
|
13
13
|
description="AI‑driven, self‑learning Web Application Firewall for Django",
|
|
14
14
|
long_description=long_description,
|
|
15
15
|
long_description_content_type="text/markdown",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|