Skip to content

PR : Add reporting for API #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 84 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
a36fc35
Create a basic new Agent class
Jul 24, 2024
5062dfe
Create the super class for API's
Jul 24, 2024
3b403fc
create an HTTP API class
Jul 24, 2024
4ba6703
Install and import requests
Jul 24, 2024
211421c
Linting
Jul 24, 2024
f81f549
Rename to timeout_in_sec
Jul 24, 2024
adbfa83
Send data using requests.post
Jul 24, 2024
1e88fcc
Create a class that encapsulates the token
Jul 24, 2024
465c746
Give back api response in http_api file
Jul 24, 2024
87a71ae
update the way to_api_response() function works
Jul 24, 2024
9689a29
Add tests for token class
Jul 24, 2024
9eecfc0
Add tests for ReportingApi class
Jul 24, 2024
434d830
Move token file into a helper module with new function get_token_from…
Jul 24, 2024
d25f1c1
Create a should_block helper function
Jul 24, 2024
58e0201
Linting
Jul 24, 2024
3ff2bf3
Create agent and add get_token_from_env func
Jul 24, 2024
24f1869
add send_heartbeat and some auxiliary funcs
Jul 24, 2024
20bf490
self.token needs to be defined for these 2 funcs
Jul 24, 2024
c6705e5
Use self.timeout_in_sec
Jul 24, 2024
41c5b05
add on_start function
Jul 24, 2024
db277ed
Update get_agent_info function
Jul 24, 2024
cd6a24f
Linting
Jul 24, 2024
164eae3
Add some stuff already to on_detected_attack
Jul 24, 2024
e0e5fef
Add new helper function limit_length_metadata
Jul 24, 2024
b04031b
Use new helper function in agent.py to limit metadata
Jul 24, 2024
78f6599
Change interval to 10 minutes
Jul 25, 2024
2305285
Merge remote-tracking branch 'origin/AIK-3167' into AIK-3210
Jul 25, 2024
d3914f4
Renaming agent to reporter and fixing left scars of merge
Jul 25, 2024
747d825
Validate token using Token class in Reporter
Jul 29, 2024
1bceaba
Use .timestamp() on datetime
Jul 29, 2024
0d3b1d3
Bugfix, should be json= instead of data=
Jul 29, 2024
ca25686
Only parse if status code is 200, use json.loads and debug if error
Jul 29, 2024
0a47b8f
Fix bug, unixtime needs to be sent in ms
Jul 29, 2024
dbfa324
Use a PKG_VERSION const
Jul 29, 2024
2bce5f6
Create a get_ip() function
Jul 29, 2024
66fcb28
Update blocking in the updateConfig function
Jul 29, 2024
224a864
Linting
Jul 29, 2024
177c9fc
Add a heartbeats.py file with heartbeat logic (interval, event sched)
Jul 29, 2024
f5e6a3b
Add missing data (empty) to the request
Jul 29, 2024
19cda6b
linting for if statement in token.py
Jul 29, 2024
1c8a006
Mistake with 2x token wrappin
Jul 29, 2024
00548d4
Merge branch 'AIK-3199' into AIK-3210
Jul 29, 2024
633e182
Merge branch 'AIK-3199' into AIK-3210
Jul 29, 2024
1ac32d0
Flask shouldn't reload, messes up our bg job
Jul 29, 2024
739f18a
Create a reporter with a local api url
Jul 29, 2024
caece69
Using an array as data for send_data function is pointless
Jul 29, 2024
bbc0b1e
Add aikido as host in docker
Jul 29, 2024
1b9fd0f
Run on_start when initiating a Reporter
Jul 29, 2024
0ffe068
Check if result is successfull of API
Jul 29, 2024
1e869ea
Fix bug with not detecting the timeout error
Jul 29, 2024
058ab89
Forgotten import + report attacks when emptying queue
Jul 29, 2024
3d2143e
Make context object picklable
Jul 29, 2024
0121d6a
Update the on_detected_attack function
Jul 29, 2024
bd98fe7
Linting
Jul 29, 2024
c5bce7d
Extract extra nformation and user-agent from headers
Jul 29, 2024
49e41f0
Allow polling for config, and do it to see if we should block
Jul 30, 2024
ae4c585
Report route to aikido server
Jul 30, 2024
cd3bfab
Fix bug with hung connection
Jul 30, 2024
771c949
Create get_subdomains_from_url helper function
Jul 30, 2024
f42108d
Add subdomains to context
Jul 30, 2024
c55eaaa
Create a scheduler in reporting thread, send out heartbeats using it
Jul 30, 2024
f5b5c3e
Fix bug with blocking not being updated by using hasattr
Jul 30, 2024
706ca0e
Merge branch 'AIK-3167' into AIK-3210
Jul 30, 2024
1bfa13a
Make sure the url is a string
Jul 30, 2024
b47aea8
Merge branch 'main' into AIK-3210
bitterpanda63 Jul 30, 2024
9877d00
Don't raise an exception at HTTPApi, just logger.error it
Jul 30, 2024
310f538
Rename to context_contains_sql_injection
Jul 30, 2024
5c50abf
Rename s to event_scheduler in heartbeats.py
Jul 30, 2024
a83ab91
Fix merge issues, add back lost code
Jul 30, 2024
f76ea56
Replac with contains_injection and add blocking code to mysqlclient
Jul 30, 2024
6a92882
Linting
Jul 30, 2024
87eb9f9
Heartbeat every 10 minutes
Jul 30, 2024
9523f51
Report sec interval needs to be near instant (5 seconds)
Jul 30, 2024
bde23b8
Split all helper functions for reporter up into files
Jul 30, 2024
d6a5d32
Add tests for get_ua_from_context
Jul 30, 2024
89dd55c
Add tests for get_unixtime_ms
Jul 30, 2024
7202571
Add tests for get_ip
Jul 30, 2024
cdf840d
Bugfix where http_api would still try and parse if an exception occured
Jul 30, 2024
6d8bae6
Add testing for http_api
Jul 30, 2024
fce720b
Add comments clarifying timeout_in_sec variable
Jul 30, 2024
a359dc3
Add tests for heartbeats.py
Jul 30, 2024
4e6dbba
REPORT_SEC_INTERVAL to EMPTY_QUEUE_INTERVAL
Jul 30, 2024
b2203d2
Update aikido_firewall/background_process/aikido_background_process.py
willem-delbare Jul 30, 2024
34ef86f
Create a new Reporter using named arguments for clarity
Jul 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions aikido_firewall/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from dotenv import load_dotenv

