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

@@ -0,0 +1,166 @@
1
+ from django.core.management.base import BaseCommand
2
+ from django.conf import settings
3
+ import os
4
+
5
+ class Command(BaseCommand):
6
+ help = 'Manage AI-WAF middleware logging settings and view log status'
7
+
8
+ def add_arguments(self, parser):
9
+ parser.add_argument(
10
+ '--enable',
11
+ action='store_true',
12
+ help='Enable middleware logging (shows settings to add)'
13
+ )
14
+ parser.add_argument(
15
+ '--disable',
16
+ action='store_true',
17
+ help='Disable middleware logging (shows settings to remove)'
18
+ )
19
+ parser.add_argument(
20
+ '--status',
21
+ action='store_true',
22
+ help='Show current middleware logging status'
23
+ )
24
+ parser.add_argument(
25
+ '--clear',
26
+ action='store_true',
27
+ help='Clear/delete middleware log files'
28
+ )
29
+
30
+ def handle(self, *args, **options):
31
+ if options['enable']:
32
+ self._show_enable_instructions()
33
+ elif options['disable']:
34
+ self._show_disable_instructions()
35
+ elif options['clear']:
36
+ self._clear_logs()
37
+ else:
38
+ self._show_status()
39
+
40
+ def _show_status(self):
41
+ """Show current middleware logging configuration"""
42
+ self.stdout.write(self.style.HTTP_INFO("🔍 AI-WAF Middleware Logging Status"))
43
+ self.stdout.write("")
44
+
45
+ # Check settings
46
+ logging_enabled = getattr(settings, 'AIWAF_MIDDLEWARE_LOGGING', False)
47
+ log_file = getattr(settings, 'AIWAF_MIDDLEWARE_LOG', 'aiwaf_requests.log')
48
+ csv_format = getattr(settings, 'AIWAF_MIDDLEWARE_CSV', True)
49
+ csv_file = log_file.replace('.log', '.csv') if csv_format else None
50
+
51
+ # Status
52
+ status_color = self.style.SUCCESS if logging_enabled else self.style.WARNING
53
+ self.stdout.write(f"Status: {status_color('ENABLED' if logging_enabled else 'DISABLED')}")
54
+ self.stdout.write(f"Log File: {log_file}")
55
+ if csv_format:
56
+ self.stdout.write(f"CSV File: {csv_file}")
57
+ self.stdout.write(f"Format: {'CSV' if csv_format else 'Text'}")
58
+ self.stdout.write("")
59
+
60
+ # File existence and sizes
61
+ if logging_enabled:
62
+ self.stdout.write("📁 Log Files:")
63
+
64
+ if csv_format and csv_file:
65
+ if os.path.exists(csv_file):
66
+ size = os.path.getsize(csv_file)
67
+ lines = self._count_csv_lines(csv_file)
68
+ self.stdout.write(f" ✅ {csv_file} ({size:,} bytes, {lines:,} entries)")
69
+ else:
70
+ self.stdout.write(f" ❌ {csv_file} (not found)")
71
+
72
+ if os.path.exists(log_file):
73
+ size = os.path.getsize(log_file)
74
+ self.stdout.write(f" ✅ {log_file} ({size:,} bytes)")
75
+ else:
76
+ self.stdout.write(f" ❌ {log_file} (not found)")
77
+
78
+ # Middleware check
79
+ middleware_list = getattr(settings, 'MIDDLEWARE', [])
80
+ middleware_installed = 'aiwaf.middleware_logger.AIWAFLoggerMiddleware' in middleware_list
81
+
82
+ self.stdout.write("")
83
+ middleware_color = self.style.SUCCESS if middleware_installed else self.style.ERROR
84
+ self.stdout.write(f"Middleware: {middleware_color('INSTALLED' if middleware_installed else 'NOT INSTALLED')}")
85
+
86
+ if logging_enabled and not middleware_installed:
87
+ self.stdout.write(self.style.WARNING("⚠️ Logging is enabled but middleware is not installed!"))
88
+
89
+ def _show_enable_instructions(self):
90
+ """Show instructions for enabling middleware logging"""
91
+ self.stdout.write(self.style.SUCCESS("🚀 Enable AI-WAF Middleware Logging"))
92
+ self.stdout.write("")
93
+ self.stdout.write("Add these settings to your Django settings.py:")
94
+ self.stdout.write("")
95
+ self.stdout.write(self.style.HTTP_INFO("# Enable AI-WAF middleware logging"))
96
+ self.stdout.write(self.style.HTTP_INFO("AIWAF_MIDDLEWARE_LOGGING = True"))
97
+ self.stdout.write(self.style.HTTP_INFO("AIWAF_MIDDLEWARE_LOG = 'aiwaf_requests.log' # Optional"))
98
+ self.stdout.write(self.style.HTTP_INFO("AIWAF_MIDDLEWARE_CSV = True # Optional (default: True)"))
99
+ self.stdout.write("")
100
+ self.stdout.write("Add middleware to MIDDLEWARE list (preferably near the end):")
101
+ self.stdout.write("")
102
+ self.stdout.write(self.style.HTTP_INFO("MIDDLEWARE = ["))
103
+ self.stdout.write(self.style.HTTP_INFO(" # ... your existing middleware ..."))
104
+ self.stdout.write(self.style.HTTP_INFO(" 'aiwaf.middleware_logger.AIWAFLoggerMiddleware',"))
105
+ self.stdout.write(self.style.HTTP_INFO("]"))
106
+ self.stdout.write("")
107
+ self.stdout.write("Benefits:")
108
+ self.stdout.write(" ✅ Fallback when main access logs unavailable")
109
+ self.stdout.write(" ✅ CSV format for easy analysis")
110
+ self.stdout.write(" ✅ Automatic integration with AI-WAF trainer")
111
+ self.stdout.write(" ✅ Captures response times for better detection")
112
+
113
+ def _show_disable_instructions(self):
114
+ """Show instructions for disabling middleware logging"""
115
+ self.stdout.write(self.style.WARNING("⏹️ Disable AI-WAF Middleware Logging"))
116
+ self.stdout.write("")
117
+ self.stdout.write("To disable, update your Django settings.py:")
118
+ self.stdout.write("")
119
+ self.stdout.write(self.style.HTTP_INFO("# Disable AI-WAF middleware logging"))
120
+ self.stdout.write(self.style.HTTP_INFO("AIWAF_MIDDLEWARE_LOGGING = False"))
121
+ self.stdout.write("")
122
+ self.stdout.write("And remove from MIDDLEWARE list:")
123
+ self.stdout.write("")
124
+ self.stdout.write(self.style.HTTP_INFO("MIDDLEWARE = ["))
125
+ self.stdout.write(self.style.HTTP_INFO(" # ... your existing middleware ..."))
126
+ self.stdout.write(self.style.HTTP_INFO(" # 'aiwaf.middleware_logger.AIWAFLoggerMiddleware', # Remove this line"))
127
+ self.stdout.write(self.style.HTTP_INFO("]"))
128
+
129
+ def _clear_logs(self):
130
+ """Clear/delete middleware log files"""
131
+ log_file = getattr(settings, 'AIWAF_MIDDLEWARE_LOG', 'aiwaf_requests.log')
132
+ csv_format = getattr(settings, 'AIWAF_MIDDLEWARE_CSV', True)
133
+ csv_file = log_file.replace('.log', '.csv') if csv_format else None
134
+
135
+ files_deleted = 0
136
+
137
+ # Delete CSV file
138
+ if csv_file and os.path.exists(csv_file):
139
+ try:
140
+ os.remove(csv_file)
141
+ self.stdout.write(self.style.SUCCESS(f"✅ Deleted {csv_file}"))
142
+ files_deleted += 1
143
+ except Exception as e:
144
+ self.stdout.write(self.style.ERROR(f"❌ Failed to delete {csv_file}: {e}"))
145
+
146
+ # Delete text log file
147
+ if os.path.exists(log_file):
148
+ try:
149
+ os.remove(log_file)
150
+ self.stdout.write(self.style.SUCCESS(f"✅ Deleted {log_file}"))
151
+ files_deleted += 1
152
+ except Exception as e:
153
+ self.stdout.write(self.style.ERROR(f"❌ Failed to delete {log_file}: {e}"))
154
+
155
+ if files_deleted == 0:
156
+ self.stdout.write(self.style.WARNING("ℹ️ No log files found to delete"))
157
+ else:
158
+ self.stdout.write(self.style.SUCCESS(f"🗑️ Deleted {files_deleted} log file(s)"))
159
+
160
+ def _count_csv_lines(self, csv_file):
161
+ """Count lines in CSV file (excluding header)"""
162
+ try:
163
+ with open(csv_file, 'r', encoding='utf-8') as f:
164
+ return sum(1 for line in f) - 1 # Subtract header
165
+ except:
166
+ return 0
@@ -0,0 +1,160 @@
1
+ # aiwaf/middleware_logger.py
2
+
3
+ import os
4
+ import csv
5
+ import time
6
+ from datetime import datetime
7
+ from django.conf import settings
8
+ from django.utils.deprecation import MiddlewareMixin
9
+ from .utils import get_ip
10
+
11
+ class AIWAFLoggerMiddleware(MiddlewareMixin):
12
+ """
13
+ Middleware that logs requests to a CSV file for AI-WAF training.
14
+ Acts as a fallback when main access logs are unavailable.
15
+ """
16
+
17
+ def __init__(self, get_response):
18
+ super().__init__(get_response)
19
+ self.log_file = getattr(settings, "AIWAF_MIDDLEWARE_LOG", "aiwaf_requests.log")
20
+ self.csv_format = getattr(settings, "AIWAF_MIDDLEWARE_CSV", True)
21
+ self.log_enabled = getattr(settings, "AIWAF_MIDDLEWARE_LOGGING", False)
22
+
23
+ # CSV file path (if using CSV format)
24
+ if self.csv_format and self.log_enabled:
25
+ self.csv_file = self.log_file.replace('.log', '.csv')
26
+ self._ensure_csv_header()
27
+
28
+ def _ensure_csv_header(self):
29
+ """Ensure CSV file has proper header row"""
30
+ if not os.path.exists(self.csv_file):
31
+ os.makedirs(os.path.dirname(self.csv_file), exist_ok=True) if os.path.dirname(self.csv_file) else None
32
+ with open(self.csv_file, 'w', newline='', encoding='utf-8') as f:
33
+ writer = csv.writer(f)
34
+ writer.writerow([
35
+ 'timestamp', 'ip_address', 'method', 'path', 'status_code',
36
+ 'response_time', 'user_agent', 'referer', 'content_length'
37
+ ])
38
+
39
+ def process_request(self, request):
40
+ """Store request start time"""
41
+ request._aiwaf_start_time = time.time()
42
+ return None
43
+
44
+ def process_response(self, request, response):
45
+ """Log the completed request"""
46
+ if not self.log_enabled:
47
+ return response
48
+
49
+ # Calculate response time
50
+ start_time = getattr(request, '_aiwaf_start_time', time.time())
51
+ response_time = time.time() - start_time
52
+
53
+ # Extract request data
54
+ log_data = {
55
+ 'timestamp': datetime.now().strftime('%d/%b/%Y:%H:%M:%S +0000'),
56
+ 'ip_address': get_ip(request),
57
+ 'method': request.method,
58
+ 'path': request.path,
59
+ 'status_code': response.status_code,
60
+ 'response_time': f"{response_time:.3f}",
61
+ 'user_agent': request.META.get('HTTP_USER_AGENT', '-'),
62
+ 'referer': request.META.get('HTTP_REFERER', '-'),
63
+ 'content_length': response.get('Content-Length', '-')
64
+ }
65
+
66
+ if self.csv_format:
67
+ self._log_to_csv(log_data)
68
+ else:
69
+ self._log_to_text(log_data)
70
+
71
+ return response
72
+
73
+ def _log_to_csv(self, data):
74
+ """Write log entry to CSV file"""
75
+ try:
76
+ with open(self.csv_file, 'a', newline='', encoding='utf-8') as f:
77
+ writer = csv.writer(f)
78
+ writer.writerow([
79
+ data['timestamp'], data['ip_address'], data['method'],
80
+ data['path'], data['status_code'], data['response_time'],
81
+ data['user_agent'], data['referer'], data['content_length']
82
+ ])
83
+ except Exception as e:
84
+ # Fail silently to avoid breaking the application
85
+ pass
86
+
87
+ def _log_to_text(self, data):
88
+ """Write log entry in common log format"""
89
+ try:
90
+ # Common Log Format with response time
91
+ log_line = f'{data["ip_address"]} - - [{data["timestamp"]}] "{data["method"]} {data["path"]} HTTP/1.1" {data["status_code"]} {data["content_length"]} "{data["referer"]}" "{data["user_agent"]}" response-time={data["response_time"]}\n'
92
+
93
+ with open(self.log_file, 'a', encoding='utf-8') as f:
94
+ f.write(log_line)
95
+ except Exception as e:
96
+ # Fail silently to avoid breaking the application
97
+ pass
98
+
99
+
100
+ class AIWAFCSVLogParser:
101
+ """
102
+ Parser for AI-WAF CSV logs that converts them to the format expected by trainer.py
103
+ """
104
+
105
+ @staticmethod
106
+ def parse_csv_log(csv_file_path):
107
+ """
108
+ Parse CSV log file and return records in the format expected by trainer.py
109
+ Returns list of dictionaries with keys: ip, timestamp, path, status, referer, user_agent, response_time
110
+ """
111
+ records = []
112
+
113
+ if not os.path.exists(csv_file_path):
114
+ return records
115
+
116
+ try:
117
+ with open(csv_file_path, 'r', newline='', encoding='utf-8') as f:
118
+ reader = csv.DictReader(f)
119
+ for row in reader:
120
+ try:
121
+ # Convert timestamp to datetime object
122
+ timestamp = datetime.strptime(row['timestamp'], '%d/%b/%Y:%H:%M:%S +0000')
123
+
124
+ record = {
125
+ 'ip': row['ip_address'],
126
+ 'timestamp': timestamp,
127
+ 'path': row['path'],
128
+ 'status': row['status_code'],
129
+ 'referer': row['referer'],
130
+ 'user_agent': row['user_agent'],
131
+ 'response_time': float(row['response_time'])
132
+ }
133
+ records.append(record)
134
+ except (ValueError, KeyError) as e:
135
+ # Skip malformed rows
136
+ continue
137
+ except Exception as e:
138
+ # Return empty list if file can't be read
139
+ pass
140
+
141
+ return records
142
+
143
+ @staticmethod
144
+ def get_log_lines_for_trainer(csv_file_path):
145
+ """
146
+ Convert CSV log to format compatible with trainer.py's _read_all_logs()
147
+ Returns list of log line strings
148
+ """
149
+ records = AIWAFCSVLogParser.parse_csv_log(csv_file_path)
150
+ log_lines = []
151
+
152
+ for record in records:
153
+ # Convert back to common log format that trainer.py expects
154
+ timestamp_str = record['timestamp'].strftime('%d/%b/%Y:%H:%M:%S +0000')
155
+ content_length = '-' # We don't track this in our format
156
+
157
+ log_line = f'{record["ip"]} - - [{timestamp_str}] "GET {record["path"]} HTTP/1.1" {record["status"]} {content_length} "{record["referer"]}" "{record["user_agent"]}" response-time={record["response_time"]:.3f}'
158
+ log_lines.append(log_line)
159
+
160
+ return log_lines
aiwaf/trainer.py CHANGED
@@ -65,16 +65,31 @@ def remove_exempt_keywords() -> None:
65
65
 
