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

aiwaf/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  default_app_config = "aiwaf.apps.AiwafConfig"
2
2
 
3
- __version__ = "0.1.9.2.1"
3
+ __version__ = "0.1.9.2.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
@@ -0,0 +1,81 @@
1
+ from django.core.management.base import BaseCommand
2
+ from django.utils import timezone
3
+ from aiwaf.storage import get_blacklist_store, get_exemption_store, get_keyword_store
4
+ from datetime import timedelta
5
+ import json
6
+
7
+ def _sort(items, order):
8
+ reverse = (order == "newest")
9
+ return sorted(items, key=lambda x: x.get("created_at") or timezone.make_aware(timezone.datetime.min),
10
+ reverse=reverse)
11
+
12
+ def _filter_since(items, seconds):
13
+ if not seconds: return items
14
+ cutoff = timezone.now() - timedelta(seconds=seconds)
15
+ return [it for it in items if it.get("created_at") and it["created_at"] >= cutoff]
16
+
17
+ def _print_table(rows, headers):
18
+ widths = [len(h) for h in headers]
19
+ for r in rows:
20
+ for i, cell in enumerate(r):
21
+ widths[i] = max(widths[i], len(str(cell)))
22
+ print(" | ".join(h.ljust(widths[i]) for i, h in enumerate(headers)))
23
+ print("-+-".join("-" * w for w in widths))
24
+ for r in rows:
25
+ print(" | ".join(str(cell).ljust(widths[i]) for i, cell in enumerate(r)))
26
+
27
+ class Command(BaseCommand):
28
+ help = "Lister les données AIWAF (IPs bloquées, exemptions, mots-clés dynamiques)."
29
+
30
+ def add_arguments(self, parser):
31
+ grp = parser.add_mutually_exclusive_group()
32
+ grp.add_argument("--ips", action="store_true", help="Lister les IPs bloquées (défaut).")
33
+ grp.add_argument("--exemptions", action="store_true", help="Lister les IPs exemptées.")
34
+ grp.add_argument("--keywords", action="store_true", help="Lister les mots-clés dynamiques.")
35
+ grp.add_argument("--all", action="store_true", help="Tout lister.")
36
+ parser.add_argument("--format", choices=["table", "json"], default="table")
37
+ parser.add_argument("--limit", type=int, default=100)
38
+ parser.add_argument("--order", choices=["newest", "oldest"], default="newest")
39
+ parser.add_argument("--since", type=int, help="Fenêtre en secondes (ex: 86400 = 24h).")
40
+
41
+ def handle(self, *args, **o):
42
+ if not any([o["exemptions"], o["keywords"], o["all"]]): # défaut = ips
43
+ o["ips"] = True
44
+ payload = {}
45
+
46
+ if o["all"] or o["ips"]:
47
+ data = get_blacklist_store().get_all()
48
+ data = _filter_since(data, o.get("since"))
49
+ data = _sort(data, o["order"])[:o["limit"]]
50
+ payload["ips"] = data
51
+
52
+ if o["all"] or o["exemptions"]:
53
+ data = get_exemption_store().get_all()
54
+ data = _filter_since(data, o.get("since"))
55
+ data = _sort(data, o["order"])[:o["limit"]]
56
+ payload["exemptions"] = data
57
+
58
+ if o["all"] or o["keywords"]:
59
+ kws = get_keyword_store().get_top_keywords(o["limit"])
60
+ payload["keywords"] = [{"keyword": k} for k in kws]
61
+
62
+ if o["format"] == "json":
63
+ def _default(v):
64
+ try: return v.isoformat()
65
+ except Exception: return str(v)
66
+ self.stdout.write(json.dumps(payload, ensure_ascii=False, indent=2, default=_default))
67
+ else:
68
+ if "ips" in payload:
69
+ print("\n== IPs bloquées ==")
70
+ rows = [[r.get("ip_address",""), r.get("reason",""), r.get("created_at","")]
71
+ for r in payload["ips"]]
72
+ _print_table(rows, ["ip_address", "reason", "created_at"])
73
+ if "exemptions" in payload:
74
+ print("\n== Exemptions ==")
75
+ rows = [[r.get("ip_address",""), r.get("reason",""), r.get("created_at","")]
76
+ for r in payload["exemptions"]]
77
+ _print_table(rows, ["ip_address", "reason", "created_at"])
78
+ if "keywords" in payload:
79
+ print("\n== Mots-clés dynamiques ==")
80
+ rows = [[r["keyword"]] for r in payload["keywords"]]
81
+ _print_table(rows, ["keyword"])
aiwaf/trainer.py CHANGED
@@ -34,19 +34,34 @@ def path_exists_in_django(path: str) -> bool:
34
34
  from django.urls import get_resolver
