Skip to content

Commit

Permalink
Isolates the OWTF webapp from the complete project (owtf#1277)
Browse files Browse the repository at this point in the history
* resolves issue owtf#1241

* fix: implement http.cookies

* fix:bug with decode

* fix: worker logs text

* fix: worker logs handling

* Revert "fix: worker logs handling"

This reverts commit 502608e.

* Revert "fix: worker logs text"

This reverts commit 8463f3d.

* patch:spacings

* fix:deprecated dependencies

* feat:frontend dockerfile done

* chore:frontend bugs fixed

* chore:changed  docker compose

* chore:fixing cors and output file issue

* chore: optimizing docker build for owtf-backend

* chore:implemented script to setup webapp

* fix:fixed formatting issues

* feat:frontend dockerfile done

* chore:frontend bugs fixed

* chore:changed  docker compose

* chore:fixing cors and output file issue

* chore: optimizing docker build for owtf-backend

* chore:implemented script to setup webapp

* fix:fixed formatting issues

* fix:dependency issue

* patch:refactored the code

* OWTF Kubernetes Deployment Manifests (owtf#1285)

* Add kubernetes manifests

* Update README.md

* Update deploy-script.sh

* OWTF-IG comprehensive update on Enumeration and Discovery (owtf#1283)

* Added dirsearch, capabilities for nmap, zip, unzip for SecLists

* Added capabilities for container in compose file

* Added dirsearch and SecLists entries

* Force rebuild of new container (for new versions)

* Fixing dirsearch virtual env issues. Typo in resources.cfg

* Move dirsearch installation from Dockerfile to install script

* Fixing tools custom installation

* Allow user to build owtf container with and without permissive network capabilities

* Adjust tools' configurations and running commands

* Fixing requests package version conflict between owtf and dirsearch

* feat:frontend dockerfile done

* chore:frontend bugs fixed

* chore:changed  docker compose

* chore:fixing cors and output file issue

* chore: optimizing docker build for owtf-backend

* chore:implemented script to setup webapp

* fix:fixed formatting issues

* resolves issue owtf#1241

* fix: implement http.cookies

* fix:bug with decode

* fix: worker logs text

* fix: worker logs handling

* Revert "fix: worker logs handling"

This reverts commit 502608e.

* Revert "fix: worker logs text"

This reverts commit 8463f3d.

* fix:deprecated dependencies

* feat:frontend dockerfile done

* chore:frontend bugs fixed

* chore:changed  docker compose

* chore:fixing cors and output file issue

* chore: optimizing docker build for owtf-backend

* chore:implemented script to setup webapp

* fix:fixed formatting issues

* fix:dependency issue

* patch:refactored the code

---------

Co-authored-by: Pratham <[email protected]>
Co-authored-by: Rahul Surwade <[email protected]>
Co-authored-by: Vinh Pham Ngoc Thanh <[email protected]>
  • Loading branch information
4 people authored Aug 20, 2024
1 parent 402f8f8 commit 8e7096c
Show file tree
Hide file tree
Showing 36 changed files with 48,376 additions and 20,895 deletions.
1 change: 0 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ jobs:
run: |
sudo apt update
sudo apt -y install libffi-dev golang postgresql-client libgnutls28-dev libyaml-dev python3-yaml python3-pip libcurl4-openssl-dev libssl-dev python3-venv
pip3 install pyopenssl
- name: install
run: |
echo "Running install base requirements"
Expand Down
3 changes: 2 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ repos:
hooks:
- id: black
args: [--line-length=120, --safe]
python_version: python3.11

python_version: python3.11
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,16 @@ install-requirements: install-python-requirements install-ui-requirements instal

web:
ifdef OWTF_ENV
cd owtf/webapp && yarn run ${OWTF_ENV}
cd owtf/webapp && yarn run start
else
@echo "--> No environment specified. Usage: make OWTF_ENV={dev, prod} web"
@echo "--> No environment specified. Usage: make web OWTF_ENV={dev}"
endif

setup-web:
@echo "--> Setting up the webapp on http://localhost:8019"
cd scripts && ./setup_webapp.sh


post-install:
@echo "--> Installing dictionaries and tools"
python3 scripts/install_tools.py
Expand Down
2 changes: 1 addition & 1 deletion docker/Dockerfile → docker/Dockerfile.backend
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ USER owtf

#Create and activating a python virtualenv
ENV VIRTUAL_ENV="${HOME}/owtf-venv"
RUN python3.9 -m venv $VIRTUAL_ENV
RUN python3.11 -m venv $VIRTUAL_ENV
ENV PATH="$VIRTUAL_ENV/bin:$PATH"

# Ensure pip and setuptools are at their latest versions
Expand Down
15 changes: 15 additions & 0 deletions docker/Dockerfile.frontend
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Stage 1: Build the React app
FROM node:18 AS builder
WORKDIR /owtf-webapp
COPY ./owtf/webapp/package.json ./owtf/webapp/yarn.lock ./
RUN yarn install --silent
COPY ./owtf/webapp .
RUN yarn build
# # Stage 2: Serve the built React app with Nginx
FROM nginx:alpine
COPY ./owtf/webapp/owtf.conf /etc/nginx/conf.d/default.conf
# Copy the built React app to Nginx's web server directory
COPY --from=builder /owtf-webapp/build /usr/share/nginx/html
EXPOSE 8019
CMD ["nginx", "-g", "daemon off;"]
# Start Nginx when the container runs
26 changes: 23 additions & 3 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
version: "3.3"
version: "3.9"
networks:
backend: {}
services:
owtf:
owtf-backend:
container_name: owtf-backend
restart: always
build:
context: ..
dockerfile: docker/Dockerfile
dockerfile: docker/Dockerfile.backend
command: ["/usr/bin/wait-for-it.sh", "db:5432", "--", "owtf"]
environment:
- DOCKER=1
Expand All @@ -16,9 +19,24 @@ services:
- 8010:8010
- 8009:8009
depends_on:
- owtf-frontend
- db
volumes:
- ..:/owtf
networks:
- backend
owtf-frontend:
container_name: owtf-frontend
restart: always
build:
context: ..
dockerfile: docker/Dockerfile.frontend
ports:
- 8019:8019
volumes:
- ..:/owtf
networks:
- backend
db:
image: postgres:alpine
ports:
Expand All @@ -27,3 +45,5 @@ services:
- POSTGRES_USER=owtf_db_user
- POSTGRES_PASSWORD=jgZKW33Q+HZk8rqylZxaPg1lbuNGHJhgzsq3gBKV32g=
- POSTGRES_DB=owtf_db
networks:
- backend
1 change: 1 addition & 0 deletions owtf/api/handlers/api_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def get(self):
try:
token = self.request.headers.get("Authorization").split()[1]
payload = jwt.decode(token, JWT_SECRET_KEY, options=JWT_OPTIONS, algorithms=[JWT_ALGORITHM])

user_id = payload.get("user_id", None)
if not user_id:
raise APIError(400, "Invalid User Id")
Expand Down
3 changes: 2 additions & 1 deletion owtf/api/handlers/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
SMTP_PORT,
SERVER_ADDR,
SERVER_PORT,
FRONTEND_SERVER_PORT,
)
from owtf.db.session import Session
from uuid import uuid4
Expand Down Expand Up @@ -340,7 +341,7 @@ def post(self):
+ ", <br/><br/>"
"""
Click here """
+ "http://{}:{}".format(SERVER_ADDR, str(SERVER_PORT))
+ "http://{}:{}".format(SERVER_ADDR, str(FRONTEND_SERVER_PORT))
+ "/email-verify/"
+ email_confirmation_dict["key_value"]
+ """ to activate your account (Link will expire in 1 hour).
Expand Down
15 changes: 15 additions & 0 deletions owtf/api/handlers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
USE_SENTRY,
SERVER_ADDR,
SESSION_COOKIE_NAME,
ALLOWED_ORIGINS,
)
from owtf.utils.strings import utf8

Expand All @@ -42,16 +43,30 @@ class SentryHandler(SentryMixin, RequestHandler):


class BaseRequestHandler(RequestHandler):
CORS_ORIGIN = ALLOWED_ORIGINS[1]

def set_default_headers(self):
# Security headers
self.add_header("X-OWTF-Version", __version__)
self.add_header("X-Frame-Options", "SAMEORIGIN")
self.add_header("X-XSS-Protection", "1; mode=block")
self.add_header("X-Content-Type-Options", "nosniff")
self.add_header("Referrer-Policy", "strict-origin-when-cross-origin")

# CORS headers
self.set_header("Access-Control-Allow-Origin", self.CORS_ORIGIN)
self.set_header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
self.set_header("Access-Control-Request-Credentials", "true")
self.set_header("Access-Control-Allow-Headers", "Authorization,Content-Type")
# Caching headers
self.add_header("Cache-Control", "no-cache,no-store,max-age=0,must-revalidate")
self.add_header("Pragma", "no-cache")
self.add_header("Expires", "-1")

def options(self, *args, **kwargs):
self.set_status(204)
self.finish()


class APIRequestHandler(BaseRequestHandler):
def initialize(self):
Expand Down
2 changes: 1 addition & 1 deletion owtf/api/handlers/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
class ConfigurationHandler(APIRequestHandler):
"""Update framework settings and tool paths."""

SUPPORTED_METHODS = ["GET", "PATCH"]
SUPPORTED_METHODS = ["GET", "PATCH", "OPTIONS"]

def get(self):
"""Return all configuration items.
Expand Down
1 change: 1 addition & 0 deletions owtf/api/handlers/jwtauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from owtf.models.user_login_token import UserLoginToken
import jwt
from owtf.settings import JWT_SECRET_KEY, JWT_OPTIONS, JWT_ALGORITHM

from owtf.db.session import Session


Expand Down
5 changes: 1 addition & 4 deletions owtf/api/handlers/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ def get(self):
class ProgressBarHandler(APIRequestHandler):
SUPPORTED_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"]

def set_default_headers(self):
self.add_header("Access-Control-Allow-Origin", "*")
self.add_header("Access-Control-Allow-Methods", "GET, POST, DELETE")

def get(self):
try:
self.write(plugin_count_output(self.session))
Expand Down Expand Up @@ -95,3 +91,4 @@ def delete(self, error_id=None):
self.finish()
except exceptions.InvalidErrorReference:
raise tornado.web.HTTPError(400)

8 changes: 4 additions & 4 deletions owtf/api/handlers/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,21 +242,21 @@ def get(self, target_id=None):
logging.warn(e.parameter)
raise tornado.web.HTTPError(400)

@tornado.web.asynchronous
@tornado.gen.coroutine
def post(self, target_url):
raise tornado.web.HTTPError(405)

@tornado.web.asynchronous
@tornado.gen.coroutine
def put(self):
raise tornado.web.HTTPError(405)

@tornado.web.asynchronous
@tornado.gen.coroutine
def patch(self):
# TODO: allow modification of urls from the ui, may be adjusting scope etc.. but i don't understand
# it's use yet ;)
raise tornado.web.HTTPError(405) # @UndefinedVariable

@tornado.web.asynchronous
@tornado.gen.coroutine
def delete(self, target_id=None):
# TODO: allow deleting of urls from the ui
raise tornado.web.HTTPError(405) # @UndefinedVariable
Expand Down
4 changes: 0 additions & 4 deletions owtf/api/handlers/work.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ class WorkerHandler(APIRequestHandler):

SUPPORTED_METHODS = ["GET", "POST", "DELETE", "OPTIONS"]

def set_default_headers(self):
self.add_header("Access-Control-Allow-Origin", "*")
self.add_header("Access-Control-Allow-Methods", "GET, POST, DELETE")

def get(self, worker_id=None, action=None):
"""Get all workers by ID.
Expand Down
3 changes: 1 addition & 2 deletions owtf/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@


class APIServer(OWTFProcess):

def pseudo_run(self):
api_v1 = Application(handlers=API_v1_HANDLERS, debug=DEBUG, autoreload=False, gzip=True)

Expand All @@ -49,7 +48,7 @@ def pseudo_run(self):
port = int(SERVER_PORT)
address = SERVER_ADDR
self.server.bind(port, address=address)
logging.warning("Starting API and UI server at http://{}:{}".format(SERVER_ADDR, str(SERVER_PORT)))
logging.warning("Starting API server at http://{}:{}".format(SERVER_ADDR, str(SERVER_PORT)))
self.logger.disable_console_logging()
tornado.options.parse_command_line(
args=["dummy_arg", "--log_file_prefix={}".format(SERVER_LOG), "--logging=info"]
Expand Down
9 changes: 4 additions & 5 deletions owtf/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from owtf.api.handlers.report import ReportExportHandler
from owtf.api.handlers.session import OWTFSessionHandler
from owtf.api.handlers.targets import TargetConfigHandler, TargetConfigSearchHandler, TargetSeverityChartHandler
from owtf.files.handlers import StaticFileHandler
from owtf.utils.file import get_dir_worker_logs
from owtf.api.handlers.transactions import (
TransactionDataHandler,
Expand Down Expand Up @@ -105,11 +106,9 @@
]

UI_HANDLERS = [
tornado.web.url(r"/static/(.*)", tornado.web.StaticFileHandler, {"path": STATIC_ROOT}),
tornado.web.url(r"/static/(.*)", StaticFileHandler, {"path": STATIC_ROOT}),
tornado.web.url(r"/debug/health/?$", HealthCheckHandler),
tornado.web.url(
r"/logs/(.*)", tornado.web.StaticFileHandler, {"path": get_dir_worker_logs()}, name="logs_files_url"
),
tornado.web.url(r"/logs/(.*)", StaticFileHandler, {"path": get_dir_worker_logs()}, name="logs_files_url"),
tornado.web.url(r"/output_files/(.*)", FileRedirectHandler, name="file_redirect_url"),
tornado.web.url(r"^/(?!api|debug|static|output_files|logs)(.*)$", IndexHandler),
tornado.web.url(r"^/(?!api|debug|static|output_files)(.*)$", IndexHandler),
]
8 changes: 6 additions & 2 deletions owtf/files/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@
import tornado
import tornado.template
import tornado.web
from owtf.api.handlers.base import BaseRequestHandler

__all__ = ["StaticFileHandler"]
__all__ = ["StaticFileHandler", "OutputFileHandler"]


class StaticFileHandler(tornado.web.StaticFileHandler):
class StaticFileHandler(tornado.web.StaticFileHandler, BaseRequestHandler):
pass


class OutputFileHandler(tornado.web.StaticFileHandler):
def set_default_headers(self):
self.add_header("Access-Control-Allow-Origin", "*")
self.add_header("Access-Control-Allow-Methods", "GET")
Expand Down
6 changes: 3 additions & 3 deletions owtf/files/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
"""
import tornado.web

from owtf.files.handlers import StaticFileHandler
from owtf.files.handlers import OutputFileHandler
from owtf.utils.file import get_dir_worker_logs, get_output_dir_target

HANDLERS = [
tornado.web.url(r"/logs/(.*)", StaticFileHandler, {"path": get_dir_worker_logs()}, name="logs_files_url"),
tornado.web.url(r"/(.*)", StaticFileHandler, {"path": get_output_dir_target()}, name="output_files_url"),
tornado.web.url(r"/logs/(.*)", OutputFileHandler, {"path": get_dir_worker_logs()}, name="logs_files_url"),
tornado.web.url(r"/(.*)", OutputFileHandler, {"path": get_output_dir_target()}, name="output_files_url"),
]
2 changes: 1 addition & 1 deletion owtf/managers/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def load_config_file(file_path, fallback_file_path):
# check if the config file exists
abort_framework("Config file not found at: {}".format(file_path))
try:
config_map = yaml.load(FileOperations.open(file_path, "r"))
config_map = yaml.safe_load(FileOperations.open(file_path, "r"))
return config_map
except yaml.YAMLError:
abort_framework("Error parsing config file at: {}".format(file_path))
Expand Down
7 changes: 4 additions & 3 deletions owtf/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@
DATABASE_PASS = "jgZKW33Q+HZk8rqylZxaPg1lbuNGHJhgzsq3gBKV32g="
DATABASE_NAME = "owtf_db"
DATABASE_USER = "owtf_db_user"
DATABASE_IP = os.environ.get("POSTGRES_HOST","127.0.0.1")
DATABASE_IP = os.environ.get("POSTGRES_HOST", "127.0.0.1")
DATABASE_PORT = 5432

# API and UI Server
SERVER_ADDR = "0.0.0.0"
SERVER_PORT = 8009
FILE_SERVER_PORT = 8010
FRONTEND_SERVER_PORT = 8019

# Default API version
DEFAULT_API_VERSION = "v1"
Expand All @@ -53,8 +54,8 @@
SESSION_COOKIE_NAME = "owtf-session"

# CORS settings. Fine grained, do not override if possible.
SIMPLE_HEADERS = ["accept", "accept-language", "content-language"]
ALLOWED_ORIGINS = ["http:/localhost:8009", "http://localhost:8010"]
SIMPLE_HEADERS = ["accept", "accept-language", "content-language", "authorization"]
ALLOWED_ORIGINS = ["http://localhost:8010", "http://localhost:8019"]
ALLOWED_METHODS = ["GET", "POST", "DELETE"]
SEND_CREDENTIALS = False

Expand Down
Loading

0 comments on commit 8e7096c

Please sign in to comment.