Skip to content
This repository was archived by the owner on Jul 15, 2022. It is now read-only.

Commit 6effee0

Browse files
authored
waf analytics (#47)
1 parent 6b5cbb9 commit 6effee0

File tree

4 files changed

+291
-0
lines changed

4 files changed

+291
-0
lines changed

pystackpath/stacks/wafsites/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
from pystackpath.stacks.wafsites.monitoring import Monitoring
66
from pystackpath.stacks.wafsites.policy_groups import PolicyGroups
77
from pystackpath.stacks.wafsites.rules import Rules
8+
from pystackpath.stacks.wafsites.events import Events
9+
from pystackpath.stacks.wafsites.metrics import Metrics
10+
from pystackpath.stacks.wafsites.traffic import Traffic
811

912

1013
class WafSites(BaseSite):
@@ -25,3 +28,12 @@ def api_urls(self):
2528

2629
def set_monitoring(self):
2730
return Monitoring(self._client, f"{self._base_api}/sites/{self.id}")
31+
32+
def events(self):
33+
return Events(self._client, f"{self._base_api}/sites/{self.id}")
34+
35+
def metrics(self):
36+
return Events(self._client, f"{self._base_api}/sites/{self.id}")
37+
38+
def traffic(self):
39+
return Traffic(self._client, f"{self._base_api}")
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import json
2+
from pystackpath.util import BaseObject, api_time_format
3+
from datetime import datetime as dt
4+
from datetime import timedelta
5+
6+
7+
ACCEPTED_ACTIONS = (
8+
'ANY_ACTION', 'ALLOW_ACTION',
9+
'BLOCK_ACTION', 'CAPTCHA_ACTION',
10+
'HANDSHAKE_ACTION', 'MONITOR_ACTION'
11+
)
12+
ACCEPTED_RESULTS = ('ANY_RESULT', 'BLOCKED_RESULT')
13+
ACCEPTED_SORT_BY = ('TIMESTAMP', 'COUNTRY', 'RULE_NAME')
14+
ACCEPTED_SORT_ORDER = ('ASCENDING', 'DESCENDING')
15+
DEFAULT_DELTA_TIME = 1 # day
16+
17+
18+
class Events(BaseObject):
19+
20+
def get(self, event_id):
21+
"""
22+
Get an Event by its ID
23+
"""
24+
response = self._client.get(f"{self._base_api}/events/{event_id}")
25+
return self.loaddict(response.json())
26+
27+
def index(
28+
self,
29+
page_request_first=None,
30+
page_request_after=None,
31+
page_request_filter=None,
32+
page_request_sort_by=None,
33+
start_date=None,
34+
end_date=None,
35+
filter_action_value=ACCEPTED_ACTIONS[0],
36+
filter_result_value=ACCEPTED_RESULTS[0],
37+
filter_client_ip=None,
38+
filter_reference_id=None,
39+
sort_by=ACCEPTED_SORT_BY[0],
40+
sort_order=ACCEPTED_SORT_ORDER[0]
41+
):
42+
"""
43+
Get all the Events.
44+
You can use the parameters to add options to your request.
45+
"""
46+
47+
params = Events._common_params(start_date, end_date, filter_action_value, \
48+
filter_result_value, filter_client_ip, filter_reference_id)
49+
50+
if page_request_first:
51+
params['page_request.first'] = page_request_first
52+
53+
if page_request_after:
54+
params['page_request.after'] = page_request_after
55+
56+
if page_request_filter:
57+
params['page_request.filter'] = page_request_filter
58+
59+
if page_request_sort_by:
60+
params['page_request.sort_by'] = page_request_sort_by
61+
62+
if sort_by not in ACCEPTED_SORT_BY:
63+
raise ValueError(f"{sort_by} is not a valid sort type: {ACCEPTED_SORT_BY}")
64+
params['sort_by'] = sort_by
65+
66+
if sort_order not in ACCEPTED_SORT_ORDER:
67+
raise ValueError(f"{sort_order} is not a valid sort type: {ACCEPTED_SORT_ORDER}")
68+
params['sort_order'] = sort_order
69+
70+
response = self._client.get(f"{self._base_api}/events", params=params)
71+
return self.loaddict(response.json())
72+
73+
74+
def get_event_statistics(
75+
self,
76+
start_date=None,
77+
end_date=None,
78+
filter_action_value=ACCEPTED_ACTIONS[0],
79+
filter_result_value=ACCEPTED_RESULTS[0],
80+
filter_client_ip=None,
81+
filter_reference_id=None
82+
):
83+
"""
84+
Get WAF Event statistics
85+
You can use the parameters to add options to your request.
86+
"""
87+
params = Events._common_params(start_date, end_date, filter_action_value, \
88+
filter_result_value, filter_client_ip, filter_reference_id)
89+
response = self._client.get(f"{self._base_api}/event_stats", params=params)
90+
return self.loaddict(response.json())
91+
92+
93+
@staticmethod
94+
def _common_params(
95+
start_date,
96+
end_date,
97+
filter_action_value,
98+
filter_result_value,
99+
filter_client_ip,
100+
filter_reference_id
101+
):
102+
params = dict()
103+
104+
if end_date is None:
105+
end_date = dt.today()
106+
if start_date is None:
107+
start_date = end_date - timedelta(days=DEFAULT_DELTA_TIME)
108+
109+
end_date_iso = api_time_format(end_date)
110+
start_date_iso = api_time_format(start_date)
111+
112+
if start_date_iso > end_date_iso:
113+
raise ValueError(f"Search start date, \"{start_date_iso}\", is later than end date, \"{end_date_iso}\"!")
114+
115+
params['start_date'] = start_date_iso
116+
params['end_date'] = end_date_iso
117+
118+
if filter_action_value not in ACCEPTED_ACTIONS:
119+
raise ValueError(f"{filter_action_value} is not a valid action filter: {ACCEPTED_ACTIONS}")
120+
params['filter.action_value'] = filter_action_value
121+
122+
if filter_result_value not in ACCEPTED_RESULTS:
123+
raise ValueError(f"{filter_result_value} is not a valid action filter: {ACCEPTED_RESULTS}")
124+
params['filter.result_value'] = filter_result_value
125+
126+
if filter_client_ip:
127+
params['filter.client_ip'] = filter_client_ip
128+
129+
if filter_reference_id:
130+
params['filter.reference_id'] = filter_reference_id
131+
132+
return params
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import json
2+
from pystackpath.util import BaseObject, api_time_format
3+
from datetime import datetime as dt
4+
from datetime import timedelta
5+
6+
7+
ACCEPTED_GRANULARITY = ('AUTO', 'PT5M', 'PT1H', 'P1D', 'P1M')
8+
ACCEPTED_GROUP_BY = (
9+
'NONE', 'SITE', 'PLATFORM', 'POP',
10+
'REGION', 'STATUS', 'STATUS_CATEGORY'
11+
)
12+
ACCEPTED_METRIC_TYPE = ('TRANSFER', 'STATUS_CODE')
13+
DEFAULT_DELTA_TIME = 1 # day
14+
15+
16+
class Metrics(BaseObject):
17+
18+
def index(
19+
self,
20+
start_date=None,
21+
end_date=None,
22+
granularity=ACCEPTED_GRANULARITY[0],
23+
group_by=ACCEPTED_GROUP_BY[0],
24+
status_category=[],
25+
status_code=[],
26+
sites=[],
27+
billing_regions=[],
28+
pops=[],
29+
platforms=[],
30+
site_type_filter=[],
31+
metric_type=ACCEPTED_METRIC_TYPE[0]
32+
):
33+
"""
34+
Get all the Metrics.
35+
You can use the parameters to add options to your request.
36+
"""
37+
38+
params = dict()
39+
40+
if end_date is None:
41+
end_date = dt.today()
42+
if start_date is None:
43+
start_date = end_date - timedelta(days=DEFAULT_DELTA_TIME)
44+
45+
end_date_iso = api_time_format(end_date)
46+
start_date_iso = api_time_format(start_date)
47+
48+
if start_date_iso > end_date_iso:
49+
raise ValueError(f"Search start date, \"{start_date_iso}\", is later than end date, \"{end_date_iso}\"!")
50+
51+
params['start_date'] = start_date_iso
52+
params['end_date'] = end_date_iso
53+
54+
if granularity not in ACCEPTED_GRANULARITY:
55+
raise ValueError(f"{granularity} is not a valid granularity value: {ACCEPTED_GRANULARITY}")
56+
params['granularity'] = granularity
57+
58+
if group_by not in ACCEPTED_GROUP_BY:
59+
raise ValueError(f"{group_by} is not a valid group_by value: {ACCEPTED_GROUP_BY}")
60+
params['group_by'] = group_by
61+
62+
if metric_type not in ACCEPTED_METRIC_TYPE:
63+
raise ValueError(f"{metric_type} is not a valid metric type: {ACCEPTED_METRIC_TYPE}")
64+
params['metric_type'] = metric_type
65+
66+
if status_category:
67+
params['status_category'] = Metrics._list_to_string(status_category)
68+
69+
if status_code:
70+
params['status_code'] = Metrics._list_to_string(status_code)
71+
72+
if sites:
73+
params['sites'] = Metrics._list_to_string(sites)
74+
75+
if billing_regions:
76+
params['billing_regions'] = Metrics._list_to_string(billing_regions)
77+
78+
if pops:
79+
params['pops'] = Metrics._list_to_string(pops)
80+
81+
if platforms:
82+
params['platforms'] = Metrics._list_to_string(platforms)
83+
84+
if site_type_filter:
85+
params['site_type_filter'] = Metrics._list_to_string(site_type_filter)
86+
87+
response = self._client.get(f"{self._base_api}/metrics", params=params)
88+
return self.loaddict(response.json())
89+
90+
91+
@staticmethod
92+
def _list_to_string(items, separator=','):
93+
if not isinstance(items, list):
94+
raise ValueError(f"{items} is not a list")
95+
96+
try:
97+
return separator.join(items)
98+
except Exception as e:
99+
raise ValueError(f"{items} is not valid data: {e}")
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import json
2+
from pystackpath.util import BaseObject, api_time_format
3+
from datetime import datetime as dt
4+
from datetime import timedelta
5+
6+
7+
ACCEPTED_RESOLUTIONS = ('HOURLY', 'MINUTELY')
8+
DEFAULT_DELTA_TIME = 1 # day
9+
10+
11+
class Traffic(BaseObject):
12+
13+
def get(
14+
self,
15+
site_id=None,
16+
start_date=None,
17+
end_date=None,
18+
resolution=ACCEPTED_RESOLUTIONS[0]
19+
):
20+
"""
21+
Get Waf Traffic
22+
"""
23+
24+
params = dict()
25+
26+
if site_id is None:
27+
params['site_id'] = site_id
28+
29+
if end_date is None:
30+
end_date = dt.today()
31+
if start_date is None:
32+
start_date = end_date - timedelta(days=DEFAULT_DELTA_TIME)
33+
34+
end_date_iso = api_time_format(end_date)
35+
start_date_iso = api_time_format(start_date)
36+
37+
if start_date_iso > end_date_iso:
38+
raise ValueError(f"Search start date, \"{start_date_iso}\", is later than end date, \"{end_date_iso}\"!")
39+
40+
params['start_date'] = start_date_iso
41+
params['end_date'] = end_date_iso
42+
43+
if resolution not in ACCEPTED_RESOLUTIONS:
44+
raise ValueError(f"{resolution} is not a valid resolution: {ACCEPTED_RESOLUTIONS}")
45+
params['resolution'] = resolution
46+
47+
response = self._client.get(f"{self._base_api}/traffic", params=params)
48+
return self.loaddict(response.json())

0 commit comments

Comments
 (0)