# Constants
PKG_VERSION = "0.0.1"

# Import logger
from aikido_firewall.helpers.logging import logger
Expand Down
28 changes: 28 additions & 0 deletions aikido_firewall/background_process/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
init.py file for api/ folder. Includes abstract class ReportingApi
"""

import json
from aikido_firewall.helpers.logging import logger


class ReportingApi:
"""This is the super class for the reporting API's"""

def to_api_response(self, res):
"""Converts results into an Api response obj"""
status = res.status_code
if status == 429:
return {"success": False, "error": "rate_limited"}
elif status == 401:
return {"success": False, "error": "invalid_token"}
elif status == 200:
try:
return json.loads(res.text)
except Exception as e:
logger.debug(e)
logger.debug(res.text)

Check warning on line 24 in aikido_firewall/background_process/api/__init__.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/api/__init__.py#L22-L24

Added lines #L22 - L24 were not covered by tests
return {"success": False, "error": "unknown_error"}

def report(self, token, event, timeout_in_sec):
"""Report event to aikido server"""
32 changes: 32 additions & 0 deletions aikido_firewall/background_process/api/http_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Exports the HTTP API class
"""

import requests
from aikido_firewall.background_process.api import ReportingApi

Check warning on line 6 in aikido_firewall/background_process/api/http_api.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/api/http_api.py#L5-L6

Added lines #L5 - L6 were not covered by tests


class ReportingApiHTTP(ReportingApi):

Check warning on line 9 in aikido_firewall/background_process/api/http_api.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/api/http_api.py#L9

Added line #L9 was not covered by tests
"""HTTP Reporting API"""

def __init__(self, reporting_url):
self.reporting_url = reporting_url

Check warning on line 13 in aikido_firewall/background_process/api/http_api.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/api/http_api.py#L12-L13

Added lines #L12 - L13 were not covered by tests

def report(self, token, event, timeout_in_sec):
try:
res = requests.post(

Check warning on line 17 in aikido_firewall/background_process/api/http_api.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/api/http_api.py#L15-L17

Added lines #L15 - L17 were not covered by tests
self.reporting_url + "api/runtime/events",
json=event,
timeout=timeout_in_sec,
headers=get_headers(token),
)
except requests.exceptions.ConnectionError:
return {"success": False, "error": "timeout"}
except Exception as e:
raise e
return self.to_api_response(res)

Check warning on line 27 in aikido_firewall/background_process/api/http_api.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/api/http_api.py#L23-L27

Added lines #L23 - L27 were not covered by tests


def get_headers(token):

Check warning on line 30 in aikido_firewall/background_process/api/http_api.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/api/http_api.py#L30

Added line #L30 was not covered by tests
"""Returns headers"""
return {"Content-Type": "application/json", "Authorization": str(token)}

Check warning on line 32 in aikido_firewall/background_process/api/http_api.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/api/http_api.py#L32

Added line #L32 was not covered by tests
44 changes: 44 additions & 0 deletions aikido_firewall/background_process/api/init_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import pytest
from aikido_firewall.background_process.api import ReportingApi

# Test ReportingApi Class :
from requests.models import Response


@pytest.fixture
def reporting_api():
return ReportingApi()


def test_to_api_response_rate_limited(reporting_api):
res = Response()
res.status_code = 429
assert reporting_api.to_api_response(res) == {
"success": False,
"error": "rate_limited",
}


def test_to_api_response_invalid_token(reporting_api):
res = Response()
res.status_code = 401
assert reporting_api.to_api_response(res) == {
"success": False,
"error": "invalid_token",
}


def test_to_api_response_unknown_error(reporting_api):
res = Response()
res.status_code = 500 # Simulating an unknown error status code
assert reporting_api.to_api_response(res) == {
"success": False,
"error": "unknown_error",
}


def test_to_api_response_valid_json(reporting_api):
res = Response()
res.status_code = 200
res._content = b'{"key": "value"}' # Simulating valid JSON response
assert reporting_api.to_api_response(res) == {"key": "value"}
30 changes: 30 additions & 0 deletions aikido_firewall/background_process/heartbeats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""
The code to send out a heartbeat is in here
"""

