flaskapi-guard 0.1.0__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.
Files changed (81) hide show
  1. flaskapi_guard/__init__.py +40 -0
  2. flaskapi_guard/core/__init__.py +13 -0
  3. flaskapi_guard/core/behavioral/__init__.py +7 -0
  4. flaskapi_guard/core/behavioral/context.py +17 -0
  5. flaskapi_guard/core/behavioral/processor.py +113 -0
  6. flaskapi_guard/core/bypass/__init__.py +7 -0
  7. flaskapi_guard/core/bypass/context.py +21 -0
  8. flaskapi_guard/core/bypass/handler.py +71 -0
  9. flaskapi_guard/core/checks/__init__.py +48 -0
  10. flaskapi_guard/core/checks/base.py +115 -0
  11. flaskapi_guard/core/checks/helpers.py +352 -0
  12. flaskapi_guard/core/checks/implementations/__init__.py +68 -0
  13. flaskapi_guard/core/checks/implementations/authentication.py +68 -0
  14. flaskapi_guard/core/checks/implementations/cloud_ip_refresh.py +23 -0
  15. flaskapi_guard/core/checks/implementations/cloud_provider.py +75 -0
  16. flaskapi_guard/core/checks/implementations/custom_request.py +44 -0
  17. flaskapi_guard/core/checks/implementations/custom_validators.py +51 -0
  18. flaskapi_guard/core/checks/implementations/emergency_mode.py +68 -0
  19. flaskapi_guard/core/checks/implementations/https_enforcement.py +89 -0
  20. flaskapi_guard/core/checks/implementations/ip_security.py +163 -0
  21. flaskapi_guard/core/checks/implementations/rate_limit.py +231 -0
  22. flaskapi_guard/core/checks/implementations/referrer.py +102 -0
  23. flaskapi_guard/core/checks/implementations/request_logging.py +18 -0
  24. flaskapi_guard/core/checks/implementations/request_size_content.py +115 -0
  25. flaskapi_guard/core/checks/implementations/required_headers.py +85 -0
  26. flaskapi_guard/core/checks/implementations/route_config.py +29 -0
  27. flaskapi_guard/core/checks/implementations/suspicious_activity.py +179 -0
  28. flaskapi_guard/core/checks/implementations/time_window.py +77 -0
  29. flaskapi_guard/core/checks/implementations/user_agent.py +68 -0
  30. flaskapi_guard/core/checks/pipeline.py +137 -0
  31. flaskapi_guard/core/events/__init__.py +9 -0
  32. flaskapi_guard/core/events/extension_events.py +170 -0
  33. flaskapi_guard/core/events/metrics.py +85 -0
  34. flaskapi_guard/core/initialization/__init__.py +10 -0
  35. flaskapi_guard/core/initialization/handler_initializer.py +120 -0
  36. flaskapi_guard/core/responses/__init__.py +7 -0
  37. flaskapi_guard/core/responses/context.py +26 -0
  38. flaskapi_guard/core/responses/factory.py +170 -0
  39. flaskapi_guard/core/routing/__init__.py +7 -0
  40. flaskapi_guard/core/routing/context.py +22 -0
  41. flaskapi_guard/core/routing/resolver.py +117 -0
  42. flaskapi_guard/core/validation/__init__.py +7 -0
  43. flaskapi_guard/core/validation/context.py +15 -0
  44. flaskapi_guard/core/validation/validator.py +93 -0
  45. flaskapi_guard/decorators/__init__.py +63 -0
  46. flaskapi_guard/decorators/access_control.py +88 -0
  47. flaskapi_guard/decorators/advanced.py +124 -0
  48. flaskapi_guard/decorators/authentication.py +66 -0
  49. flaskapi_guard/decorators/base.py +228 -0
  50. flaskapi_guard/decorators/behavioral.py +162 -0
  51. flaskapi_guard/decorators/content_filtering.py +102 -0
  52. flaskapi_guard/decorators/rate_limiting.py +48 -0
  53. flaskapi_guard/detection_engine/__init__.py +12 -0
  54. flaskapi_guard/detection_engine/compiler.py +247 -0
  55. flaskapi_guard/detection_engine/monitor.py +574 -0
  56. flaskapi_guard/detection_engine/preprocessor.py +464 -0
  57. flaskapi_guard/detection_engine/semantic.py +553 -0
  58. flaskapi_guard/extension.py +542 -0
  59. flaskapi_guard/handlers/__init__.py +22 -0
  60. flaskapi_guard/handlers/behavior_handler.py +403 -0
  61. flaskapi_guard/handlers/cloud_handler.py +275 -0
  62. flaskapi_guard/handlers/dynamic_rule_handler.py +367 -0
  63. flaskapi_guard/handlers/ipban_handler.py +155 -0
  64. flaskapi_guard/handlers/ipinfo_handler.py +244 -0
  65. flaskapi_guard/handlers/ratelimit_handler.py +257 -0
  66. flaskapi_guard/handlers/redis_handler.py +291 -0
  67. flaskapi_guard/handlers/security_headers_handler.py +581 -0
  68. flaskapi_guard/handlers/suspatterns_handler.py +917 -0
  69. flaskapi_guard/models.py +870 -0
  70. flaskapi_guard/protocols/__init__.py +10 -0
  71. flaskapi_guard/protocols/agent_protocol.py +77 -0
  72. flaskapi_guard/protocols/geo_ip_protocol.py +17 -0
  73. flaskapi_guard/protocols/redis_protocol.py +19 -0
  74. flaskapi_guard/scripts/__init__.py +1 -0
  75. flaskapi_guard/scripts/rate_lua.py +24 -0
  76. flaskapi_guard/utils.py +838 -0
  77. flaskapi_guard-0.1.0.dist-info/LICENSE +21 -0
  78. flaskapi_guard-0.1.0.dist-info/METADATA +851 -0
  79. flaskapi_guard-0.1.0.dist-info/RECORD +81 -0
  80. flaskapi_guard-0.1.0.dist-info/WHEEL +5 -0
  81. flaskapi_guard-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,40 @@