35
35
  from django.urls.resolvers import URLResolver
36
36
 
37
- candidate = path.split("?")[0].lstrip("/")
37
+ candidate = path.split("?")[0].strip("/") # Remove query params and normalize slashes
38
+
39
+ # Try exact resolution first - this is the most reliable method
38
40
  try:
39
41
  get_resolver().resolve(f"/{candidate}")
40
42
  return True
41
43
  except:
42
44
  pass
43
-
44
- root = get_resolver()
45
- for p in root.url_patterns:
46
- if isinstance(p, URLResolver):
47
- prefix = p.pattern.describe().strip("^/")
48
- if prefix and candidate.startswith(prefix):
49
- return True
45
+
46
+ # Also try with trailing slash if it doesn't have one
47
+ if not candidate.endswith("/"):
48
+ try:
49
+ get_resolver().resolve(f"/{candidate}/")
50
+ return True
51
+ except:
52
+ pass
53
+
54
+ # Try without trailing slash if it has one
55
+ if candidate.endswith("/"):
56
+ try:
57
+ get_resolver().resolve(f"/{candidate.rstrip('/')}")
58
+ return True
59
+ except:
60
+ pass
61
+
62
+ # If direct resolution fails, be conservative
63
+ # Only do basic prefix matching for known include patterns
64
+ # but don't assume sub-paths exist just because the prefix exists
50
65
  return False
51
66
 
52
67
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiwaf
3
- Version: 0.1.9.2.1
3
+ Version: 0.1.9.2.2
4
4
  Summary: AI-powered Web Application Firewall
5
5
  Home-page: https://github.com/aayushgauba/aiwaf
6
6
  Author: Aayush Gauba
@@ -1,4 +1,4 @@
1
- aiwaf/__init__.py,sha256=SLcMD_OTXr3DXtHpuCKxFvNl_pjrg-J5KLcJ-Swutuo,220
1
+ aiwaf/__init__.py,sha256=EwzM3mRDf7i5IVX0-pTMpVFRf51lpIIbh6ZzkzOw10M,220
2
2
  aiwaf/apps.py,sha256=nCez-Ptlv2kaEk5HenA8b1pATz1VfhrHP1344gwcY1A,142
3
3
  aiwaf/blacklist_manager.py,sha256=LYCeKFB-7e_C6Bg2WeFJWFIIQlrfRMPuGp30ivrnhQY,1196
4
4
  aiwaf/decorators.py,sha256=IUKOdM_gdroffImRZep1g1wT6gNqD10zGwcp28hsJCs,825
@@ -6,13 +6,14 @@ aiwaf/middleware.py,sha256=8EC4AKfUjHhmVSKpquimkMUebBekr92pqyVF97wlbx0,27408
6
6
  aiwaf/middleware_logger.py,sha256=LWZVDAnjh6CGESirA8eMbhGgJKB7lVDGRQqVroH95Lo,4742
7
7
  aiwaf/models.py,sha256=vQxgY19BDVMjoO903UNrTZC1pNoLltMU6wbyWPoAEns,2719
