aiwaf 0.1.9.1.8__tar.gz → 0.1.9.2.0__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 (42) hide show
  1. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/PKG-INFO +121 -12
  2. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/README.md +120 -11
  3. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/__init__.py +1 -1
  4. aiwaf-0.1.9.2.0/aiwaf/management/commands/aiwaf_reset.py +183 -0
  5. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/middleware.py +210 -42
  6. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/storage.py +23 -0
  7. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/trainer.py +90 -9
  8. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf.egg-info/PKG-INFO +121 -12
  9. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/pyproject.toml +1 -1
  10. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/setup.py +1 -1
  11. aiwaf-0.1.9.1.8/aiwaf/management/commands/aiwaf_reset.py +0 -136
  12. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/LICENSE +0 -0
  13. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/apps.py +0 -0
  14. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/blacklist_manager.py +0 -0
  15. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/decorators.py +0 -0
  16. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/__init__.py +0 -0
  17. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/__init__.py +0 -0
  18. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/add_exemption.py +0 -0
  19. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/add_ipexemption.py +0 -0
  20. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/aiwaf_diagnose.py +0 -0
  21. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/aiwaf_logging.py +0 -0
  22. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/check_dependencies.py +0 -0
  23. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/clear_blacklist.py +0 -0
  24. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/clear_cache.py +0 -0
  25. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/debug_csv.py +0 -0
  26. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/detect_and_train.py +0 -0
  27. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/diagnose_blocking.py +0 -0
  28. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/regenerate_model.py +0 -0
  29. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/setup_models.py +0 -0
  30. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/test_exemption.py +0 -0
  31. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/management/commands/test_exemption_fix.py +0 -0
  32. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/middleware_logger.py +0 -0
  33. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/models.py +0 -0
  34. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/resources/model.pkl +0 -0
  35. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/templatetags/__init__.py +0 -0
  36. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/templatetags/aiwaf_tags.py +0 -0
  37. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf/utils.py +0 -0
  38. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf.egg-info/SOURCES.txt +0 -0
  39. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf.egg-info/dependency_links.txt +0 -0
  40. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf.egg-info/requires.txt +0 -0
  41. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/aiwaf.egg-info/top_level.txt +0 -0
  42. {aiwaf-0.1.9.1.8 → aiwaf-0.1.9.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiwaf
3
- Version: 0.1.9.1.8
3
+ Version: 0.1.9.2.0
4
4
  Summary: AI-powered Web Application Firewall
5
5
  Home-page: https://github.com/aayushgauba/aiwaf
6
6
  Author: Aayush Gauba
@@ -25,7 +25,13 @@ Dynamic: requires-python
25
25
  # AI‑WAF
26
26
 
27
27
  > A self‑learning, Django‑friendly Web Application Firewall
28
- > with rate‑limiting, anomaly detection, honeypots, UUID‑tamper protection, dynamic keyword extraction, file‑extension probing detection, exempt path awareness, and daily retraining.
28
+ > with **enhanced context-aware protection**, rate‑limiting, anomaly detection, honeypots, UUID‑tamper protection, **smart keyword learning**, file‑extension probing detection, exempt path awareness, and daily retraining.
29
+
30
+ **🆕 Latest Enhancements:**
31
+ - ✅ **Smart Keyword Filtering** - Prevents blocking legitimate pages like `/profile/`
32
+ - ✅ **Granular Reset Commands** - Clear specific data types (`--blacklist`, `--keywords`, `--exemptions`)
33
+ - ✅ **Context-Aware Learning** - Only learns from suspicious requests, not legitimate site functionality
34
+ - ✅ **Enhanced Configuration** - `AIWAF_ALLOWED_PATH_KEYWORDS` and `AIWAF_EXEMPT_KEYWORDS`
29
35
 
30
36
  ---
31
37
 
@@ -88,9 +94,14 @@ aiwaf/
88
94
  - Burst count
89
95
  - Total 404s
90
96
 
91
- - **Dynamic Keyword Extraction & Cleanup**
92
- - Every retrain adds top 10 keyword segments from 4xx/5xx paths
93
- - **If a path is added to `AIWAF_EXEMPT_PATHS`, its keywords are automatically removed from the database**
97
+ - **Enhanced Dynamic Keyword Learning**
98
+ - **Smart Context-Aware Learning**: Only learns keywords from suspicious requests on non-existent paths
99
+ - **Legitimate Path Protection**: Automatically excludes keywords from valid Django URLs (like `/profile/`, `/admin/`)
100
+ - **Configuration Options**:
101
+ - `AIWAF_ALLOWED_PATH_KEYWORDS` - Explicitly allow certain keywords in legitimate paths
102
+ - `AIWAF_EXEMPT_KEYWORDS` - Keywords that should never trigger blocking
103
+ - **Automatic Cleanup**: Keywords from `AIWAF_EXEMPT_PATHS` are automatically removed from the database
104
+ - **False Positive Prevention**: Stops learning legitimate site functionality as "malicious"
94
105
 
95
106
  - **File‑Extension Probing Detection**
96
107
  Tracks repeated 404s on common extensions (e.g. `.php`, `.asp`) and blocks IPs.
@@ -196,20 +207,44 @@ python manage.py add_ipexemption <ip-address> --reason "optional reason"
196
207
 
197
208
  ### Resetting AI-WAF
198
209
 
199
- Clear all blacklist and exemption entries:
210
+ The `aiwaf_reset` command provides **granular control** for clearing different types of data:
200
211
 
201
212
  ```bash
202
- # Clear everything (with confirmation prompt)
213
+ # Clear everything (default - backward compatible)
203
214
  python manage.py aiwaf_reset
204
215
 
205
- # Clear everything without confirmation
216
+ # Clear everything without confirmation prompt
206
217
  python manage.py aiwaf_reset --confirm
207
218
 
208
- # Clear only blacklist entries
209
- python manage.py aiwaf_reset --blacklist-only
219
+ # 🆕 GRANULAR CONTROL - Clear specific data types
220
+ python manage.py aiwaf_reset --blacklist # Clear only blocked IPs
221
+ python manage.py aiwaf_reset --exemptions # Clear only exempted IPs
222
+ python manage.py aiwaf_reset --keywords # Clear only learned keywords
223
+
224
+ # 🔧 COMBINE OPTIONS - Mix and match as needed
225
+ python manage.py aiwaf_reset --blacklist --keywords # Keep exemptions
226
+ python manage.py aiwaf_reset --exemptions --keywords # Keep blacklist
227
+ python manage.py aiwaf_reset --blacklist --exemptions # Keep keywords
228
+
229
+ # 🚀 COMMON USE CASES
230
+ # Fix false positive keywords (like "profile" blocking legitimate pages)
231
+ python manage.py aiwaf_reset --keywords --confirm
232
+ python manage.py detect_and_train # Retrain with enhanced filtering
233
+
234
+ # Clear blocked IPs but preserve exemptions and learning
235
+ python manage.py aiwaf_reset --blacklist --confirm
236
+
237
+ # Legacy support (still works for backward compatibility)
238
+ python manage.py aiwaf_reset --blacklist-only # Legacy: blacklist only
239
+ python manage.py aiwaf_reset --exemptions-only # Legacy: exemptions only
240
+ ```
210
241
 
211
- # Clear only exemption entries
212
- python manage.py aiwaf_reset --exemptions-only
242
+ **Enhanced Feedback:**
243
+ ```bash
244
+ $ python manage.py aiwaf_reset --keywords
245
+ 🔧 AI-WAF Reset: Clear 15 learned keywords
246
+ Are you sure you want to proceed? [y/N]: y
247
+ ✅ Reset complete: Deleted 15 learned keywords
213
248
  ```
214
249
 
215
250
  ### Checking Dependencies
@@ -482,6 +517,21 @@ AIWAF_EXEMPT_PATHS = [ # optional but highly recommended
482
517
  "/media/",
483
518
  "/health/",
484
519
  ]
520
+
521
+ # 🆕 ENHANCED KEYWORD FILTERING OPTIONS
522
+ AIWAF_ALLOWED_PATH_KEYWORDS = [ # Keywords allowed in legitimate paths
523
+ "profile", "user", "account", "settings", "dashboard",
524
+ "admin", "api", "auth", "search", "contact", "about",
525
+ # Add your site-specific legitimate keywords
526
+ "buddycraft", "sc2", "starcraft", # Example: gaming site keywords
527
+ ]
528
+
529
+ AIWAF_EXEMPT_KEYWORDS = [ # Keywords that never trigger blocking
530
+ "api", "webhook", "health", "static", "media",
531
+ "upload", "download", "backup", "profile"
532
+ ]
533
+
534
+ AIWAF_DYNAMIC_TOP_N = 10 # Number of dynamic keywords to learn (default: 10)
485
535
  ```
486
536
 
487
537
  > **Note:** You no longer need to define `AIWAF_MALICIOUS_KEYWORDS` or `AIWAF_STATUS_CODES` — they evolve dynamically.
@@ -680,6 +730,65 @@ python manage.py detect_and_train
680
730
 
681
731
  ---
682
732
 
733
+ ## 🔧 Troubleshooting
734
+
735
+ ### Legitimate Pages Being Blocked
736
+
737
+ **Problem**: Users can't access legitimate pages like `/en/profile/` due to keyword blocking.
738
+
739
+ **Cause**: AIWAF learned legitimate keywords (like "profile") as suspicious from previous traffic.
740
+
741
+ **Solution**:
742
+ ```bash
743
+ # 1. Clear problematic learned keywords
744
+ python manage.py aiwaf_reset --keywords --confirm
745
+
746
+ # 2. Add legitimate keywords to settings
747
+ # In settings.py:
748
+ AIWAF_ALLOWED_PATH_KEYWORDS = [
749
+ "profile", "user", "account", "dashboard",
750
+ # Add your site-specific keywords
751
+ ]
752
+
753
+ # 3. Retrain with enhanced filtering (won't learn legitimate keywords)
754
+ python manage.py detect_and_train
755
+
756
+ # 4. Test - legitimate pages should now work!
757
+ ```
758
+
759
+ ### Preventing Future False Positives
760
+
761
+ Configure AIWAF to recognize your site's legitimate keywords:
762
+
763
+ ```python
764
+ # settings.py
765
+ AIWAF_ALLOWED_PATH_KEYWORDS = [
766
+ # Common legitimate keywords
767
+ "profile", "user", "account", "settings", "dashboard",
768
+ "admin", "search", "contact", "about", "help",
769
+
770
+ # Your site-specific keywords
771
+ "buddycraft", "sc2", "starcraft", # Gaming site example
772
+ "shop", "cart", "checkout", # E-commerce example
773
+ "blog", "article", "news", # Content site example
774
+ ]
775
+ ```
776
+
777
+ ### Reset Command Options
778
+
779
+ ```bash
780
+ # Clear everything (safest for troubleshooting)
781
+ python manage.py aiwaf_reset --confirm
782
+
783
+ # Clear only problematic keywords
784
+ python manage.py aiwaf_reset --keywords --confirm
785
+
786
+ # Clear blocked IPs but keep exemptions
787
+ python manage.py aiwaf_reset --blacklist --confirm
788
+ ```
789
+
790
+ ---
791
+
683
792
  ## 🧠 How It Works
684
793
 
685
794
  | Middleware | Purpose |
@@ -2,7 +2,13 @@
2
2
  # AI‑WAF
3
3
 
4
4
  > A self‑learning, Django‑friendly Web Application Firewall
5
- > with rate‑limiting, anomaly detection, honeypots, UUID‑tamper protection, dynamic keyword extraction, file‑extension probing detection, exempt path awareness, and daily retraining.
5
+ > with **enhanced context-aware protection**, rate‑limiting, anomaly detection, honeypots, UUID‑tamper protection, **smart keyword learning**, file‑extension probing detection, exempt path awareness, and daily retraining.
6
+
7
+ **🆕 Latest Enhancements:**
8
+ - ✅ **Smart Keyword Filtering** - Prevents blocking legitimate pages like `/profile/`
9
+ - ✅ **Granular Reset Commands** - Clear specific data types (`--blacklist`, `--keywords`, `--exemptions`)
10
+ - ✅ **Context-Aware Learning** - Only learns from suspicious requests, not legitimate site functionality
11
+ - ✅ **Enhanced Configuration** - `AIWAF_ALLOWED_PATH_KEYWORDS` and `AIWAF_EXEMPT_KEYWORDS`
6
12
 
7
13
  ---
8
14
 
@@ -65,9 +71,14 @@ aiwaf/
65
71
  - Burst count
66
72
  - Total 404s
67
73
 
68
- - **Dynamic Keyword Extraction & Cleanup**
69
- - Every retrain adds top 10 keyword segments from 4xx/5xx paths
70
- - **If a path is added to `AIWAF_EXEMPT_PATHS`, its keywords are automatically removed from the database**
74
+ - **Enhanced Dynamic Keyword Learning**
75
+ - **Smart Context-Aware Learning**: Only learns keywords from suspicious requests on non-existent paths
76
+ - **Legitimate Path Protection**: Automatically excludes keywords from valid Django URLs (like `/profile/`, `/admin/`)
77
+ - **Configuration Options**:
78
+ - `AIWAF_ALLOWED_PATH_KEYWORDS` - Explicitly allow certain keywords in legitimate paths
79
+ - `AIWAF_EXEMPT_KEYWORDS` - Keywords that should never trigger blocking
80
+ - **Automatic Cleanup**: Keywords from `AIWAF_EXEMPT_PATHS` are automatically removed from the database
81
+ - **False Positive Prevention**: Stops learning legitimate site functionality as "malicious"
71
82
 
72
83
  - **File‑Extension Probing Detection**
73
84
  Tracks repeated 404s on common extensions (e.g. `.php`, `.asp`) and blocks IPs.
@@ -173,20 +184,44 @@ python manage.py add_ipexemption <ip-address> --reason "optional reason"
173
184
 
174
185
  ### Resetting AI-WAF
175
186
 
176
- Clear all blacklist and exemption entries:
187
+ The `aiwaf_reset` command provides **granular control** for clearing different types of data:
177
188
 
178
189
  ```bash
179
- # Clear everything (with confirmation prompt)
190
+ # Clear everything (default - backward compatible)
180
191
  python manage.py aiwaf_reset
181
192
 
182
- # Clear everything without confirmation
193
+ # Clear everything without confirmation prompt
183
194
  python manage.py aiwaf_reset --confirm
184
195
 
185
- # Clear only blacklist entries
186
- python manage.py aiwaf_reset --blacklist-only
196
+ # 🆕 GRANULAR CONTROL - Clear specific data types
197
+ python manage.py aiwaf_reset --blacklist # Clear only blocked IPs
198
+ python manage.py aiwaf_reset --exemptions # Clear only exempted IPs
199
+ python manage.py aiwaf_reset --keywords # Clear only learned keywords
200
+
201
+ # 🔧 COMBINE OPTIONS - Mix and match as needed
202
+ python manage.py aiwaf_reset --blacklist --keywords # Keep exemptions
203
+ python manage.py aiwaf_reset --exemptions --keywords # Keep blacklist
204
+ python manage.py aiwaf_reset --blacklist --exemptions # Keep keywords
205
+
206
+ # 🚀 COMMON USE CASES
207
+ # Fix false positive keywords (like "profile" blocking legitimate pages)
208
+ python manage.py aiwaf_reset --keywords --confirm
209
+ python manage.py detect_and_train # Retrain with enhanced filtering
210
+
211
+ # Clear blocked IPs but preserve exemptions and learning
212
+ python manage.py aiwaf_reset --blacklist --confirm
213
+
214
+ # Legacy support (still works for backward compatibility)
215
+ python manage.py aiwaf_reset --blacklist-only # Legacy: blacklist only
216
+ python manage.py aiwaf_reset --exemptions-only # Legacy: exemptions only
217
+ ```
187
218
 
188
- # Clear only exemption entries
189
- python manage.py aiwaf_reset --exemptions-only
219
+ **Enhanced Feedback:**
220
+ ```bash
221
+ $ python manage.py aiwaf_reset --keywords
222
+ 🔧 AI-WAF Reset: Clear 15 learned keywords
223
+ Are you sure you want to proceed? [y/N]: y
224
+ ✅ Reset complete: Deleted 15 learned keywords
190
225
  ```
191
226
 
192
227
  ### Checking Dependencies
@@ -459,6 +494,21 @@ AIWAF_EXEMPT_PATHS = [ # optional but highly recommended
459
494
  "/media/",
460
495
  "/health/",
461
496
  ]
497
+
498
+ # 🆕 ENHANCED KEYWORD FILTERING OPTIONS
499
+ AIWAF_ALLOWED_PATH_KEYWORDS = [ # Keywords allowed in legitimate paths
500
+ "profile", "user", "account", "settings", "dashboard",
501
+ "admin", "api", "auth", "search", "contact", "about",
502
+ # Add your site-specific legitimate keywords
503
+ "buddycraft", "sc2", "starcraft", # Example: gaming site keywords
504
+ ]
505
+
506
+ AIWAF_EXEMPT_KEYWORDS = [ # Keywords that never trigger blocking
507
+ "api", "webhook", "health", "static", "media",
508
+ "upload", "download", "backup", "profile"
509
+ ]
510
+
511
+ AIWAF_DYNAMIC_TOP_N = 10 # Number of dynamic keywords to learn (default: 10)
462
512
  ```
463
513
 
464
514
  > **Note:** You no longer need to define `AIWAF_MALICIOUS_KEYWORDS` or `AIWAF_STATUS_CODES` — they evolve dynamically.
@@ -657,6 +707,65 @@ python manage.py detect_and_train
657
707
 
658
708
  ---
659
709
 
710
+ ## 🔧 Troubleshooting
711
+
712
+ ### Legitimate Pages Being Blocked
713
+
714
+ **Problem**: Users can't access legitimate pages like `/en/profile/` due to keyword blocking.
715
+
716
+ **Cause**: AIWAF learned legitimate keywords (like "profile") as suspicious from previous traffic.
717
+
718
+ **Solution**:
719
+ ```bash
720
+ # 1. Clear problematic learned keywords
721
+ python manage.py aiwaf_reset --keywords --confirm
722
+
723
+ # 2. Add legitimate keywords to settings
724
+ # In settings.py:
725
+ AIWAF_ALLOWED_PATH_KEYWORDS = [
726
+ "profile", "user", "account", "dashboard",
727
+ # Add your site-specific keywords
728
+ ]
729
+
730
+ # 3. Retrain with enhanced filtering (won't learn legitimate keywords)
731
+ python manage.py detect_and_train
732
+
733
+ # 4. Test - legitimate pages should now work!
734
+ ```
735
+
736
+ ### Preventing Future False Positives
737
+
738
+ Configure AIWAF to recognize your site's legitimate keywords:
739
+
740
+ ```python
741
+ # settings.py
742
+ AIWAF_ALLOWED_PATH_KEYWORDS = [
743
+ # Common legitimate keywords
744
+ "profile", "user", "account", "settings", "dashboard",
745
+ "admin", "search", "contact", "about", "help",
746
+
747
+ # Your site-specific keywords
748
+ "buddycraft", "sc2", "starcraft", # Gaming site example
749
+ "shop", "cart", "checkout", # E-commerce example
750
+ "blog", "article", "news", # Content site example
751
+ ]
752
+ ```
753
+
754
+ ### Reset Command Options
755
+
756
+ ```bash
757
+ # Clear everything (safest for troubleshooting)
758
+ python manage.py aiwaf_reset --confirm
759
+
760
+ # Clear only problematic keywords
761
+ python manage.py aiwaf_reset --keywords --confirm
762
+
763
+ # Clear blocked IPs but keep exemptions
764
+ python manage.py aiwaf_reset --blacklist --confirm
765
+ ```
766
+
767
+ ---
768
+
660
769
  ## 🧠 How It Works
661
770
 
662
771
  | Middleware | Purpose |
@@ -1,6 +1,6 @@
1
1
  default_app_config = "aiwaf.apps.AiwafConfig"
2
2
 
3
- __version__ = "0.1.9.1.8"
3
+ __version__ = "0.1.9.2.0"
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
@@ -0,0 +1,183 @@
1
+ from django.core.management.base import BaseCommand
2
+ from aiwaf.storage import get_blacklist_store, get_exemption_store, get_keyword_store
3
+ import sys
4
+
5
+ class Command(BaseCommand):
6
+ help = 'Reset AI-WAF by clearing blacklist, exemption, and/or keyword entries'
7
+
8
+ def add_arguments(self, parser):
9
+ parser.add_argument(
10
+ '--blacklist',
11
+ action='store_true',
12
+ help='Clear blacklist entries (default: all)'
13
+ )
14
+ parser.add_argument(
15
+ '--exemptions',
16
+ action='store_true',
17
+ help='Clear exemption entries (default: all)'
18
+ )
19
+ parser.add_argument(
20
+ '--keywords',
21
+ action='store_true',
22
+ help='Clear learned dynamic keywords (default: all)'
23
+ )
24
+ parser.add_argument(
25
+ '--confirm',
26
+ action='store_true',
27
+ help='Skip confirmation prompt'
28
+ )
29
+
30
+ # Legacy flags for backward compatibility
31
+ parser.add_argument(
32
+ '--blacklist-only',
33
+ action='store_true',
34
+ help='(Legacy) Clear only blacklist entries'
35
+ )
36
+ parser.add_argument(
37
+ '--exemptions-only',
38
+ action='store_true',
39
+ help='(Legacy) Clear only exemption entries'
40
+ )
41
+
42
+ def handle(self, *args, **options):
43
+ # Parse arguments
44
+ blacklist_flag = options.get('blacklist', False)
45
+ exemptions_flag = options.get('exemptions', False)
46
+ keywords_flag = options.get('keywords', False)
47
+ confirm = options.get('confirm', False)
48
+
49
+ # Legacy support
50
+ blacklist_only = options.get('blacklist_only', False)
51
+ exemptions_only = options.get('exemptions_only', False)
52
+
53
+ # Handle legacy flags
54
+ if blacklist_only:
55
+ blacklist_flag = True
56
+ exemptions_flag = False
57
+ keywords_flag = False
58
+ elif exemptions_only:
59
+ blacklist_flag = False
60
+ exemptions_flag = True
61
+ keywords_flag = False
62
+
63
+ # If no specific flags, clear everything
64
+ if not (blacklist_flag or exemptions_flag or keywords_flag):
65
+ blacklist_flag = exemptions_flag = keywords_flag = True
66
+
67
+ try:
68
+ blacklist_store = get_blacklist_store()
69
+ exemption_store = get_exemption_store()
70
+ keyword_store = get_keyword_store()
71
+ except Exception as e:
72
+ self.stdout.write(self.style.ERROR(f'Error initializing stores: {e}'))
73
+ return
74
+
75
+ # Count current entries safely
76
+ counts = {'blacklist': 0, 'exemptions': 0, 'keywords': 0}
77
+ entries = {'blacklist': [], 'exemptions': [], 'keywords': []}
78
+
79
+ if blacklist_flag:
80
+ try:
81
+ entries['blacklist'] = blacklist_store.get_all()
82
+ counts['blacklist'] = len(entries['blacklist'])
83
+ except Exception as e:
84
+ self.stdout.write(self.style.WARNING(f'Warning: Could not count blacklist entries: {e}'))
85
+
86
+ if exemptions_flag:
87
+ try:
88
+ entries['exemptions'] = exemption_store.get_all()
89
+ counts['exemptions'] = len(entries['exemptions'])
90
+ except Exception as e:
91
+ self.stdout.write(self.style.WARNING(f'Warning: Could not count exemption entries: {e}'))
92
+
93
+ if keywords_flag:
94
+ try:
95
+ entries['keywords'] = keyword_store.get_all_keywords()
96
+ counts['keywords'] = len(entries['keywords'])
97
+ except Exception as e:
98
+ self.stdout.write(self.style.WARNING(f'Warning: Could not count keyword entries: {e}'))
99
+
100
+ # Build action description
101
+ actions = []
102
+ if blacklist_flag:
103
+ actions.append(f"{counts['blacklist']} blacklist entries")
104
+ if exemptions_flag:
105
+ actions.append(f"{counts['exemptions']} exemption entries")
106
+ if keywords_flag:
107
+ actions.append(f"{counts['keywords']} learned keywords")
108
+
109
+ action = "Clear " + ", ".join(actions)
110
+
111
+ # Show what will be cleared
112
+ self.stdout.write(f"🔧 AI-WAF Reset: {action}")
113
+
114
+ if not confirm:
115
+ try:
116
+ response = input("Are you sure you want to proceed? [y/N]: ")
117
+ if response.lower() not in ['y', 'yes']:
118
+ self.stdout.write(self.style.WARNING('Operation cancelled'))
119
+ return
120
+ except (EOFError, KeyboardInterrupt):
121
+ self.stdout.write(self.style.WARNING('\nOperation cancelled'))
122
+ return
123
+
124
+ # Perform the reset
125
+ deleted_counts = {'blacklist': 0, 'exemptions': 0, 'keywords': 0, 'errors': []}
126
+
127
+ if blacklist_flag:
128
+ # Clear blacklist entries
129
+ try:
130
+ for entry in entries['blacklist']:
131
+ try:
132
+ blacklist_store.remove_ip(entry['ip_address'])
133
+ deleted_counts['blacklist'] += 1
134
+ except Exception as e:
135
+ deleted_counts['errors'].append(f"Error removing blacklist IP {entry.get('ip_address', 'unknown')}: {e}")
136
+ except Exception as e:
137
+ deleted_counts['errors'].append(f"Error clearing blacklist: {e}")
138
+
139
+ if exemptions_flag:
140
+ # Clear exemption entries
141
+ try:
142
+ for entry in entries['exemptions']:
143
+ try:
144
+ exemption_store.remove_ip(entry['ip_address'])
145
+ deleted_counts['exemptions'] += 1
146
+ except Exception as e:
147
+ deleted_counts['errors'].append(f"Error removing exemption IP {entry.get('ip_address', 'unknown')}: {e}")
148
+ except Exception as e:
149
+ deleted_counts['errors'].append(f"Error clearing exemptions: {e}")
150
+
151
+ if keywords_flag:
152
+ # Clear keyword entries
153
+ try:
154
+ for keyword in entries['keywords']:
155
+ try:
156
+ keyword_store.remove_keyword(keyword)
157
+ deleted_counts['keywords'] += 1
158
+ except Exception as e:
159
+ deleted_counts['errors'].append(f"Error removing keyword '{keyword}': {e}")
160
+ except Exception as e:
161
+ deleted_counts['errors'].append(f"Error clearing keywords: {e}")
162
+
163
+ # Report results
164
+ if deleted_counts['errors']:
165
+ for error in deleted_counts['errors']:
166
+ self.stdout.write(self.style.WARNING(f"⚠️ {error}"))
167
+
168
+ # Build success message
169
+ success_parts = []
170
+ if blacklist_flag:
171
+ success_parts.append(f"{deleted_counts['blacklist']} blacklist entries")
172
+ if exemptions_flag:
173
+ success_parts.append(f"{deleted_counts['exemptions']} exemption entries")
174
+ if keywords_flag:
175
+ success_parts.append(f"{deleted_counts['keywords']} learned keywords")
176
+
177
+ success_message = "✅ Reset complete: Deleted " + ", ".join(success_parts)
178
+ self.stdout.write(self.style.SUCCESS(success_message))
179
+
180
+ if deleted_counts['errors']:
181
+ self.stdout.write(
182
+ self.style.WARNING(f"⚠️ Completed with {len(deleted_counts['errors'])} errors (see above)")
183
+ )