66
66
  def _read_all_logs() -> list[str]:
67
67
  lines = []
68
+
69
+ # First try to read from main access log
68
70
  if LOG_PATH and os.path.exists(LOG_PATH):
69
71
  with open(LOG_PATH, "r", errors="ignore") as f:
70
72
  lines.extend(f.readlines())
71
- for p in sorted(glob.glob(f"{LOG_PATH}.*")):
72
- opener = gzip.open if p.endswith(".gz") else open
73
- try:
74
- with opener(p, "rt", errors="ignore") as f:
75
- lines.extend(f.readlines())
76
- except OSError:
77
- continue
73
+ for p in sorted(glob.glob(f"{LOG_PATH}.*")):
74
+ opener = gzip.open if p.endswith(".gz") else open
75
+ try:
76
+ with opener(p, "rt", errors="ignore") as f:
77
+ lines.extend(f.readlines())
78
+ except OSError:
79
+ continue
80
+
81
+ # If no lines found from main log, try AI-WAF middleware CSV log
82
+ if not lines:
83
+ middleware_csv = getattr(settings, "AIWAF_MIDDLEWARE_LOG", "aiwaf_requests.log").replace('.log', '.csv')
84
+ if os.path.exists(middleware_csv):
85
+ try:
86
+ from .middleware_logger import AIWAFCSVLogParser
87
+ csv_lines = AIWAFCSVLogParser.get_log_lines_for_trainer(middleware_csv)
88
+ lines.extend(csv_lines)
89
+ print(f"📋 Using AI-WAF middleware CSV log: {middleware_csv} ({len(csv_lines)} entries)")
90
+ except Exception as e:
91
+ print(f"⚠️ Failed to read middleware CSV log: {e}")
92
+
78
93
  return lines