8
8
  aiwaf/storage.py,sha256=5ImrZMRn3u7HNsPH0fDjWhDrD2tgG2IHVnOXtLz0fk4,10253
9
- aiwaf/trainer.py,sha256=47HP81kTaJCOfyONUm18r-FVc1YeRvcliO_akpX3BqI,18613
9
+ aiwaf/trainer.py,sha256=U-X79nFhSTEbVexFHo3IXFf1HgvXrFnQ__WqTar0o4M,19118
10
10
  aiwaf/utils.py,sha256=BJk5vJCYdGPl_4QQiknjhCbkzv5HZCXgFcBJDMJpHok,3390
11
11
  aiwaf/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  aiwaf/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  aiwaf/management/commands/add_exemption.py,sha256=U_ByfJw1EstAZ8DaSoRb97IGwYzXs0DBJkVAqeN4Wak,1128
14
14
  aiwaf/management/commands/add_ipexemption.py,sha256=sSf3d9hGK9RqqlBYkCrnrd8KZWGT-derSpoWnEY4H60,952
15
15
  aiwaf/management/commands/aiwaf_diagnose.py,sha256=nXFRhq66N4QC3e4scYJ2sUngJce-0yDxtBO3R2BllRM,6134
16
+ aiwaf/management/commands/aiwaf_list.py,sha256=tZK3FugApmPxxvmoB4-nLY9fpZJgiRtD137Bre5hEp8,3839
16
17
  aiwaf/management/commands/aiwaf_logging.py,sha256=FCIqULn2tii2vD9VxL7vk3PV4k4vr7kaA00KyaCExYY,7692
17
18
  aiwaf/management/commands/aiwaf_reset.py,sha256=pcF0zOYDSqjpCwDtk2HYJZLgr76td8OFRENtl20c1dQ,7472
18
19
  aiwaf/management/commands/check_dependencies.py,sha256=GOZl00pDwW2cJjDvIaCeB3yWxmeYcJDRTIpmOTLvy2c,37204
@@ -28,8 +29,8 @@ aiwaf/management/commands/test_exemption_fix.py,sha256=ngyGaHUCmQQ6y--6j4q1viZJt
28
29
  aiwaf/resources/model.pkl,sha256=5t6h9BX8yoh2xct85MXOO60jdlWyg1APskUOW0jZE1Y,1288265
29
30
  aiwaf/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
31
  aiwaf/templatetags/aiwaf_tags.py,sha256=XXfb7Tl4DjU3Sc40GbqdaqOEtKTUKELBEk58u83wBNw,357
31
- aiwaf-0.1.9.2.1.dist-info/licenses/LICENSE,sha256=Ir8PX4dxgAcdB0wqNPIkw84fzIIRKE75NoUil9RX0QU,1069
32
- aiwaf-0.1.9.2.1.dist-info/METADATA,sha256=OgVYn0PPKBDcGCVlhYEFa7uc9XU4Rn-0ZS-W2CE9a1Q,26824
33
- aiwaf-0.1.9.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
- aiwaf-0.1.9.2.1.dist-info/top_level.txt,sha256=kU6EyjobT6UPCxuWpI_BvcHDG0I2tMgKaPlWzVxe2xI,6
35
- aiwaf-0.1.9.2.1.dist-info/RECORD,,
32
+ aiwaf-0.1.9.2.2.dist-info/licenses/LICENSE,sha256=Ir8PX4dxgAcdB0wqNPIkw84fzIIRKE75NoUil9RX0QU,1069
33
+ aiwaf-0.1.9.2.2.dist-info/METADATA,sha256=NFu9QZWsGPcmAJaHeJroSXZL_PstDr33NbSffV94bLQ,26824
34
+ aiwaf-0.1.9.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
+ aiwaf-0.1.9.2.2.dist-info/top_level.txt,sha256=kU6EyjobT6UPCxuWpI_BvcHDG0I2tMgKaPlWzVxe2xI,6
36
+ aiwaf-0.1.9.2.2.dist-info/RECORD,,