aiwaf 0.1.8.3__tar.gz → 0.1.8.4__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 (27) hide show
  1. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/PKG-INFO +12 -2
  2. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/README.md +11 -1
  3. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/middleware.py +18 -0
  4. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/trainer.py +33 -6
  5. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf.egg-info/PKG-INFO +12 -2
  6. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/pyproject.toml +1 -1
  7. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/setup.py +1 -1
  8. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/LICENSE +0 -0
  9. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/__init__.py +0 -0
  10. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/apps.py +0 -0
  11. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/blacklist_manager.py +0 -0
  12. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/management/__init__.py +0 -0
  13. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/management/commands/__init__.py +0 -0
  14. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/management/commands/add_ipexemption.py +0 -0
  15. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/management/commands/aiwaf_reset.py +0 -0
  16. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/management/commands/detect_and_train.py +0 -0
  17. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/models.py +0 -0
  18. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/resources/model.pkl +0 -0
  19. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/storage.py +0 -0
  20. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/templatetags/__init__.py +0 -0
  21. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/templatetags/aiwaf_tags.py +0 -0
  22. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf/utils.py +0 -0
  23. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf.egg-info/SOURCES.txt +0 -0
  24. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf.egg-info/dependency_links.txt +0 -0
  25. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf.egg-info/requires.txt +0 -0
  26. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/aiwaf.egg-info/top_level.txt +0 -0
  27. {aiwaf-0.1.8.3 → aiwaf-0.1.8.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiwaf
3
- Version: 0.1.8.3
3
+ Version: 0.1.8.4
4
4
  Summary: AI-powered Web Application Firewall
5
5
  Home-page: https://github.com/aayushgauba/aiwaf
6
6
  Author: Aayush Gauba
@@ -89,7 +89,17 @@ aiwaf/
89
89
  **Exempt Path & IP Awareness**
90
90
 
91
91
  **Exempt Paths:**
92
- Set `AIWAF_EXEMPT_PATHS` in your Django `settings.py` (not in your code). Fully respects this setting across all modules exempt paths are:
92
+ AI‑WAF automatically exempts common login paths (`/admin/`, `/login/`, `/accounts/login/`, etc.) from all blocking mechanisms. You can add additional exempt paths in your Django `settings.py`:
93
+
94
+ ```python
95
+ AIWAF_EXEMPT_PATHS = [
96
+ "/api/webhooks/",
97
+ "/health/",
98
+ "/special-endpoint/",
99
+ ]
100
+ ```
101
+
102
+ All exempt paths are:
93
103
  - Skipped from keyword learning
94
104
  - Immune to AI blocking
95
105
  - Ignored in log training
@@ -68,7 +68,17 @@ aiwaf/
68
68
  **Exempt Path & IP Awareness**
69
69
 
70
70
  **Exempt Paths:**
71
- Set `AIWAF_EXEMPT_PATHS` in your Django `settings.py` (not in your code). Fully respects this setting across all modules exempt paths are:
71
+ AI‑WAF automatically exempts common login paths (`/admin/`, `/login/`, `/accounts/login/`, etc.) from all blocking mechanisms. You can add additional exempt paths in your Django `settings.py`:
72
+
73
+ ```python
74
+ AIWAF_EXEMPT_PATHS = [
75
+ "/api/webhooks/",
76
+ "/health/",
77
+ "/special-endpoint/",
78
+ ]
79
+ ```
80
+
81
+ All exempt paths are:
72
82
  - Skipped from keyword learning
73
83
  - Immune to AI blocking
74
84
  - Ignored in log training
@@ -22,10 +22,28 @@ def is_ip_exempted(ip):
22
22
 
23
23
  def is_exempt_path(path):
24
24
  path = path.lower()
25
+
26
+ # Default login paths that should always be exempt
27
+ default_login_paths = [
28
+ "/admin/login/",
29
+ "/admin/",
30
+ "/login/",
31
+ "/accounts/login/",
32
+ "/auth/login/",
33
+ "/signin/",
34
+ ]
35
+
36
+ # Check default login paths
37
+ for login_path in default_login_paths:
38
+ if path.startswith(login_path):
39
+ return True
40
+
41
+ # Check user-configured exempt paths
25
42
  exempt_paths = getattr(settings, "AIWAF_EXEMPT_PATHS", [])
26
43
  for exempt in exempt_paths:
27
44
  if path == exempt or path.startswith(exempt.rstrip("/") + "/"):
28
45
  return True
46
+
29
47
  return False
30
48
 
31
49
  MODEL_PATH = getattr(
@@ -34,6 +34,23 @@ IPExemption = apps.get_model("aiwaf", "IPExemption")
34
34
 
35
35
  def is_exempt_path(path: str) -> bool:
36
36
  path = path.lower()
37
+
38
+ # Default login paths that should always be exempt
39
+ default_login_paths = [
40
+ "/admin/login/",
41
+ "/admin/",
42
+ "/login/",
43
+ "/accounts/login/",
44
+ "/auth/login/",
45
+ "/signin/",
46
+ ]
47
+
48
+ # Check default login paths
49
+ for login_path in default_login_paths:
50
+ if path.startswith(login_path):
51
+ return True
52
+
53
+ # Check user-configured exempt paths
37
54
  for exempt in getattr(settings, "AIWAF_EXEMPT_PATHS", []):
38
55
  if path == exempt or path.startswith(exempt.rstrip("/") + "/"):
39
56
  return True
@@ -116,6 +133,7 @@ def train() -> None:
116
133
 
117
134
  parsed = []
118
135
  ip_404 = defaultdict(int)
136
+ ip_404_login = defaultdict(int) # Track 404s on login paths separately
119
137
  ip_times = defaultdict(list)
120
138
 
121
139
  for line in raw_lines:
@@ -125,15 +143,24 @@ def train() -> None:
125
143
  parsed.append(rec)
126
144
  ip_times[rec["ip"]].append(rec["timestamp"])
127
145
  if rec["status"] == "404":
128
- ip_404[rec["ip"]] += 1
146
+ if is_exempt_path(rec["path"]):
147
+ ip_404_login[rec["ip"]] += 1 # Login path 404s
148
+ else:
149
+ ip_404[rec["ip"]] += 1 # Non-login path 404s
129
150
 
130
- # 3. Optional immediate 404‐flood blocking
151
+ # 3. Optional immediate 404‐flood blocking (only for non-login paths)
131
152
  for ip, count in ip_404.items():
132
153
  if count >= 6:
133
- BlacklistEntry.objects.get_or_create(
134
- ip_address=ip,
135
- defaults={"reason": "Excessive 404s (≥6)"}
136
- )
154
+ # Only block if they have significant non-login 404s
155
+ login_404s = ip_404_login.get(ip, 0)
156
+ total_404s = count + login_404s
157
+
158
+ # Don't block if majority of 404s are on login paths
159
+ if count > login_404s: # More non-login 404s than login 404s
160
+ BlacklistEntry.objects.get_or_create(
161
+ ip_address=ip,
162
+ defaults={"reason": f"Excessive 404s (≥6 non-login, {count}/{total_404s})"}
163
+ )
137
164
 
138
165
  feature_dicts = []
139
166
  for r in parsed:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiwaf
3
- Version: 0.1.8.3
3
+ Version: 0.1.8.4
4
4
  Summary: AI-powered Web Application Firewall
5
5
  Home-page: https://github.com/aayushgauba/aiwaf
6
6
  Author: Aayush Gauba
@@ -89,7 +89,17 @@ aiwaf/
89
89
  **Exempt Path & IP Awareness**
90
90
 
91
91
  **Exempt Paths:**
92
- Set `AIWAF_EXEMPT_PATHS` in your Django `settings.py` (not in your code). Fully respects this setting across all modules exempt paths are:
92
+ AI‑WAF automatically exempts common login paths (`/admin/`, `/login/`, `/accounts/login/`, etc.) from all blocking mechanisms. You can add additional exempt paths in your Django `settings.py`:
93
+
94
+ ```python
95
+ AIWAF_EXEMPT_PATHS = [
96
+ "/api/webhooks/",
97
+ "/health/",
98
+ "/special-endpoint/",
99
+ ]
100
+ ```
101
+
102
+ All exempt paths are:
93
103
  - Skipped from keyword learning
94
104
  - Immune to AI blocking
95
105
  - Ignored in log training
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aiwaf"
3
- version = "0.1.8.3"
3
+ version = "0.1.8.4"
4
4
  description = "AI-powered Web Application Firewall"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.8"
@@ -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.8.3",
12
+ version="0.1.8.4",
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