aiwaf 0.1.9.1.0__tar.gz → 0.1.9.1.2__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 (39) hide show
  1. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/PKG-INFO +1 -1
  2. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/__init__.py +1 -1
  3. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/trainer.py +42 -7
  4. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf.egg-info/PKG-INFO +1 -1
  5. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/pyproject.toml +1 -1
  6. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/setup.py +1 -1
  7. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/LICENSE +0 -0
  8. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/README.md +0 -0
  9. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/apps.py +0 -0
  10. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/blacklist_manager.py +0 -0
  11. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/decorators.py +0 -0
  12. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/__init__.py +0 -0
  13. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/__init__.py +0 -0
  14. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/add_exemption.py +0 -0
  15. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/add_ipexemption.py +0 -0
  16. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/aiwaf_diagnose.py +0 -0
  17. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/aiwaf_logging.py +0 -0
  18. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/aiwaf_reset.py +0 -0
  19. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/clear_cache.py +0 -0
  20. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/debug_csv.py +0 -0
  21. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/detect_and_train.py +0 -0
  22. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/diagnose_blocking.py +0 -0
  23. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/regenerate_model.py +0 -0
  24. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/setup_models.py +0 -0
  25. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/test_exemption.py +0 -0
  26. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/management/commands/test_exemption_fix.py +0 -0
  27. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/middleware.py +0 -0
  28. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/middleware_logger.py +0 -0
  29. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/models.py +0 -0
  30. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/resources/model.pkl +0 -0
  31. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/storage.py +0 -0
  32. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/templatetags/__init__.py +0 -0
  33. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/templatetags/aiwaf_tags.py +0 -0
  34. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf/utils.py +0 -0
  35. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf.egg-info/SOURCES.txt +0 -0
  36. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf.egg-info/dependency_links.txt +0 -0
  37. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf.egg-info/requires.txt +0 -0
  38. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/aiwaf.egg-info/top_level.txt +0 -0
  39. {aiwaf-0.1.9.1.0 → aiwaf-0.1.9.1.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiwaf
3
- Version: 0.1.9.1.0
3
+ Version: 0.1.9.1.2
4
4
  Summary: AI-powered Web Application Firewall
5
5
  Home-page: https://github.com/aayushgauba/aiwaf
6
6
  Author: Aayush Gauba
@@ -1,6 +1,6 @@
1
1
  default_app_config = "aiwaf.apps.AiwafConfig"
2
2
 
3
- __version__ = "0.1.9.1.0"
3
+ __version__ = "0.1.9.1.2"
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
@@ -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)
@@ -66,7 +67,7 @@ def remove_exempt_keywords() -> None:
66
67
  def _read_all_logs() -> list[str]:
67
68
  lines = []
68
69
 
69
- # First try to read from main access log
70
+ # First try to read from main access log files
70
71
  if LOG_PATH and os.path.exists(LOG_PATH):
71
72
  with open(LOG_PATH, "r", errors="ignore") as f:
72
73
  lines.extend(f.readlines())
@@ -78,9 +79,45 @@ def _read_all_logs() -> list[str]:
78
79
  except OSError:
79
80
  continue
80
81
 
82
+ # If no log files found, fall back to RequestLog model data
83
+ if not lines:
84
+ lines = _get_logs_from_model()
85
+
81
86
  return lines
82
87
 
83
88
 
89
+ def _get_logs_from_model() -> list[str]:
90
+ """Get log data from RequestLog model when log files are not available"""
91
+ try:
92
+ # Import here to avoid circular imports
93
+ from .models import RequestLog
94
+ from datetime import datetime, timedelta
95
+
96
+ # Get logs from the last 30 days
97
+ cutoff_date = datetime.now() - timedelta(days=30)
98
+ request_logs = RequestLog.objects.filter(timestamp__gte=cutoff_date).order_by('timestamp')
99
+
100
+ log_lines = []
101
+ for log in request_logs:
102
+ # Convert RequestLog to Apache-style log format that _parse() expects
103
+ # Format: IP - - [timestamp] "METHOD path HTTP/1.1" status content_length "referer" "user_agent" response-time=X.X
104
+ timestamp_str = log.timestamp.strftime("%d/%b/%Y:%H:%M:%S %z")
105
+ log_line = (
106
+ f'{log.ip_address} - - [{timestamp_str}] '
107
+ f'"{log.method} {log.path} HTTP/1.1" {log.status_code} '
108
+ f'{log.content_length} "{log.referer}" "{log.user_agent}" '
109
+ f'response-time={log.response_time}\n'
110
+ )
111
+ log_lines.append(log_line)
112
+
113
+ print(f"Loaded {len(log_lines)} log entries from RequestLog model")
114
+ return log_lines
115
+
116
+ except Exception as e:
117
+ print(f"Warning: Could not load logs from RequestLog model: {e}")
118
+ return []
119
+
120
+
84
121
  def _parse(line: str) -> dict | None:
85
122
  m = _LOG_RX.search(line)
86
123
  if not m:
@@ -102,13 +139,12 @@ def _parse(line: str) -> dict | None:
102
139
  def train() -> None:
103
140
  remove_exempt_keywords()
104
141
 
105
- # Remove any IPs in IPExemption from the blacklist using storage system
142
+ # Remove any IPs in IPExemption from the blacklist using BlacklistManager
106
143
  exemption_store = get_exemption_store()
107
- blacklist_store = get_blacklist_store()
108
144
 
109
145
  exempted_ips = [entry['ip_address'] for entry in exemption_store.get_all()]
110
146
  for ip in exempted_ips:
111
- blacklist_store.remove_ip(ip)
147
+ BlacklistManager.unblock(ip)
112
148
 
113
149
  raw_lines = _read_all_logs()
114
150
  if not raw_lines:
@@ -141,8 +177,7 @@ def train() -> None:
141
177
 
142
178
  # Don't block if majority of 404s are on login paths
143
179
  if count > login_404s: # More non-login 404s than login 404s
144
- blacklist_store = get_blacklist_store()
145
- blacklist_store.add_ip(ip, f"Excessive 404s (≥6 non-login, {count}/{total_404s})")
180
+ BlacklistManager.block(ip, f"Excessive 404s (≥6 non-login, {count}/{total_404s})")
146
181
 
147
182
  feature_dicts = []
148
183
  for r in parsed:
@@ -239,7 +274,7 @@ def train() -> None:
239
274
  continue
240
275
 
241
276
  # Block if it shows clear signs of malicious behavior
242
- blacklist_store.add_ip(ip, f"AI anomaly + suspicious patterns (kw:{avg_kw_hits:.1f}, 404s:{max_404s}, burst:{avg_burst:.1f})")
277
+ BlacklistManager.block(ip, f"AI anomaly + suspicious patterns (kw:{avg_kw_hits:.1f}, 404s:{max_404s}, burst:{avg_burst:.1f})")
243
278
  blocked_count += 1
244
279
  print(f" - {ip}: Blocked for suspicious behavior (kw:{avg_kw_hits:.1f}, 404s:{max_404s}, burst:{avg_burst:.1f})")
245
280
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiwaf
3
- Version: 0.1.9.1.0
3
+ Version: 0.1.9.1.2
4
4
  Summary: AI-powered Web Application Firewall
5
5
  Home-page: https://github.com/aayushgauba/aiwaf
6
6
  Author: Aayush Gauba
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aiwaf"
3
- version = "0.1.9.1.0"
3
+ version = "0.1.9.1.2"
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.9.1.0",
12
+ version="0.1.9.1.2",
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