From 8fb42186899e997b1cc9674ff5b573ad9146c2ff Mon Sep 17 00:00:00 2001 From: nik012003 Date: Tue, 28 Jun 2022 16:02:52 +0200 Subject: [PATCH] written new tests --- Dockerfile | 7 +- backend/app.py | 12 +-- backend/utils.py | 7 +- tests/{proxyapi.py => firegexapi.py} | 43 ++++++---- tests/test.py | 112 ++++++++++++++++++++------- 5 files changed, 127 insertions(+), 54 deletions(-) rename tests/{proxyapi.py => firegexapi.py} (76%) diff --git a/Dockerfile b/Dockerfile index 343ca03..973a32b 100755 --- a/Dockerfile +++ b/Dockerfile @@ -6,12 +6,15 @@ RUN apt-get update && apt-get -y install build-essential libboost-system-dev lib RUN mkdir /execute WORKDIR /execute -COPY ./backend/ /execute/ +ADD ./backend/requirements.txt /execute/requirements.txt RUN pip install --no-cache-dir -r /execute/requirements.txt ARG GCC_PARAMS -RUN c++ -O3 $GCC_PARAMS -o proxy/proxy proxy/proxy.cpp -pthread -lboost_system -lboost_thread +RUN mkdir proxy +ADD ./backend/proxy/proxy.cpp /execute/proxy/proxy.cpp +RUN c++ -O3 -march=native $GCC_PARAMS -o proxy/proxy proxy/proxy.cpp -pthread -lboost_system -lboost_thread +COPY ./backend/ /execute/ COPY ./frontend/build/ ./frontend/ RUN usermod -a -G root nobody diff --git a/backend/app.py b/backend/app.py index daf0141..7054f36 100644 --- a/backend/app.py +++ b/backend/app.py @@ -10,7 +10,8 @@ ON_DOCKER = len(sys.argv) > 1 and sys.argv[1] == "DOCKER" DEBUG = len(sys.argv) > 1 and sys.argv[1] == "DEBUG" # DB init -db = SQLite('firegex') +if not os.path.exists("db"): os.mkdir("db") +db = SQLite('db/firegex.db') db.connect() conf = KeyValueStorage(db) firewall = ProxyManager(db) @@ -25,12 +26,13 @@ def shutdown_event(): app.add_middleware(SessionMiddleware, secret_key=os.urandom(32)) SESSION_TOKEN = secrets.token_hex(8) APP_STATUS = "init" -REACT_BUILD_DIR = "../frontend/build/" if not ON_DOCKER else "../frontend/" +REACT_BUILD_DIR = "../frontend/build/" if not ON_DOCKER else "frontend/" REACT_HTML_PATH = os.path.join(REACT_BUILD_DIR,"index.html") def is_loggined(request: Request): + global SESSION_TOKEN return request.session.get("token", "") == SESSION_TOKEN def login_check(request: Request): @@ -54,7 +56,7 @@ class PasswordChangeForm(BaseModel): @app.post("/api/login") async def login_api(request: Request, form: PasswordForm): - global APP_STATUS + global APP_STATUS, SESSION_TOKEN if APP_STATUS != "run": raise HTTPException(status_code=400) if form.password == "": @@ -75,7 +77,7 @@ async def logout(request: Request): @app.post('/api/change-password') async def change_password(request: Request, form: PasswordChangeForm): login_check(request) - global APP_STATUS + global APP_STATUS, SESSION_TOKEN if APP_STATUS != "run": raise HTTPException(status_code=400) if form.password == "": @@ -91,7 +93,7 @@ async def change_password(request: Request, form: PasswordChangeForm): @app.post('/api/set-password') async def set_password(request: Request, form: PasswordForm): - global APP_STATUS + global APP_STATUS, SESSION_TOKEN if APP_STATUS != "init": raise HTTPException(status_code=400) if form.password == "": return {"status":"Cannot insert an empty password!"} diff --git a/backend/utils.py b/backend/utils.py index 66ec185..663233a 100755 --- a/backend/utils.py +++ b/backend/utils.py @@ -13,13 +13,12 @@ class SQLite(): self.lock = threading.Lock() def connect(self) -> None: - if not os.path.exists("db"): os.mkdir("db") try: - self.conn = sqlite3.connect("db/" + self.db_name + '.db', check_same_thread = False) + self.conn = sqlite3.connect(self.db_name, check_same_thread = False) except Exception: - with open("db/" + self.db_name + '.db', 'x'): + with open(self.db_name, 'x'): pass - self.conn = sqlite3.connect("db/" + self.db_name + '.db', check_same_thread = False) + self.conn = sqlite3.connect(self.db_name, check_same_thread = False) def dict_factory(cursor, row): d = {} for idx, col in enumerate(cursor.description): diff --git a/tests/proxyapi.py b/tests/firegexapi.py similarity index 76% rename from tests/proxyapi.py rename to tests/firegexapi.py index 590dfa3..117a14e 100644 --- a/tests/proxyapi.py +++ b/tests/firegexapi.py @@ -1,13 +1,16 @@ from requests import Session -class ProxyAPI: - def __init__(self,address,password): +class FiregexAPI: + def __init__(self,address): self.s = Session() self.address = address - self.password = password - def connect(self): - req = self.s.post(f"{self.address}api/login", json={"password":self.password}) + def login(self,password): + req = self.s.post(f"{self.address}api/login", json={"password":password}) + return req.json()["status"] == "ok" + + def logout(self): + req = self.s.get(f"{self.address}api/logout") return req.json()["status"] == "ok" def create_service(self,service_name,service_port): @@ -16,16 +19,14 @@ class ProxyAPI: def get_service_details(self,service_name): req = self.s.get(f"{self.address}api/services") - internal_port = service_id = None + service = None try: for service in req.json(): if service["name"] == service_name: - service_id = service["id"] - internal_port = service["internal_port"] - break + return service except Exception: pass - return service_id,internal_port + return service def get_service_status(self,service_id): req = self.s.get(f"{self.address}api/service/{service_id}") @@ -34,7 +35,20 @@ class ProxyAPI: def get_service_regexes(self,service_id): req = self.s.get(f"{self.address}api/service/{service_id}/regexes") return req.json() - + + def get_regex(self,regex_id): + req = self.s.get(f"{self.address}api/regex/{regex_id}") + return req.json() + + def add_regex(self,service_id,regex,is_blacklist = True, is_case_sensitive = True, mode = "B"): + req = self.s.post(f"{self.address}api/regexes/add", + json={"is_blacklist":is_blacklist,"is_case_sensitive":is_case_sensitive,"service_id":service_id,"mode":mode,"regex":regex}) + return req.json()["status"] == "ok" + + def delete_regex(self,regex_id): + req = self.s.get(f"{self.address}api/regex/{regex_id}/delete") + return req.json()["status"] == "ok" + def start(self,service_id): req = self.s.get(f"{self.address}api/service/{service_id}/start") return req.json()["status"] == "ok" @@ -50,9 +64,4 @@ class ProxyAPI: def delete(self,service_id): req = self.s.get(f"{self.address}api/service/{service_id}/delete") return req.json()["status"] == "ok" - - def add_regex(self,service_id,regex,is_blacklist = True, is_case_sensitive = True, mode = "B"): - req = self.s.post(f"{self.address}api/regexes/add", - json={"is_blacklist":is_blacklist,"is_case_sensitive":is_case_sensitive,"service_id":service_id,"mode":mode,"regex":regex}) - return req.json()["status"] == "ok" - + \ No newline at end of file diff --git a/tests/test.py b/tests/test.py index 28968be..7e6acf7 100755 --- a/tests/test.py +++ b/tests/test.py @@ -2,7 +2,7 @@ import argparse, socket,secrets, base64 from time import sleep from multiprocessing import Process -from proxyapi import ProxyAPI +from firegexapi import FiregexAPI pref = "\033[" reset = f"{pref}0m" @@ -33,16 +33,16 @@ puts(f"Testing will start on ", color=colors.cyan, end="") puts(f"{args.address}", color=colors.yellow) -proxy = ProxyAPI(args.address,args.password) +firegex = FiregexAPI(args.address) service_created = False #Connect to Firegex -if (proxy.connect()): puts(f"Sucessfully logged in ✔", color=colors.green) +if (firegex.login(args.password)): puts(f"Sucessfully logged in ✔", color=colors.green) else: puts(f"Test Failed: Unknown response or wrong passowrd ✗", color=colors.red); exit(1) #Create new Service -if (proxy.create_service(args.service_name,args.service_port)): +if (firegex.create_service(args.service_name,args.service_port)): puts(f"Sucessfully created service {args.service_name} with public port {args.service_port} ✔", color=colors.green) service_created = True else: puts(f"Test Failed: Couldn't create service ✗", color=colors.red); exit(1) @@ -50,7 +50,7 @@ else: puts(f"Test Failed: Couldn't create service ✗", color=colors.red); exit( #Delete the Service and exit def exit_test(status_code=0): if service_created: - if(proxy.delete(service_id)): + if(firegex.delete(service_id)): puts(f"Sucessfully delete service with id {service_id} ✔", color=colors.green) else: puts(f"Test Failed: Couldn't delete service ✗", color=colors.red); exit(1) @@ -59,13 +59,17 @@ def exit_test(status_code=0): exit(status_code) #Find the Service -service_id, internal_port = proxy.get_service_details(args.service_name) -if (internal_port): puts(f"Sucessfully received the internal port {internal_port} ✔", color=colors.green) +service = firegex.get_service_details(args.service_name) +if (service): + internal_port= service["internal_port"] + service_id = service["id"] + puts(f"Sucessfully received the internal port {internal_port} ✔", color=colors.green) else: puts(f"Test Failed: Coulnd't get the service internal port ✗", color=colors.red); exit_test(1) #Start listener def startServer(port): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(('127.0.0.1', port)) sock.listen(8) while True: @@ -78,7 +82,7 @@ server = Process(target=startServer,args=[internal_port]) server.start() #Start firewall -if(proxy.start(service_id)): puts(f"Sucessfully started service with id {service_id} ✔", color=colors.green) +if(firegex.start(service_id)): puts(f"Sucessfully started service with id {service_id} ✔", color=colors.green) else: puts(f"Test Failed: Coulnd't start the service ✗", color=colors.red); exit_test(1) #Hacky solution - wait a bit for the server to start @@ -101,25 +105,33 @@ else: #Add new regex secret = bytes(secrets.token_hex(16).encode()) regex = base64.b64encode(secret).decode() -if(proxy.add_regex(service_id,regex)): puts(f"Sucessfully added regex {secret} ✔", color=colors.green) -else: puts(f"Test Failed: Coulnd't start the service ✗", color=colors.red); exit_test(1) +if(firegex.add_regex(service_id,regex)): puts(f"Sucessfully added regex {secret} ✔", color=colors.green) +else: puts(f"Test Failed: Coulnd't add the regex {secret} ✗", color=colors.red); exit_test(1) #Check if regex is present in the service +n_blocked = 0 + def checkRegex(regex): - for i,r in enumerate(proxy.get_service_regexes(service_id)): + global n_blocked + for r in firegex.get_service_regexes(service_id): if r["regex"] == regex: #Test the regex if not sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)): puts(f"The malicious request was successfully blocked ✔", color=colors.green) + n_blocked += 1 + if firegex.get_regex(r["id"])["n_packets"] == n_blocked: + puts(f"The packed was reported as blocked ✔", color=colors.green) + else: + puts(f"Test Failed: The packed wasn't reported as blocked ✗", color=colors.red); exit_test(1) else: - puts(f"Test Failed: The request wasn't blocked ✗", color=colors.red); exit_test(1) + puts(f"Test Failed: The request wasn't blocked ✗", color=colors.red);exit_test(1) return - puts(f"Test Failed: The regex wasn't found ✗", color=colors.red) + puts(f"Test Failed: The regex wasn't found ✗", color=colors.red); exit_test(1) checkRegex(regex) #Pause the proxy -if(proxy.pause(service_id)): puts(f"Sucessfully paused service with id {service_id} ✔", color=colors.green) +if(firegex.pause(service_id)): puts(f"Sucessfully paused service with id {service_id} ✔", color=colors.green) else: puts(f"Test Failed: Coulnd't pause the service ✗", color=colors.red); exit_test(1) #Check if it's actually paused @@ -127,20 +139,68 @@ if sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)): puts(f"The request wasn't blocked ✔", color=colors.green) else: puts(f"Test Failed: The request was blocked when it shouldn't have", color=colors.red) - #Stop the proxy -if(proxy.stop(service_id)): puts(f"Sucessfully stopped service with id {service_id} ✔", color=colors.green) +if(firegex.stop(service_id)): puts(f"Sucessfully stopped service with id {service_id} ✔", color=colors.green) else: puts(f"Test Failed: Coulnd't stop the service ✗", color=colors.red); exit_test(1) -sleep(100) -#Check if proxy is stopped -try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.bind(('0.0.0.0', args.service_port)) - puts(f"I could bind to the port, so {service_id} was stopped correctly ✔", color=colors.green) - sock.close() -except Exception as e: - print(e) - puts(f"Test Failed: Coulnd't bind to port {args.service_port} ✗", color=colors.red); exit_test(1) +#Check if proxy is stopped and check if WAIT works +def bindForSeconds(port,delay=4): + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind(('127.0.0.1', port)) + sock.listen() + puts(f"The test could bind to port {port} ✔", color=colors.green) + sleep(delay) + sock.close() + except Exception as e: + puts(f"The test couldn't bind to port {port} ✗", color=colors.red) + +bindingTest = Process(target=bindForSeconds, args=[args.service_port]) +bindingTest.start() +sleep(1) + +#Restart it +if(firegex.pause(service_id)): puts(f"Sucessfully started in pause mode ✔", color=colors.green) +else: puts(f"Test Failed: Coulnd't start the service ✗", color=colors.red); exit_test(1) +if firegex.get_service_details(args.service_name)["status"] == "wait": + puts(f"Service started in WAIT mode ✔", color=colors.green) +else: + puts(f"Service started but it's not WAIT mode ✗", color=colors.red); exit_test(1) + +bindingTest.join() +sleep(1) +#Check if service started in pause mode successfully +if firegex.get_service_details(args.service_name)["status"] == "pause": + puts(f"Service started in PAUSE mode ✔", color=colors.green) +else: + puts(f"Service is not in PAUSE mode ✗", color=colors.red); exit_test(1) + +if sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)): + puts(f"The request wasn't blocked ✔", color=colors.green) +else: + puts(f"Test Failed: The request was blocked when it shouldn't have", color=colors.red) + +#Restart it and check +if(firegex.start(service_id)): puts(f"Sucessfully started service with id {service_id} ✔", color=colors.green) +else: puts(f"Test Failed: Coulnd't start the service ✗", color=colors.red); exit_test(1) + +checkRegex(regex) + +#Delete the regex +def removeRegex(regex): + for r in firegex.get_service_regexes(service_id): + if r["regex"] == regex: + if(firegex.delete_regex(r["id"])): puts(f"Sucessfully deleted regex ✔", color=colors.green) + else: puts(f"Test Failed: Coulnd't deleted the regex ✗", color=colors.red); exit_test(1) + return + puts(f"Test Failed: The regex wasn't found ✗", color=colors.red) + +removeRegex(regex) + +if sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)): + puts(f"The request wasn't blocked ✔", color=colors.green) +else: + puts(f"Test Failed: The request was blocked when it shouldn't have", color=colors.red) exit_test() \ No newline at end of file