aiwaf 0.1.9.0.1__py3-none-any.whl → 0.1.9.0.3__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.

Potentially problematic release.


This version of aiwaf might be problematic. Click here for more details.

aiwaf/__init__.py CHANGED
@@ -1,24 +1,6 @@
1
1
  default_app_config = "aiwaf.apps.AiwafConfig"
2
2
 
3
- __version__ = "0.1.9.0.1"
3
+ __version__ = "0.1.9.0.3"
4
4
 
5
5
  # Note: Middleware classes are available from aiwaf.middleware
6
- # Import them only when needed to avoid circular imports during Django app loading= "aiwaf.apps.AiwafConfig"
7
-
8
- __version__ = "0.1.9.0.1"
9
-
10
- # Import main middleware classes for easier access
11
- try:
12
- from .middleware import (
13
- IPAndKeywordBlockMiddleware,
14
- RateLimitMiddleware,
15
- AIAnomalyMiddleware,
16
- HoneypotTimingMiddleware,
17
- UUIDTamperMiddleware
18
- )
19
- except ImportError as e:
20
- # Handle import errors gracefully during package installation
21
- import sys
22
- if 'runserver' in sys.argv or 'migrate' in sys.argv or 'shell' in sys.argv:
23
- print(f"Warning: Could not import middleware classes: {e}")
24
- print("Tip: Run 'python manage.py aiwaf_diagnose' to troubleshoot")
6
+ # Import them only when needed to avoid circular imports during Django app loading
@@ -0,0 +1,79 @@
1
+ from django.core.management.base import BaseCommand
2
+ import os
3
+ import warnings
4
+
5
+ class Command(BaseCommand):
6
+ help = 'Regenerate AI-WAF model with current scikit-learn version'
7
+
8
+ def add_arguments(self, parser):
9
+ parser.add_argument(
10
+ '--force',
11
+ action='store_true',
12
+ help='Force regeneration even if model exists',
13
+ )
14
+
15
+ def handle(self, *args, **options):
16
+ self.stdout.write(self.style.HTTP_INFO("🔄 AI-WAF Model Regeneration"))
17
+ self.stdout.write("")
18
+
19
+ # Check current sklearn version
20
+ try:
21
+ import sklearn
22
+ self.stdout.write(f"Current scikit-learn version: {sklearn.__version__}")
23
+ except ImportError:
24
+ self.stdout.write(self.style.ERROR("❌ scikit-learn not available"))
25
+ self.stdout.write("Install with: pip install scikit-learn")
26
+ return
27
+
28
+ # Check if model exists
29
+ from aiwaf.trainer import MODEL_PATH
30
+ model_exists = os.path.exists(MODEL_PATH)
31
+
32
+ if model_exists and not options['force']:
33
+ self.stdout.write(f"Model exists at: {MODEL_PATH}")
34
+
35
+ # Try to load and check version
36
+ try:
37
+ import joblib
38
+ with warnings.catch_warnings():
39
+ warnings.filterwarnings("ignore", category=UserWarning, module="sklearn.base")
40
+ model_data = joblib.load(MODEL_PATH)
41
+
42
+ if isinstance(model_data, dict) and 'sklearn_version' in model_data:
43
+ stored_version = model_data['sklearn_version']
44
+ if stored_version == sklearn.__version__:
45
+ self.stdout.write(self.style.SUCCESS("✅ Model is up-to-date"))
46
+ return
47
+ else:
48
+ self.stdout.write(f"⚠️ Model version mismatch:")
49
+ self.stdout.write(f" Stored: {stored_version}")
50
+ self.stdout.write(f" Current: {sklearn.__version__}")
51
+ else:
52
+ self.stdout.write("⚠️ Legacy model format detected")
53
+
54
+ except Exception as e:
55
+ self.stdout.write(f"⚠️ Could not check model: {e}")
56
+
57
+ self.stdout.write("")
58
+ self.stdout.write("Regenerating model to fix version compatibility...")
59
+
60
+ # Regenerate model
61
+ self.stdout.write("🚀 Starting model training...")
62
+
63
+ try:
64
+ from aiwaf.trainer import train
65
+ train()
66
+ self.stdout.write("")
67
+ self.stdout.write(self.style.SUCCESS("✅ Model regenerated successfully!"))
68
+ self.stdout.write("")
69
+ self.stdout.write("The model is now compatible with your current scikit-learn version.")
70
+ self.stdout.write("Version warnings should no longer appear.")
71
+
72
+ except Exception as e:
73
+ self.stdout.write("")
74
+ self.stdout.write(self.style.ERROR(f"❌ Model regeneration failed: {e}"))
75
+ self.stdout.write("")
76
+ self.stdout.write("Possible solutions:")
77
+ self.stdout.write("1. Check that you have log data available")
78
+ self.stdout.write("2. Verify AIWAF_ACCESS_LOG setting")
79
+ self.stdout.write("3. Run 'python manage.py detect_and_train' for full training")
aiwaf/middleware.py CHANGED
@@ -25,7 +25,43 @@ MODEL_PATH = getattr(
25
25
  "AIWAF_MODEL_PATH",
26
26
  os.path.join(os.path.dirname(__file__), "resources", "model.pkl")
27
27
  )
