guard-core 0.1.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.
Files changed (94) hide show
  1. guard_core-0.1.0/LICENSE +21 -0
  2. guard_core-0.1.0/PKG-INFO +55 -0
  3. guard_core-0.1.0/README.md +2 -0
  4. guard_core-0.1.0/guard_core/__init__.py +42 -0
  5. guard_core-0.1.0/guard_core/core/__init__.py +3 -0
  6. guard_core-0.1.0/guard_core/core/behavioral/__init__.py +4 -0
  7. guard_core-0.1.0/guard_core/core/behavioral/context.py +14 -0
  8. guard_core-0.1.0/guard_core/core/behavioral/processor.py +95 -0
  9. guard_core-0.1.0/guard_core/core/bypass/__init__.py +4 -0
  10. guard_core-0.1.0/guard_core/core/bypass/context.py +18 -0
  11. guard_core-0.1.0/guard_core/core/bypass/handler.py +52 -0
  12. guard_core-0.1.0/guard_core/core/checks/__init__.py +43 -0
  13. guard_core-0.1.0/guard_core/core/checks/base.py +48 -0
  14. guard_core-0.1.0/guard_core/core/checks/helpers.py +174 -0
  15. guard_core-0.1.0/guard_core/core/checks/implementations/__init__.py +65 -0
  16. guard_core-0.1.0/guard_core/core/checks/implementations/authentication.py +60 -0
  17. guard_core-0.1.0/guard_core/core/checks/implementations/cloud_ip_refresh.py +20 -0
  18. guard_core-0.1.0/guard_core/core/checks/implementations/cloud_provider.py +58 -0
  19. guard_core-0.1.0/guard_core/core/checks/implementations/custom_request.py +39 -0
  20. guard_core-0.1.0/guard_core/core/checks/implementations/custom_validators.py +44 -0
  21. guard_core-0.1.0/guard_core/core/checks/implementations/emergency_mode.py +59 -0
  22. guard_core-0.1.0/guard_core/core/checks/implementations/https_enforcement.py +62 -0
  23. guard_core-0.1.0/guard_core/core/checks/implementations/ip_security.py +137 -0
  24. guard_core-0.1.0/guard_core/core/checks/implementations/rate_limit.py +193 -0
  25. guard_core-0.1.0/guard_core/core/checks/implementations/referrer.py +92 -0
  26. guard_core-0.1.0/guard_core/core/checks/implementations/request_logging.py +14 -0
  27. guard_core-0.1.0/guard_core/core/checks/implementations/request_size_content.py +103 -0
  28. guard_core-0.1.0/guard_core/core/checks/implementations/required_headers.py +67 -0
  29. guard_core-0.1.0/guard_core/core/checks/implementations/route_config.py +18 -0
  30. guard_core-0.1.0/guard_core/core/checks/implementations/suspicious_activity.py +130 -0
  31. guard_core-0.1.0/guard_core/core/checks/implementations/time_window.py +69 -0
  32. guard_core-0.1.0/guard_core/core/checks/implementations/user_agent.py +59 -0
  33. guard_core-0.1.0/guard_core/core/checks/pipeline.py +74 -0
  34. guard_core-0.1.0/guard_core/core/events/__init__.py +4 -0
  35. guard_core-0.1.0/guard_core/core/events/metrics.py +56 -0
  36. guard_core-0.1.0/guard_core/core/events/middleware_events.py +121 -0
  37. guard_core-0.1.0/guard_core/core/initialization/__init__.py +5 -0
  38. guard_core-0.1.0/guard_core/core/initialization/handler_initializer.py +94 -0
  39. guard_core-0.1.0/guard_core/core/responses/__init__.py +4 -0
  40. guard_core-0.1.0/guard_core/core/responses/context.py +18 -0
  41. guard_core-0.1.0/guard_core/core/responses/factory.py +93 -0
  42. guard_core-0.1.0/guard_core/core/routing/__init__.py +4 -0
  43. guard_core-0.1.0/guard_core/core/routing/context.py +13 -0
  44. guard_core-0.1.0/guard_core/core/routing/resolver.py +73 -0
  45. guard_core-0.1.0/guard_core/core/validation/__init__.py +4 -0
  46. guard_core-0.1.0/guard_core/core/validation/context.py +12 -0
  47. guard_core-0.1.0/guard_core/core/validation/validator.py +69 -0
  48. guard_core-0.1.0/guard_core/decorators/__init__.py +39 -0
  49. guard_core-0.1.0/guard_core/decorators/access_control.py +64 -0
  50. guard_core-0.1.0/guard_core/decorators/advanced.py +102 -0
  51. guard_core-0.1.0/guard_core/decorators/authentication.py +45 -0
  52. guard_core-0.1.0/guard_core/decorators/base.py +200 -0
  53. guard_core-0.1.0/guard_core/decorators/behavioral.py +77 -0
  54. guard_core-0.1.0/guard_core/decorators/content_filtering.py +59 -0
  55. guard_core-0.1.0/guard_core/decorators/rate_limiting.py +27 -0
  56. guard_core-0.1.0/guard_core/detection_engine/__init__.py +11 -0
  57. guard_core-0.1.0/guard_core/detection_engine/compiler.py +148 -0
  58. guard_core-0.1.0/guard_core/detection_engine/monitor.py +377 -0
  59. guard_core-0.1.0/guard_core/detection_engine/preprocessor.py +291 -0
  60. guard_core-0.1.0/guard_core/detection_engine/semantic.py +340 -0
  61. guard_core-0.1.0/guard_core/exceptions.py +9 -0
  62. guard_core-0.1.0/guard_core/handlers/__init__.py +21 -0
  63. guard_core-0.1.0/guard_core/handlers/behavior_handler.py +308 -0
  64. guard_core-0.1.0/guard_core/handlers/cloud_handler.py +275 -0
  65. guard_core-0.1.0/guard_core/handlers/dynamic_rule_handler.py +319 -0
  66. guard_core-0.1.0/guard_core/handlers/ipban_handler.py +125 -0
  67. guard_core-0.1.0/guard_core/handlers/ipinfo_handler.py +218 -0
  68. guard_core-0.1.0/guard_core/handlers/ratelimit_handler.py +257 -0
  69. guard_core-0.1.0/guard_core/handlers/redis_handler.py +258 -0
  70. guard_core-0.1.0/guard_core/handlers/security_headers_handler.py +462 -0
  71. guard_core-0.1.0/guard_core/handlers/suspatterns_handler.py +841 -0
  72. guard_core-0.1.0/guard_core/models.py +510 -0
  73. guard_core-0.1.0/guard_core/protocols/__init__.py +16 -0
  74. guard_core-0.1.0/guard_core/protocols/agent_protocol.py +15 -0
  75. guard_core-0.1.0/guard_core/protocols/geo_ip_protocol.py +14 -0
  76. guard_core-0.1.0/guard_core/protocols/middleware_protocol.py +38 -0
  77. guard_core-0.1.0/guard_core/protocols/redis_protocol.py +15 -0
  78. guard_core-0.1.0/guard_core/protocols/request_protocol.py +26 -0
  79. guard_core-0.1.0/guard_core/protocols/response_protocol.py +18 -0
  80. guard_core-0.1.0/guard_core/scripts/__init__.py +0 -0
  81. guard_core-0.1.0/guard_core/scripts/rate_lua.py +17 -0
  82. guard_core-0.1.0/guard_core/utils.py +639 -0
  83. guard_core-0.1.0/guard_core.egg-info/PKG-INFO +55 -0
  84. guard_core-0.1.0/guard_core.egg-info/SOURCES.txt +92 -0
  85. guard_core-0.1.0/guard_core.egg-info/dependency_links.txt +1 -0
  86. guard_core-0.1.0/guard_core.egg-info/requires.txt +32 -0
  87. guard_core-0.1.0/guard_core.egg-info/top_level.txt +1 -0
  88. guard_core-0.1.0/pyproject.toml +246 -0
  89. guard_core-0.1.0/setup.cfg +4 -0
  90. guard_core-0.1.0/setup.py +9 -0
  91. guard_core-0.1.0/tests/test_exceptions.py +14 -0
  92. guard_core-0.1.0/tests/test_models.py +215 -0
  93. guard_core-0.1.0/tests/test_protocols.py +53 -0
  94. guard_core-0.1.0/tests/test_utils.py +880 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Renzo F
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.4
2
+ Name: guard-core
3
+ Version: 0.1.0
4
+ Summary: Framework-agnostic security engine for the Guard ecosystem.
5
+ Author-email: Renzo Franceschini <rennf93@users.noreply.github.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/rennf93/guard-core
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Requires-Python: <3.15,>=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: cachetools
22
+ Requires-Dist: httpx
23
+ Requires-Dist: maxminddb
24
+ Requires-Dist: pydantic
25
+ Requires-Dist: redis
26
+ Requires-Dist: requests
27
+ Requires-Dist: typing-extensions
28
+ Provides-Extra: dev
29
+ Requires-Dist: bandit[toml]; extra == "dev"
30
+ Requires-Dist: deptry; extra == "dev"
31
+ Requires-Dist: fastapi-guard-agent; extra == "dev"
32
+ Requires-Dist: httpx; extra == "dev"
33
+ Requires-Dist: mkdocs; extra == "dev"
34
+ Requires-Dist: mkdocstrings; extra == "dev"
35
+ Requires-Dist: mkdocstrings-python; extra == "dev"
36
+ Requires-Dist: mkdocs-material; extra == "dev"
37
+ Requires-Dist: mypy; extra == "dev"
38
+ Requires-Dist: pip-audit; extra == "dev"
39
+ Requires-Dist: pre-commit; extra == "dev"
40
+ Requires-Dist: pymarkdownlnt; extra == "dev"
41
+ Requires-Dist: pytest; extra == "dev"
42
+ Requires-Dist: pytest-asyncio; extra == "dev"
43
+ Requires-Dist: pytest-cov; extra == "dev"
44
+ Requires-Dist: pytest-mock; extra == "dev"
45
+ Requires-Dist: radon; extra == "dev"
46
+ Requires-Dist: ruff; extra == "dev"
47
+ Requires-Dist: safety; extra == "dev"
48
+ Requires-Dist: types-cachetools; extra == "dev"
49
+ Requires-Dist: types-requests; extra == "dev"
50
+ Requires-Dist: vulture; extra == "dev"
51
+ Requires-Dist: xenon; extra == "dev"
52
+ Dynamic: license-file
53
+
54
+ # guard-core
55
+ API Guard Core - Core library for Guard Agent, FastAPI Guard, FlaskAPI Guard and DjAPI Guard
@@ -0,0 +1,2 @@
1
+ # guard-core
2
+ API Guard Core - Core library for Guard Agent, FastAPI Guard, FlaskAPI Guard and DjAPI Guard
@@ -0,0 +1,42 @@
1
+ from guard_core.decorators import RouteConfig, SecurityDecorator
2
+ from guard_core.handlers.behavior_handler import BehaviorRule, BehaviorTracker
3
+ from guard_core.handlers.cloud_handler import CloudManager, cloud_handler
4
+ from guard_core.handlers.ipban_handler import IPBanManager, ip_ban_manager
5
+ from guard_core.handlers.ipinfo_handler import IPInfoManager
6
+ from guard_core.handlers.ratelimit_handler import RateLimitManager, rate_limit_handler
7
+ from guard_core.handlers.redis_handler import RedisManager, redis_handler
8
+ from guard_core.handlers.security_headers_handler import (
9
+ SecurityHeadersManager,
10
+ security_headers_manager,
11
+ )
12
+ from guard_core.handlers.suspatterns_handler import sus_patterns_handler
13
+ from guard_core.models import SecurityConfig
14
+ from guard_core.protocols.geo_ip_protocol import GeoIPHandler
15
+ from guard_core.protocols.redis_protocol import RedisHandlerProtocol
16
+ from guard_core.protocols.request_protocol import GuardRequest
17
+ from guard_core.protocols.response_protocol import GuardResponse, GuardResponseFactory
18
+
19
+ __all__ = [
20
+ "SecurityConfig",
21
+ "SecurityDecorator",
22
+ "RouteConfig",
23
+ "BehaviorTracker",
24
+ "BehaviorRule",
25
+ "ip_ban_manager",
26
+ "IPBanManager",
27
+ "cloud_handler",
28
+ "CloudManager",
29
+ "IPInfoManager",
30
+ "rate_limit_handler",
31
+ "RateLimitManager",
32
+ "redis_handler",
33
+ "RedisManager",
34
+ "security_headers_manager",
35
+ "SecurityHeadersManager",
36
+ "sus_patterns_handler",
37
+ "GeoIPHandler",
38
+ "RedisHandlerProtocol",
39
+ "GuardRequest",
40
+ "GuardResponse",
41
+ "GuardResponseFactory",
42
+ ]
@@ -0,0 +1,3 @@
1
+ from guard_core.core.events import MetricsCollector, SecurityEventBus
2
+
3
+ __all__ = ["SecurityEventBus", "MetricsCollector"]
@@ -0,0 +1,4 @@
1
+ from guard_core.core.behavioral.context import BehavioralContext
2
+ from guard_core.core.behavioral.processor import BehavioralProcessor
3
+
4
+ __all__ = ["BehavioralContext", "BehavioralProcessor"]
@@ -0,0 +1,14 @@
1
+ from dataclasses import dataclass
2
+ from logging import Logger
3
+
4
+ from guard_core.core.events import SecurityEventBus
5
+ from guard_core.decorators.base import BaseSecurityDecorator
6
+ from guard_core.models import SecurityConfig
7
+
8
+
9
+ @dataclass
10
+ class BehavioralContext:
11
+ config: SecurityConfig
12
+ logger: Logger
13
+ event_bus: SecurityEventBus
14
+ guard_decorator: BaseSecurityDecorator | None
@@ -0,0 +1,95 @@
1
+ from guard_core.core.behavioral.context import BehavioralContext
2
+ from guard_core.decorators.base import RouteConfig
3
+ from guard_core.protocols.request_protocol import GuardRequest
4
+ from guard_core.protocols.response_protocol import GuardResponse
5
+
6
+
7
+ class BehavioralProcessor:
8
+ def __init__(self, context: BehavioralContext) -> None:
9
+ self.context = context
10
+
11
+ async def process_usage_rules(
12
+ self, request: GuardRequest, client_ip: str, route_config: RouteConfig
13
+ ) -> None:
14
+ if not self.context.guard_decorator:
15
+ return
16
+
17
+ endpoint_id = self.get_endpoint_id(request)
18
+ for rule in route_config.behavior_rules:
19
+ if rule.rule_type in ["usage", "frequency"]:
20
+ behavior_tracker = self.context.guard_decorator.behavior_tracker
21
+ threshold_exceeded = await behavior_tracker.track_endpoint_usage(
22
+ endpoint_id, client_ip, rule
23
+ )
24
+ if threshold_exceeded:
25
+ details = f"{rule.threshold} calls in {rule.window}s"
26
+ message = f"Behavioral {rule.rule_type}"
27
+ reason = "threshold exceeded"
28
+
29
+ await self.context.event_bus.send_middleware_event(
30
+ event_type="decorator_violation",
31
+ request=request,
32
+ action_taken="behavioral_action_triggered",
33
+ reason=f"{message} {reason}: {details}",
34
+ decorator_type="behavioral",
35
+ violation_type=rule.rule_type,
36
+ threshold=rule.threshold,
37
+ window=rule.window,
38
+ action=rule.action,
39
+ endpoint_id=endpoint_id,
40
+ )
41
+
42
+ await self.context.guard_decorator.behavior_tracker.apply_action(
43
+ rule,
44
+ client_ip,
45
+ endpoint_id,
46
+ f"Usage threshold exceeded: {details}",
47
+ )
48
+
49
+ async def process_return_rules(
50
+ self,
51
+ request: GuardRequest,
52
+ response: GuardResponse,
53
+ client_ip: str,
54
+ route_config: RouteConfig,
55
+ ) -> None:
56
+ if not self.context.guard_decorator:
57
+ return
58
+
59
+ endpoint_id = self.get_endpoint_id(request)
60
+ for rule in route_config.behavior_rules:
61
+ if rule.rule_type == "return_pattern":
62
+ behavior_tracker = self.context.guard_decorator.behavior_tracker
63
+ pattern_detected = await behavior_tracker.track_return_pattern(
64
+ endpoint_id, client_ip, response, rule
65
+ )
66
+ if pattern_detected:
67
+ details = f"{rule.threshold} for '{rule.pattern}' in {rule.window}s"
68
+
69
+ await self.context.event_bus.send_middleware_event(
70
+ event_type="decorator_violation",
71
+ request=request,
72
+ action_taken="behavioral_action_triggered",
73
+ reason=f"Return pattern threshold exceeded: {details}",
74
+ decorator_type="behavioral",
75
+ violation_type="return_pattern",
76
+ threshold=rule.threshold,
77
+ window=rule.window,
78
+ pattern=rule.pattern,
79
+ action=rule.action,
80
+ endpoint_id=endpoint_id,
81
+ )
82
+
83
+ await self.context.guard_decorator.behavior_tracker.apply_action(
84
+ rule,
85
+ client_ip,
86
+ endpoint_id,
87
+ f"Return pattern threshold exceeded: {details}",
88
+ )
89
+
90
+ def get_endpoint_id(self, request: GuardRequest) -> str:
91
+ if hasattr(request, "scope") and "route" in request.scope:
92
+ route = request.scope["route"]
93
+ if hasattr(route, "endpoint"):
94
+ return f"{route.endpoint.__module__}.{route.endpoint.__qualname__}"
95
+ return f"{request.method}:{request.url_path}"
@@ -0,0 +1,4 @@
1
+ from guard_core.core.bypass.context import BypassContext
2
+ from guard_core.core.bypass.handler import BypassHandler
3
+
4
+ __all__ = ["BypassContext", "BypassHandler"]
@@ -0,0 +1,18 @@
1
+ from dataclasses import dataclass
2
+ from logging import Logger
3
+
4
+ from guard_core.core.events import SecurityEventBus
5
+ from guard_core.core.responses import ErrorResponseFactory
6
+ from guard_core.core.routing import RouteConfigResolver
7
+ from guard_core.core.validation import RequestValidator
8
+ from guard_core.models import SecurityConfig
9
+
10
+
11
+ @dataclass
12
+ class BypassContext:
13
+ config: SecurityConfig
14
+ logger: Logger
15
+ event_bus: SecurityEventBus
16
+ route_resolver: RouteConfigResolver
17
+ response_factory: ErrorResponseFactory
18
+ validator: RequestValidator
@@ -0,0 +1,52 @@
1
+ from collections.abc import Awaitable, Callable
2
+
3
+ from guard_core.core.bypass.context import BypassContext
4
+ from guard_core.decorators.base import RouteConfig
5
+ from guard_core.protocols.request_protocol import GuardRequest
6
+ from guard_core.protocols.response_protocol import GuardResponse
7
+
8
+
9
+ class BypassHandler:
10
+ def __init__(self, context: BypassContext) -> None:
11
+ self.context = context
12
+
13
+ async def handle_passthrough(
14
+ self,
15
+ request: GuardRequest,
16
+ call_next: Callable[[GuardRequest], Awaitable[GuardResponse]],
17
+ ) -> GuardResponse | None:
18
+ if not request.client_host:
19
+ response = await call_next(request)
20
+ return await self.context.response_factory.apply_modifier(response)
21
+
22
+ if await self.context.validator.is_path_excluded(request):
23
+ response = await call_next(request)
24
+ return await self.context.response_factory.apply_modifier(response)
25
+
26
+ return None
27
+
28
+ async def handle_security_bypass(
29
+ self,
30
+ request: GuardRequest,
31
+ call_next: Callable[[GuardRequest], Awaitable[GuardResponse]],
32
+ route_config: RouteConfig | None,
33
+ ) -> GuardResponse | None:
34
+ if not route_config or not self.context.route_resolver.should_bypass_check(
35
+ "all", route_config
36
+ ):
37
+ return None
38
+
39
+ await self.context.event_bus.send_middleware_event(
40
+ event_type="security_bypass",
41
+ request=request,
42
+ action_taken="all_checks_bypassed",
43
+ reason="Route configured to bypass all security checks",
44
+ bypassed_checks=list(route_config.bypassed_checks),
45
+ endpoint=str(request.url_path),
46
+ )
47
+
48
+ if not self.context.config.passive_mode:
49
+ response = await call_next(request)
50
+ return await self.context.response_factory.apply_modifier(response)
51
+
52
+ return None
@@ -0,0 +1,43 @@
1
+ from guard_core.core.checks.base import SecurityCheck
2
+ from guard_core.core.checks.implementations import (
3
+ AuthenticationCheck,
4
+ CloudIpRefreshCheck,
5
+ CloudProviderCheck,
6
+ CustomRequestCheck,
7
+ CustomValidatorsCheck,
8
+ EmergencyModeCheck,
9
+ HttpsEnforcementCheck,
10
+ IpSecurityCheck,
11
+ RateLimitCheck,
12
+ ReferrerCheck,
13
+ RequestLoggingCheck,
14
+ RequestSizeContentCheck,
15
+ RequiredHeadersCheck,
16
+ RouteConfigCheck,
17
+ SuspiciousActivityCheck,
18
+ TimeWindowCheck,
19
+ UserAgentCheck,
20
+ )
21
+ from guard_core.core.checks.pipeline import SecurityCheckPipeline
22
+
23
+ __all__ = [
24
+ "SecurityCheck",
25
+ "SecurityCheckPipeline",
26
+ "RouteConfigCheck",
27
+ "EmergencyModeCheck",
28
+ "HttpsEnforcementCheck",
29
+ "RequestLoggingCheck",
30
+ "RequestSizeContentCheck",
31
+ "RequiredHeadersCheck",
32
+ "AuthenticationCheck",
33
+ "ReferrerCheck",
34
+ "CustomValidatorsCheck",
35
+ "TimeWindowCheck",
36
+ "CloudIpRefreshCheck",
37
+ "IpSecurityCheck",
38
+ "CloudProviderCheck",
39
+ "UserAgentCheck",
40
+ "RateLimitCheck",
41
+ "SuspiciousActivityCheck",
42
+ "CustomRequestCheck",
43
+ ]
@@ -0,0 +1,48 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import TYPE_CHECKING, Any
3
+
4
+ from guard_core.protocols.request_protocol import GuardRequest
5
+ from guard_core.protocols.response_protocol import GuardResponse
6
+
7
+ if TYPE_CHECKING:
8
+ from guard_core.protocols.middleware_protocol import GuardMiddlewareProtocol
9
+
10
+
11
+ class SecurityCheck(ABC):
12
+ def __init__(self, middleware: "GuardMiddlewareProtocol") -> None:
13
+ self.middleware = middleware
14
+ self.config = middleware.config
15
+ self.logger = middleware.logger
16
+
17
+ @abstractmethod
18
+ async def check(self, request: GuardRequest) -> GuardResponse | None:
19
+ pass # pragma: no cover
20
+
21
+ @property
22
+ @abstractmethod
23
+ def check_name(self) -> str:
24
+ pass # pragma: no cover
25
+
26
+ async def send_event(
27
+ self,
28
+ event_type: str,
29
+ request: GuardRequest,
30
+ action_taken: str,
31
+ reason: str,
32
+ **kwargs: Any,
33
+ ) -> None:
34
+ await self.middleware.event_bus.send_middleware_event(
35
+ event_type=event_type,
36
+ request=request,
37
+ action_taken=action_taken,
38
+ reason=reason,
39
+ **kwargs,
40
+ )
41
+
42
+ async def create_error_response(
43
+ self, status_code: int, default_message: str
44
+ ) -> GuardResponse:
45
+ return await self.middleware.create_error_response(status_code, default_message)
46
+
47
+ def is_passive_mode(self) -> bool:
48
+ return self.config.passive_mode
@@ -0,0 +1,174 @@
1
+ import re
2
+ from ipaddress import ip_address, ip_network
3
+ from typing import Any
4
+ from urllib.parse import urlparse
5
+
6
+ from guard_core.decorators.base import RouteConfig
7
+ from guard_core.models import SecurityConfig
8
+ from guard_core.protocols.request_protocol import GuardRequest
9
+ from guard_core.utils import detect_penetration_attempt
10
+
11
+
12
+ def is_ip_in_blacklist(client_ip: str, ip_addr: object, blacklist: list[str]) -> bool:
13
+ for blocked in blacklist:
14
+ if "/" in blocked:
15
+ if ip_addr in ip_network(blocked, strict=False):
16
+ return True
17
+ elif client_ip == blocked:
18
+ return True
19
+ return False
20
+
21
+
22
+ def is_ip_in_whitelist(
23
+ client_ip: str, ip_addr: object, whitelist: list[str]
24
+ ) -> bool | None:
25
+ if not whitelist:
26
+ return None
27
+
28
+ for allowed in whitelist:
29
+ if "/" in allowed:
30
+ if ip_addr in ip_network(allowed, strict=False):
31
+ return True
32
+ elif client_ip == allowed:
33
+ return True
34
+ return False
35
+
36
+
37
+ def check_country_access(
38
+ client_ip: str, route_config: RouteConfig, geo_ip_handler: Any
39
+ ) -> bool | None:
40
+ if not geo_ip_handler:
41
+ return None
42
+
43
+ country = None
44
+
45
+ if route_config.blocked_countries:
46
+ country = geo_ip_handler.get_country(client_ip)
47
+ if country and country in route_config.blocked_countries:
48
+ return False
49
+
50
+ if route_config.whitelist_countries:
51
+ if country is None:
52
+ country = geo_ip_handler.get_country(client_ip)
53
+
54
+ if country:
55
+ return country in route_config.whitelist_countries
56
+ return False
57
+
58
+ return None
59
+
60
+
61
+ def _check_ip_blacklist(
62
+ client_ip: str, ip_addr: object, route_config: RouteConfig
63
+ ) -> bool:
64
+ if not route_config.ip_blacklist:
65
+ return False
66
+ return is_ip_in_blacklist(client_ip, ip_addr, route_config.ip_blacklist)
67
+
68
+
69
+ def _check_ip_whitelist(
70
+ client_ip: str, ip_addr: object, route_config: RouteConfig
71
+ ) -> bool | None:
72
+ return is_ip_in_whitelist(client_ip, ip_addr, route_config.ip_whitelist or [])
73
+
74
+
75
+ async def check_route_ip_access(
76
+ client_ip: str, route_config: RouteConfig, middleware: Any
77
+ ) -> bool | None:
78
+ try:
79
+ ip_addr = ip_address(client_ip)
80
+
81
+ if _check_ip_blacklist(client_ip, ip_addr, route_config):
82
+ return False
83
+
84
+ whitelist_result = _check_ip_whitelist(client_ip, ip_addr, route_config)
85
+ if whitelist_result is not None:
86
+ return whitelist_result
87
+
88
+ country_result = check_country_access(
89
+ client_ip, route_config, middleware.geo_ip_handler
90
+ )
91
+ if country_result is not None:
92
+ return country_result
93
+
94
+ return None
95
+ except ValueError:
96
+ return False
97
+
98
+
99
+ async def check_user_agent_allowed(
100
+ user_agent: str, route_config: RouteConfig | None, config: Any
101
+ ) -> bool:
102
+ from guard_core.utils import is_user_agent_allowed as global_user_agent_check
103
+
104
+ if route_config and route_config.blocked_user_agents:
105
+ for pattern in route_config.blocked_user_agents:
106
+ if re.search(pattern, user_agent, re.IGNORECASE):
107
+ return False
108
+
109
+ return await global_user_agent_check(user_agent, config)
110
+
111
+
112
+ def validate_auth_header(auth_header: str, auth_type: str) -> tuple[bool, str]:
113
+ if auth_type == "bearer":
114
+ if not auth_header.startswith("Bearer "):
115
+ return False, "Missing or invalid Bearer token"
116
+ elif auth_type == "basic":
117
+ if not auth_header.startswith("Basic "):
118
+ return False, "Missing or invalid Basic authentication"
119
+ else:
120
+ if not auth_header:
121
+ return False, f"Missing {auth_type} authentication"
122
+
123
+ return True, ""
124
+
125
+
126
+ def is_referrer_domain_allowed(referrer: str, allowed_domains: list[str]) -> bool:
127
+ try:
128
+ referrer_domain = urlparse(referrer).netloc.lower()
129
+ for allowed_domain in allowed_domains:
130
+ if referrer_domain == allowed_domain.lower() or referrer_domain.endswith(
131
+ f".{allowed_domain.lower()}"
132
+ ):
133
+ return True
134
+ return False
135
+ except Exception:
136
+ return False
137
+
138
+
139
+ def _get_effective_penetration_setting(
140
+ config: SecurityConfig, route_config: RouteConfig | None
141
+ ) -> tuple[bool, bool | None]:
142
+ route_specific_detection = None
143
+ penetration_enabled = config.enable_penetration_detection
144
+
145
+ if route_config and hasattr(route_config, "enable_suspicious_detection"):
146
+ route_specific_detection = route_config.enable_suspicious_detection
147
+ penetration_enabled = route_specific_detection
148
+
149
+ return penetration_enabled, route_specific_detection
150
+
151
+
152
+ def _get_detection_disabled_reason(
153
+ config: SecurityConfig, route_specific_detection: bool | None
154
+ ) -> str:
155
+ if route_specific_detection is False and config.enable_penetration_detection:
156
+ return "disabled_by_decorator"
157
+ return "not_enabled"
158
+
159
+
160
+ async def detect_penetration_patterns(
161
+ request: GuardRequest,
162
+ route_config: RouteConfig | None,
163
+ config: SecurityConfig,
164
+ should_bypass_check_fn: Any,
165
+ ) -> tuple[bool, str]:
166
+ penetration_enabled, route_specific_detection = _get_effective_penetration_setting(
167
+ config, route_config
168
+ )
169
+
170
+ if penetration_enabled and not should_bypass_check_fn("penetration", route_config):
171
+ return await detect_penetration_attempt(request)
172
+
173
+ reason = _get_detection_disabled_reason(config, route_specific_detection)
174
+ return False, reason
@@ -0,0 +1,65 @@
1
+ from guard_core.core.checks.implementations.authentication import (
2
+ AuthenticationCheck,
3
+ )
4
+ from guard_core.core.checks.implementations.cloud_ip_refresh import (
5
+ CloudIpRefreshCheck,
6
+ )
7
+ from guard_core.core.checks.implementations.cloud_provider import (
8
+ CloudProviderCheck,
9
+ )
10
+ from guard_core.core.checks.implementations.custom_request import (
11
+ CustomRequestCheck,
12
+ )
13
+ from guard_core.core.checks.implementations.custom_validators import (
14
+ CustomValidatorsCheck,
15
+ )
16
+ from guard_core.core.checks.implementations.emergency_mode import (
17
+ EmergencyModeCheck,
18
+ )
19
+ from guard_core.core.checks.implementations.https_enforcement import (
20
+ HttpsEnforcementCheck,
21
+ )
22
+ from guard_core.core.checks.implementations.ip_security import (
23
+ IpSecurityCheck,
24
+ )
25
+ from guard_core.core.checks.implementations.rate_limit import RateLimitCheck
26
+ from guard_core.core.checks.implementations.referrer import ReferrerCheck
27
+ from guard_core.core.checks.implementations.request_logging import (
28
+ RequestLoggingCheck,
29
+ )
30
+ from guard_core.core.checks.implementations.request_size_content import (
31
+ RequestSizeContentCheck,
32
+ )
33
+ from guard_core.core.checks.implementations.required_headers import (
34
+ RequiredHeadersCheck,
35
+ )
36
+ from guard_core.core.checks.implementations.route_config import (
37
+ RouteConfigCheck,
38
+ )
39
+ from guard_core.core.checks.implementations.suspicious_activity import (
40
+ SuspiciousActivityCheck,
41
+ )
42
+ from guard_core.core.checks.implementations.time_window import (
43
+ TimeWindowCheck,
44
+ )
45
+ from guard_core.core.checks.implementations.user_agent import UserAgentCheck
46
+
47
+ __all__ = [
48
+ "AuthenticationCheck",
49
+ "CloudIpRefreshCheck",
50
+ "CloudProviderCheck",
51
+ "CustomRequestCheck",
52
+ "CustomValidatorsCheck",
53
+ "EmergencyModeCheck",
54
+ "HttpsEnforcementCheck",
55
+ "IpSecurityCheck",
56
+ "RateLimitCheck",
57
+ "ReferrerCheck",
58
+ "RequestLoggingCheck",
59
+ "RequestSizeContentCheck",
60
+ "RequiredHeadersCheck",
61
+ "RouteConfigCheck",
62
+ "SuspiciousActivityCheck",
63
+ "TimeWindowCheck",
64
+ "UserAgentCheck",
65
+ ]