79
94
 
80
95
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiwaf
3
- Version: 0.1.8.7
3
+ Version: 0.1.8.8
4
4
  Summary: AI-powered Web Application Firewall
5
5
  Home-page: https://github.com/aayushgauba/aiwaf
6
6
  Author: Aayush Gauba
@@ -83,7 +83,28 @@ aiwaf/
83
83
  - Submit forms faster than `AIWAF_MIN_FORM_TIME` seconds (default: 1 second)
84
84
 
85
85
  - **UUID Tampering Protection**
86
- Blocks guessed or invalid UUIDs that dont resolve to real models.
86
+ Blocks guessed or invalid UUIDs that don't resolve to real models.
87
+
88
+ - **Built-in Request Logger**
89
+ Optional middleware logger that captures requests to CSV:
90
+ - **Automatic fallback** when main access logs unavailable
91
+ - **CSV format** for easy analysis and training
92
+ - **Captures response times** for better anomaly detection
93
+ - **Zero configuration** - works out of the box
94
+
95
+
96
+ **Exempt Path & IP Awareness**
97
+
98
+ **Exempt Paths:**
99
+ 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`:
100
+
101
+ ```python
102
+ AIWAF_EXEMPT_PATHS = [
103
+ "/api/webhooks/",
104
+ "/health/",
105
+ "/special-endpoint/",
106
+ ]
107
+ ```
87
108
 
88
109
 
89
110
  **Exempt Path & IP Awareness**
@@ -213,6 +234,42 @@ AIWAF_CSV_DATA_DIR = "aiwaf_data" # Directory for CSV files
213
234
 
214
235
  ---
215
236
 
237
+ ### Built-in Request Logger (Optional)
238
+
239
+ Enable AI-WAF's built-in request logger as a fallback when main access logs aren't available:
240
+
241
+ ```python
242
+ # Enable middleware logging
243
+ AIWAF_MIDDLEWARE_LOGGING = True # Enable/disable logging
244
+ AIWAF_MIDDLEWARE_LOG = "aiwaf_requests.log" # Log file path
245
+ AIWAF_MIDDLEWARE_CSV = True # Use CSV format (recommended)
246
+ ```
247
+
248
+ **Then add middleware to MIDDLEWARE list:**
249
+
250
+ ```python
251
+ MIDDLEWARE = [
252
+ # ... your existing middleware ...
253
+ 'aiwaf.middleware_logger.AIWAFLoggerMiddleware', # Add near the end
254
+ ]
255
+ ```
256
+
257
+ **Manage middleware logging:**
258
+
259
+ ```bash
260
+ python manage.py aiwaf_logging --status # Check logging status
261
+ python manage.py aiwaf_logging --enable # Show setup instructions
262
+ python manage.py aiwaf_logging --clear # Clear log files
263
+ ```
264
+
265
+ **Benefits:**
266
+ - **Automatic fallback** when `AIWAF_ACCESS_LOG` unavailable
267
+ - **CSV format** with precise timestamps and response times
268
+ - **Zero configuration** - trainer automatically detects and uses CSV logs
269
+ - **Lightweight** - fails silently to avoid breaking your application
270
+
271
+ ---
272
+
216
273
  ### Optional (defaults shown)
217
274
 
218
275
  ```python