28
- MODEL = joblib.load(MODEL_PATH)
28
+
29
+ def load_model_safely():
30
+ """Load the AI model with version compatibility checking."""
31
+ import warnings
32
+ import sklearn
33
+
34
+ try:
35
+ # Suppress sklearn version warnings temporarily
36
+ with warnings.catch_warnings():
37
+ warnings.filterwarnings("ignore", category=UserWarning, module="sklearn.base")
38
+ model_data = joblib.load(MODEL_PATH)
39
+
40
+ # Handle both old format (direct model) and new format (with metadata)
41
+ if isinstance(model_data, dict) and 'model' in model_data:
42
+ # New format with metadata
43
+ model = model_data['model']
44
+ stored_version = model_data.get('sklearn_version', 'unknown')
45
+ current_version = sklearn.__version__
46
+
47
+ if stored_version != current_version:
48
+ print(f"ℹ️ Model was trained with sklearn v{stored_version}, current v{current_version}")
49
+ print(" Run 'python manage.py detect_and_train' to update model if needed.")
50
+
51
+ return model
52
+ else:
53
+ # Old format - direct model object
54
+ print("ℹ️ Using legacy model format. Consider retraining for better compatibility.")
55
+ return model_data
56
+
57
+ except Exception as e:
58
+ print(f"Warning: Could not load AI model from {MODEL_PATH}: {e}")
59
+ print("AI anomaly detection will be disabled until model is retrained.")
60
+ print("Run 'python manage.py detect_and_train' to regenerate the model.")
61
+ return None
62
+
63
+ # Load model with safety checks
64
+ MODEL = load_model_safely()
29
65
 
30
66
  STATIC_KW = getattr(
31
67
  settings,
@@ -130,8 +166,8 @@ class AIAnomalyMiddleware(MiddlewareMixin):
130
166
 
131
167
  def __init__(self, get_response=None):
132
168
  super().__init__(get_response)
133
- model_path = os.path.join(os.path.dirname(__file__), "resources", "model.pkl")
134
- self.model = joblib.load(model_path)
169
+ # Use the safely loaded global MODEL instead of loading again
170
+ self.model = MODEL
135
171
 
136
172
  def process_request(self, request):
137
173
  if is_exempt(request):
@@ -164,7 +200,9 @@ class AIAnomalyMiddleware(MiddlewareMixin):
164
200
  total_404 = sum(1 for (_, _, st, _) in data if st == 404)
165
201
  feats = [path_len, kw_hits, resp_time, status_idx, burst_count, total_404]
166
202
  X = np.array(feats, dtype=float).reshape(1, -1)
167
- if self.model.predict(X)[0] == -1:
203
+
204
+ # Only use AI model if it's available
205
+ if self.model is not None and self.model.predict(X)[0] == -1:
168
206
  if not is_ip_exempted(ip):
169
207
  BlacklistManager.block(ip, "AI anomaly")
170
208
  return JsonResponse({"error": "blocked"}, status=403)
aiwaf/trainer.py CHANGED
@@ -17,7 +17,7 @@ from .utils import is_exempt_path
17
17
  from .storage import get_blacklist_store, get_exemption_store, get_keyword_store
18
18
 
19
19
  # ─────────── Configuration ───────────
20
- LOG_PATH = settings.AIWAF_ACCESS_LOG
20
+ LOG_PATH = getattr(settings, 'AIWAF_ACCESS_LOG', None)
21
21
  MODEL_PATH = os.path.join(os.path.dirname(__file__), "resources", "model.pkl")
22
22
 
23
23
  STATIC_KW = [".php", "xmlrpc", "wp-", ".env", ".git", ".bak", "conflg", "shell", "filemanager"]
@@ -192,11 +192,28 @@ def train() -> None:
192
192
  contamination=getattr(settings, "AIWAF_AI_CONTAMINATION", 0.05),
193
193
  random_state=42
194
194
  )
