aiwaf 0.1.9.0.5__tar.gz → 0.1.9.0.6__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.

Files changed (41) hide show
  1. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/PKG-INFO +30 -27
  2. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/README.md +29 -26
  3. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/__init__.py +1 -1
  4. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/blacklist_manager.py +3 -3
  5. aiwaf-0.1.9.0.6/aiwaf/management/commands/add_exemption.py +30 -0
  6. aiwaf-0.1.9.0.6/aiwaf/management/commands/clear_cache.py +18 -0
  7. aiwaf-0.1.9.0.6/aiwaf/management/commands/diagnose_blocking.py +96 -0
  8. aiwaf-0.1.9.0.6/aiwaf/management/commands/setup_models.py +35 -0
  9. aiwaf-0.1.9.0.6/aiwaf/middleware_logger.py +129 -0
  10. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/models.py +28 -1
  11. aiwaf-0.1.9.0.6/aiwaf/storage.py +229 -0
  12. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/trainer.py +0 -12
  13. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf.egg-info/PKG-INFO +30 -27
  14. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf.egg-info/SOURCES.txt +4 -1
  15. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/pyproject.toml +1 -1
  16. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/setup.py +1 -1
  17. aiwaf-0.1.9.0.5/aiwaf/management/commands/debug_csv.py +0 -155
  18. aiwaf-0.1.9.0.5/aiwaf/middleware_logger.py +0 -169
  19. aiwaf-0.1.9.0.5/aiwaf/storage.py +0 -444
  20. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/LICENSE +0 -0
  21. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/apps.py +0 -0
  22. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/decorators.py +0 -0
  23. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/management/__init__.py +0 -0
  24. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/management/commands/__init__.py +0 -0
  25. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/management/commands/add_ipexemption.py +0 -0
  26. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/management/commands/aiwaf_diagnose.py +0 -0
  27. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/management/commands/aiwaf_logging.py +0 -0
  28. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/management/commands/aiwaf_reset.py +0 -0
  29. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/management/commands/detect_and_train.py +0 -0
  30. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/management/commands/regenerate_model.py +0 -0
  31. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/management/commands/test_exemption.py +0 -0
  32. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/management/commands/test_exemption_fix.py +0 -0
  33. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/middleware.py +0 -0
  34. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/resources/model.pkl +0 -0
  35. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/templatetags/__init__.py +0 -0
  36. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/templatetags/aiwaf_tags.py +0 -0
  37. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf/utils.py +0 -0
  38. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf.egg-info/dependency_links.txt +0 -0
  39. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf.egg-info/requires.txt +0 -0
  40. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/aiwaf.egg-info/top_level.txt +0 -0
  41. {aiwaf-0.1.9.0.5 → aiwaf-0.1.9.0.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiwaf
3
- Version: 0.1.9.0.5
3
+ Version: 0.1.9.0.6
4
4
  Summary: AI-powered Web Application Firewall
5
5
  Home-page: https://github.com/aayushgauba/aiwaf
6
6
  Author: Aayush Gauba
@@ -68,7 +68,7 @@ aiwaf/
68
68
  ## 🚀 Features
69
69
 
70
70
  - **IP Blocklist**
71
- Instantly blocks suspicious IPs (supports CSV fallback or Django model).
71
+ Instantly blocks suspicious IPs using Django models with real-time performance.
72
72
 
73
73
  - **Rate Limiting**
74
74
  Sliding‑window blocks flooders (> `AIWAF_RATE_MAX` per `AIWAF_RATE_WINDOW`), then blacklists them.
@@ -98,9 +98,9 @@ aiwaf/
98
98
  Blocks guessed or invalid UUIDs that don't resolve to real models.
99
99
 
100
100
  - **Built-in Request Logger**
101
- Optional middleware logger that captures requests to CSV:
101
+ Optional middleware logger that captures requests to Django models:
102
102
  - **Automatic fallback** when main access logs unavailable
103
- - **CSV format** for easy analysis and training
103
+ - **Real-time storage** in database for instant access
104
104
  - **Captures response times** for better anomaly detection
105
105
  - **Zero configuration** - works out of the box
106
106
 
@@ -221,28 +221,33 @@ AIWAF_ACCESS_LOG = "/var/log/nginx/access.log"
221
221
 
222
222
  ---
223
223
 
224
- ### Storage Configuration
224
+ ### Database Models
225
225
 
226
- **Choose storage backend:**
226
+ AI-WAF uses Django models for real-time, high-performance storage:
227
227
 
228
228
  ```python
229
- # Use Django models (default) - requires database tables
230
- AIWAF_STORAGE_MODE = "models"
231
-
232
- # OR use CSV files - no database required
233
- AIWAF_STORAGE_MODE = "csv"
234
- AIWAF_CSV_DATA_DIR = "aiwaf_data" # Directory for CSV files
229
+ # All data is stored in Django models - no configuration needed
230
+ # Tables created automatically with migrations:
231
+ # - aiwaf_blacklistentry # Blocked IP addresses
232
+ # - aiwaf_ipexemption # Exempt IP addresses
233
+ # - aiwaf_dynamickeyword # Dynamic keywords with counts
234
+ # - aiwaf_featuresample # Feature samples for ML training
235
+ # - aiwaf_requestlog # Request logs (if middleware logging enabled)
235
236
  ```
236
237
 
237
- **CSV Mode Features:**
238
- - No database migrations required
239
- - Files stored in `aiwaf_data/` directory:
240
- - `blacklist.csv` - Blocked IP addresses
241
- - `exemptions.csv` - Exempt IP addresses
242
- - `keywords.csv` - Dynamic keywords
243
- - `access_samples.csv` - Feature samples for ML training
244
- - Perfect for lightweight deployments or when you prefer file-based storage
245
- - Management commands work identically in both modes
238
+ **Benefits of Django Models:**
239
+ - ⚡ **Real-time performance** - No file I/O bottlenecks
240
+ - 🔄 **Instant updates** - Changes visible immediately across all processes
241
+ - 🚀 **Better concurrency** - No file locking issues
242
+ - 📊 **Rich querying** - Use Django ORM for complex operations
243
+ - 🔍 **Admin integration** - View/manage data through Django admin
244
+
245
+ **Database Setup:**
246
+ ```bash
247
+ # Create and apply migrations
248
+ python manage.py makemigrations aiwaf
249
+ python manage.py migrate aiwaf
250
+ ```
246
251
 
247
252
  ---
248
253
 
@@ -253,8 +258,6 @@ Enable AI-WAF's built-in request logger as a fallback when main access logs aren
253
258
  ```python
254
259
  # Enable middleware logging
255
260
  AIWAF_MIDDLEWARE_LOGGING = True # Enable/disable logging
256
- AIWAF_MIDDLEWARE_LOG = "aiwaf_requests.log" # Log file path
257
- AIWAF_MIDDLEWARE_CSV = True # Use CSV format (recommended)
258
261
  ```
259
262
 
260
263
  **Then add middleware to MIDDLEWARE list:**
@@ -276,8 +279,8 @@ python manage.py aiwaf_logging --clear # Clear log files
276
279
 
277
280
  **Benefits:**
278
281
  - **Automatic fallback** when `AIWAF_ACCESS_LOG` unavailable
279
- - **CSV format** with precise timestamps and response times
280
- - **Zero configuration** - trainer automatically detects and uses CSV logs
282
+ - **Database storage** with precise timestamps and response times
283
+ - **Zero configuration** - trainer automatically detects and uses model logs
281
284
  - **Lightweight** - fails silently to avoid breaking your application
282
285
 
283
286
  ---
@@ -386,7 +389,7 @@ python manage.py detect_and_train
386
389
  ```
387
390
 
388
391
  ### What happens:
389
- 1. Read access logs (incl. rotated or gzipped) **OR** AI-WAF middleware CSV logs
392
+ 1. Read access logs (incl. rotated or gzipped) **OR** AI-WAF middleware model logs
390
393
  2. Auto‑block IPs with ≥ 6 total 404s
391
394
  3. Extract features & train IsolationForest
392
395
  4. Save `model.pkl` with current scikit-learn version
@@ -411,7 +414,7 @@ python manage.py detect_and_train
411
414
  5. Extract top 10 dynamic keywords from 4xx/5xx
412
415
  6. Remove any keywords associated with newly exempt paths
413
416
 
414
- **Note:** If main access log (`AIWAF_ACCESS_LOG`) is unavailable, trainer automatically falls back to AI-WAF middleware CSV logs.
417
+ **Note:** If main access log (`AIWAF_ACCESS_LOG`) is unavailable, trainer automatically falls back to AI-WAF middleware model logs.
415
418
 
416
419
  ---
417
420
 
@@ -47,7 +47,7 @@ aiwaf/
47
47
  ## 🚀 Features
48
48
 
49
49
  - **IP Blocklist**
50
- Instantly blocks suspicious IPs (supports CSV fallback or Django model).
50
+ Instantly blocks suspicious IPs using Django models with real-time performance.
51
51
 
52
52
  - **Rate Limiting**
53
53
  Sliding‑window blocks flooders (> `AIWAF_RATE_MAX` per `AIWAF_RATE_WINDOW`), then blacklists them.
@@ -77,9 +77,9 @@ aiwaf/
77
77
  Blocks guessed or invalid UUIDs that don't resolve to real models.
78
78
 
79
79
  - **Built-in Request Logger**
80
- Optional middleware logger that captures requests to CSV:
80
+ Optional middleware logger that captures requests to Django models:
81
81
  - **Automatic fallback** when main access logs unavailable
82
- - **CSV format** for easy analysis and training
82
+ - **Real-time storage** in database for instant access
83
83
  - **Captures response times** for better anomaly detection
84
84
  - **Zero configuration** - works out of the box
85
85
 
@@ -200,28 +200,33 @@ AIWAF_ACCESS_LOG = "/var/log/nginx/access.log"
200
200
 
201
201
  ---
202
202
 
203
- ### Storage Configuration
203
+ ### Database Models
204
204
 
205
- **Choose storage backend:**
205
+ AI-WAF uses Django models for real-time, high-performance storage:
206
206
 
207
207
  ```python
208
- # Use Django models (default) - requires database tables
209
- AIWAF_STORAGE_MODE = "models"
210
-
211
- # OR use CSV files - no database required
212
- AIWAF_STORAGE_MODE = "csv"
213
- AIWAF_CSV_DATA_DIR = "aiwaf_data" # Directory for CSV files
208
+ # All data is stored in Django models - no configuration needed
209
+ # Tables created automatically with migrations:
210
+ # - aiwaf_blacklistentry # Blocked IP addresses
211
+ # - aiwaf_ipexemption # Exempt IP addresses
212
+ # - aiwaf_dynamickeyword # Dynamic keywords with counts
213
+ # - aiwaf_featuresample # Feature samples for ML training
214
+ # - aiwaf_requestlog # Request logs (if middleware logging enabled)
214
215
  ```
215
216
 
216
- **CSV Mode Features:**
217
- - No database migrations required
218
- - Files stored in `aiwaf_data/` directory:
219
- - `blacklist.csv` - Blocked IP addresses
220
- - `exemptions.csv` - Exempt IP addresses
221
- - `keywords.csv` - Dynamic keywords
222
- - `access_samples.csv` - Feature samples for ML training
223
- - Perfect for lightweight deployments or when you prefer file-based storage
224
- - Management commands work identically in both modes
217
+ **Benefits of Django Models:**
218
+ - ⚡ **Real-time performance** - No file I/O bottlenecks
219
+ - 🔄 **Instant updates** - Changes visible immediately across all processes
220
+ - 🚀 **Better concurrency** - No file locking issues
221
+ - 📊 **Rich querying** - Use Django ORM for complex operations
222
+ - 🔍 **Admin integration** - View/manage data through Django admin
223
+
224
+ **Database Setup:**
225
+ ```bash
226
+ # Create and apply migrations
227
+ python manage.py makemigrations aiwaf
228
+ python manage.py migrate aiwaf
229
+ ```
225
230
 
226
231
  ---
227
232
 
@@ -232,8 +237,6 @@ Enable AI-WAF's built-in request logger as a fallback when main access logs aren
232
237
  ```python
233
238
  # Enable middleware logging
234
239
  AIWAF_MIDDLEWARE_LOGGING = True # Enable/disable logging
235
- AIWAF_MIDDLEWARE_LOG = "aiwaf_requests.log" # Log file path
236
- AIWAF_MIDDLEWARE_CSV = True # Use CSV format (recommended)
237
240
  ```
238
241
 
239
242
  **Then add middleware to MIDDLEWARE list:**
@@ -255,8 +258,8 @@ python manage.py aiwaf_logging --clear # Clear log files
255
258
 
256
259
  **Benefits:**
257
260
  - **Automatic fallback** when `AIWAF_ACCESS_LOG` unavailable
258
- - **CSV format** with precise timestamps and response times
259
- - **Zero configuration** - trainer automatically detects and uses CSV logs
261
+ - **Database storage** with precise timestamps and response times
262
+ - **Zero configuration** - trainer automatically detects and uses model logs
260
263
  - **Lightweight** - fails silently to avoid breaking your application
261
264
 
262
265
  ---
@@ -365,7 +368,7 @@ python manage.py detect_and_train
365
368
  ```
366
369
 
367
370
  ### What happens:
368
- 1. Read access logs (incl. rotated or gzipped) **OR** AI-WAF middleware CSV logs
371
+ 1. Read access logs (incl. rotated or gzipped) **OR** AI-WAF middleware model logs
369
372
  2. Auto‑block IPs with ≥ 6 total 404s
370
373
  3. Extract features & train IsolationForest
371
374
  4. Save `model.pkl` with current scikit-learn version
@@ -390,7 +393,7 @@ python manage.py detect_and_train
390
393
  5. Extract top 10 dynamic keywords from 4xx/5xx
391
394
  6. Remove any keywords associated with newly exempt paths
392
395
 
393
- **Note:** If main access log (`AIWAF_ACCESS_LOG`) is unavailable, trainer automatically falls back to AI-WAF middleware CSV logs.
396
+ **Note:** If main access log (`AIWAF_ACCESS_LOG`) is unavailable, trainer automatically falls back to AI-WAF middleware model logs.
394
397
 
395
398
  ---
396
399
 
@@ -1,6 +1,6 @@
1
1
  default_app_config = "aiwaf.apps.AiwafConfig"
2
2
 
3
- __version__ = "0.1.9.0.5"
3
+ __version__ = "0.1.9.0.6"
4
4
 
5
5
  # Note: Middleware classes are available from aiwaf.middleware
6
6
  # Import them only when needed to avoid circular imports during Django app loading
@@ -12,7 +12,7 @@ class BlacklistManager:
12
12
  return # Don't block exempted IPs
13
13
 
14
14
  store = get_blacklist_store()
15
- store.add_ip(ip, reason)
15
+ store.block_ip(ip, reason)
16
16
 
17
17
  @staticmethod
18
18
  def is_blocked(ip):
@@ -29,9 +29,9 @@ class BlacklistManager:
29
29
  @staticmethod
30
30
  def all_blocked():
31
31
  store = get_blacklist_store()
32
- return store.get_all()
32
+ return store.get_all_blocked_ips()
33
33
 
34
34
  @staticmethod
35
35
  def unblock(ip):
36
36
  store = get_blacklist_store()
37
- store.remove_ip(ip)
37
+ store.unblock_ip(ip)
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from django.core.management.base import BaseCommand
4
+ from aiwaf.storage import get_exemption_store
5
+
6
+ class Command(BaseCommand):
7
+ help = 'Add IP to exemption list using Django models'
8
+
9
+ def add_arguments(self, parser):
10
+ parser.add_argument('ip', help='IP address to exempt')
11
+ parser.add_argument('--reason', default='Manual exemption', help='Reason for exemption')
12
+
13
+ def handle(self, *args, **options):
14
+ ip = options['ip']
15
+ reason = options['reason']
16
+
17
+ self.stdout.write(f"Adding IP {ip} to exemption list...")
18
+
19
+ exemption_store = get_exemption_store()
20
+ exemption_store.add_exemption(ip, reason)
21
+
22
+ # Verify it was added
23
+ if exemption_store.is_exempted(ip):
24
+ self.stdout.write(self.style.SUCCESS(f"✅ Successfully exempted IP: {ip}"))
25
+ else:
26
+ self.stdout.write(self.style.ERROR(f"❌ Failed to exempt IP: {ip}"))
27
+
28
+ # Show all exempted IPs
29
+ all_exempted = exemption_store.get_all_exempted_ips()
30
+ self.stdout.write(f"\nAll exempted IPs: {all_exempted}")
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from django.core.management.base import BaseCommand
4
+ from django.core.cache import cache
5
+
6
+ class Command(BaseCommand):
7
+ help = 'Clear Django cache'
8
+
9
+ def handle(self, *args, **options):
10
+ cache.clear()
11
+ self.stdout.write(self.style.SUCCESS("✅ Django cache cleared successfully!"))
12
+
13
+ # Also show what was cleared
14
+ self.stdout.write("🧹 Cleared all cached data including:")
15
+ self.stdout.write(" - Rate limiting data")
16
+ self.stdout.write(" - Blacklist cache")
17
+ self.stdout.write(" - AI anomaly data")
18
+ self.stdout.write(" - Honeypot timing data")
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from django.core.management.base import BaseCommand
4
+ from django.core.cache import cache
5
+ from aiwaf.blacklist_manager import BlacklistManager
6
+ from aiwaf.storage import get_exemption_store, get_blacklist_store
7
+ from aiwaf.utils import get_ip
8
+ from django.test import RequestFactory
9
+
10
+ class Command(BaseCommand):
11
+ help = 'Comprehensive diagnosis of blocking issues'
12
+
13
+ def add_arguments(self, parser):
14
+ parser.add_argument('--ip', default='97.187.30.95', help='IP address to test')
15
+ parser.add_argument('--clear-cache', action='store_true', help='Clear Django cache')
16
+
17
+ def handle(self, *args, **options):
18
+ test_ip = options['ip']
19
+
20
+ self.stdout.write(f"\n🔍 Comprehensive Blocking Diagnosis for IP: {test_ip}")
21
+ self.stdout.write("=" * 60)
22
+
23
+ if options['clear_cache']:
24
+ cache.clear()
25
+ self.stdout.write("🧹 Cleared Django cache")
26
+
27
+ # 1. Check exemption status
28
+ exemption_store = get_exemption_store()
29
+ is_exempted = exemption_store.is_exempted(test_ip)
30
+ self.stdout.write(f"1. ✅ IP exempted in storage: {is_exempted}")
31
+
32
+ # 2. Check blacklist status
33
+ blacklist_store = get_blacklist_store()
34
+ is_in_blacklist = blacklist_store.is_blocked(test_ip)
35
+ self.stdout.write(f"2. 🚫 IP in blacklist storage: {is_in_blacklist}")
36
+
37
+ # 3. Check BlacklistManager final decision
38
+ manager_blocked = BlacklistManager.is_blocked(test_ip)
39
+ self.stdout.write(f"3. 🎯 BlacklistManager says blocked: {manager_blocked}")
40
+
41
+ # 4. Check Django cache for blacklist entries
42
+ cache_key = f"blacklist:{test_ip}"
43
+ cached_value = cache.get(cache_key)
44
+ self.stdout.write(f"4. 💾 Cache value for blacklist:{test_ip}: {cached_value}")
45
+
46
+ # 5. Test what IP would be detected from a request
47
+ factory = RequestFactory()
48
+
49
+ # Test different scenarios
50
+ scenarios = [
51
+ ("Direct IP", {'REMOTE_ADDR': test_ip}),
52
+ ("X-Forwarded-For", {'HTTP_X_FORWARDED_FOR': test_ip}),
53
+ ("X-Real-IP", {'HTTP_X_REAL_IP': test_ip}),
54
+ ("CloudFlare", {'HTTP_CF_CONNECTING_IP': test_ip}),
55
+ ]
56
+
57
+ self.stdout.write(f"\n5. 🌐 IP Detection Tests:")
58
+ for name, meta in scenarios:
59
+ request = factory.get('/', **meta)
60
+ detected_ip = get_ip(request)
61
+ self.stdout.write(f" {name}: {detected_ip}")
62
+ if detected_ip == test_ip:
63
+ self.stdout.write(f" ✅ Match!")
64
+
65
+ # 6. Check rate limiting cache entries
66
+ self.stdout.write(f"\n6. 🚦 Rate Limiting Cache Entries:")
67
+ rate_keys = [
68
+ f"ratelimit:{test_ip}",
69
+ f"aiwaf:{test_ip}",
70
+ f"honeypot_get:{test_ip}"
71
+ ]
72
+
73
+ for key in rate_keys:
74
+ value = cache.get(key)
75
+ if value:
76
+ self.stdout.write(f" {key}: {value}")
77
+ else:
78
+ self.stdout.write(f" {key}: None")
79
+
80
+ # 7. Summary
81
+ self.stdout.write(f"\n📋 SUMMARY:")
82
+ if is_exempted and not manager_blocked:
83
+ self.stdout.write(self.style.SUCCESS("✅ IP should NOT be blocked"))
84
+ if options.get('still_blocked'):
85
+ self.stdout.write(self.style.WARNING("⚠️ If still blocked, check:"))
86
+ self.stdout.write(" - Web server logs (nginx, apache)")
87
+ self.stdout.write(" - Other middleware or security software")
88
+ self.stdout.write(" - Browser cache/cookies")
89
+ elif not is_exempted:
90
+ self.stdout.write(self.style.WARNING(f"⚠️ IP {test_ip} is NOT exempted"))
91
+ elif manager_blocked:
92
+ self.stdout.write(self.style.ERROR(f"❌ IP is being blocked despite exemption"))
93
+
94
+ self.stdout.write(f"\n💡 To clear all caches and reset:")
95
+ self.stdout.write(f" python manage.py shell -c \"from django.core.cache import cache; cache.clear()\"")
96
+ self.stdout.write(f"=" * 60)
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from django.core.management.base import BaseCommand
4
+ from django.db import transaction
5
+
6
+ class Command(BaseCommand):
7
+ help = 'Create Django database migrations for AI-WAF models (after removing CSV support)'
8
+
9
+ def handle(self, *args, **options):
10
+ self.stdout.write("🔄 Creating AI-WAF database migrations...")
11
+
12
+ try:
13
+ # Import the management command functions
14
+ from django.core.management import call_command
15
+
16
+ # Create migrations for aiwaf app
17
+ self.stdout.write("Creating migrations for aiwaf models...")
18
+ call_command('makemigrations', 'aiwaf', verbosity=2)
19
+
20
+ # Apply migrations
21
+ self.stdout.write("Applying migrations...")
22
+ call_command('migrate', 'aiwaf', verbosity=2)
23
+
24
+ self.stdout.write(self.style.SUCCESS("✅ Successfully created and applied AI-WAF migrations!"))
25
+ self.stdout.write("")
26
+ self.stdout.write("🎯 Next steps:")
27
+ self.stdout.write("1. Add your IP to exemptions: python manage.py add_exemption YOUR_IP")
28
+ self.stdout.write("2. Test the system: python manage.py diagnose_blocking --ip YOUR_IP")
29
+ self.stdout.write("3. Clear any old cache: python manage.py clear_cache")
30
+
31
+ except Exception as e:
32
+ self.stdout.write(self.style.ERROR(f"❌ Error during migration: {e}"))
33
+ self.stdout.write("You may need to run these commands manually:")
34
+ self.stdout.write(" python manage.py makemigrations aiwaf")
35
+ self.stdout.write(" python manage.py migrate aiwaf")
@@ -0,0 +1,129 @@
1
+ # aiwaf/middleware_logger.py
2
+
3
+ import time
4
+ from datetime import datetime
5
+ from django.conf import settings
6
+ from django.utils.deprecation import MiddlewareMixin
7
+ from django.utils import timezone
8
+ from .utils import get_ip
9
+
10
+ # Defer model imports to avoid AppRegistryNotReady during Django app loading
11
+ RequestLog = None
12
+
13
+ def _import_models():
14
+ """Import Django models only when needed and apps are ready."""
15
+ global RequestLog
16
+
17
+ if RequestLog is not None:
18
+ return # Already imported
19
+
20
+ try:
21
+ from django.apps import apps
22
+ if apps.ready and apps.is_installed('aiwaf'):
23
+ from .models import RequestLog
24
+ except (ImportError, RuntimeError, Exception):
25
+ # Keep models as None if can't import
26
+ pass
27
+
28
+ class AIWAFLoggerMiddleware(MiddlewareMixin):
29
+ """
30
+ Middleware that logs requests to Django models for AI-WAF training.
31
+ Acts as a fallback when main access logs are unavailable.
32
+ """
33
+
34
+ def __init__(self, get_response):
35
+ super().__init__(get_response)
36
+ self.log_enabled = getattr(settings, "AIWAF_MIDDLEWARE_LOGGING", False)
37
+
38
+ def process_request(self, request):
39
+ """Store request start time"""
40
+ request._aiwaf_start_time = time.time()
41
+ return None
42
+
43
+ def process_response(self, request, response):
44
+ """Log the completed request to Django model"""
45
+ if not self.log_enabled:
46
+ return response
47
+
48
+ # Calculate response time
49
+ start_time = getattr(request, '_aiwaf_start_time', time.time())
50
+ response_time = time.time() - start_time
51
+
52
+ # Import models and log to database
53
+ _import_models()
54
+ if RequestLog is not None:
55
+ try:
56
+ RequestLog.objects.create(
57
+ ip_address=get_ip(request),
58
+ method=request.method,
59
+ path=request.path[:500], # Truncate long paths
60
+ status_code=response.status_code,
61
+ response_time=response_time,
62
+ user_agent=request.META.get('HTTP_USER_AGENT', '')[:2000], # Truncate long user agents
63
+ referer=request.META.get('HTTP_REFERER', '')[:500], # Truncate long referers
64
+ content_length=response.get('Content-Length', '-'),
65
+ timestamp=timezone.now()
66
+ )
67
+ except Exception as e:
68
+ # Fail silently to avoid breaking the application
69
+ pass
70
+
71
+ return response
72
+
73
+
74
+ class AIWAFModelLogParser:
75
+ """
76
+ Parser for AI-WAF Django model logs that converts them to the format expected by trainer.py
77
+ """
78
+
79
+ @staticmethod
80
+ def parse_model_logs():
81
+ """
82
+ Parse Django model logs and return records in the format expected by trainer.py
83
+ Returns list of dictionaries with keys: ip, timestamp, path, status, referer, user_agent, response_time
84
+ """
85
+ records = []
86
+
87
+ _import_models()
88
+ if RequestLog is None:
89
+ return records
90
+
91
+ try:
92
+ # Get all request logs
93
+ logs = RequestLog.objects.all().order_by('-timestamp')
94
+
95
+ for log in logs:
96
+ record = {
97
+ 'ip': str(log.ip_address),
98
+ 'timestamp': log.timestamp,
99
+ 'path': log.path,
100
+ 'status': str(log.status_code),
101
+ 'referer': log.referer if log.referer else '-',
102
+ 'user_agent': log.user_agent if log.user_agent else '-',
103
+ 'response_time': log.response_time
104
+ }
105
+ records.append(record)
106
+ except Exception as e:
107
+ # Return empty list if models can't be accessed
108
+ pass
109
+
110
+ return records
111
+
112
+ @staticmethod
113
+ def get_log_lines_for_trainer():
114
+ """
115
+ Convert Django model logs to format compatible with trainer.py's _read_all_logs()
116
+ Returns list of log line strings
117
+ """
118
+ records = AIWAFModelLogParser.parse_model_logs()
119
+ log_lines = []
120
+
121
+ for record in records:
122
+ # Convert to common log format that trainer.py expects
123
+ timestamp_str = record['timestamp'].strftime('%d/%b/%Y:%H:%M:%S +0000')
124
+ content_length = '-' # We don't track this in detail
125
+
126
+ log_line = f'{record["ip"]} - - [{timestamp_str}] "{record.get("method", "GET")} {record["path"]} HTTP/1.1" {record["status"]} {content_length} "{record["referer"]}" "{record["user_agent"]}" response-time={record["response_time"]:.3f}'
127
+ log_lines.append(log_line)
128
+
129
+ return log_lines
@@ -43,4 +43,31 @@ class IPExemption(models.Model):
43
43
  created_at = models.DateTimeField(auto_now_add=True)
44
44
 
45
45
  def __str__(self):
46
- return f"{self.ip_address} (Exempted: {self.reason})"
46
+ return f"{self.ip_address} (Exempted: {self.reason})"
47
+
48
+
49
+ # Model to store request logs for AI-WAF training
50
+ class RequestLog(models.Model):
51
+ ip_address = models.GenericIPAddressField(db_index=True)
52
+ method = models.CharField(max_length=10)
53
+ path = models.CharField(max_length=500)
54
+ status_code = models.IntegerField()
55
+ response_time = models.FloatField()
56
+ user_agent = models.TextField(blank=True, default="")
57
+ referer = models.CharField(max_length=500, blank=True, default="")
58
+ content_length = models.CharField(max_length=20, blank=True, default="-")
59
+ timestamp = models.DateTimeField(auto_now_add=True)
60
+
61
+ class Meta:
62
+ verbose_name = "Request Log"
63
+ verbose_name_plural = "Request Logs"
64
+ indexes = [
65
+ models.Index(fields=["ip_address"]),
66
+ models.Index(fields=["timestamp"]),
67
+ models.Index(fields=["status_code"]),
68
+ models.Index(fields=["method"]),
69
+ ]
70
+ ordering = ['-timestamp']
71
+
72
+ def __str__(self):
73
+ return f"{self.ip_address} {self.method} {self.path} - {self.status_code}"