from aikido_firewall.helpers.logging import logger

Check warning on line 5 in aikido_firewall/background_process/heartbeats.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/heartbeats.py#L5

Added line #L5 was not covered by tests


def send_heartbeats_every_x_secs(reporter, interval_in_secs, s):

Check warning on line 8 in aikido_firewall/background_process/heartbeats.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/heartbeats.py#L8

Added line #L8 was not covered by tests
"""
Start sending out heartbeats every x seconds
"""
if reporter.serverless:
logger.debug("Running in serverless environment, not starting heartbeats")
return
if not reporter.token:
logger.debug("No token provided, not starting heartbeats")
return

Check warning on line 17 in aikido_firewall/background_process/heartbeats.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/heartbeats.py#L12-L17

Added lines #L12 - L17 were not covered by tests

logger.debug("Starting heartbeats")

Check warning on line 19 in aikido_firewall/background_process/heartbeats.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/heartbeats.py#L19

Added line #L19 was not covered by tests

s.enter(0, 1, send_heartbeat_wrapper, (reporter, interval_in_secs, s))

Check warning on line 21 in aikido_firewall/background_process/heartbeats.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/heartbeats.py#L21

Added line #L21 was not covered by tests


def send_heartbeat_wrapper(rep, interval_in_secs, s):

Check warning on line 24 in aikido_firewall/background_process/heartbeats.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/heartbeats.py#L24

Added line #L24 was not covered by tests
"""
Wrapper function for send_heartbeat so we get an interval
"""
s.enter(interval_in_secs, 1, send_heartbeat_wrapper, (rep, interval_in_secs, s))
logger.debug("Heartbeat...")
rep.send_heartbeat()

Check warning on line 30 in aikido_firewall/background_process/heartbeats.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/heartbeats.py#L28-L30