195
- model.fit(X)
195
+
196
+ # Suppress sklearn warnings during training
197
+ import warnings
198
+ with warnings.catch_warnings():
199
+ warnings.filterwarnings("ignore", category=UserWarning, module="sklearn")
200
+ model.fit(X)
196
201
 
197
202
  os.makedirs(os.path.dirname(MODEL_PATH), exist_ok=True)
198
- joblib.dump(model, MODEL_PATH)
199
- print(f"Model trained on {len(X)} samples → {MODEL_PATH}")
203
+
204
+ # Save model with version metadata
205
+ import sklearn
206
+ from django.utils import timezone as django_timezone
207
+ model_data = {
208
+ 'model': model,
209
+ 'sklearn_version': sklearn.__version__,
210
+ 'created_at': str(django_timezone.now()),
211
+ 'feature_count': len(feature_cols),
212
+ 'samples_count': len(X)
213
+ }
214
+ joblib.dump(model_data, MODEL_PATH)
215
+ print(f"✅ Model trained on {len(X)} samples → {MODEL_PATH}")
216
+ print(f"📦 Created with scikit-learn v{sklearn.__version__}")
200
217
 
201
218
  # Check for anomalies and intelligently decide which IPs to block
202
219
  preds = model.predict(X)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiwaf
3
- Version: 0.1.9.0.1
3
+ Version: 0.1.9.0.3
4
4
  Summary: AI-powered Web Application Firewall
5
5
  Home-page: https://github.com/aayushgauba/aiwaf
6
6
  Author: Aayush Gauba
@@ -12,7 +12,7 @@ License-File: LICENSE
12
12
  Requires-Dist: Django>=3.2
13
13
  Requires-Dist: numpy>=1.21
14
14
  Requires-Dist: pandas>=1.3
15
- Requires-Dist: scikit-learn>=1.0
15
+ Requires-Dist: scikit-learn<2.0,>=1.0
16
16
  Requires-Dist: joblib>=1.1
17
17
  Dynamic: author
18
18
  Dynamic: home-page