1
+ # flaskapi_guard/__init__.py
2
+ from flaskapi_guard.decorators import RouteConfig, SecurityDecorator
3
+ from flaskapi_guard.extension import FlaskAPIGuard
4
+ from flaskapi_guard.handlers.behavior_handler import BehaviorRule, BehaviorTracker
5
+ from flaskapi_guard.handlers.cloud_handler import CloudManager, cloud_handler
6
+ from flaskapi_guard.handlers.ipban_handler import IPBanManager, ip_ban_manager
7
+ from flaskapi_guard.handlers.ipinfo_handler import IPInfoManager
8
+ from flaskapi_guard.handlers.ratelimit_handler import RateLimitManager, rate_limit_handler
9
+ from flaskapi_guard.handlers.redis_handler import RedisManager, redis_handler
10
+ from flaskapi_guard.handlers.security_headers_handler import (
11
+ SecurityHeadersManager,
12
+ security_headers_manager,
13
+ )
14
+ from flaskapi_guard.handlers.suspatterns_handler import sus_patterns_handler
15
+ from flaskapi_guard.models import SecurityConfig
16
+ from flaskapi_guard.protocols.geo_ip_protocol import GeoIPHandler
17
+ from flaskapi_guard.protocols.redis_protocol import RedisHandlerProtocol
18
+
19
+ __all__ = [
20
+ "FlaskAPIGuard",
21
+ "SecurityConfig",
22
+ "SecurityDecorator",
23
+ "RouteConfig",
24
+ "BehaviorTracker",
25
+ "BehaviorRule",
26
+ "ip_ban_manager",
27
+ "IPBanManager",
28
+ "cloud_handler",
29
+ "CloudManager",
30
+ "IPInfoManager",
31
+ "rate_limit_handler",
32
+ "RateLimitManager",
33
+ "redis_handler",
34
+ "RedisManager",
35
+ "security_headers_manager",
36
+ "SecurityHeadersManager",
37
+ "sus_patterns_handler",
38
+ "GeoIPHandler",
39
+ "RedisHandlerProtocol",
40
+ ]
@@ -0,0 +1,13 @@
1
+ """Extension supporting modules.
2
+
3
+ This package contains event bus, metrics, and security check modules
4
+ that support the main FlaskAPIGuard class.
5
+
6
+ The FlaskAPIGuard class itself is defined in flaskapi_guard/extension.py
7
+ and should be imported from there:
8
+ from flaskapi_guard.extension import FlaskAPIGuard
9
+ """
10
+
11
+ from flaskapi_guard.core.events import MetricsCollector, SecurityEventBus
12
+
13
+ __all__ = ["SecurityEventBus", "MetricsCollector"]
@@ -0,0 +1,7 @@
1
+ # flaskapi_guard/core/behavioral/__init__.py
2
+ """Behavioral rule processing module."""
3
+
4
+ from flaskapi_guard.core.behavioral.context import BehavioralContext
5
+ from flaskapi_guard.core.behavioral.processor import BehavioralProcessor
6
+
7
+ __all__ = ["BehavioralContext", "BehavioralProcessor"]
@@ -0,0 +1,17 @@
1
+ # flaskapi_guard/core/behavioral/context.py
2
+ from dataclasses import dataclass
3
+ from logging import Logger
4
+
5
+ from flaskapi_guard.core.events import SecurityEventBus
6
+ from flaskapi_guard.decorators.base import BaseSecurityDecorator
7
+ from flaskapi_guard.models import SecurityConfig
8
+
9
+
10
+ @dataclass
11
+ class BehavioralContext:
12
+ """Context for behavioral rule processing."""
13
+
14
+ config: SecurityConfig
15
+ logger: Logger
16
+ event_bus: SecurityEventBus
17
+ guard_decorator: BaseSecurityDecorator | None
@@ -0,0 +1,113 @@
1
+ # flaskapi_guard/core/behavioral/processor.py
2
+ from flask import Request, Response, current_app
3
+
4
+ from flaskapi_guard.core.behavioral.context import BehavioralContext
5
+ from flaskapi_guard.decorators.base import RouteConfig
6
+
7
+
8
+ class BehavioralProcessor:
9
+ """Handles behavioral rule processing operations."""
10
+
11
+ def __init__(self, context: BehavioralContext) -> None:
12
+ """
13
+ Initialize the BehavioralProcessor.
14
+
15
+ Args:
16
+ context: Behavioral context with config, logger, and dependencies
17
+ """
18
+ self.context = context
19
+
20
+ def process_usage_rules(
21
+ self, request: Request, client_ip: str, route_config: RouteConfig
22
+ ) -> None:
23
+ """Process behavioral usage rules from decorators before request processing."""
24
+ if not self.context.guard_decorator:
25
+ return
26
+
27
+ endpoint_id = self.get_endpoint_id(request)
28
+ for rule in route_config.behavior_rules:
29
+ if rule.rule_type in ["usage", "frequency"]:
30
+ behavior_tracker = self.context.guard_decorator.behavior_tracker
31
+ threshold_exceeded = behavior_tracker.track_endpoint_usage(
32
+ endpoint_id, client_ip, rule
33
+ )
34
+ if threshold_exceeded:
35
+ details = f"{rule.threshold} calls in {rule.window}s"
36
+ message = f"Behavioral {rule.rule_type}"
37
+ reason = "threshold exceeded"
38
+
39
+ # Send decorator violation event for behavioral rule violation
40
+ self.context.event_bus.send_middleware_event(
41
+ event_type="decorator_violation",
42
+ request=request,
43
+ action_taken="behavioral_action_triggered",
44
+ reason=f"{message} {reason}: {details}",
45
+ decorator_type="behavioral",
46
+ violation_type=rule.rule_type,
47
+ threshold=rule.threshold,
48
+ window=rule.window,
49
+ action=rule.action,
50
+ endpoint_id=endpoint_id,
51
+ )
52
+
53
+ self.context.guard_decorator.behavior_tracker.apply_action(
54
+ rule,
55
+ client_ip,
56
+ endpoint_id,
57
+ f"Usage threshold exceeded: {details}",
58
+ )
59
+
60
+ def process_return_rules(
61
+ self,
62
+ request: Request,
63
+ response: Response,
64
+ client_ip: str,
65
+ route_config: RouteConfig,
66
+ ) -> None:
67
+ """Process behavioral return pattern rules from decorators after response."""
68
+ if not self.context.guard_decorator:
69
+ return
70
+
71
+ endpoint_id = self.get_endpoint_id(request)
72
+ for rule in route_config.behavior_rules:
73
+ if rule.rule_type == "return_pattern":
74
+ behavior_tracker = self.context.guard_decorator.behavior_tracker
75
+ pattern_detected = behavior_tracker.track_return_pattern(
76
+ endpoint_id, client_ip, response, rule
77
+ )
78
+ if pattern_detected:
79
+ details = f"{rule.threshold} for '{rule.pattern}' in {rule.window}s"
80
+
81
+ # Send decorator violation event for return pattern violation
82
+ self.context.event_bus.send_middleware_event(
83
+ event_type="decorator_violation",
84
+ request=request,
85
+ action_taken="behavioral_action_triggered",
86
+ reason=f"Return pattern threshold exceeded: {details}",
87
+ decorator_type="behavioral",
88
+ violation_type="return_pattern",
89
+ threshold=rule.threshold,
90
+ window=rule.window,
91
+ pattern=rule.pattern,
92
+ action=rule.action,
93
+ endpoint_id=endpoint_id,
94
+ )
95
+
96
+ self.context.guard_decorator.behavior_tracker.apply_action(
97
+ rule,
98
+ client_ip,
99
+ endpoint_id,
100
+ f"Return pattern threshold exceeded: {details}",
101
+ )
102
+
103
+ def get_endpoint_id(self, request: Request) -> str:
104
+ """Generate unique endpoint identifier."""
105
+ if request.endpoint is None:
106
+ return f"{request.method}:{request.path}"
107
+ view_func = current_app.view_functions.get(request.endpoint)
108
+ if view_func is not None:
109
+ # This is an internal identifier for tracking, not returned to users.
110
+ # Values come from Python introspection (module,
111
+ # qualname), not from user input.
112
+ return f"{view_func.__module__}.{view_func.__qualname__}"
113
+ return f"{request.method}:{request.path}"
@@ -0,0 +1,7 @@
1
+ # flaskapi_guard/core/bypass/__init__.py
2
+ """Bypass handler module."""
3
+
4
+ from flaskapi_guard.core.bypass.context import BypassContext
5
+ from flaskapi_guard.core.bypass.handler import BypassHandler
6
+
7
+ __all__ = ["BypassContext", "BypassHandler"]
@@ -0,0 +1,21 @@
1
+ # flaskapi_guard/core/bypass/context.py
2
+ from dataclasses import dataclass
3
+ from logging import Logger
4
+
5
+ from flaskapi_guard.core.events import SecurityEventBus
6
+ from flaskapi_guard.core.responses import ErrorResponseFactory
7
+ from flaskapi_guard.core.routing import RouteConfigResolver
8
+ from flaskapi_guard.core.validation import RequestValidator
9
+ from flaskapi_guard.models import SecurityConfig
10
+
11
+
12
+ @dataclass
13
+ class BypassContext:
14
+ """Context for bypass handler operations."""
15
+
16
+ config: SecurityConfig
17
+ logger: Logger
18
+ event_bus: SecurityEventBus
19
+ route_resolver: RouteConfigResolver
20
+ response_factory: ErrorResponseFactory
21
+ validator: RequestValidator
@@ -0,0 +1,71 @@
1
+ # flaskapi_guard/core/bypass/handler.py
2
+ from flask import Request, Response
3
+
4
+ from flaskapi_guard.core.bypass.context import BypassContext
5
+ from flaskapi_guard.decorators.base import RouteConfig
6
+
7
+
8
+ class BypassHandler:
9
+ """Handles security check bypassing operations."""
10
+
11
+ def __init__(self, context: BypassContext) -> None:
12
+ """
13
+ Initialize the BypassHandler.
14
+
15
+ Args:
16
+ context: Bypass context with config, logger, and dependencies
17
+ """
18
+ self.context = context
19
+
20
+ def handle_passthrough(
21
+ self,
22
+ request: Request,
23
+ ) -> Response | None:
24
+ """
25
+ Handle special cases that require immediate passthrough.
26
+
27
+ This includes requests with no client information and excluded paths.
28
+
29
+ Returns:
30
+ None to let Flask proceed with the request
31
+ """
32
+ # No client information
33
+ if not request.remote_addr:
34
+ return None
35
+
36
+ # Excluded paths
37
+ if self.context.validator.is_path_excluded(request):
38
+ return None
39
+
40
+ return None
41
+
42
+ def handle_security_bypass(
43
+ self,
44
+ request: Request,
45
+ route_config: RouteConfig | None,
46
+ ) -> Response | None:
47
+ """
48
+ Handle bypassed security checks.
49
+
50
+ Returns:
51
+ None to let Flask proceed with the request
52
+ """
53
+ if not route_config or not self.context.route_resolver.should_bypass_check(
54
+ "all", route_config
55
+ ):
56
+ return None
57
+
58
+ # Send security bypass event for monitoring
59
+ self.context.event_bus.send_middleware_event(
60
+ event_type="security_bypass",
61
+ request=request,
62
+ action_taken="all_checks_bypassed",
63
+ reason="Route configured to bypass all security checks",
64
+ bypassed_checks=list(route_config.bypassed_checks),
65
+ endpoint=request.path,
66
+ )
67
+
68
+ if not self.context.config.passive_mode:
69
+ return None
70
+
71
+ return None
@@ -0,0 +1,48 @@
1
+ # flaskapi_guard/core/checks/__init__.py
2
+ """Security checks module with modular architecture."""
3
+
4
+ from flaskapi_guard.core.checks.base import SecurityCheck
5
+ from flaskapi_guard.core.checks.implementations import (
6
+ AuthenticationCheck,
7
+ CloudIpRefreshCheck,
8
+ CloudProviderCheck,
9
+ CustomRequestCheck,
10
+ CustomValidatorsCheck,
11
+ EmergencyModeCheck,
12
+ HttpsEnforcementCheck,
13
+ IpSecurityCheck,
14
+ RateLimitCheck,
15
+ ReferrerCheck,
16
+ RequestLoggingCheck,
17
+ RequestSizeContentCheck,
18
+ RequiredHeadersCheck,
19
+ RouteConfigCheck,
20
+ SuspiciousActivityCheck,
21
+ TimeWindowCheck,
22
+ UserAgentCheck,
23
+ )
24
+ from flaskapi_guard.core.checks.pipeline import SecurityCheckPipeline
25
+
26
+ __all__ = [
27
+ # Base
28
+ "SecurityCheck",
29
+ "SecurityCheckPipeline",
30
+ # Implementations
31
+ "RouteConfigCheck",
32
+ "EmergencyModeCheck",
33
+ "HttpsEnforcementCheck",
34
+ "RequestLoggingCheck",
35
+ "RequestSizeContentCheck",
36
+ "RequiredHeadersCheck",
37
+ "AuthenticationCheck",
38
+ "ReferrerCheck",
39
+ "CustomValidatorsCheck",
40
+ "TimeWindowCheck",
41
+ "CloudIpRefreshCheck",
42
+ "IpSecurityCheck",
43
+ "CloudProviderCheck",
44
+ "UserAgentCheck",
45
+ "RateLimitCheck",
46
+ "SuspiciousActivityCheck",
47
+ "CustomRequestCheck",
48
+ ]
@@ -0,0 +1,115 @@
1
+ # flaskapi_guard/core/checks/base.py
2
+ import logging
3
+ from abc import ABC, abstractmethod
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from flask import Request, Response
7
+
8
+ from flaskapi_guard.models import SecurityConfig
9
+
10
+ if TYPE_CHECKING:
11
+ from flaskapi_guard.extension import FlaskAPIGuard
12
+
13
+
14
+ class SecurityCheck(ABC):
15
+ """
16
+ Base class for security checks in the middleware pipeline.
17
+
18
+ Each security check implements a single security concern and can
19
+ independently block or allow a request to proceed.
20
+ """
21
+
22
+ def __init__(self, middleware: "FlaskAPIGuard") -> None:
23
+ """
24
+ Initialize the security check.
25
+
26
+ Args:
27
+ middleware: Reference to the parent FlaskAPIGuard instance
28
+ for accessing config, handlers, and utilities.
29
+ """
30
+ self.middleware = middleware
31
+ assert middleware.config is not None, (
32
+ "FlaskAPIGuard must be initialized with config"
33
+ )
34
+ self.config: SecurityConfig = middleware.config
35
+ assert middleware.logger is not None, (
36
+ "FlaskAPIGuard must be initialized with logger"
37
+ )
38
+ self.logger: logging.Logger = middleware.logger
39
+
40
+ @abstractmethod
41
+ def check(self, request: Request) -> Response | None:
42
+ """
43
+ Perform the security check on the request.
44
+
45
+ Args:
46
+ request: The incoming Flask request.
47
+
48
+ Returns:
49
+ Response if the check fails and request should be blocked.
50
+ None if the check passes and request should continue.
51
+ """
52
+ pass # pragma: no cover
53
+
54
+ @property
55
+ @abstractmethod
56
+ def check_name(self) -> str:
57
+ """
58
+ Name of this security check for logging and debugging.
59
+
60
+ Returns:
61
+ Human-readable name of the check (e.g., "https_enforcement").
62
+ """
63
+ pass # pragma: no cover
64
+
65
+ def send_event(
66
+ self,
67
+ event_type: str,
68
+ request: Request,
69
+ action_taken: str,
70
+ reason: str,
71
+ **kwargs: Any,
72
+ ) -> None:
73
+ """
74
+ Send a security event to the agent handler if enabled.
75
+
76
+ This is a helper method to simplify event sending from checks.
77
+
78
+ Args:
79
+ event_type: Type of security event.
80
+ request: The request that triggered the event.
81
+ action_taken: Action taken by the check.
82
+ reason: Reason for the action.
83
+ **kwargs: Additional metadata for the event.
84
+ """
85
+ if self.middleware.event_bus is None:
86
+ return
87
+ self.middleware.event_bus.send_middleware_event(
88
+ event_type=event_type,
89
+ request=request,
90
+ action_taken=action_taken,
91
+ reason=reason,
92
+ **kwargs,
93
+ )
94
+
95
+ def create_error_response(self, status_code: int, default_message: str) -> Response:
96
+ """
97
+ Create an error response with custom message and security headers.
98
+
99
+ Args:
100
+ status_code: HTTP status code for the error.
101
+ default_message: Default error message if no custom message configured.
102
+
103
+ Returns:
104
+ Response object with appropriate status and headers.
105
+ """
106
+ return self.middleware.create_error_response(status_code, default_message)
107
+
108
+ def is_passive_mode(self) -> bool:
109
+ """
110
+ Check if middleware is in passive mode (log only, don't block).
111
+
112
+ Returns:
113
+ True if passive mode is enabled, False otherwise.
114
+ """
115
+ return self.config.passive_mode