Added lines #L28 - L30 were not covered by tests
172 changes: 172 additions & 0 deletions aikido_firewall/background_process/reporter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
""" This file simply exports the Reporter class"""

import time
import socket
import platform
import json
from copy import deepcopy
from aikido_firewall.helpers.logging import logger
from aikido_firewall.helpers.limit_length_metadata import limit_length_metadata
from aikido_firewall.helpers.token import Token
from aikido_firewall import PKG_VERSION
from aikido_firewall.background_process.heartbeats import send_heartbeats_every_x_secs

Check warning on line 12 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L3-L12

Added lines #L3 - L12 were not covered by tests


class Reporter:

Check warning on line 15 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L15

Added line #L15 was not covered by tests
"""Reporter class"""

timeout_in_sec = 5
heartbeat_secs = 10

Check warning on line 19 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L18-L19

Added lines #L18 - L19 were not covered by tests

def __init__(self, block, api, token, serverless, event_scheduler):
self.block = block
self.api = api
self.token = token # Should be instance of the Token class!

Check warning on line 24 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L21-L24

Added lines #L21 - L24 were not covered by tests

if isinstance(serverless, str) and len(serverless) == 0:
raise ValueError("Serverless cannot be an empty string")
self.serverless = serverless

Check warning on line 28 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L26-L28

Added lines #L26 - L28 were not covered by tests

self.on_start()
send_heartbeats_every_x_secs(self, self.heartbeat_secs, event_scheduler)

Check warning on line 31 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L30-L31

Added lines #L30 - L31 were not covered by tests

def on_detected_attack(self, attack, context):

Check warning on line 33 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L33

Added line #L33 was not covered by tests
"""
This will send something to the API when an attack is detected
"""
if not self.token:
return

Check warning on line 38 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L37-L38

Added lines #L37 - L38 were not covered by tests
# Modify attack so we can send it out :
try:
attack["user"] = None
attack["payload"] = json.dumps(attack["payload"])[:4096]
attack["metadata"] = limit_length_metadata(attack["metadata"], 4096)
attack["blocked"] = self.block

Check warning on line 44 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L40-L44

Added lines #L40 - L44 were not covered by tests

payload = {

Check warning on line 46 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L46

Added line #L46 was not covered by tests
"type": "detected_attack",
"time": get_unixtime_ms(),
"agent": self.get_reporter_info(),
"attack": attack,
"request": {
"method": context.method,
"url": context.url,
"ipAddress": context.remote_address,
"userAgent": get_ua_from_context(context),
"body": context.body,
"headers": context.headers,
"source": context.source,
"route": context.route,
},
}
logger.debug(json.dumps(payload))
result = self.api.report(

Check warning on line 63 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L62-L63

Added lines #L62 - L63 were not covered by tests
self.token,
payload,
self.timeout_in_sec,
)
logger.debug("Result : %s", result)
except Exception as e:
logger.debug(e)
logger.info("Failed to report attack")

Check warning on line 71 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L68-L71

Added lines #L68 - L71 were not covered by tests

def send_heartbeat(self):

Check warning on line 73 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L73

Added line #L73 was not covered by tests
"""
This will send a heartbeat to the server
"""
if not self.token:
return
logger.debug("Aikido Reporter : Sending out heartbeat")
res = self.api.report(

Check warning on line 80 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L77-L80

Added lines #L77 - L80 were not covered by tests
self.token,
{
"type": "heartbeat",
"time": get_unixtime_ms(),
"agent": self.get_reporter_info(),
"stats": {
"sinks": {},
"startedAt": 0,
"endedAt": 0,
"requests": {
"total": 0,
"aborted": 0,
"attacksDetected": {
"total": 0,
"blocked": 0,
},
},
},
"hostnames": [],
"routes": [],
"users": [],
},
self.timeout_in_sec,
)
self.update_service_config(res)

Check warning on line 105 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L105

Added line #L105 was not covered by tests

def on_start(self):

Check warning on line 107 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L107

Added line #L107 was not covered by tests
"""
This will send out an Event signalling the start to the server
"""
if not self.token:
return
res = self.api.report(

Check warning on line 113 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L111-L113

Added lines #L111 - L113 were not covered by tests
self.token,
{
"type": "started",
"time": get_unixtime_ms(),
"agent": self.get_reporter_info(),
},
self.timeout_in_sec,
)
self.update_service_config(res)

