1+ import time
2+
3+ from werkzeug .wrappers import Request
4+
15import px_activities_client
2- import px_cookie_validator
3- from px_context import PxContext
4- import px_blocker
5- import px_api
6- import px_constants
7- import px_utils
8- from perimeterx .px_proxy import PXProxy
96from px_config import PxConfig
7+ from px_context import PxContext
8+ from px_request_verifier import PxRequestVerifier
109
1110
1211class PerimeterX (object ):
@@ -15,99 +14,86 @@ def __init__(self, app, config=None):
1514 # merging user's defined configurations with the default one
1615 px_config = PxConfig (config )
1716 logger = px_config .logger
17+
1818 if not px_config .app_id :
19- logger .error ('PX App ID is missing' )
19+ logger .error ('Unable to initialize module, missing mandatory configuration: app_id ' )
2020 raise ValueError ('PX App ID is missing' )
2121
22- # if APP_ID is not set, use the deafult perimeterx server - else, use the appid specific sapi.
2322 if not px_config .auth_token :
24- logger .error ('PX Auth Token is missing' )
23+ logger .error ('Unable to initialize module, missing mandatory configuration: auth_token ' )
2524 raise ValueError ('PX Auth Token is missing' )
2625
2726 if not px_config .cookie_key :
28- logger .error ('PX Cookie Key is missing' )
27+ logger .error ('Unable to initialize module, missing mandatory configuration: px_cookie ' )
2928 raise ValueError ('PX Cookie Key is missing' )
29+
3030 self .reverse_proxy_prefix = px_config .app_id [2 :].lower ()
31- self ._PXBlocker = px_blocker .PXBlocker ()
3231 self ._config = px_config
32+ self ._module_enabled = self ._config .module_enabled
33+ self ._request_verifier = PxRequestVerifier (px_config )
3334 px_activities_client .init_activities_configuration (px_config )
3435 px_activities_client .send_enforcer_telemetry_activity (config = px_config , update_reason = 'initial_config' )
3536
3637 def __call__ (self , environ , start_response ):
37- return self ._verify (environ , start_response )
38-
39- def _verify (self , environ , start_response ):
40- config = self .config
41- logger = config .logger
4238 try :
43- ctx = PxContext (environ , config )
44- uri = ctx .uri
45- px_proxy = PXProxy (config )
46- if px_proxy .should_reverse_request (uri ):
47- body = environ ['wsgi.input' ].read (int (environ .get ('CONTENT_LENGTH' ))) if environ .get (
48- 'CONTENT_LENGTH' ) else ''
49- return px_proxy .handle_reverse_request (self .config , ctx , start_response , body )
50- if px_utils .is_static_file (ctx ):
51- logger .debug ('Filter static file request. uri: ' + uri )
52- return self .app (environ , start_response )
53- if not self ._config ._module_enabled :
54- logger .debug ('Module is disabled, request will not be verified' )
55- return self .app (environ , start_response )
56-
57- if ctx .whitelist_route :
58- logger .debug ('The requested uri is whitelisted, passing request' )
39+ start = time .time ()
40+ context = None
41+ request = Request (environ )
42+ context , verified_response = self .verify (request )
43+ self ._config .logger .debug ("PerimeterX Enforcer took: {} ms" .format ((time .time () - start ) * 1000 ))
44+ if verified_response is True :
5945 return self .app (environ , start_response )
6046
61- # PX Cookie verification
62- if not px_cookie_validator .verify (ctx , config ):
63- # Server-to-Server verification fallback
64- if not px_api .verify (ctx , self .config ):
65- return self .app (environ , start_response )
66- return self .handle_verification (ctx , self .config , environ , start_response )
67- except :
68- logger .error ("Caught exception, passing request" )
69- self .pass_traffic (PxContext ({}, config ))
70- return self .app (environ , start_response )
47+ return verified_response (environ , start_response )
7148
72- def handle_verification (self , ctx , config , environ , start_response ):
73- score = ctx .score
74- result = None
75- headers = None
76- status = None
77- pass_request = True
78- if score < config .blocking_score :
79- self .pass_traffic (ctx )
80- else :
81- pass_request = False
82- self .block_traffic (ctx )
83-
84- if config .additional_activity_handler :
85- config .additional_activity_handler (ctx , config )
86-
87- if config .module_mode == px_constants .MODULE_MODE_BLOCKING and result is None and not pass_request :
88- result , headers , status = self .px_blocker .handle_blocking (ctx = ctx , config = config )
89- if config .custom_request_handler :
90- custom_body , custom_headers , custom_status = config .custom_request_handler (ctx , self .config , environ )
91- if custom_body is not None :
92- start_response (custom_status , custom_headers )
93- return custom_body
94-
95- if headers is not None :
96- start_response (status , headers )
97- return result
98- else :
49+ except Exception as err :
50+ self ._config .logger .error ("Caught exception, passing request. Exception: {}" .format (err ))
51+ if context :
52+ self .report_pass_traffic (context )
53+ else :
54+ self .report_pass_traffic (PxContext ({}, self ._config ))
9955 return self .app (environ , start_response )
10056
101- def pass_traffic (self , ctx ):
57+ def verify (self , request ):
58+ config = self .config
59+ logger = config .logger
60+ logger .debug ('Starting request verification' )
61+ ctx = None
62+ try :
63+ if not self ._module_enabled :
64+ logger .debug ('Request will not be verified, module is disabled' )
65+ return ctx , True
66+ ctx = PxContext (request , config )
67+ return ctx , self ._request_verifier .verify_request (ctx , request )
68+ except Exception as err :
69+ logger .error ("Caught exception, passing request. Exception: {}" .format (err ))
70+ if ctx :
71+ self .report_pass_traffic (ctx )
72+ else :
73+ self .report_pass_traffic (PxContext ({}, config ))
74+ return True
75+
76+
77+ def report_pass_traffic (self , ctx ):
10278 px_activities_client .send_page_requested_activity (ctx , self .config )
10379
104- def block_traffic (self , ctx ):
80+ def report_block_traffic (self , ctx ):
10581 px_activities_client .send_block_activity (ctx , self .config )
10682
10783 @property
10884 def config (self ):
10985 return self ._config
11086
111- @property
112- def px_blocker (self ):
113- return self ._PXBlocker
87+ def disable_module (self ):
88+ if not self ._module_enabled :
89+ self ._config .logger .debug ("Trying to disable the module, module already disabled" )
90+ else :
91+ self ._module_enabled = False
92+
93+ def enable_module (self ):
94+ if self ._module_enabled :
95+ self ._config .logger .debug ("Trying to enable the module, module already enabled" )
96+ else :
97+ self ._module_enabled = True
98+
99+
0 commit comments