@@ -371,6 +371,7 @@ MIDDLEWARE = [
371
371
 
372
372
  **Common Issues:**
373
373
  - **AppRegistryNotReady Error**: Fixed in v0.1.9.0.1 - update with `pip install --upgrade aiwaf`
374
+ - **Scikit-learn Version Warnings**: Fixed in v0.1.9.0.3 - regenerate model with `python manage.py regenerate_model`
374
375
  - Missing Django: `pip install Django`
375
376
  - Old AI-WAF version: `pip install --upgrade aiwaf`
376
377
  - Missing migrations: `python manage.py migrate`
@@ -388,6 +389,24 @@ python manage.py detect_and_train
388
389
  1. Read access logs (incl. rotated or gzipped) **OR** AI-WAF middleware CSV logs
389
390
  2. Auto‑block IPs with ≥ 6 total 404s
390
391
  3. Extract features & train IsolationForest
392
+ 4. Save `model.pkl` with current scikit-learn version
393
+
394
+ ### Model Regeneration
395
+
396
+ If you see scikit-learn version warnings, regenerate the model:
397
+
398
+ ```bash
399
+ # Quick model regeneration (recommended)
400
+ python manage.py regenerate_model
401
+
402
+ # Full retraining with fresh data
403
+ python manage.py detect_and_train
404
+ ```
405
+
406
+ **Benefits:**
407
+ - ✅ Eliminates version compatibility warnings
408
+ - ✅ Uses current scikit-learn optimizations
409
+ - ✅ Maintains same protection level
391
410
  4. Save `model.pkl`
392
411
  5. Extract top 10 dynamic keywords from 4xx/5xx
393
412
  6. Remove any keywords associated with newly exempt paths
@@ -1,12 +1,12 @@
1
- aiwaf/__init__.py,sha256=4PDddOVwIGrxJMbJroJ6SmT5rGamZF5NPJzZir7i-dM,855
1
+ aiwaf/__init__.py,sha256=mj3cwko8cLPwJPmo9pF0dWcJJOzRCz4o5dB-cYBhqyc,220
2
2
  aiwaf/apps.py,sha256=nCez-Ptlv2kaEk5HenA8b1pATz1VfhrHP1344gwcY1A,142
3
3
  aiwaf/blacklist_manager.py,sha256=92ltIrFfv8WOC4CXwvNVZYfivkRZHGNg3E2QAbHQipQ,550
4
4
  aiwaf/decorators.py,sha256=IUKOdM_gdroffImRZep1g1wT6gNqD10zGwcp28hsJCs,825
5
- aiwaf/middleware.py,sha256=1JPrc0npI_a5bnB-thN0ME1ehfTbWBl1j9wTndZwRdQ,9505
5
+ aiwaf/middleware.py,sha256=fajFXsETb2kGQJzHi7cEV3bQA88yqHbZvRDPNR1y2OA,11188
6
6
  aiwaf/middleware_logger.py,sha256=uTYTvIc4Mv1pjY50aXaqQ5cWAO9qqquijAyVMs1KWlM,6517
7
7
  aiwaf/models.py,sha256=XaG1pd_oZu3y-fw66u4wblGlWcUY9gvsTNKGD0kQk7Y,1672
8
8
  aiwaf/storage.py,sha256=aaszMkskRO0RZPwD2vsgP35TthI_xQEs5IxsCsxjGcw,13734
9
- aiwaf/trainer.py,sha256=bgVoBewnNVMJdgxcNchfhsPOnFXxStoBOqNhFYnpsqs,9244
9
+ aiwaf/trainer.py,sha256=Cem-qi1KMjfw7MFDxyxjn7nAJGPrk-I8An4HHniiT00,9877
10
10
  aiwaf/utils.py,sha256=BJk5vJCYdGPl_4QQiknjhCbkzv5HZCXgFcBJDMJpHok,3390
11
11
  aiwaf/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  aiwaf/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -15,11 +15,12 @@ aiwaf/management/commands/aiwaf_diagnose.py,sha256=nXFRhq66N4QC3e4scYJ2sUngJce-0
15
15
  aiwaf/management/commands/aiwaf_logging.py,sha256=FCIqULn2tii2vD9VxL7vk3PV4k4vr7kaA00KyaCExYY,7692
16
16
  aiwaf/management/commands/aiwaf_reset.py,sha256=0FIBqpZS8xgFFvAKJ-0zAC_-QNQwRkOHpXb8N-OdFr8,3740
17
17
  aiwaf/management/commands/detect_and_train.py,sha256=-o-LZ7QZ5GeJPCekryox1DGXKMmFEkwwrcDsiM166K0,269
18
+ aiwaf/management/commands/regenerate_model.py,sha256=SUy7TCTTDJy4kRZNAbTIVBxSmljUaAC6ms0JTfSO6BE,3445
18
19
  aiwaf/resources/model.pkl,sha256=5t6h9BX8yoh2xct85MXOO60jdlWyg1APskUOW0jZE1Y,1288265
19
20
  aiwaf/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
21
  aiwaf/templatetags/aiwaf_tags.py,sha256=XXfb7Tl4DjU3Sc40GbqdaqOEtKTUKELBEk58u83wBNw,357
21
- aiwaf-0.1.9.0.1.dist-info/licenses/LICENSE,sha256=Ir8PX4dxgAcdB0wqNPIkw84fzIIRKE75NoUil9RX0QU,1069
22
- aiwaf-0.1.9.0.1.dist-info/METADATA,sha256=PfFRoPruk3Dx51ERtgqdk61ig9PsY0FL-EpmQFjBTNY,13002
23
- aiwaf-0.1.9.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- aiwaf-0.1.9.0.1.dist-info/top_level.txt,sha256=kU6EyjobT6UPCxuWpI_BvcHDG0I2tMgKaPlWzVxe2xI,6
25
- aiwaf-0.1.9.0.1.dist-info/RECORD,,
22
+ aiwaf-0.1.9.0.3.dist-info/licenses/LICENSE,sha256=Ir8PX4dxgAcdB0wqNPIkw84fzIIRKE75NoUil9RX0QU,1069
23
+ aiwaf-0.1.9.0.3.dist-info/METADATA,sha256=-5zOyXmpp_KL_C1kCtgKOqyUT4gS2cCzpoM8UOupfeY,13571
24
+ aiwaf-0.1.9.0.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
25
+ aiwaf-0.1.9.0.3.dist-info/top_level.txt,sha256=kU6EyjobT6UPCxuWpI_BvcHDG0I2tMgKaPlWzVxe2xI,6
26
+ aiwaf-0.1.9.0.3.dist-info/RECORD,,