Check warning on line 122 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L122

Added line #L122 was not covered by tests

def get_reporter_info(self):

Check warning on line 124 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L124

Added line #L124 was not covered by tests
"""
This returns info about the reporter
"""
return {

Check warning on line 128 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L128

Added line #L128 was not covered by tests
"dryMode": not self.block,
"hostname": socket.gethostname(),
"version": PKG_VERSION,
"library": "firewall_python",
"ipAddress": get_ip(),
"packages": [],
"serverless": bool(self.serverless),
"stack": [],
"os": {"name": platform.system(), "version": platform.release()},
"preventedPrototypePollution": False, # Get this out of the API maybe?
"nodeEnv": "",
}

def update_service_config(self, res):

Check warning on line 142 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L142

Added line #L142 was not covered by tests
"""
Update configuration based on the server's response
"""
if res["success"] is False:
logger.debug(res)
return
if "block" in res.keys() and res["block"] != self.block:
logger.debug("Updating blocking, setting blocking to : %s", res["block"])
self.block = bool(res["block"])

Check warning on line 151 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L146-L151

Added lines #L146 - L151 were not covered by tests


def get_unixtime_ms():

Check warning on line 154 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L154

Added line #L154 was not covered by tests
"""Get the current unix time but in ms"""
return int(time.time() * 1000)

Check warning on line 156 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L156

Added line #L156 was not covered by tests


def get_ip():

Check warning on line 159 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L159

Added line #L159 was not covered by tests
"""Tries to fetch the IP and returns 0.0.0.0 on failure"""
try:
return socket.gethostbyname(socket.gethostname())
except Exception:
return "0.0.0.0"

Check warning on line 164 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L161-L164

Added lines #L161 - L164 were not covered by tests


def get_ua_from_context(context):

Check warning on line 167 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L167

Added line #L167 was not covered by tests
"""Tries to retrieve the user agent from context"""
for k, v in context.headers.items():
if k.lower() == "user-agent":
return v
return None

Check warning on line 172 in aikido_firewall/background_process/reporter.py

View check run for this annotation

Codecov / codecov/patch

aikido_firewall/background_process/reporter.py#L169-L172

Added lines #L169 - L172 were not covered by tests
33 changes: 23 additions & 10 deletions aikido_firewall/context/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import threading
from urllib.parse import parse_qs
from http.cookies import SimpleCookie

from aikido_firewall.helpers.build_route_from_url import build_route_from_url
from aikido_firewall.helpers.get_subdomains_from_url import get_subdomains_from_url

SUPPORTED_SOURCES = ["django", "flask", "django-gunicorn"]
UINPUT_SOURCES = ["body", "cookies", "query", "headers"]
Expand Down Expand Up @@ -51,7 +52,11 @@ class Context:
for vulnerability detection
"""

def __init__(self, req, source):
def __init__(self, context_obj=None, req=None, source=None):
if context_obj:
self.__dict__.update(context_obj)
return

if not source in SUPPORTED_SOURCES:
raise ValueError(f"Source {source} not supported")
self.source = source
Expand All @@ -63,6 +68,8 @@ def __init__(self, req, source):
self.set_django_attrs(req)
elif source == "django-gunicorn":
self.set_django_gunicorn_attrs(req)
self.route = build_route_from_url(self.url)
self.subdomains = get_subdomains_from_url(self.url)

def set_django_gunicorn_attrs(self, req):
"""Set properties that are specific to django-gunicorn"""
Expand Down Expand Up @@ -93,14 +100,20 @@ def __reduce__(self):
return (
self.__class__,
(
self.method,
self.remote_address,
self.url,
self.body,
self.headers,
self.query,
self.cookies,
self.source,
{
"method": self.method,
"remote_address": self.remote_address,
"url": self.url,
"body": self.body,
"headers": self.headers,
"query": self.query,
"cookies": self.cookies,
"source": self.source,
"route": self.route,
"subdomains": self.subdomains,
},
None,
None,
),
)

Expand Down
Loading
Loading