@@ -244,14 +301,40 @@ Add in **this** order to your `MIDDLEWARE` list:
244
301
  ```python
245
302
  MIDDLEWARE = [
246
303
  "aiwaf.middleware.IPAndKeywordBlockMiddleware",
247
- "aiwaf.middleware.RateLimitMiddleware",
304
+ "aiwaf.middleware.RateLimitMiddleware",
248
305
  "aiwaf.middleware.AIAnomalyMiddleware",
249
306
  "aiwaf.middleware.HoneypotTimingMiddleware",
250
307
  "aiwaf.middleware.UUIDTamperMiddleware",
251
308
  # ... other middleware ...
309
+ "aiwaf.middleware_logger.AIWAFLoggerMiddleware", # Optional: Add if using built-in logger
252
310
  ]
253
311
  ```
254
312
 
313
+ > **⚠️ Order matters!** AI-WAF protection middleware should come early. The logger middleware should come near the end to capture final response data.
314
+
315
+ ---
316
+
317
+ ## Running Detection & Training
318
+
319
+ ```bash
320
+ python manage.py detect_and_train
321
+ ```
322
+
323
+ ### What happens:
324
+ 1. Read access logs (incl. rotated or gzipped) **OR** AI-WAF middleware CSV logs
325
+ 2. Auto‑block IPs with ≥ 6 total 404s
326
+ 3. Extract features & train IsolationForest
327
+ 4. Save `model.pkl`
328
+ 5. Extract top 10 dynamic keywords from 4xx/5xx
329
+ 6. Remove any keywords associated with newly exempt paths
330
+
331
+ **Note:** If main access log (`AIWAF_ACCESS_LOG`) is unavailable, trainer automatically falls back to AI-WAF middleware CSV logs.
332
+
333
+ ---
334
+
335
+ ## 🧠 How It Works
336
+ ```
337
+
255
338
  ---
256
339
 
257
340
  ## Running Detection & Training
@@ -3,20 +3,22 @@ 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
5
  aiwaf/middleware.py,sha256=1JPrc0npI_a5bnB-thN0ME1ehfTbWBl1j9wTndZwRdQ,9505
6
+ aiwaf/middleware_logger.py,sha256=uTYTvIc4Mv1pjY50aXaqQ5cWAO9qqquijAyVMs1KWlM,6517
6
7
  aiwaf/models.py,sha256=XaG1pd_oZu3y-fw66u4wblGlWcUY9gvsTNKGD0kQk7Y,1672
7
8
  aiwaf/storage.py,sha256=Z0KWArfLmOHnvUcL5aVx8W_aHMr-qoEW8FVGrM23BvA,11639
8
- aiwaf/trainer.py,sha256=qzQOtMW0_OA5JWWh6Znbc5BG3gcQ6Cb_NNWMOgLf3VQ,8487
9
+ aiwaf/trainer.py,sha256=bgVoBewnNVMJdgxcNchfhsPOnFXxStoBOqNhFYnpsqs,9244
9
10
  aiwaf/utils.py,sha256=BJk5vJCYdGPl_4QQiknjhCbkzv5HZCXgFcBJDMJpHok,3390
10
11
  aiwaf/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
12
  aiwaf/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
13
  aiwaf/management/commands/add_ipexemption.py,sha256=srgdVPDJtF7G9GGIqaZ7L3qTuNheoS_uwlhlRO4W2bc,945
14
+ aiwaf/management/commands/aiwaf_logging.py,sha256=FCIqULn2tii2vD9VxL7vk3PV4k4vr7kaA00KyaCExYY,7692
13
15
  aiwaf/management/commands/aiwaf_reset.py,sha256=0FIBqpZS8xgFFvAKJ-0zAC_-QNQwRkOHpXb8N-OdFr8,3740
14
16
  aiwaf/management/commands/detect_and_train.py,sha256=-o-LZ7QZ5GeJPCekryox1DGXKMmFEkwwrcDsiM166K0,269
15
17
  aiwaf/resources/model.pkl,sha256=5t6h9BX8yoh2xct85MXOO60jdlWyg1APskUOW0jZE1Y,1288265
16
18
  aiwaf/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
19
  aiwaf/templatetags/aiwaf_tags.py,sha256=XXfb7Tl4DjU3Sc40GbqdaqOEtKTUKELBEk58u83wBNw,357
18
- aiwaf-0.1.8.7.dist-info/licenses/LICENSE,sha256=Ir8PX4dxgAcdB0wqNPIkw84fzIIRKE75NoUil9RX0QU,1069
19
- aiwaf-0.1.8.7.dist-info/METADATA,sha256=qAIF4-sV_Br3BPp6Ivn3fXzY9uWvdtMco1zXBlkKkW0,8664
20
- aiwaf-0.1.8.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
- aiwaf-0.1.8.7.dist-info/top_level.txt,sha256=kU6EyjobT6UPCxuWpI_BvcHDG0I2tMgKaPlWzVxe2xI,6
22
- aiwaf-0.1.8.7.dist-info/RECORD,,
20
+ aiwaf-0.1.8.8.dist-info/licenses/LICENSE,sha256=Ir8PX4dxgAcdB0wqNPIkw84fzIIRKE75NoUil9RX0QU,1069
21
+ aiwaf-0.1.8.8.dist-info/METADATA,sha256=851Url25O97G0KGi3gHFF-zYSaI91BHiK7CbKJrLbk0,11261
22
+ aiwaf-0.1.8.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ aiwaf-0.1.8.8.dist-info/top_level.txt,sha256=kU6EyjobT6UPCxuWpI_BvcHDG0I2tMgKaPlWzVxe2xI,6
24
+ aiwaf-0.1.8.8.dist-info/RECORD,,