From f3ed518b6503bf79f5edd7fc5ab671c2e169f8c0 Mon Sep 17 00:00:00 2001 From: Daniele Maglie Date: Mon, 15 Jan 2024 13:32:24 +0100 Subject: [PATCH] Pushed new branch. --- .gitignore | 5 + Dockerfile | 24 ++ Makefile | 37 +++ README.md | 3 + application.py | 56 +++++ bin/worker.py | 10 + boot.py | 37 +++ handlers/not_found.py | 18 ++ handlers/ping.py | 23 ++ ioutils/base.py | 55 +++++ ioutils/errors.py | 82 +++++++ ioutils/parameters.py | 137 +++++++++++ ioutils/parameters.py.save | 143 ++++++++++++ ioutils/protected.py | 93 ++++++++ ioutils/request.py | 58 +++++ ioutils/response.py | 214 +++++++++++++++++ package-lock.json | 6 + package.json | 1 + requirements.txt | 2 + tests/01_reporter/test_0004_ticket.py | 73 ++++++ .../test_0005_retrieve_ticket_items.py | 39 ++++ .../02_provider/test_0006_set_ticket_items.py | 39 ++++ tests/base.py | 78 +++++++ tests/bench_params.txt | 4 + tests/mock_storage.py | 10 + tests/test_0001_health.py | 15 ++ tests/test_0002_errors.py | 60 +++++ tests/test_0003_authentication.py | 39 ++++ v1/handlers/account/get.py | 49 ++++ v1/handlers/account/get_all.py | 41 ++++ v1/handlers/account/guest/create.py | 65 ++++++ v1/handlers/account/guest/get.py | 50 ++++ v1/handlers/account/guest/get_all.py | 42 ++++ v1/handlers/account/guest/remove.py | 50 ++++ .../account/internal/change_password.py | 51 ++++ v1/handlers/account/internal/create.py | 63 +++++ v1/handlers/account/internal/get.py | 48 ++++ v1/handlers/account/internal/get_all.py | 40 ++++ v1/handlers/account/internal/remove.py | 48 ++++ v1/handlers/account/internal/set_status.py | 83 +++++++ .../account/provider/change_password.py | 51 ++++ v1/handlers/account/provider/create.py | 66 ++++++ v1/handlers/account/provider/get.py | 49 ++++ v1/handlers/account/provider/get_all.py | 41 ++++ v1/handlers/account/provider/remove.py | 49 ++++ v1/handlers/account/provider/set_status.py | 83 +++++++ .../account/reporter/change_password.py | 51 ++++ v1/handlers/account/reporter/create.py | 64 +++++ v1/handlers/account/reporter/get.py | 49 ++++ v1/handlers/account/reporter/get_all.py | 41 ++++ v1/handlers/account/reporter/remove.py | 49 ++++ v1/handlers/account/reporter/set_status.py | 83 +++++++ v1/handlers/authentication/login.py | 73 ++++++ v1/handlers/authentication/logout.py | 25 ++ v1/handlers/authentication/refresh.py | 71 ++++++ v1/handlers/dda/create.py | 54 +++++ v1/handlers/dda/get_all.py | 43 ++++ v1/handlers/dda/get_all_by_account.py | 56 +++++ v1/handlers/dda/get_global.py | 47 ++++ v1/handlers/dda/remove.py | 51 ++++ v1/handlers/dda/set_status.py | 88 +++++++ v1/handlers/forensic/get_by_ticket.py | 73 ++++++ v1/handlers/forensic/get_supported_formats.py | 45 ++++ v1/handlers/forensic/get_supported_hashes.py | 49 ++++ v1/handlers/forensic/upload.py | 54 +++++ v1/handlers/log/ticket/get_all.py | 52 +++++ v1/handlers/log/ticket/item/get_all.py | 52 +++++ v1/handlers/ticket/create.py | 74 ++++++ v1/handlers/ticket/error/create.py | 64 +++++ v1/handlers/ticket/error/get_by_account.py | 69 ++++++ v1/handlers/ticket/error/get_by_ticket.py | 70 ++++++ v1/handlers/ticket/get.py | 83 +++++++ v1/handlers/ticket/get_all.py | 76 ++++++ v1/handlers/ticket/get_total.py | 45 ++++ v1/handlers/ticket/item/fqdn/get_all.py | 60 +++++ .../ticket/item/fqdn/get_all_by_ticket.py | 82 +++++++ .../fqdn/get_all_by_ticket_checksum_txt.py | 69 ++++++ .../ticket/item/fqdn/get_all_by_ticket_txt.py | 69 ++++++ .../ticket/item/fqdn/get_all_checksum_txt.py | 60 +++++ v1/handlers/ticket/item/fqdn/get_all_txt.py | 60 +++++ v1/handlers/ticket/item/get_all.py | 69 ++++++ v1/handlers/ticket/item/get_all_status.py | 53 +++++ .../ticket/item/get_available_by_ticket.py | 57 +++++ v1/handlers/ticket/item/get_details.py | 55 +++++ v1/handlers/ticket/item/ipv4/get_all.py | 60 +++++ .../ticket/item/ipv4/get_all_by_ticket.py | 82 +++++++ .../ipv4/get_all_by_ticket_checksum_txt.py | 69 ++++++ .../ticket/item/ipv4/get_all_by_ticket_txt.py | 69 ++++++ .../ticket/item/ipv4/get_all_checksum_txt.py | 60 +++++ v1/handlers/ticket/item/ipv4/get_all_txt.py | 60 +++++ v1/handlers/ticket/item/ipv6/get_all.py | 60 +++++ .../ticket/item/ipv6/get_all_by_ticket.py | 82 +++++++ .../ipv6/get_all_by_ticket_checksum_txt.py | 69 ++++++ .../ticket/item/ipv6/get_all_by_ticket_txt.py | 69 ++++++ .../ticket/item/ipv6/get_all_checksum_txt.py | 60 +++++ v1/handlers/ticket/item/ipv6/get_all_txt.py | 60 +++++ v1/handlers/ticket/item/set_flag_active.py | 96 ++++++++ v1/handlers/ticket/item/set_processed.py | 63 +++++ v1/handlers/ticket/item/set_unprocessed.py | 65 ++++++ v1/handlers/ticket/remove.py | 65 ++++++ v1/handlers/whitelist/create.py | 65 ++++++ v1/handlers/whitelist/get_all.py | 45 ++++ v1/handlers/whitelist/get_all_by_account.py | 56 +++++ v1/handlers/whitelist/get_global.py | 48 ++++ v1/handlers/whitelist/remove.py | 52 +++++ v1/handlers/whitelist/set_status.py | 96 ++++++++ v1/routes.py | 219 ++++++++++++++++++ 107 files changed, 6285 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 README.md create mode 100644 application.py create mode 100644 bin/worker.py create mode 100644 boot.py create mode 100644 handlers/not_found.py create mode 100644 handlers/ping.py create mode 100644 ioutils/base.py create mode 100644 ioutils/errors.py create mode 100644 ioutils/parameters.py create mode 100644 ioutils/parameters.py.save create mode 100644 ioutils/protected.py create mode 100644 ioutils/request.py create mode 100644 ioutils/response.py create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 requirements.txt create mode 100644 tests/01_reporter/test_0004_ticket.py create mode 100644 tests/02_provider/test_0005_retrieve_ticket_items.py create mode 100644 tests/02_provider/test_0006_set_ticket_items.py create mode 100644 tests/base.py create mode 100644 tests/bench_params.txt create mode 100644 tests/mock_storage.py create mode 100644 tests/test_0001_health.py create mode 100644 tests/test_0002_errors.py create mode 100644 tests/test_0003_authentication.py create mode 100644 v1/handlers/account/get.py create mode 100644 v1/handlers/account/get_all.py create mode 100644 v1/handlers/account/guest/create.py create mode 100644 v1/handlers/account/guest/get.py create mode 100644 v1/handlers/account/guest/get_all.py create mode 100644 v1/handlers/account/guest/remove.py create mode 100644 v1/handlers/account/internal/change_password.py create mode 100644 v1/handlers/account/internal/create.py create mode 100644 v1/handlers/account/internal/get.py create mode 100644 v1/handlers/account/internal/get_all.py create mode 100644 v1/handlers/account/internal/remove.py create mode 100644 v1/handlers/account/internal/set_status.py create mode 100644 v1/handlers/account/provider/change_password.py create mode 100644 v1/handlers/account/provider/create.py create mode 100644 v1/handlers/account/provider/get.py create mode 100644 v1/handlers/account/provider/get_all.py create mode 100644 v1/handlers/account/provider/remove.py create mode 100644 v1/handlers/account/provider/set_status.py create mode 100644 v1/handlers/account/reporter/change_password.py create mode 100644 v1/handlers/account/reporter/create.py create mode 100644 v1/handlers/account/reporter/get.py create mode 100644 v1/handlers/account/reporter/get_all.py create mode 100644 v1/handlers/account/reporter/remove.py create mode 100644 v1/handlers/account/reporter/set_status.py create mode 100644 v1/handlers/authentication/login.py create mode 100644 v1/handlers/authentication/logout.py create mode 100644 v1/handlers/authentication/refresh.py create mode 100644 v1/handlers/dda/create.py create mode 100644 v1/handlers/dda/get_all.py create mode 100644 v1/handlers/dda/get_all_by_account.py create mode 100644 v1/handlers/dda/get_global.py create mode 100644 v1/handlers/dda/remove.py create mode 100644 v1/handlers/dda/set_status.py create mode 100644 v1/handlers/forensic/get_by_ticket.py create mode 100644 v1/handlers/forensic/get_supported_formats.py create mode 100644 v1/handlers/forensic/get_supported_hashes.py create mode 100644 v1/handlers/forensic/upload.py create mode 100644 v1/handlers/log/ticket/get_all.py create mode 100644 v1/handlers/log/ticket/item/get_all.py create mode 100644 v1/handlers/ticket/create.py create mode 100644 v1/handlers/ticket/error/create.py create mode 100644 v1/handlers/ticket/error/get_by_account.py create mode 100644 v1/handlers/ticket/error/get_by_ticket.py create mode 100644 v1/handlers/ticket/get.py create mode 100644 v1/handlers/ticket/get_all.py create mode 100644 v1/handlers/ticket/get_total.py create mode 100644 v1/handlers/ticket/item/fqdn/get_all.py create mode 100644 v1/handlers/ticket/item/fqdn/get_all_by_ticket.py create mode 100644 v1/handlers/ticket/item/fqdn/get_all_by_ticket_checksum_txt.py create mode 100644 v1/handlers/ticket/item/fqdn/get_all_by_ticket_txt.py create mode 100644 v1/handlers/ticket/item/fqdn/get_all_checksum_txt.py create mode 100644 v1/handlers/ticket/item/fqdn/get_all_txt.py create mode 100644 v1/handlers/ticket/item/get_all.py create mode 100644 v1/handlers/ticket/item/get_all_status.py create mode 100644 v1/handlers/ticket/item/get_available_by_ticket.py create mode 100644 v1/handlers/ticket/item/get_details.py create mode 100644 v1/handlers/ticket/item/ipv4/get_all.py create mode 100644 v1/handlers/ticket/item/ipv4/get_all_by_ticket.py create mode 100644 v1/handlers/ticket/item/ipv4/get_all_by_ticket_checksum_txt.py create mode 100644 v1/handlers/ticket/item/ipv4/get_all_by_ticket_txt.py create mode 100644 v1/handlers/ticket/item/ipv4/get_all_checksum_txt.py create mode 100644 v1/handlers/ticket/item/ipv4/get_all_txt.py create mode 100644 v1/handlers/ticket/item/ipv6/get_all.py create mode 100644 v1/handlers/ticket/item/ipv6/get_all_by_ticket.py create mode 100644 v1/handlers/ticket/item/ipv6/get_all_by_ticket_checksum_txt.py create mode 100644 v1/handlers/ticket/item/ipv6/get_all_by_ticket_txt.py create mode 100644 v1/handlers/ticket/item/ipv6/get_all_checksum_txt.py create mode 100644 v1/handlers/ticket/item/ipv6/get_all_txt.py create mode 100644 v1/handlers/ticket/item/set_flag_active.py create mode 100644 v1/handlers/ticket/item/set_processed.py create mode 100644 v1/handlers/ticket/item/set_unprocessed.py create mode 100644 v1/handlers/ticket/remove.py create mode 100644 v1/handlers/whitelist/create.py create mode 100644 v1/handlers/whitelist/get_all.py create mode 100644 v1/handlers/whitelist/get_all_by_account.py create mode 100644 v1/handlers/whitelist/get_global.py create mode 100644 v1/handlers/whitelist/remove.py create mode 100644 v1/handlers/whitelist/set_status.py create mode 100644 v1/routes.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7800d32 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +__pycache__/ +build/ +.eggs/ +.egg-info/ +.pytest_cache diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b465600 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +FROM python:3.11.5-alpine + +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +WORKDIR /srv/app + +RUN addgroup -S user && adduser -S user -G user + +USER user + +COPY requirements.txt . + +RUN pip install -r requirements.txt + +COPY . . + +COPY ./data . + +RUN source data/environment.sh + +EXPOSE 58008 + +CMD ["make", "run_server"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4088abc --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +# Initializer + +setup: + @echo "Installing required packages" + pip install -r requirements.txt + +# Executables + +run_server: + @echo " -- Running API server (Piracy Shield ${PIRACYSHIELD_VERSION}) --" + @python boot.py + +run_worker: + @echo " -- Running queue worker (Piracy Shield ${PIRACYSHIELD_VERSION}) --" + @python bin/worker.py + +run_mock_storage: + @export AZURITE_ACCOUNTS="account1:key1:key2"; azurite -s -l /tmp/azurite_emulated_store + +create_mock_container: + @echo "Creating mock container on /tmp/azurite_emulated_store" + @python tests/mock_storage.py + +# Testing operations + +test: + @echo "Running tests" + pytest + +sast: + @echo "Running SAST check" + semgrep scan --config auto + +bench: + @echo "Running benchmark" + ab -v 2 -n 20 -c 10 -k -T application/json -p tests/bench_params.txt 127.0.0.1:58008/api/v1/authentication/login + #ab -v 2 -n 20 -c 10 -k 127.0.0.1:58008/api/v1/ping diff --git a/README.md b/README.md new file mode 100644 index 0000000..4bd16a1 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +### API + +API request handler. diff --git a/application.py b/application.py new file mode 100644 index 0000000..bce47bf --- /dev/null +++ b/application.py @@ -0,0 +1,56 @@ +from piracyshield_component.log.logger import Logger + +import tornado + +from handlers.ping import PingHandler +from handlers.not_found import NotFoundHandler + +class Application(tornado.web.Application): + + """ + Application initializer. + """ + + def __init__(self, debug: bool, handlers: list, version: str, prefix: str, cookie_secret: str, cache_path: str): + """ + This is a list of handlers that directly extend the RequestHandler class, instead of relying on a BaseHandler class. + + :param handlers: list of handlers based on a BaseHandler class. + :param version: version of the API (ex. "v1"). + :param handlers: API url prefix (ex. "/api"). + :param cookie_secret: this is a secret to provide more security for the cookie signing when they are set. + :param cache_path: folder for cache uploads. + :return: a list of routes and their handlers. + """ + + if prefix: + version = f'{prefix}/{version}' + + # checks if the prefix option is set and starts adding the custom prefix to each route + handlers = [(version + handle[0], handle[1]) for handle in handlers] + + complete_handlers = handlers + self._get_default_handlers() + + self.logger = Logger('api') + + self.logger.info('Started') + + tornado.web.Application.__init__( + self, + debug = debug, + handlers = complete_handlers, + cookie_secret = cookie_secret, + cache_path = cache_path + ) + + def _get_default_handlers(self) -> list: + """ + This is a list of handlers that directly extend the RequestHandler class, instead of relying on a BaseHandler class. + + :return: a list of routes and their handlers. + """ + + return [ + (r'/api/v1/ping', PingHandler), + (r'.*', NotFoundHandler) + ] diff --git a/bin/worker.py b/bin/worker.py new file mode 100644 index 0000000..5a39122 --- /dev/null +++ b/bin/worker.py @@ -0,0 +1,10 @@ +from piracyshield_component.config import Config + +from piracyshield_service.task.worker import TaskWorkerService + +# available tasks list +from piracyshield_service.task.tasks.test import test_task_caller + +service = TaskWorkerService() + +service.start() diff --git a/boot.py b/boot.py new file mode 100644 index 0000000..6a54f6f --- /dev/null +++ b/boot.py @@ -0,0 +1,37 @@ +import tornado.ioloop + +from piracyshield_component.config import Config +from piracyshield_component.environment import Environment + +from v1.routes import APIv1 + +from application import Application + +api_config = Config('api').get('general') + +if __name__ == "__main__": + app = Application( + # wether to run the application using debug mode + debug = api_config['debug'], + + # load current routes + handlers = APIv1.routes, + + # adds a standard version prefix + version = api_config['version'], + + # sets a prefix for each route + prefix = api_config['prefix'], + + # cookie secret + cookie_secret = api_config['cookie_secret'], + + # cache absolute location + cache_path = Environment.CACHE_PATH + ) + + http_server = tornado.httpserver.HTTPServer(app, xheaders = True) + + http_server.listen(api_config['port']) + + tornado.ioloop.IOLoop.instance().start() diff --git a/handlers/not_found.py b/handlers/not_found.py new file mode 100644 index 0000000..e63e380 --- /dev/null +++ b/handlers/not_found.py @@ -0,0 +1,18 @@ +import sys +import os + +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +from ioutils.request import RequestHandler +from ioutils.errors import ErrorCode, ErrorMessage + +class NotFoundHandler(RequestHandler): + + """ + Handle for 404 routes. + """ + + def prepare(self): + self.error(status_code = 404, error_code = ErrorCode.ROUTE_NOT_FOUND, message = ErrorMessage.ROUTE_NOT_FOUND) diff --git a/handlers/ping.py b/handlers/ping.py new file mode 100644 index 0000000..9628d8f --- /dev/null +++ b/handlers/ping.py @@ -0,0 +1,23 @@ +import sys +import os +import random + +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +from ioutils.request import RequestHandler + +class PingHandler(RequestHandler): + + """ + Handle simple pings to check the API availability. + """ + + responses = [ + 'Pong!', + 'Do APIs dream of electric requests?' + ] + + def get(self): + self.success(data = random.choice(self.responses)) diff --git a/ioutils/base.py b/ioutils/base.py new file mode 100644 index 0000000..a50fb84 --- /dev/null +++ b/ioutils/base.py @@ -0,0 +1,55 @@ +from .request import RequestHandler + +from .parameters import JSONParametersHandler, JSONParametersNonValidException, JSONParametersMissingException, JSONParametersTooManyException + +from .errors import ErrorCode, ErrorMessage + +class BaseHandler(RequestHandler): + + """ + Base class for initial input sanitizing and management. + """ + + request_data = {} + + def handle_post(self, required_fields: list, optional_fields: list = None, sanitization_rules: list = None) -> None | Exception: + """ + Handle POST parameters. + + :param required_fields: a list of mandatory fields. + :param optional_fields: a list of non-mandatory fields. + :param sanitization_rules: a list of rules based on the Filter class component. + """ + + request_body = self.request.body.decode('utf-8') + + try: + json_handler = JSONParametersHandler(request_body) + + # will raise an exception if the content is not what we're expecting + processed_request = json_handler.process_request( + required_fields = required_fields, + optional_fields = optional_fields, + sanitization_rules = sanitization_rules + ) + + self.request_data = {} + + # save the processed parameters so we can access them from child classes + for key, value in processed_request.items(): + self.request_data[key] = value + + except JSONParametersNonValidException: + self.error(status_code = 400, error_code = ErrorCode.NON_VALID_PARAMETERS, message = ErrorMessage.NON_VALID_PARAMETERS) + + return False + + except JSONParametersMissingException: + self.error(status_code = 400, error_code = ErrorCode.MISSING_PARAMETERS, message = ErrorMessage.MISSING_PARAMETERS) + + return False + + except JSONParametersTooManyException: + self.error(status_code = 400, error_code = ErrorCode.TOO_MANY_PARAMETERS, message = ErrorMessage.TOO_MANY_PARAMETERS) + + return False diff --git a/ioutils/errors.py b/ioutils/errors.py new file mode 100644 index 0000000..e08eb64 --- /dev/null +++ b/ioutils/errors.py @@ -0,0 +1,82 @@ + +class ErrorCode: + + """ + API error codes. + """ + + GENERIC = '1000' + + PERMISSION_DENIED = '1001' + + FORBIDDEN = '1002' + + ROUTE_NOT_FOUND = '1003' + + METHOD_NOT_ALLOWED = '1004' + + TOO_MANY_REQUESTS = '1005' + + MISSING_TOKEN = '1006' + + MISSING_REFRESH_TOKEN = '1007' + + TOKEN_FORMAT_NON_VALID = '1008' + + NON_VALID_PARAMETERS = '1009' + + MISSING_PARAMETERS = '1010' + + TOO_MANY_PARAMETERS = '1011' + + MISSING_FILE = '1012' + + NO_DATA_AVAILABLE = '1013' + + CHANGE_PASSWORD = '1014' + +class ErrorMessage: + + """ + API error messages. + """ + + GENERIC = 'Generic application error.' + + PERMISSION_DENIED = "Permission denied." + + # routing + + FORBIDDEN = 'Forbidden.' + + ROUTE_NOT_FOUND = 'Route not found.' + + METHOD_NOT_ALLOWED = 'Method not allowed.' + + TOO_MANY_REQUESTS = 'Too many requests.' + + # jwt token + + MISSING_TOKEN = 'Missing authentication token.' + + MISSING_REFRESH_TOKEN = 'Missing refresh token from cookie or POST parameters.' + + TOKEN_FORMAT_NON_VALID = 'Token format non valid.' + + # json POST parameters + + NON_VALID_PARAMETERS = 'Expecting JSON data.' + + MISSING_PARAMETERS = 'Missing required parameters.' + + TOO_MANY_PARAMETERS = 'Too many parameters.' + + # files + + MISSING_FILE = 'Missing required file.' + + NO_DATA_AVAILABLE = 'No data available for this request.' + + # account settings + + CHANGE_PASSWORD = 'A password change has been activated for your account. You must first authenticate via web app and follow the instructions.' diff --git a/ioutils/parameters.py b/ioutils/parameters.py new file mode 100644 index 0000000..4385a05 --- /dev/null +++ b/ioutils/parameters.py @@ -0,0 +1,137 @@ +from piracyshield_component.security.filter import Filter + +import json + +class JSONParametersHandler: + + """ + Pre-handle for the JSON request. + """ + + request_body = {} + + default_sanitization_rules = { + 'string': [ + 'strip' + ] + } + + def __init__(self, request_body): + self.request_body = request_body + + def process_request(self, required_fields: list = None, optional_fields: list = None, sanitization_rules: list = None) -> dict: + """ + Validates and sanitizes incoming JSON request data. + + # TODO: need to determine a sanitization template for the rules as this is still a generic approach. + + :param required_fields: list of required fields. + :param optional_fields: list of non-mandatory fields. + :param sanitization_rules: list of required sanitizations. + """ + + # try to load the JSON data, this will raise an exception if the content is not valid + try: + self.request_body = json.loads(self.request_body) + + except Exception: + raise JSONParametersNonValidException() + + if required_fields: + self._validate_input(required_fields, optional_fields) + + if sanitization_rules: + self.request_body = self._sanitize_input(self.request_body, sanitization_rules) + + else: + self.request_body = self._sanitize_input(self.request_body, self.default_sanitization_rules) + + return self.request_body + + def _validate_input(self, required_fields: list, optional_fields: list) -> None | Exception: + """ + Validates that the incoming JSON request contains all required fields. + + :param required_fields: list of required fields. + :param optional_fields: list of non-mandatory fields. + """ + + if not optional_fields: + # if there's no optional field we want the exact number of parameters + if len(self.request_body) > len(required_fields): + raise JSONParametersTooManyException() + + missing_fields = [] + + for field in required_fields: + if field not in self.request_body: + missing_fields.append(field) + + if missing_fields: + raise JSONParametersMissingException() + + # TODO: should we report the missing fields back to the user? + + return None + + def _sanitize_input(self, data: any, sanitization_rules: list) -> any: + """ + Cleans the input data. + + :param data: any parameter in the request. + :param sanitization_rules: list of cleaning rules. + :return: the cleaned data. + """ + + if isinstance(data, dict): + sanitized_data = {} + + for key, value in data.items(): + sanitized_value = self._sanitize_input(value, sanitization_rules) + + sanitized_data[key] = sanitized_value + + return sanitized_data + + elif isinstance(data, list): + sanitized_data = [] + + for item in data: + sanitized_value = self._sanitize_input(item, sanitization_rules) + + if item: + sanitized_data.append(sanitized_value) + + return sanitized_data + + elif isinstance(data, str): + if 'string' in sanitization_rules.keys(): + if 'strip' in sanitization_rules['string']: + return Filter.strip(data) + + else: + return data + +class JSONParametersNonValidException(Exception): + + """ + Not JSON data. + """ + + pass + +class JSONParametersMissingException(Exception): + + """ + The parameters we're looking for are completely missing. + """ + + pass + +class JSONParametersTooManyException(Exception): + + """ + More parameters than expected is an error. + """ + + pass diff --git a/ioutils/parameters.py.save b/ioutils/parameters.py.save new file mode 100644 index 0000000..b462907 --- /dev/null +++ b/ioutils/parameters.py.save @@ -0,0 +1,143 @@ +from piracyshield_component.security.filter import Filter + +import json + +class JSONParametersHandler: + + """ + Pre-handle for the JSON request. + """ + + request_body = {} + + default_sanitization_rules = { + 'string': [ + 'strip' + ] + } + + def __init__(self, request_body): + self.request_body = request_body + + def process_request(self, required_fields: list = None, optional_fields: list = None, sanitization_rules: list = None) -> dict: + """ + Validates and sanitizes incoming JSON request data. + + # TODO: need to determine a sanitization template for the rules as this is still a generic approach. + + :param required_fields: list of required fields. + :param optional_fields: list of non-mandatory fields. + :param sanitization_rules: list of required sanitizations. + """ + + # try to load the JSON data, this will raise an exception if the content is not valid + try: + self.request_body = json.loads(self.request_body) + + except Exception: + raise JSONParametersNonValidException() + + if required_fields: + self._validate_input(required_fields, optional_fields) + + if sanitization_rules: + self.request_body = self._sanitize_input(self.request_body, sanitization_rules) + + else: + self.request_body = self._sanitize_input(self.request_body, self.default_sanitization_rules) + + return self.request_body + + def _validate_input(self, required_fields: list, optional_fields: list) -> None | Exception: + """ + Validates that the incoming JSON request contains all required fields. + + :param required_fields: list of required fields. + :param optional_fields: list of non-mandatory fields. + """ + + if not optional_fields: + # if there's no optional field we want the exact number of parameters + if len(self.request_body) > len(required_fields): + raise JSONParametersTooManyException() + + missing_fields = [] + + for field in required_fields: + if field not in self.request_body: + missing_fields.append(field) + + if missing_fields: + raise JSONParametersMissingException() + + # TODO: should we report the missing fields back to the user? + + return None + + def _sanitize_input(self, data: any, sanitization_rules: list) -> any: + """ + Cleans the input data. + + :param data: any parameter in the request. + :param sanitization_rules: list of cleaning rules. + :return: the cleaned data. + """ + + if isinstance(data, dict): + sanitized_data = {} + + for key, value in data.items(): + if value: + sanitized_value = self._sanitize_input(value, sanitization_rules) + + if sanitized_value: + sanitized_data[key] = sanitized_value + + + else: + sanitized_data[key] = value + + return sanitized_data + + elif isinstance(data, list): + sanitized_data = [] + + for item in data: + sanitized_value = self._sanitize_input(item, sanitization_rules) + + if item: + sanitized_data.append(sanitized_value) + + return sanitized_data + + elif isinstance(data, str): + if 'string' in sanitization_rules.keys(): + if 'strip' in sanitization_rules['string']: + return Filter.strip(data) + + else: + return data + +class JSONParametersNonValidException(Exception): + + """ + Not JSON data. + """ + + pass + +class JSONParametersMissingException(Exception): + + """ + The parameters we're looking for are completely missing. + """ + + pass + +class JSONParametersTooManyException(Exception): + + """ + More parameters than expected is an error. + """ + + pass diff --git a/ioutils/protected.py b/ioutils/protected.py new file mode 100644 index 0000000..991b0f6 --- /dev/null +++ b/ioutils/protected.py @@ -0,0 +1,93 @@ +from .base import BaseHandler + +from piracyshield_component.exception import ApplicationException + +from piracyshield_service.authentication.verify_access_token import AuthenticationVerifyAccessTokenService + +from piracyshield_service.permission.service import PermissionService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from .errors import ErrorCode, ErrorMessage + +class ProtectedHandler(BaseHandler): + + """ + Restricts access to authenticated users only. + """ + + bypassed_routes = [ + '/change_password', + '/logout' + ] + + authentication_verify_access_token_service = None + + permission_service = None + + account_data = {} + + def prepare(self): + self.authentication_verify_access_token_service = AuthenticationVerifyAccessTokenService() + + super().prepare() + + def initialize_account(self): + """ + Performs the checks required to verify the JWT token and set up the account services. + """ + + authorization_header = self.request.headers.get('Authorization') + + # no token is passed + if authorization_header is None: + self.error(status_code = 401, error_code = ErrorCode.MISSING_TOKEN, message = ErrorMessage.MISSING_TOKEN) + + return False + + # we get something but not what we're looking for + if not authorization_header.startswith('Bearer '): + self.error(status_code = 401, error_code = ErrorCode.TOKEN_FORMAT_NON_VALID, message = ErrorMessage.TOKEN_FORMAT_NON_VALID) + + return False + + # get the token only + token = authorization_header[7:] + + try: + # set the current account data + # TODO: absolutely need to validate the payload. + self.account_data = self.authentication_verify_access_token_service.execute(token) + + if not self.account_data.get('email'): + self.error(status_code = 401, error_code = ErrorCode.TOKEN_FORMAT_NON_VALID, message = ErrorMessage.TOKEN_FORMAT_NON_VALID) + + return False + + # verify account role + try: + AccountRoleModel(self.account_data.get('role')) + + except ValueError: + self.error(status_code = 401, error_code = ErrorCode.TOKEN_FORMAT_NON_VALID, message = ErrorMessage.TOKEN_FORMAT_NON_VALID) + + return False + + # prevent application access if there's a mandatory password change + if self.account_data.get('flags').get('change_password') == True: + # hacky way to prevent useful routes from being filtered as well + if not any(path in self.request.path for path in self.bypassed_routes): + #if 'change_password' not in self.request.path: + self.error(status_code = 401, error_code = ErrorCode.CHANGE_PASSWORD, message = ErrorMessage.CHANGE_PASSWORD) + + return False + + # initialize permission service + self.permission_service = PermissionService(self.account_data.get('role')) + + except ApplicationException as e: + self.error(status_code = 401, error_code = e.code, message = e.message) + + return False + + return True diff --git a/ioutils/request.py b/ioutils/request.py new file mode 100644 index 0000000..b6da808 --- /dev/null +++ b/ioutils/request.py @@ -0,0 +1,58 @@ +from piracyshield_component.log.logger import Logger +from piracyshield_component.exception import ApplicationException + +from .response import ResponseHandler + +import tornado.web +import time + +class RequestHandler(ResponseHandler): + + """ + Requests gateway. + """ + + # override the default methods + SUPPORTED_METHODS = ("GET", "POST") + + # max requests allowed in a second + MAX_REQUESTS_PER_SECOND = 100 + + # requests container + REQUESTS = {} + + def prepare(self) -> None: + """ + Handles the request general procedures. + This method implements a very simple request limit check. + """ + + self.application.logger.debug(f'> GET `{self.request.uri}` from `{self.request.remote_ip}`') + + # get the current timestamp in seconds + timestamp = int(time.time()) + + # TODO: this should be better handled and also provide a way to temporary ban each IP when flooding. + + # check if the number of requests for this second has exceeded the limit + if timestamp in self.REQUESTS: + if self.REQUESTS[timestamp] >= self.MAX_REQUESTS_PER_SECOND: + self.error(status_code = 429, error_code = ErrorCode.TOO_MANY_REQUESTS, message = ErrorMessage.TOO_MANY_REQUESTS) + + return + + # increment the number of requests for this second + self.REQUESTS[timestamp] = self.REQUESTS.get(timestamp, 0) + 1 + + # decrement the number of requests after one second + tornado.ioloop.IOLoop.current().call_later(1.0, self._decrement_requests_count, timestamp) + + def _decrement_requests_count(self, timestamp): + """ + Decrement the requests count per timestamp. + + :param timestamp: current timestamp. + """ + + if timestamp in self.REQUESTS: + self.REQUESTS[timestamp] -= 1 diff --git a/ioutils/response.py b/ioutils/response.py new file mode 100644 index 0000000..5d0d720 --- /dev/null +++ b/ioutils/response.py @@ -0,0 +1,214 @@ +import tornado.web + +from .errors import ErrorCode, ErrorMessage + +import datetime +import json + +class ResponseHandler(tornado.web.RequestHandler): + + """ + Response handler. + """ + + def set_default_headers(self) -> None: + """ + Sets the default headers. + """ + + self.set_header('Access-Control-Allow-Origin', '*') + + self.set_header('Access-Control-Allow-Methods', 'POST, GET') + + self.set_header('Access-Control-Max-Age', 3600) + + # response for this API is always a JSON + self.set_header('Content-Type', 'application/json') + + # sets the server name + # TODO: let this be configurable + self.set_header('Server', 'piracy-shield') + + def set_refresh_cookie(self, value: str) -> None: + """ + Cookie setter. + + TODO: need to extend this and have these data loaded from the external config. + + :param key: name of the cookie. + :param value: value of the cookie. + """ + + self.set_secure_cookie( + name = 'refresh_token', + value = value, + expires_days = 1, + httponly = True, + samesite = "Strict" + # secure = True + ) + + def get_refresh_cookie(self) -> any: + """ + Handy function to return the refresh token cookie. + """ + + return self.get_secure_cookie('refresh_token') + + def clear_cookie(self, key: str, **kwargs) -> None: + """ + Cookie remover. + + :param key: name of the cookie. + """ + + # set to -365 days + expires = -31536000 + + self.set_cookie(key, value = '', expires = expires, **kwargs) + + def success_txt(self, data: str) -> None: + """ + Returns a string in TXT. + + :param data: a string to send back as response. + """ + + self.set_header('Content-Type', 'text/plain; charset=UTF-8') + + self.set_status(200) + + self.finish(self.str_to_txt(data)) + + def success_list_txt(self, data: list) -> None: + """ + Returns a list in TXT. + + :param data: a list to send back as response. + """ + + self.set_header('Content-Type', 'text/plain; charset=UTF-8') + + self.set_status(200) + + self.finish(self.list_to_txt(data)) + + def success(self, data = None, note = None) -> None: + """ + Success response. + + :param data: returns data if needed. + """ + + self.set_status(200) + + response = { + 'status': 'success' + } + + # this will return empty data as well + response['data'] = data + + # generic purpose informations that we want to communicate + if note: + response['note'] = note + + self.finish(self.to_json(response)) + + def error(self, status_code: int, error_code: int, message: str) -> None: + """ + Returns custom format error. + + :param status_code: HTTP status code. + :param error_code: custom error code. + :param message: reason of the error. + """ + + self.set_status(status_code) + + response = { + 'status': 'error', + 'code': error_code, + 'message': message + } + + self.application.logger.debug(f'< ERR `{self.request.uri}` {status_code}') + + self.finish(self.to_json(response)) + + # prevent further execution of the code + self._handled = False + + # stop execution of the request + self._finished = True + + def write_error(self, status_code, **kwargs) -> None: + """ + Override the generic error handler. + + :param status_code: HTTP status code. + """ + + match status_code: + case 403: + self.error( + status_code = 403, + error_code = ErrorCode.FORBIDDEN, + message = ErrorMessage.FORBIDDEN + ) + + case 404: + self.error( + status_code = 404, + error_code = ErrorCode.ROUTE_NOT_FOUND, + message = ErrorMessage.ROUTE_NOT_FOUND + ) + + case 405: + self.error( + status_code = 405, + error_code = ErrorCode.METHOD_NOT_ALLOWED, + message = ErrorMessage.METHOD_NOT_ALLOWED + ) + + case _: + self.error( + status_code = 400, + error_code = ErrorCode.GENERIC, + message = ErrorMessage.GENERIC + ) + + def to_json(self, response: dict) -> str: + """ + Converts dictionary into a valid JSON string. + + :param response: response data. + """ + + return json.dumps(response) + + def str_to_txt(self, data: str) -> str: + """ + Converts a list into an UTF-8 string of line by line elements. + + :param data: the data to convert. + """ + + if data: + return data.encode('utf-8') + + return '' + + def list_to_txt(self, data: list) -> str: + """ + Converts a list into an UTF-8 string of line by line elements. + + :param data: the data to convert. + """ + + if data: + converted_data = '\n'.join(data) + + return converted_data.encode('utf-8') + + return '' diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a1493f2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "api", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/package.json @@ -0,0 +1 @@ +{} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..75b3ae4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +tornado +pytest diff --git a/tests/01_reporter/test_0004_ticket.py b/tests/01_reporter/test_0004_ticket.py new file mode 100644 index 0000000..f00e602 --- /dev/null +++ b/tests/01_reporter/test_0004_ticket.py @@ -0,0 +1,73 @@ +import pytest +import requests +import secrets + +import sys +import os +import time + +sys.path.append('../') + +from base import reporter_authentication, authenticated_post_request + +class TestReporterCreateTicket: + + ticket_wait_time = 76 + + ticket_parameters = { + 'dda_id': '2326485749e94573bf5724ff5006f30c', + 'description': '__MOCK_TICKET__', + 'forensic_evidence': { + 'hash': {} + }, + 'fqdn': [ + 'mock-website.com', + 'google.com' + ], + 'ipv4': [ + '9.8.7.6', + '1.1.1.1' + ], + 'ipv6': [ + '2001:db8:3333:4444:5555:6666:7777:8888' + ] + } + + @pytest.fixture(scope = "function", autouse = True) + def setup_method(self, reporter_authentication): + self.access_token, self.refresh_token = reporter_authentication + + def test_create_and_remove_ticket(self): + self.ticket_parameters['forensic_evidence']['hash'] = { + 'sha256': secrets.token_hex(32) + } + + create_response = authenticated_post_request('/api/v1/ticket/create', self.access_token, self.ticket_parameters) + + assert create_response.status_code == 200 + assert create_response.json()['status'] == 'success' + + time.sleep(1) + + remove_response = authenticated_post_request('/api/v1/ticket/remove', self.access_token, { + 'ticket_id': create_response.json()['data']['ticket_id'] + }) + + assert remove_response.status_code == 200 + assert remove_response.json()['status'] == 'success' + + time.sleep(1) + + def test_create_real_ticket(self): + self.ticket_parameters['forensic_evidence']['hash'] = { + 'sha256': secrets.token_hex(32) + } + + response = authenticated_post_request('/api/v1/ticket/create', self.access_token, self.ticket_parameters) + + assert response.status_code == 200 + assert response.json()['status'] == 'success' + + print(f"Waiting for the ticket to change status ({self.ticket_wait_time}s)") + + time.sleep(self.ticket_wait_time) diff --git a/tests/02_provider/test_0005_retrieve_ticket_items.py b/tests/02_provider/test_0005_retrieve_ticket_items.py new file mode 100644 index 0000000..f1918fe --- /dev/null +++ b/tests/02_provider/test_0005_retrieve_ticket_items.py @@ -0,0 +1,39 @@ +import pytest +import requests + +import sys +import os + +sys.path.append('../') + +from base import provider_authentication, authenticated_get_request + +class TestProviderRetrieveTicketItems: + + @pytest.fixture(scope = "function", autouse = True) + def setup_method(self, provider_authentication): + self.access_token, self.refresh_token = provider_authentication + + def test_fqdn_get_all(self): + response = authenticated_get_request('/api/v1/fqdn/get/all', self.access_token) + + assert response.status_code == 200 + assert response.json()['status'] == 'success' + + def test_fqdn_get_all_txt(self): + response = authenticated_get_request('/api/v1/fqdn/get/all/txt', self.access_token) + + assert response.status_code == 200 + assert response.headers.get('Content-Type', '').lower() == 'text/plain; charset=utf-8' + + def test_ipv4_get_all(self): + response = authenticated_get_request('/api/v1/fqdn/get/all', self.access_token) + + assert response.status_code == 200 + assert response.json()['status'] == 'success' + + def test_ipv4_get_all_txt(self): + response = authenticated_get_request('/api/v1/fqdn/get/all/txt', self.access_token) + + assert response.status_code == 200 + assert response.headers.get('Content-Type', '').lower() == 'text/plain; charset=utf-8' diff --git a/tests/02_provider/test_0006_set_ticket_items.py b/tests/02_provider/test_0006_set_ticket_items.py new file mode 100644 index 0000000..5de54c8 --- /dev/null +++ b/tests/02_provider/test_0006_set_ticket_items.py @@ -0,0 +1,39 @@ +import pytest +import requests + +import sys +import os + +sys.path.append('../') + +from base import provider_authentication, authenticated_post_request + +class TestProviderSetTicketItems: + + @pytest.fixture(scope = "function", autouse = True) + def setup_method(self, provider_authentication): + self.access_token, self.refresh_token = provider_authentication + + def test_set_processed_non_existent(self): + response = authenticated_post_request('/api/v1/ticket/item/set/processed', self.access_token, { + 'value': '1.2.3.4' + }) + + assert response.status_code == 400 + assert response.json()['status'] == 'error' + + def test_set_processed_fqdn(self): + response = authenticated_post_request('/api/v1/ticket/item/set/processed', self.access_token, { + 'value': 'mock-website.com' + }) + + assert response.status_code == 200 + assert response.json()['status'] == 'success' + + def test_set_processed_ipv4(self): + response = authenticated_post_request('/api/v1/ticket/item/set/processed', self.access_token, { + 'value': '9.8.7.6' + }) + + assert response.status_code == 200 + assert response.json()['status'] == 'success' diff --git a/tests/base.py b/tests/base.py new file mode 100644 index 0000000..3912611 --- /dev/null +++ b/tests/base.py @@ -0,0 +1,78 @@ +from piracyshield_component.config import Config + +import pytest +import os +import requests + +application_config = Config('api').get('general') + +URL = f"http://127.0.0.1:{application_config['port']}" + +def get_request(endpoint: str): + return requests.get(f'{URL}{endpoint}') + +def post_request(endpoint: str, data: dict): + return requests.post(f'{URL}{endpoint}', json = data) + +def authenticated_get_request(endpoint: str, access_token: str): + return requests.get(f'{URL}{endpoint}', headers = { + 'Authorization': f'Bearer {access_token}' + }) + +def authenticated_post_request(endpoint: str, access_token: str, data: dict): + return requests.post(f'{URL}{endpoint}', headers = { + 'Authorization': f'Bearer {access_token}' + }, json = data) + +def authenticate(email, password): + """ + General authentication utility. + """ + + response = requests.post(f'{URL}/api/v1/authentication/login', json = { + 'email': email, + 'password': password + }) + + response_json = response.json() + + access_token = response_json['data']['access_token'] + refresh_token = response_json['data']['refresh_token'] + + assert access_token is not None + assert refresh_token is not None + + return [ access_token, refresh_token ] + +@pytest.fixture +def internal_authentication(): + """ + Passes parameters to authenticate a provider account. + """ + + return authenticate( + email = os.environ.get('PIRACYSHIELD_MOCK_INTERNAL_EMAIL'), + password = os.environ.get('PIRACYSHIELD_MOCK_INTERNAL_PASSWORD') + ) + +@pytest.fixture +def reporter_authentication(): + """ + Passes parameters to authenticate a provider account. + """ + + return authenticate( + email = os.environ.get('PIRACYSHIELD_MOCK_REPORTER_EMAIL'), + password = os.environ.get('PIRACYSHIELD_MOCK_REPORTER_PASSWORD') + ) + +@pytest.fixture +def provider_authentication(): + """ + Passes parameters to authenticate a provider account. + """ + + return authenticate( + email = os.environ.get('PIRACYSHIELD_MOCK_PROVIDER_EMAIL'), + password = os.environ.get('PIRACYSHIELD_MOCK_PROVIDER_PASSWORD') + ) diff --git a/tests/bench_params.txt b/tests/bench_params.txt new file mode 100644 index 0000000..9ab5eb8 --- /dev/null +++ b/tests/bench_params.txt @@ -0,0 +1,4 @@ +{ + "email": "test@test.com", + "password": "testing123" +} diff --git a/tests/mock_storage.py b/tests/mock_storage.py new file mode 100644 index 0000000..b1841a1 --- /dev/null +++ b/tests/mock_storage.py @@ -0,0 +1,10 @@ +from piracyshield_data_storage.blob.drivers.azure import AzureBlobStorage + +import os + +mock_storage = AzureBlobStorage( + connection_string = os.environ.get("PIRACYSHIELD_MOCK_STORAGE_CONNECTION_STRING"), + container_name = os.environ.get("PIRACYSHIELD_MOCK_STORAGE_CONTAINER_NAME") +) + +mock_storage.create_container() diff --git a/tests/test_0001_health.py b/tests/test_0001_health.py new file mode 100644 index 0000000..eb84582 --- /dev/null +++ b/tests/test_0001_health.py @@ -0,0 +1,15 @@ +import pytest +import requests + +from base import get_request + +class TestGeneral: + + def test_ping(self): + """ + Check the API availability. + """ + + response = get_request('/api/v1/ping') + + assert response.status_code == 200 diff --git a/tests/test_0002_errors.py b/tests/test_0002_errors.py new file mode 100644 index 0000000..1aec1c0 --- /dev/null +++ b/tests/test_0002_errors.py @@ -0,0 +1,60 @@ +import pytest +import requests + +from base import URL + +class TestErrors: + + def test_route_not_found(self): + """ + Test a non existent route. + """ + + response = requests.get(f'{URL}/fake/route') + + assert response.status_code == 404 + + def test_method_not_allowed(self): + """ + Test an existing route with the wrong method. + """ + + response = requests.get(f'{URL}/api/v1/account/guest/create') + + assert response.status_code == 405 + + def test_create_user(self): + """ + Test a non authorized account creation request. + """ + + response = requests.post(f'{URL}/api/v1/account/guest/create', {'name': 'test'}) + + assert response.status_code == 401 + + def test_missing_authentication_parameter(self): + """ + Miss a parameter. + """ + + response = requests.post(f'{URL}/api/v1/authentication/login', {'email': 'test@fake.com'}) + + assert response.status_code == 400 + + def test_fake_authentication(self): + """ + Test using a non existent e-mail. + """ + + response = requests.post(f'{URL}/api/v1/authentication/login', {'email': 'test@fake.com', 'password': 'very_fake'}) + + assert response.status_code == 400 + + def test_bad_format_refresh_token(self): + """ + Try to refresh a bad token. + """ + + response = requests.post(f'{URL}/api/v1/authentication/refresh', {'refresh_token': 'non valid token'}) + + assert response.status_code == 400 diff --git a/tests/test_0003_authentication.py b/tests/test_0003_authentication.py new file mode 100644 index 0000000..3f00d29 --- /dev/null +++ b/tests/test_0003_authentication.py @@ -0,0 +1,39 @@ +import pytest +import os +import requests + +from base import internal_authentication, post_request, authenticated_get_request + +class TestAuthentication: + + access_token = None + + refresh_token = None + + @pytest.fixture(scope = "function", autouse = True) + def setup_method(self, internal_authentication): + self.access_token, self.refresh_token = internal_authentication + + def test_token_refresh(self): + """ + Test authentication refresh token. + """ + + response = post_request('/api/v1/authentication/refresh', { + 'refresh_token': self.refresh_token + }) + + response_json = response.json() + + self.access_token = response_json['data']['access_token'] + + assert response.status_code == 200 + + def test_logout(self): + """ + Test authentication logout. + """ + + response = authenticated_get_request('/api/v1/authentication/logout', self.access_token) + + assert response.status_code == 200 diff --git a/v1/handlers/account/get.py b/v1/handlers/account/get.py new file mode 100644 index 0000000..9be1457 --- /dev/null +++ b/v1/handlers/account/get.py @@ -0,0 +1,49 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.permission.service import PermissionService +from piracyshield_service.account.general.get import GeneralAccountGetService + +from piracyshield_component.exception import ApplicationException + +class GetGeneralAccountHandler(ProtectedHandler): + + """ + Handles getting a single account by its account identifier. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_account() + + general_account_get_service = GeneralAccountGetService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + general_account_get_service.execute, + self.request_data.get('account_id') + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/get_all.py b/v1/handlers/account/get_all.py new file mode 100644 index 0000000..d23fa8f --- /dev/null +++ b/v1/handlers/account/get_all.py @@ -0,0 +1,41 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.permission.service import PermissionService +from piracyshield_service.account.general.get_all import GeneralAccountGetAllService + +from piracyshield_component.exception import ApplicationException + +class GetAllGeneralAccountHandler(ProtectedHandler): + + """ + Handles getting multiple accounts. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_account() + + general_account_get_all_service = GeneralAccountGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + general_account_get_all_service.execute + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/guest/create.py b/v1/handlers/account/guest/create.py new file mode 100644 index 0000000..b9cbce9 --- /dev/null +++ b/v1/handlers/account/guest/create.py @@ -0,0 +1,65 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.permission.service import PermissionService +from piracyshield_service.guest.create import GuestCreateService + +from piracyshield_component.exception import ApplicationException + +class CreateGuestAccountHandler(ProtectedHandler): + + """ + Handles the creation of a new account. + """ + + required_fields = [ + 'name', + 'email', + 'password', + 'confirm_password', + 'flags' + ] + + async def post(self): + """ + Handles the account creation. + """ + + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_create_account() + + guest_account_create_service = GuestCreateService() + + account_id = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + guest_account_create_service.execute, + self.request_data.get('name'), + self.request_data.get('email'), + self.request_data.get('password'), + self.request_data.get('confirm_password'), + self.request_data.get('flags'), + self.account_data.get('account_id') + ) + + self.success(data = { + 'account_id': account_id + }) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/guest/get.py b/v1/handlers/account/guest/get.py new file mode 100644 index 0000000..4f9e64c --- /dev/null +++ b/v1/handlers/account/guest/get.py @@ -0,0 +1,50 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.permission.service import PermissionService +from piracyshield_service.guest.get import GuestGetService + +from piracyshield_component.exception import ApplicationException + +class GetGuestAccountHandler(ProtectedHandler): + + """ + Handles getting a single account by its ID. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_view_account() + + guest_account_get_service = GuestGetService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + guest_account_get_service.execute, + self.request_data.get('account_id') + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/guest/get_all.py b/v1/handlers/account/guest/get_all.py new file mode 100644 index 0000000..6fab7bc --- /dev/null +++ b/v1/handlers/account/guest/get_all.py @@ -0,0 +1,42 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.permission.service import PermissionService +from piracyshield_service.guest.get_all import GuestGetAllService + +from piracyshield_component.exception import ApplicationException + +class GetAllGuestAccountHandler(ProtectedHandler): + + """ + Handles getting multiple accounts. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_view_account() + + guest_account_get_all_service = GuestGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + guest_account_get_all_service.execute + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/guest/remove.py b/v1/handlers/account/guest/remove.py new file mode 100644 index 0000000..258d171 --- /dev/null +++ b/v1/handlers/account/guest/remove.py @@ -0,0 +1,50 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.permission.service import PermissionService +from piracyshield_service.guest.remove import GuestRemoveService + +from piracyshield_component.exception import ApplicationException + +class RemoveGuestAccountHandler(ProtectedHandler): + + """ + Handles the account removal. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_delete_account() + + guest_account_remove_service = GuestRemoveService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + guest_account_remove_service.execute, + self.request_data.get('account_id') + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/internal/change_password.py b/v1/handlers/account/internal/change_password.py new file mode 100644 index 0000000..ac062dc --- /dev/null +++ b/v1/handlers/account/internal/change_password.py @@ -0,0 +1,51 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.internal.change_password import InternalChangePasswordService + +from piracyshield_component.exception import ApplicationException + +class ChangePasswordInternalAccountHandler(ProtectedHandler): + + """ + Handles account password change. + """ + + required_fields = [ + 'current_password', + 'new_password', + 'confirm_password' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + internal_account_change_password_service = InternalChangePasswordService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + internal_account_change_password_service.execute, + self.account_data.get('account_id'), + self.request_data.get('current_password'), + self.request_data.get('new_password'), + self.request_data.get('confirm_password') + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/internal/create.py b/v1/handlers/account/internal/create.py new file mode 100644 index 0000000..779867f --- /dev/null +++ b/v1/handlers/account/internal/create.py @@ -0,0 +1,63 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.internal.create import InternalCreateService + +from piracyshield_component.exception import ApplicationException + +class CreateInternalAccountHandler(ProtectedHandler): + + """ + Handles the creation of a new account. + """ + + required_fields = [ + 'name', + 'email', + 'password', + 'confirm_password', + 'flags' + ] + + async def post(self): + """ + Handles the account creation. + """ + + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_create_account() + + internal_account_create_service = InternalCreateService() + + account_id = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + internal_account_create_service.execute, + self.request_data.get('name'), + self.request_data.get('email'), + self.request_data.get('password'), + self.request_data.get('confirm_password'), + self.request_data.get('flags'), + self.account_data.get('account_id') + ) + + self.success(data = { + 'account_id': account_id + }) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/internal/get.py b/v1/handlers/account/internal/get.py new file mode 100644 index 0000000..cd4c0d4 --- /dev/null +++ b/v1/handlers/account/internal/get.py @@ -0,0 +1,48 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.internal.get import InternalGetService + +from piracyshield_component.exception import ApplicationException + +class GetInternalAccountHandler(ProtectedHandler): + + """ + Handles getting a single account by its ID. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_account() + + internal_account_get_service = InternalGetService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + internal_account_get_service.execute, + self.request_data.get('account_id') + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/internal/get_all.py b/v1/handlers/account/internal/get_all.py new file mode 100644 index 0000000..631985b --- /dev/null +++ b/v1/handlers/account/internal/get_all.py @@ -0,0 +1,40 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.internal.get_all import InternalGetAllService + +from piracyshield_component.exception import ApplicationException + +class GetAllInternalAccountHandler(ProtectedHandler): + + """ + Handles getting multiple accounts. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_account() + + internal_account_get_all_service = InternalGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + internal_account_get_all_service.execute + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/internal/remove.py b/v1/handlers/account/internal/remove.py new file mode 100644 index 0000000..0aea87d --- /dev/null +++ b/v1/handlers/account/internal/remove.py @@ -0,0 +1,48 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.internal.remove import InternalRemoveService + +from piracyshield_component.exception import ApplicationException + +class RemoveInternalAccountHandler(ProtectedHandler): + + """ + Handles the account removal. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_delete_account() + + internal_account_remove_service = InternalRemoveService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + internal_account_remove_service.execute, + self.request_data.get('account_id') + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/internal/set_status.py b/v1/handlers/account/internal/set_status.py new file mode 100644 index 0000000..087ab7a --- /dev/null +++ b/v1/handlers/account/internal/set_status.py @@ -0,0 +1,83 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.internal.set_status import InternalSetStatusService + +from piracyshield_component.exception import ApplicationException + +class SetStatusActiveInternalAccountHandler(ProtectedHandler): + + """ + Handles account activation. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_account() + + internal_account_set_status_service = InternalSetStatusService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + internal_account_set_status_service.execute, + self.request_data.get('account_id'), + True + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) + +class SetStatusNonActiveInternalAccountHandler(ProtectedHandler): + + """ + Handles account deactivation. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_account() + + internal_account_set_status_service = InternalSetStatusService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + internal_account_set_status_service.execute, + self.request_data.get('account_id'), + False + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/provider/change_password.py b/v1/handlers/account/provider/change_password.py new file mode 100644 index 0000000..bfe9663 --- /dev/null +++ b/v1/handlers/account/provider/change_password.py @@ -0,0 +1,51 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.provider.change_password import ProviderChangePasswordService + +from piracyshield_component.exception import ApplicationException + +class ChangePasswordProviderAccountHandler(ProtectedHandler): + + """ + Handles account password change. + """ + + required_fields = [ + 'current_password', + 'new_password', + 'confirm_password' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + provider_account_change_password_service = ProviderChangePasswordService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + provider_account_change_password_service.execute, + self.account_data.get('account_id'), + self.request_data.get('current_password'), + self.request_data.get('new_password'), + self.request_data.get('confirm_password') + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/provider/create.py b/v1/handlers/account/provider/create.py new file mode 100644 index 0000000..87232dd --- /dev/null +++ b/v1/handlers/account/provider/create.py @@ -0,0 +1,66 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.provider.create import ProviderCreateService + +from piracyshield_component.exception import ApplicationException + +class CreateProviderAccountHandler(ProtectedHandler): + + """ + Handles the creation of a new account. + """ + + required_fields = [ + 'name', + 'email', + 'password', + 'confirm_password', + 'flags' + ] + + async def post(self): + """ + Handles the account creation. + """ + + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + print(self.request_data) + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_create_account() + + provider_account_create_service = ProviderCreateService() + + account_id = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + provider_account_create_service.execute, + self.request_data.get('name'), + self.request_data.get('email'), + self.request_data.get('password'), + self.request_data.get('confirm_password'), + self.request_data.get('flags'), + self.account_data.get('account_id') + ) + + self.success(data = { + 'account_id': account_id + }) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/provider/get.py b/v1/handlers/account/provider/get.py new file mode 100644 index 0000000..a2b43c6 --- /dev/null +++ b/v1/handlers/account/provider/get.py @@ -0,0 +1,49 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.provider.get import ProviderGetService + +from piracyshield_component.exception import ApplicationException + +class GetProviderAccountHandler(ProtectedHandler): + + """ + Handles getting a single account by its ID. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_view_account() + + provider_account_get_service = ProviderGetService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + provider_account_get_service.execute, + self.request_data.get('account_id') + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/provider/get_all.py b/v1/handlers/account/provider/get_all.py new file mode 100644 index 0000000..9b25b45 --- /dev/null +++ b/v1/handlers/account/provider/get_all.py @@ -0,0 +1,41 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.provider.get_all import ProviderGetAllService + +from piracyshield_component.exception import ApplicationException + +class GetAllProviderAccountHandler(ProtectedHandler): + + """ + Handles getting multiple accounts. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_view_account() + + provider_account_get_all_service = ProviderGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + provider_account_get_all_service.execute + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/provider/remove.py b/v1/handlers/account/provider/remove.py new file mode 100644 index 0000000..ea61bab --- /dev/null +++ b/v1/handlers/account/provider/remove.py @@ -0,0 +1,49 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.provider.remove import ProviderRemoveService + +from piracyshield_component.exception import ApplicationException + +class RemoveProviderAccountHandler(ProtectedHandler): + + """ + Handles the account removal. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_delete_account() + + provider_account_remove_service = ProviderRemoveService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + provider_account_remove_service.execute, + self.request_data.get('account_id') + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/provider/set_status.py b/v1/handlers/account/provider/set_status.py new file mode 100644 index 0000000..3a0ea50 --- /dev/null +++ b/v1/handlers/account/provider/set_status.py @@ -0,0 +1,83 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.provider.set_status import ProviderSetStatusService + +from piracyshield_component.exception import ApplicationException + +class SetStatusActiveProviderAccountHandler(ProtectedHandler): + + """ + Handles account activation. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_account() + + provider_account_set_status_service = ProviderSetStatusService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + provider_account_set_status_service.execute, + self.request_data.get('account_id'), + True + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) + +class SetStatusNonActiveProviderAccountHandler(ProtectedHandler): + + """ + Handles account deactivation. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_account() + + provider_account_set_status_service = ProviderSetStatusService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + provider_account_set_status_service.execute, + self.request_data.get('account_id'), + False + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/reporter/change_password.py b/v1/handlers/account/reporter/change_password.py new file mode 100644 index 0000000..8317e28 --- /dev/null +++ b/v1/handlers/account/reporter/change_password.py @@ -0,0 +1,51 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.reporter.change_password import ReporterChangePasswordService + +from piracyshield_component.exception import ApplicationException + +class ChangePasswordReporterAccountHandler(ProtectedHandler): + + """ + Handles account password change. + """ + + required_fields = [ + 'current_password', + 'new_password', + 'confirm_password' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + reporter_account_change_password_service = ReporterChangePasswordService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + reporter_account_change_password_service.execute, + self.account_data.get('account_id'), + self.request_data.get('current_password'), + self.request_data.get('new_password'), + self.request_data.get('confirm_password') + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/reporter/create.py b/v1/handlers/account/reporter/create.py new file mode 100644 index 0000000..9c5744c --- /dev/null +++ b/v1/handlers/account/reporter/create.py @@ -0,0 +1,64 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.reporter.create import ReporterCreateService + +from piracyshield_component.exception import ApplicationException + +class CreateReporterAccountHandler(ProtectedHandler): + + """ + Handles the creation of a new account. + """ + + required_fields = [ + 'name', + 'email', + 'password', + 'confirm_password', + 'flags' + ] + + async def post(self): + """ + Handles the account creation. + """ + + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_create_account() + + reporter_account_create_service = ReporterCreateService() + + account_id = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + reporter_account_create_service.execute, + self.request_data.get('name'), + self.request_data.get('email'), + self.request_data.get('password'), + self.request_data.get('confirm_password'), + self.request_data.get('flags'), + self.account_data.get('account_id') + ) + + self.success(data = { + 'account_id': account_id + }) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/reporter/get.py b/v1/handlers/account/reporter/get.py new file mode 100644 index 0000000..1fc485e --- /dev/null +++ b/v1/handlers/account/reporter/get.py @@ -0,0 +1,49 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.reporter.get import ReporterGetService + +from piracyshield_component.exception import ApplicationException + +class GetReporterAccountHandler(ProtectedHandler): + + """ + Handles getting a single account by its ID. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_view_account() + + reporter_account_get_service = ReporterGetService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + reporter_account_get_service.execute, + self.request_data.get('account_id') + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/reporter/get_all.py b/v1/handlers/account/reporter/get_all.py new file mode 100644 index 0000000..8c61f56 --- /dev/null +++ b/v1/handlers/account/reporter/get_all.py @@ -0,0 +1,41 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.reporter.get_all import ReporterGetAllService + +from piracyshield_component.exception import ApplicationException + +class GetAllReporterAccountHandler(ProtectedHandler): + + """ + Handles getting multiple accounts. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_view_account() + + reporter_account_get_all_service = ReporterGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + reporter_account_get_all_service.execute + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/reporter/remove.py b/v1/handlers/account/reporter/remove.py new file mode 100644 index 0000000..7b9b1e6 --- /dev/null +++ b/v1/handlers/account/reporter/remove.py @@ -0,0 +1,49 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.reporter.remove import ReporterRemoveService + +from piracyshield_component.exception import ApplicationException + +class RemoveReporterAccountHandler(ProtectedHandler): + + """ + Handles the account removal. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # ensure that we have the proper permissions for this operation + self.permission_service.can_delete_account() + + reporter_account_remove_service = ReporterRemoveService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + reporter_account_remove_service.execute, + self.request_data.get('account_id') + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/account/reporter/set_status.py b/v1/handlers/account/reporter/set_status.py new file mode 100644 index 0000000..212a0b7 --- /dev/null +++ b/v1/handlers/account/reporter/set_status.py @@ -0,0 +1,83 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.reporter.set_status import ReporterSetStatusService + +from piracyshield_component.exception import ApplicationException + +class SetStatusActiveReporterAccountHandler(ProtectedHandler): + + """ + Handles account activation. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_account() + + reporter_account_set_status_service = ReporterSetStatusService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + reporter_account_set_status_service.execute, + self.request_data.get('account_id'), + True + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) + +class SetStatusNonActiveReporterAccountHandler(ProtectedHandler): + + """ + Handles account deactivation. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_account() + + reporter_account_set_status_service = ReporterSetStatusService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + reporter_account_set_status_service.execute, + self.request_data.get('account_id'), + False + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/authentication/login.py b/v1/handlers/authentication/login.py new file mode 100644 index 0000000..d4cbbf5 --- /dev/null +++ b/v1/handlers/authentication/login.py @@ -0,0 +1,73 @@ +import sys +import os + +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.base import BaseHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.authentication.authenticate import AuthenticationAuthenticateService +from piracyshield_service.authentication.generate_access_token import AuthenticationGenerateAccessTokenService +from piracyshield_service.authentication.generate_refresh_token import AuthenticationGenerateRefreshTokenService + +from piracyshield_component.exception import ApplicationException + +class AuthenticationLoginHandler(BaseHandler): + + """ + Handles the account authentication. + """ + + required_fields = [ + 'email', + 'password' + ] + + async def post(self): + """ + Handles the account authentication. + """ + + if self.handle_post(self.required_fields) == False: + return + + try: + access_token, refresh_token = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + self.process, + self.request_data.get('email'), + self.request_data.get('password') + ) + + self.success(data = { + 'access_token': access_token, + 'refresh_token': refresh_token + }) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) + + def process(self, email: str, password: str) -> tuple: + authentication_authenticate_service = AuthenticationAuthenticateService() + + # try to authenticate + payload = authentication_authenticate_service.execute( + email = email, + password = password + ) + + authentication_generate_access_token_service = AuthenticationGenerateAccessTokenService() + authentication_generate_refresh_token_service = AuthenticationGenerateRefreshTokenService() + + # generate token pairs + access_token = authentication_generate_access_token_service.execute(payload) + refresh_token = authentication_generate_refresh_token_service.execute(payload) + + # store the refresh_token in a http-only cookie + self.set_refresh_cookie(value = refresh_token) + + return access_token, refresh_token diff --git a/v1/handlers/authentication/logout.py b/v1/handlers/authentication/logout.py new file mode 100644 index 0000000..46938bd --- /dev/null +++ b/v1/handlers/authentication/logout.py @@ -0,0 +1,25 @@ +import sys +import os + +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +from ioutils.protected import ProtectedHandler + +from piracyshield_component.exception import ApplicationException + +class AuthenticationLogoutHandler(ProtectedHandler): + + """ + Removes the authentication refresh token. + The effective logout remains on the access token expiration time, this is why it should be set to a short time. + """ + + def get(self): + if self.initialize_account() == False: + return + + self.clear_cookie('refresh_token') + + self.success(data = 'Goodbye!') diff --git a/v1/handlers/authentication/refresh.py b/v1/handlers/authentication/refresh.py new file mode 100644 index 0000000..9faf860 --- /dev/null +++ b/v1/handlers/authentication/refresh.py @@ -0,0 +1,71 @@ +import sys +import os + +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.base import BaseHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.authentication.verify_refresh_token import AuthenticationVerifyRefreshTokenService +from piracyshield_service.authentication.generate_access_token import AuthenticationGenerateAccessTokenService + +from piracyshield_component.exception import ApplicationException + +class AuthenticationRefreshHandler(BaseHandler): + + """ + Get another JWT access token once the main has expired. + """ + + optional_fields = [ + 'refresh_token' + ] + + async def post(self): + # use stored refresh token when available + refresh_token = self.get_refresh_cookie() + + # if no cookie available, generate a new access_token via POSTed refresh_token + if not refresh_token: + # if no refresh_token is found, we have an error + if self.handle_post(required_fields = None, optional_fields = self.optional_fields) == False: + return + + if not self.request_data.get('refresh_token'): + return self.error(status_code = 403, error_code = ErrorCode.MISSING_REFRESH_TOKEN, message = ErrorMessage.MISSING_REFRESH_TOKEN) + + refresh_token = self.request_data.get('refresh_token') + + try: + access_token = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + self.process, + refresh_token + ) + + # return the access_token + self.success(data = { + 'access_token': access_token + }) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) + + def process(self, refresh_token: str) -> str: + authentication_verify_refresh_token_service = AuthenticationVerifyRefreshTokenService() + + # verify the token and unwrap the payload + payload = authentication_verify_refresh_token_service.execute( + token = refresh_token + ) + + authentication_generate_access_token_service = AuthenticationGenerateAccessTokenService() + + # generate a new access token + access_token = authentication_generate_access_token_service.execute(payload) + + return access_token diff --git a/v1/handlers/dda/create.py b/v1/handlers/dda/create.py new file mode 100644 index 0000000..45ed7eb --- /dev/null +++ b/v1/handlers/dda/create.py @@ -0,0 +1,54 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.dda.create import DDACreateService + +from piracyshield_component.exception import ApplicationException + +class CreateDDAHandler(ProtectedHandler): + + """ + Handles the creation of a new DDA instance. + """ + + required_fields = [ + 'description', + 'instance', + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_create_dda() + + dda_create_service = DDACreateService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + dda_create_service.execute, + self.request_data.get('description'), + self.request_data.get('instance'), + self.request_data.get('account_id'), + self.account_data.get('account_id') + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/dda/get_all.py b/v1/handlers/dda/get_all.py new file mode 100644 index 0000000..63fb3ab --- /dev/null +++ b/v1/handlers/dda/get_all.py @@ -0,0 +1,43 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.dda.get_all_by_account import DDAGetAllByAccountService + +from piracyshield_component.exception import ApplicationException + +class GetAllDDAHandler(ProtectedHandler): + + """ + Handles getting multiple DDA identifiers. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_dda() + + # check what level of view we have + dda_get_all_by_account_service = DDAGetAllByAccountService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + dda_get_all_by_account_service.execute, + self.account_data.get('account_id') + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/dda/get_all_by_account.py b/v1/handlers/dda/get_all_by_account.py new file mode 100644 index 0000000..00ef98c --- /dev/null +++ b/v1/handlers/dda/get_all_by_account.py @@ -0,0 +1,56 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.dda.get_all_by_account import DDAGetAllByAccountService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllByAccountDDAHandler(ProtectedHandler): + + """ + Handles getting multiple DDA identifiers by account. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_dda() + + # check what level of view we have + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + dda_get_all_by_account_service = DDAGetAllByAccountService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + dda_get_all_by_account_service.execute, + self.request_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/dda/get_global.py b/v1/handlers/dda/get_global.py new file mode 100644 index 0000000..78f909e --- /dev/null +++ b/v1/handlers/dda/get_global.py @@ -0,0 +1,47 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_service.dda.get_global import DDAGetGlobalService + +from piracyshield_component.exception import ApplicationException + +class GetGlobalDDAHandler(ProtectedHandler): + + """ + Handles getting multiple DDA identifiers. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_dda() + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + dda_get_global_service = DDAGetGlobalService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + dda_get_global_service.execute + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/dda/remove.py b/v1/handlers/dda/remove.py new file mode 100644 index 0000000..c7b5948 --- /dev/null +++ b/v1/handlers/dda/remove.py @@ -0,0 +1,51 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.dda.remove import DDARemoveService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class RemoveDDAHandler(ProtectedHandler): + + """ + Handles the DDA identifier removal. + """ + + required_fields = [ + 'dda_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_delete_dda() + + dda_remove_service = DDARemoveService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + dda_remove_service.execute, + self.request_data.get('dda_id') + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/dda/set_status.py b/v1/handlers/dda/set_status.py new file mode 100644 index 0000000..2b4eb74 --- /dev/null +++ b/v1/handlers/dda/set_status.py @@ -0,0 +1,88 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.dda.set_status import DDASetStatusService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class SetStatusActiveDDAHandler(ProtectedHandler): + + """ + Handles the status of a DDA identifier. + """ + + required_fields = [ + 'dda_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_dda() + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + dda_set_status_service = DDASetStatusService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + dda_set_status_service.execute, + self.request_data.get('dda_id'), + True + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) + +class SetStatusNonActiveDDAHandler(ProtectedHandler): + + """ + Handles the status of a DDA identifier. + """ + + required_fields = [ + 'dda_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_dda() + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + dda_set_status_service = DDASetStatusService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + dda_set_status_service.execute, + self.request_data.get('dda_id'), + False + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/forensic/get_by_ticket.py b/v1/handlers/forensic/get_by_ticket.py new file mode 100644 index 0000000..1d5affb --- /dev/null +++ b/v1/handlers/forensic/get_by_ticket.py @@ -0,0 +1,73 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.forensic.get_by_ticket import ForensicGetByTicketService +from piracyshield_service.forensic.get_by_ticket_for_reporter import ForensicGetByTicketForReporterService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetByTicketForensicHandler(ProtectedHandler): + + """ + Handles the available forensic evidence by ticket identifier. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # verify permissions + self.permission_service.can_upload_ticket() + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + forensic_get_by_ticket_service = ForensicGetByTicketService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + forensic_get_by_ticket_service.execute, + self.request_data.get('ticket_id') + ) + + self.success( + data = response + ) + + elif self.account_data.get('role') == AccountRoleModel.REPORTER.value: + forensic_get_by_ticket_for_reporter_service = ForensicGetByTicketForReporterService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + forensic_get_by_ticket_for_reporter_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success( + data = response + ) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/forensic/get_supported_formats.py b/v1/handlers/forensic/get_supported_formats.py new file mode 100644 index 0000000..3d43e93 --- /dev/null +++ b/v1/handlers/forensic/get_supported_formats.py @@ -0,0 +1,45 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.forensic.get_supported_formats import ForensicGetSupportedFormatsService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetSupportedFormatsForensicHandler(ProtectedHandler): + + """ + Handles the available archive formats of a forensic evidence. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + # verify permissions + self.permission_service.can_upload_ticket() + + forensic_get_supported_formats_service = ForensicGetSupportedFormatsService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + forensic_get_supported_formats_service.execute + ) + + self.success( + data = response + ) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/forensic/get_supported_hashes.py b/v1/handlers/forensic/get_supported_hashes.py new file mode 100644 index 0000000..e4e2b94 --- /dev/null +++ b/v1/handlers/forensic/get_supported_hashes.py @@ -0,0 +1,49 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.forensic.get_supported_hashes import ForensicGetSupportedHashesService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetSupportedHashesForensicHandler(ProtectedHandler): + + """ + Handles the available hashes of a forensic evidence. + """ + + async def get(self): + """ + Get the list of hashes available. + """ + + if self.initialize_account() == False: + return + + try: + # verify permissions + self.permission_service.can_upload_ticket() + + forensic_get_supported_hashes_service = ForensicGetSupportedHashesService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + forensic_get_supported_hashes_service.execute + ) + + self.success( + data = response + ) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/forensic/upload.py b/v1/handlers/forensic/upload.py new file mode 100644 index 0000000..62d631a --- /dev/null +++ b/v1/handlers/forensic/upload.py @@ -0,0 +1,54 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.forensic.create_archive import ForensicCreateArchiveService + +from piracyshield_component.exception import ApplicationException + +class UploadForensicHandler(ProtectedHandler): + + """ + Appends the forensic evidence. + """ + + async def post(self, ticket_id): + if self.initialize_account() == False: + return + + # verify permissions + self.permission_service.can_upload_ticket() + + # TODO: we could add some mime type filters but we might need to interrogate the ticket model to have a dynamic implementation. + + # no archive passed? + if 'archive' not in self.request.files: + return self.error(status_code = 400, error_code = ErrorCode.MISSING_FILE, message = ErrorMessage.MISSING_FILE) + + # get the file data + archive_handler = self.request.files['archive'][0] + + try: + forensic_create_archive_service = ForensicCreateArchiveService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + forensic_create_archive_service.execute, + ticket_id, + archive_handler['filename'], + archive_handler['body'] + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/log/ticket/get_all.py b/v1/handlers/log/ticket/get_all.py new file mode 100644 index 0000000..bb2ce48 --- /dev/null +++ b/v1/handlers/log/ticket/get_all.py @@ -0,0 +1,52 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.log.ticket.get_all import LogTicketGetAllService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllTicketLogHandler(ProtectedHandler): + + """ + Handles getting all the logs for a specific ticket identifier. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + log_ticket_get_all_service = LogTicketGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + log_ticket_get_all_service.execute, + self.request_data.get('ticket_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/log/ticket/item/get_all.py b/v1/handlers/log/ticket/item/get_all.py new file mode 100644 index 0000000..9958c7d --- /dev/null +++ b/v1/handlers/log/ticket/item/get_all.py @@ -0,0 +1,52 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.log.ticket.item.get_all import LogTicketItemGetAllService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllTicketItemLogHandler(ProtectedHandler): + + """ + Handles getting all the logs for a specific ticket item identifier. + """ + + required_fields = [ + 'ticket_item_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + log_ticket_item_get_all_service = LogTicketItemGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + log_ticket_item_get_all_service.execute, + self.request_data.get('ticket_item_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/create.py b/v1/handlers/ticket/create.py new file mode 100644 index 0000000..6a05418 --- /dev/null +++ b/v1/handlers/ticket/create.py @@ -0,0 +1,74 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.ticket.create import TicketCreateService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class CreateTicketHandler(ProtectedHandler): + + """ + Handles the creation of a new ticket. + """ + + required_fields = [ + 'forensic_evidence' + ] + + optional_fields = [ + 'dda_id', + 'description', + 'fqdn', + 'ipv4', + 'ipv6', + 'assigned_to' + ] + + async def post(self): + """ + Handles the ticket creation. + """ + + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields, self.optional_fields) == False: + return + + try: + # verify permissions + self.permission_service.can_create_ticket() + + ticket_create_service = TicketCreateService() + + ticket_id, revoke_time = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_create_service.execute, + self.request_data.get('dda_id'), + self.request_data.get('forensic_evidence'), + self.request_data.get('fqdn') or [], + self.request_data.get('ipv4') or [], + self.request_data.get('ipv6') or [], + self.request_data.get('assigned_to') or [], + self.account_data.get('account_id'), + self.request_data.get('description') or None + ) + + self.success( + data = { 'ticket_id': ticket_id }, + note = f'Ticket created. If this is a mistake, you have {revoke_time} seconds to remove it before it gets visible to the providers.' + ) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/error/create.py b/v1/handlers/ticket/error/create.py new file mode 100644 index 0000000..552146e --- /dev/null +++ b/v1/handlers/ticket/error/create.py @@ -0,0 +1,64 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.ticket.error.create import TicketErrorCreateService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class CreateTicketErrorHandler(ProtectedHandler): + + """ + Handles the creation of a new error ticket. + """ + + required_fields = [ + 'ticket_id' + ] + + optional_fields = [ + 'fqdn', + 'ipv4', + 'ipv6' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields, self.optional_fields) == False: + return + + try: + # verify permissions + self.permission_service.can_create_ticket() + + ticket_error_create_service = TicketErrorCreateService() + + ticket_error_id, ticket_id = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_error_create_service.execute, + self.request_data.get('ticket_id'), + self.request_data.get('fqdn') or [], + self.request_data.get('ipv4') or [], + self.request_data.get('ipv6') or [], + self.account_data.get('account_id') + ) + + self.success(data = { + 'ticket_error_id': ticket_error_id, + 'ticket_id': ticket_id + }) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/error/get_by_account.py b/v1/handlers/ticket/error/get_by_account.py new file mode 100644 index 0000000..e3b60f8 --- /dev/null +++ b/v1/handlers/ticket/error/get_by_account.py @@ -0,0 +1,69 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.error.get import TicketErrorGetService +from piracyshield_service.ticket.error.get_by_reporter import TicketErrorGetByReporterService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetByReporterTicketErrorHandler(ProtectedHandler): + + """ + Handles getting error ticket for reporter account. + """ + + required_fields = [ + 'ticket_error_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # verify permissions + self.permission_service.can_view_ticket() + + # check what level of view we have + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_error_get_service = TicketErrorGetService() + + # we can get every kind of document + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_error_get_service.execute, + self.request_data.get('ticket_error_id') + ) + + self.success(data = response) + + if self.account_data.get('role') == AccountRoleModel.REPORTER.value: + ticket_error_get_by_reporter = TicketErrorGetByReporterService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_error_get_by_reporter.execute, + self.request_data.get('ticket_error_id'), + self.account_data.get('account_id') + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/error/get_by_ticket.py b/v1/handlers/ticket/error/get_by_ticket.py new file mode 100644 index 0000000..5179d07 --- /dev/null +++ b/v1/handlers/ticket/error/get_by_ticket.py @@ -0,0 +1,70 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.error.get_by_ticket import TicketErrorGetByTicketService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetByTicketTicketErrorHandler(ProtectedHandler): + + """ + Handles getting multiple error tickets. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # verify permissions + self.permission_service.can_view_ticket() + + # check what level of view we have + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_error_get_by_ticket = TicketErrorGetByTicketService() + + # we can get every kind of document + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_error_get_by_ticket.execute, + self.request_data.get('ticket_id') + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.REPORTER.value: + ticket_error_get_by_ticket = TicketErrorGetByTicketService() + + # get only tickets created by that specific account + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_error_get_by_ticket.execute, + self.request_data.get('ticket_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/get.py b/v1/handlers/ticket/get.py new file mode 100644 index 0000000..7a3b21c --- /dev/null +++ b/v1/handlers/ticket/get.py @@ -0,0 +1,83 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.get import TicketGetService +from piracyshield_service.ticket.get_by_reporter import TicketGetByReporterService +from piracyshield_service.ticket.get_by_provider import TicketGetByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetTicketHandler(ProtectedHandler): + + """ + Handles getting a single ticket by its ID. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # verify permissions + self.permission_service.can_view_ticket() + + # check what level of view we have + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_get_service = TicketGetService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_get_service.execute, + self.request_data.get('ticket_id') + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.REPORTER.value: + ticket_get_by_reporter_service = TicketGetByReporterService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_get_by_reporter_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_get_by_provider_service = TicketGetByProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_get_by_provider_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/get_all.py b/v1/handlers/ticket/get_all.py new file mode 100644 index 0000000..a29f140 --- /dev/null +++ b/v1/handlers/ticket/get_all.py @@ -0,0 +1,76 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.get_all import TicketGetAllService +from piracyshield_service.ticket.get_all_by_reporter import TicketGetAllByReporterService +from piracyshield_service.ticket.get_all_by_provider import TicketGetAllByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllTicketHandler(ProtectedHandler): + + """ + Handles getting multiple tickets. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + # verify permissions + self.permission_service.can_view_ticket() + + # check what level of view we have + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_get_all_service = TicketGetAllService() + + # we can get every kind of document + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_get_all_service.execute + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.REPORTER.value: + ticket_get_all_by_reporter_service = TicketGetAllByReporterService() + + # get only tickets created by that specific account + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_get_all_by_reporter_service.execute, + self.account_data.get('account_id') + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_get_all_by_provider_service = TicketGetAllByProviderService() + + # get every ticket + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_get_all_by_provider_service.execute, + self.account_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/get_total.py b/v1/handlers/ticket/get_total.py new file mode 100644 index 0000000..e53ba3e --- /dev/null +++ b/v1/handlers/ticket/get_total.py @@ -0,0 +1,45 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.get_total import TicketGetTotalService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetTotalTicketHandler(ProtectedHandler): + + """ + Handles getting all the tickets. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value or self.account_data.get('role') == AccountRoleModel.REPORTER.value: + ticket_get_total_service = TicketGetTotalService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_get_total_service.execute + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/fqdn/get_all.py b/v1/handlers/ticket/item/fqdn/get_all.py new file mode 100644 index 0000000..a493fcb --- /dev/null +++ b/v1/handlers/ticket/item/fqdn/get_all.py @@ -0,0 +1,60 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.fqdn.get_all import TicketItemFQDNGetAllService +from piracyshield_service.ticket.item.fqdn.get_all_by_provider import TicketItemFQDNGetAllByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllFQDNHandler(ProtectedHandler): + + """ + Handles getting all FQDN items. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_fqdn_get_all_service = TicketItemFQDNGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_service.execute + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_fqdn_get_all_by_provider_service = TicketItemFQDNGetAllByProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_by_provider_service.execute, + self.account_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/fqdn/get_all_by_ticket.py b/v1/handlers/ticket/item/fqdn/get_all_by_ticket.py new file mode 100644 index 0000000..d096c74 --- /dev/null +++ b/v1/handlers/ticket/item/fqdn/get_all_by_ticket.py @@ -0,0 +1,82 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.fqdn.get_all_by_ticket import TicketItemFQDNGetAllByTicketService +from piracyshield_service.ticket.item.fqdn.get_all_by_ticket_for_reporter import TicketItemFQDNGetAllByTicketForReporterService +from piracyshield_service.ticket.item.fqdn.get_all_by_ticket_for_provider import TicketItemFQDNGetAllByTicketForProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetTicketFQDNHandler(ProtectedHandler): + + """ + Handles getting all FQDN items for a ticket. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_fqdn_get_all_by_ticket_service = TicketItemFQDNGetAllByTicketService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_by_ticket_service.execute, + self.request_data.get('ticket_id') + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.REPORTER.value: + ticket_item_fqdn_get_all_by_ticket_for_reporter_service = TicketItemFQDNGetAllByTicketForReporterService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_by_ticket_for_reporter_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_fqdn_get_all_by_ticket_for_provider_service = TicketItemFQDNGetAllByTicketForProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_by_ticket_for_provider_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/fqdn/get_all_by_ticket_checksum_txt.py b/v1/handlers/ticket/item/fqdn/get_all_by_ticket_checksum_txt.py new file mode 100644 index 0000000..07875f4 --- /dev/null +++ b/v1/handlers/ticket/item/fqdn/get_all_by_ticket_checksum_txt.py @@ -0,0 +1,69 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.fqdn.get_all_by_ticket_checksum import TicketItemFQDNGetAllByTicketChecksumService +from piracyshield_service.ticket.item.fqdn.get_all_by_ticket_checksum_for_provider import TicketItemFQDNGetAllByTicketChecksumForProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetTicketFQDNTXTChecksumHandler(ProtectedHandler): + + """ + Handles getting the checksum of all FQDN items for a ticket in a TXT. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_fqdn_get_all_by_ticket_checksum_service = TicketItemFQDNGetAllByTicketChecksumService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_by_ticket_checksum_service.execute, + self.request_data.get('ticket_id') + ) + + self.success_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_fqdn_get_all_by_ticket_checksum_for_provider_service = TicketItemFQDNGetAllByTicketChecksumForProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_by_ticket_checksum_for_provider_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/fqdn/get_all_by_ticket_txt.py b/v1/handlers/ticket/item/fqdn/get_all_by_ticket_txt.py new file mode 100644 index 0000000..435c3d1 --- /dev/null +++ b/v1/handlers/ticket/item/fqdn/get_all_by_ticket_txt.py @@ -0,0 +1,69 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.fqdn.get_all_by_ticket import TicketItemFQDNGetAllByTicketService +from piracyshield_service.ticket.item.fqdn.get_all_by_ticket_for_provider import TicketItemFQDNGetAllByTicketForProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetTicketFQDNTXTHandler(ProtectedHandler): + + """ + Handles getting all FQDN items for a ticket in a TXT. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_fqdn_get_all_by_ticket_service = TicketItemFQDNGetAllByTicketService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_by_ticket_service.execute, + self.request_data.get('ticket_id') + ) + + self.success_list_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_fqdn_get_all_by_ticket_for_provider_service = TicketItemFQDNGetAllByTicketForProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_by_ticket_for_provider_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success_list_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/fqdn/get_all_checksum_txt.py b/v1/handlers/ticket/item/fqdn/get_all_checksum_txt.py new file mode 100644 index 0000000..ce5da35 --- /dev/null +++ b/v1/handlers/ticket/item/fqdn/get_all_checksum_txt.py @@ -0,0 +1,60 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.fqdn.get_all_checksum import TicketItemFQDNGetAllChecksumService +from piracyshield_service.ticket.item.fqdn.get_all_checksum_by_provider import TicketItemFQDNGetAllChecksumByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllFQDNTXTChecksumHandler(ProtectedHandler): + + """ + Handles getting all FQDN items in TXT format. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_fqdn_get_all_checksum_service = TicketItemFQDNGetAllChecksumService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_checksum_service.execute + ) + + self.success_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_fqdn_get_all_checksum_by_provider_service = TicketItemFQDNGetAllChecksumByProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_checksum_by_provider_service.execute, + self.account_data.get('account_id') + ) + + self.success_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/fqdn/get_all_txt.py b/v1/handlers/ticket/item/fqdn/get_all_txt.py new file mode 100644 index 0000000..9891cb6 --- /dev/null +++ b/v1/handlers/ticket/item/fqdn/get_all_txt.py @@ -0,0 +1,60 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.fqdn.get_all import TicketItemFQDNGetAllService +from piracyshield_service.ticket.item.fqdn.get_all_by_provider import TicketItemFQDNGetAllByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllFQDNTXTHandler(ProtectedHandler): + + """ + Handles getting all FQDN items in TXT format. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_fqdn_get_all_service = TicketItemFQDNGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_service.execute + ) + + self.success_list_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_fqdn_get_all_by_provider_service = TicketItemFQDNGetAllByProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_fqdn_get_all_by_provider_service.execute, + self.account_data.get('account_id') + ) + + self.success_list_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/get_all.py b/v1/handlers/ticket/item/get_all.py new file mode 100644 index 0000000..0c1c975 --- /dev/null +++ b/v1/handlers/ticket/item/get_all.py @@ -0,0 +1,69 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.get_all import TicketItemGetAllService +from piracyshield_service.ticket.item.get_all_by_provider import TicketItemGetAllByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllTicketItemHandler(ProtectedHandler): + + """ + Handles getting multiple tickets. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # verify permissions + self.permission_service.can_view_ticket() + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_get_all_service = TicketItemGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_get_all_service.execute, + self.request_data.get('ticket_id') + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_get_all_by_provider_service = TicketItemGetAllByProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_get_all_by_provider_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/get_all_status.py b/v1/handlers/ticket/item/get_all_status.py new file mode 100644 index 0000000..34ceaf7 --- /dev/null +++ b/v1/handlers/ticket/item/get_all_status.py @@ -0,0 +1,53 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.get_all_status import TicketItemGetAllStatusService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllStatusTicketItemHandler(ProtectedHandler): + + """ + Handles getting multiple tickets. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_get_all_status_service = TicketItemGetAllStatusService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_get_all_status_service.execute, + self.request_data.get('ticket_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/get_available_by_ticket.py b/v1/handlers/ticket/item/get_available_by_ticket.py new file mode 100644 index 0000000..c641724 --- /dev/null +++ b/v1/handlers/ticket/item/get_available_by_ticket.py @@ -0,0 +1,57 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.get_available_by_ticket import TicketItemGetAvailableByTicketService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAvailableByTicketTicketItemHandler(ProtectedHandler): + + """ + Handles getting multiple tickets. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # verify permissions + self.permission_service.can_view_ticket() + + if self.account_data.get('role') == AccountRoleModel.REPORTER.value: + ticket_item_get_available_by_ticket_service = TicketItemGetAvailableByTicketService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_get_available_by_ticket_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/get_details.py b/v1/handlers/ticket/item/get_details.py new file mode 100644 index 0000000..a516b14 --- /dev/null +++ b/v1/handlers/ticket/item/get_details.py @@ -0,0 +1,55 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.get_details import TicketItemGetDetailsService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetDetailsTicketItemHandler(ProtectedHandler): + + """ + Handles getting multiple tickets. + """ + + required_fields = [ + 'ticket_id', + 'ticket_item_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_get_details_service = TicketItemGetDetailsService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_get_details_service.execute, + self.request_data.get('ticket_id'), + self.request_data.get('ticket_item_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv4/get_all.py b/v1/handlers/ticket/item/ipv4/get_all.py new file mode 100644 index 0000000..7c2478e --- /dev/null +++ b/v1/handlers/ticket/item/ipv4/get_all.py @@ -0,0 +1,60 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv4.get_all import TicketItemIPv4GetAllService +from piracyshield_service.ticket.item.ipv4.get_all_by_provider import TicketItemIPv4GetAllByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllIPv4Handler(ProtectedHandler): + + """ + Handles getting all IPv4 items. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv4_get_all_service = TicketItemIPv4GetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_service.execute + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv4_get_all_by_provider_service = TicketItemIPv4GetAllByProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_by_provider_service.execute, + self.account_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv4/get_all_by_ticket.py b/v1/handlers/ticket/item/ipv4/get_all_by_ticket.py new file mode 100644 index 0000000..a8da6b0 --- /dev/null +++ b/v1/handlers/ticket/item/ipv4/get_all_by_ticket.py @@ -0,0 +1,82 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv4.get_all_by_ticket import TicketItemIPv4GetAllByTicketService +from piracyshield_service.ticket.item.ipv4.get_all_by_ticket_for_reporter import TicketItemIPv4GetAllByTicketForReporterService +from piracyshield_service.ticket.item.ipv4.get_all_by_ticket_for_provider import TicketItemIPv4GetAllByTicketForProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetTicketIPv4Handler(ProtectedHandler): + + """ + Handles getting all IPv4 items for a ticket. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv4_get_all_by_ticket_service = TicketItemIPv4GetAllByTicketService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_by_ticket_service.execute, + self.request_data.get('ticket_id') + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.REPORTER.value: + ticket_item_ipv4_get_all_by_ticket_for_reporter_service = TicketItemIPv4GetAllByTicketForReporterService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_by_ticket_for_reporter_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv4_get_all_by_ticket_for_provider_service = TicketItemIPv4GetAllByTicketForProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_by_ticket_for_provider_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv4/get_all_by_ticket_checksum_txt.py b/v1/handlers/ticket/item/ipv4/get_all_by_ticket_checksum_txt.py new file mode 100644 index 0000000..8fa1325 --- /dev/null +++ b/v1/handlers/ticket/item/ipv4/get_all_by_ticket_checksum_txt.py @@ -0,0 +1,69 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv4.get_all_by_ticket_checksum import TicketItemIPv4GetAllByTicketChecksumService +from piracyshield_service.ticket.item.ipv4.get_all_by_ticket_checksum_for_provider import TicketItemIPv4GetAllByTicketChecksumForProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetTicketIPv4TXTChecksumHandler(ProtectedHandler): + + """ + Handles getting the checksum all IPv4 items for a ticket in a TXT. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv4_get_all_by_ticket_checksum_service = TicketItemIPv4GetAllByTicketChecksumService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_by_ticket_checksum_service.execute, + self.request_data.get('ticket_id') + ) + + self.success_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv4_get_all_by_ticket_checksum_for_provider_service = TicketItemIPv4GetAllByTicketChecksumForProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_by_ticket_checksum_for_provider_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv4/get_all_by_ticket_txt.py b/v1/handlers/ticket/item/ipv4/get_all_by_ticket_txt.py new file mode 100644 index 0000000..5598c0c --- /dev/null +++ b/v1/handlers/ticket/item/ipv4/get_all_by_ticket_txt.py @@ -0,0 +1,69 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv4.get_all_by_ticket import TicketItemIPv4GetAllByTicketService +from piracyshield_service.ticket.item.ipv4.get_all_by_ticket_for_provider import TicketItemIPv4GetAllByTicketForProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetTicketIPv4TXTHandler(ProtectedHandler): + + """ + Handles getting all IPv4 items for a ticket in a TXT. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv4_get_all_by_ticket_service = TicketItemIPv4GetAllByTicketService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_by_ticket_service.execute, + self.request_data.get('ticket_id') + ) + + self.success_list_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv4_get_all_by_ticket_for_provider_service = TicketItemIPv4GetAllByTicketForProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_by_ticket_for_provider_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success_list_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv4/get_all_checksum_txt.py b/v1/handlers/ticket/item/ipv4/get_all_checksum_txt.py new file mode 100644 index 0000000..1183c0f --- /dev/null +++ b/v1/handlers/ticket/item/ipv4/get_all_checksum_txt.py @@ -0,0 +1,60 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv4.get_all_checksum import TicketItemIPv4GetAllChecksumService +from piracyshield_service.ticket.item.ipv4.get_all_checksum_by_provider import TicketItemIPv4GetAllChecksumByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllIPv4TXTChecksumHandler(ProtectedHandler): + + """ + Handles getting all IPv4 items. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv4_get_all_checksum_service = TicketItemIPv4GetAllChecksumService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_checksum_service.execute + ) + + self.success_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv4_get_all_checksum_by_provider_service = TicketItemIPv4GetAllChecksumByProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_checksum_by_provider_service.execute, + self.account_data.get('account_id') + ) + + self.success_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv4/get_all_txt.py b/v1/handlers/ticket/item/ipv4/get_all_txt.py new file mode 100644 index 0000000..72416d3 --- /dev/null +++ b/v1/handlers/ticket/item/ipv4/get_all_txt.py @@ -0,0 +1,60 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv4.get_all import TicketItemIPv4GetAllService +from piracyshield_service.ticket.item.ipv4.get_all_by_provider import TicketItemIPv4GetAllByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllIPv4TXTHandler(ProtectedHandler): + + """ + Handles getting all IPv4 items. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv4_get_all_service = TicketItemIPv4GetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_service.execute + ) + + self.success_list_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv4_get_all_by_provider_service = TicketItemIPv4GetAllByProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv4_get_all_by_provider_service.execute, + self.account_data.get('account_id') + ) + + self.success_list_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv6/get_all.py b/v1/handlers/ticket/item/ipv6/get_all.py new file mode 100644 index 0000000..3b074d5 --- /dev/null +++ b/v1/handlers/ticket/item/ipv6/get_all.py @@ -0,0 +1,60 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv6.get_all import TicketItemIPv6GetAllService +from piracyshield_service.ticket.item.ipv6.get_all_by_provider import TicketItemIPv6GetAllByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllIPv6Handler(ProtectedHandler): + + """ + Handles getting all IPv6 items. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv6_get_all_service = TicketItemIPv6GetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_service.execute + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv6_get_all_by_provider_service = TicketItemIPv6GetAllByProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_by_provider_service.execute, + self.account_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv6/get_all_by_ticket.py b/v1/handlers/ticket/item/ipv6/get_all_by_ticket.py new file mode 100644 index 0000000..53de609 --- /dev/null +++ b/v1/handlers/ticket/item/ipv6/get_all_by_ticket.py @@ -0,0 +1,82 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv6.get_all_by_ticket import TicketItemIPv6GetAllByTicketService +from piracyshield_service.ticket.item.ipv6.get_all_by_ticket_for_reporter import TicketItemIPv6GetAllByTicketForReporterService +from piracyshield_service.ticket.item.ipv6.get_all_by_ticket_for_provider import TicketItemIPv6GetAllByTicketForProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetTicketIPv6Handler(ProtectedHandler): + + """ + Handles getting all IPv6 items for a ticket. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv6_get_all_by_ticket_service = TicketItemIPv6GetAllByTicketService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_by_ticket_service.execute, + self.request_data.get('ticket_id') + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.REPORTER.value: + ticket_item_ipv6_get_all_by_ticket_for_reporter_service = TicketItemIPv6GetAllByTicketForReporterService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_by_ticket_for_reporter_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv6_get_all_by_ticket_for_provider_service = TicketItemIPv6GetAllByTicketForProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_by_ticket_for_provider_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv6/get_all_by_ticket_checksum_txt.py b/v1/handlers/ticket/item/ipv6/get_all_by_ticket_checksum_txt.py new file mode 100644 index 0000000..67f33de --- /dev/null +++ b/v1/handlers/ticket/item/ipv6/get_all_by_ticket_checksum_txt.py @@ -0,0 +1,69 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv6.get_all_by_ticket_checksum import TicketItemIPv6GetAllByTicketChecksumService +from piracyshield_service.ticket.item.ipv6.get_all_by_ticket_checksum_for_provider import TicketItemIPv6GetAllByTicketChecksumForProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetTicketIPv6TXTChecksumHandler(ProtectedHandler): + + """ + Handles getting the checksum all IPv6 items for a ticket in a TXT. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv6_get_all_by_ticket_checksum_service = TicketItemIPv6GetAllByTicketChecksumService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_by_ticket_checksum_service.execute, + self.request_data.get('ticket_id') + ) + + self.success_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv6_get_all_by_ticket_checksum_for_provider_service = TicketItemIPv6GetAllByTicketChecksumForProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_by_ticket_checksum_for_provider_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv6/get_all_by_ticket_txt.py b/v1/handlers/ticket/item/ipv6/get_all_by_ticket_txt.py new file mode 100644 index 0000000..7148978 --- /dev/null +++ b/v1/handlers/ticket/item/ipv6/get_all_by_ticket_txt.py @@ -0,0 +1,69 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv6.get_all_by_ticket import TicketItemIPv6GetAllByTicketService +from piracyshield_service.ticket.item.ipv6.get_all_by_ticket_for_provider import TicketItemIPv6GetAllByTicketForProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetTicketIPv6TXTHandler(ProtectedHandler): + + """ + Handles getting all IPv6 items for a ticket in a TXT. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv6_get_all_by_ticket_service = TicketItemIPv6GetAllByTicketService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_by_ticket_service.execute, + self.request_data.get('ticket_id') + ) + + self.success_list_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv6_get_all_by_ticket_for_provider_service = TicketItemIPv6GetAllByTicketForProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_by_ticket_for_provider_service.execute, + self.request_data.get('ticket_id'), + self.account_data.get('account_id') + ) + + self.success_list_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv6/get_all_checksum_txt.py b/v1/handlers/ticket/item/ipv6/get_all_checksum_txt.py new file mode 100644 index 0000000..52a8da2 --- /dev/null +++ b/v1/handlers/ticket/item/ipv6/get_all_checksum_txt.py @@ -0,0 +1,60 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv6.get_all_checksum import TicketItemIPv6GetAllChecksumService +from piracyshield_service.ticket.item.ipv6.get_all_checksum_by_provider import TicketItemIPv6GetAllChecksumByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllIPv6TXTChecksumHandler(ProtectedHandler): + + """ + Handles getting all IPv6 items. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv6_get_all_checksum_service = TicketItemIPv6GetAllChecksumService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_checksum_service.execute + ) + + self.success_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv6_get_all_checksum_by_provider_service = TicketItemIPv6GetAllChecksumByProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_checksum_by_provider_service.execute, + self.account_data.get('account_id') + ) + + self.success_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/ipv6/get_all_txt.py b/v1/handlers/ticket/item/ipv6/get_all_txt.py new file mode 100644 index 0000000..56e219c --- /dev/null +++ b/v1/handlers/ticket/item/ipv6/get_all_txt.py @@ -0,0 +1,60 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.ipv6.get_all import TicketItemIPv6GetAllService +from piracyshield_service.ticket.item.ipv6.get_all_by_provider import TicketItemIPv6GetAllByProviderService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllIPv6TXTHandler(ProtectedHandler): + + """ + Handles getting all IPv6 items. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_ticket() + + # only internal and provider accounts should get this data + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_ipv6_get_all_service = TicketItemIPv6GetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_service.execute + ) + + self.success_list_txt(data = response) + + elif self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_ipv6_get_all_by_provider_service = TicketItemIPv6GetAllByProviderService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_ipv6_get_all_by_provider_service.execute, + self.account_data.get('account_id') + ) + + self.success_list_txt(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/set_flag_active.py b/v1/handlers/ticket/item/set_flag_active.py new file mode 100644 index 0000000..94a84ed --- /dev/null +++ b/v1/handlers/ticket/item/set_flag_active.py @@ -0,0 +1,96 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.set_flag_active import TicketItemSetFlagActiveService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class SetFlagActiveTicketItemHandler(ProtectedHandler): + + """ + Handles setting the activity that can be done on a single ticket item. + """ + + required_fields = [ + 'value' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_ticket() + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_set_flag_active_service = TicketItemSetFlagActiveService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_set_flag_active_service.execute, + self.account_data.get('account_id'), + self.request_data.get('value'), + True + ) + + self.success() + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) + +class SetFlagNonActiveTicketItemHandler(ProtectedHandler): + + """ + Handles setting the activity that can be done on a single ticket item. + """ + + required_fields = [ + 'value' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_ticket() + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + ticket_item_set_flag_active_service = TicketItemSetFlagActiveService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_set_flag_active_service.execute, + self.account_data.get('account_id'), + self.request_data.get('value'), + False + ) + + self.success() + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/set_processed.py b/v1/handlers/ticket/item/set_processed.py new file mode 100644 index 0000000..284a385 --- /dev/null +++ b/v1/handlers/ticket/item/set_processed.py @@ -0,0 +1,63 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.set_processed import TicketItemSetProcessedService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class SetTicketItemProcessedHandler(ProtectedHandler): + + """ + Handles setting the processed status of a single ticket item. + """ + + required_fields = [ + 'value' + ] + + optional_fields = [ + 'timestamp' + 'note' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields, self.optional_fields) == False: + return + + try: + self.permission_service.can_edit_ticket() + + if self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_set_processed_service = TicketItemSetProcessedService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_set_processed_service.execute, + self.account_data.get('account_id'), + self.request_data.get('value'), + self.request_data.get('timestamp') or None, + self.request_data.get('note') or None + ) + + self.success() + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/item/set_unprocessed.py b/v1/handlers/ticket/item/set_unprocessed.py new file mode 100644 index 0000000..76c7bcc --- /dev/null +++ b/v1/handlers/ticket/item/set_unprocessed.py @@ -0,0 +1,65 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.ticket.item.set_unprocessed import TicketItemSetUnprocessedService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class SetTicketItemUnprocessedHandler(ProtectedHandler): + + """ + Handles setting the unprocessed status of a single ticket item. + """ + + required_fields = [ + 'value', + 'reason' + ] + + optional_fields = [ + 'timestamp' + 'note' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields, self.optional_fields) == False: + return + + try: + self.permission_service.can_edit_ticket() + + if self.account_data.get('role') == AccountRoleModel.PROVIDER.value: + ticket_item_set_unprocessed_service = TicketItemSetUnprocessedService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_item_set_unprocessed_service.execute, + self.account_data.get('account_id'), + self.request_data.get('value'), + self.request_data.get('reason'), + self.request_data.get('timestamp') or None, + self.request_data.get('note') or None + ) + + self.success() + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/ticket/remove.py b/v1/handlers/ticket/remove.py new file mode 100644 index 0000000..76609b9 --- /dev/null +++ b/v1/handlers/ticket/remove.py @@ -0,0 +1,65 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler + +from piracyshield_service.ticket.remove import TicketRemoveService + +from piracyshield_data_model.account.role.model import AccountRoleModel +from piracyshield_data_model.ticket.status.model import TicketStatusModel + +from piracyshield_component.exception import ApplicationException + +class RemoveTicketHandler(ProtectedHandler): + + """ + Handles the ticket removal. + """ + + required_fields = [ + 'ticket_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + # verify permissions + self.permission_service.can_delete_ticket() + + ticket_remove_service = TicketRemoveService() + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_remove_service.execute, + self.request_data.get('ticket_id') + ) + + self.success() + + elif self.account_data.get('role') == AccountRoleModel.REPORTER.value: + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + ticket_remove_service.execute, + self.request_data.get('ticket_id') + ) + + self.success() + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/whitelist/create.py b/v1/handlers/whitelist/create.py new file mode 100644 index 0000000..3d0e262 --- /dev/null +++ b/v1/handlers/whitelist/create.py @@ -0,0 +1,65 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.whitelist.create import WhitelistCreateService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class CreateWhitelistItemHandler(ProtectedHandler): + + """ + Handles the creation of a new whitelist item. + """ + + required_fields = [ + 'genre', + 'item' + ] + + optional_fields = [ + 'registrar', + 'as_code' + ] + + async def post(self): + """ + Handles the whitelist item creation. + """ + + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields, self.optional_fields) == False: + return + + try: + self.permission_service.can_create_whitelist_item() + + whitelist_create_service = WhitelistCreateService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + whitelist_create_service.execute, + self.request_data.get('genre'), + self.request_data.get('item'), + self.account_data.get('account_id'), + self.request_data.get('registrar') or None, + self.request_data.get('as_code') or None + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/whitelist/get_all.py b/v1/handlers/whitelist/get_all.py new file mode 100644 index 0000000..728411e --- /dev/null +++ b/v1/handlers/whitelist/get_all.py @@ -0,0 +1,45 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.whitelist.get_all import WhitelistGetAllService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllWhitelistItemHandler(ProtectedHandler): + + """ + Handles getting multiple whitelist items. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_whitelist_item() + + # check what level of view we have + whitelist_get_all_service = WhitelistGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + whitelist_get_all_service.execute, + self.account_data.get('account_id') + ) + + self.success(data = response) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/whitelist/get_all_by_account.py b/v1/handlers/whitelist/get_all_by_account.py new file mode 100644 index 0000000..19e6355 --- /dev/null +++ b/v1/handlers/whitelist/get_all_by_account.py @@ -0,0 +1,56 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.whitelist.get_all import WhitelistGetAllService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetAllByAccountWhitelistItemHandler(ProtectedHandler): + + """ + Handles getting multiple whitelist items. + """ + + required_fields = [ + 'account_id' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_view_whitelist_item() + + # check what level of view we have + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + whitelist_get_all_service = WhitelistGetAllService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + whitelist_get_all_service.execute, + self.request_data.get('account_id') + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/whitelist/get_global.py b/v1/handlers/whitelist/get_global.py new file mode 100644 index 0000000..64cbd1f --- /dev/null +++ b/v1/handlers/whitelist/get_global.py @@ -0,0 +1,48 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.whitelist.get_global import WhitelistGetGlobalService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class GetGlobalWhitelistItemHandler(ProtectedHandler): + + """ + Handles getting multiple whitelist items. + """ + + async def get(self): + if self.initialize_account() == False: + return + + try: + self.permission_service.can_view_whitelist_item() + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + # check what level of view we have + whitelist_get_global_service = WhitelistGetGlobalService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + whitelist_get_global_service.execute + ) + + self.success(data = response) + + else: + self.error(status_code = 403, error_code = ErrorCode.PERMISSION_DENIED, message = ErrorMessage.PERMISSION_DENIED) + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/whitelist/remove.py b/v1/handlers/whitelist/remove.py new file mode 100644 index 0000000..af14f68 --- /dev/null +++ b/v1/handlers/whitelist/remove.py @@ -0,0 +1,52 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.whitelist.remove import WhitelistRemoveService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class RemoveWhitelistItemHandler(ProtectedHandler): + + """ + Handles the whitelist item removal. + """ + + required_fields = [ + 'item' + ] + + async def post(self): + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_delete_whitelist_item() + + whitelist_remove_service = WhitelistRemoveService() + + response = await tornado.ioloop.IOLoop.current().run_in_executor( + None, + whitelist_remove_service.execute, + self.request_data.get('item'), + self.account_data.get('account_id') + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/handlers/whitelist/set_status.py b/v1/handlers/whitelist/set_status.py new file mode 100644 index 0000000..96c0374 --- /dev/null +++ b/v1/handlers/whitelist/set_status.py @@ -0,0 +1,96 @@ +import sys +import os + +# I hate python imports +current = os.path.dirname(os.path.realpath(__file__)) +parent = os.path.dirname(current) +sys.path.append(parent) + +import tornado + +from ioutils.protected import ProtectedHandler +from ioutils.errors import ErrorCode, ErrorMessage + +from piracyshield_service.whitelist.set_status import WhitelistSetStatusService + +from piracyshield_data_model.account.role.model import AccountRoleModel + +from piracyshield_component.exception import ApplicationException + +class SetStatusActiveWhitelistItemHandler(ProtectedHandler): + + """ + Handles the status of a whitelist item. + """ + + required_fields = [ + 'item' + ] + + async def post(self): + """ + Handles the whitelist item active status. + """ + + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_whitelist_item() + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + whitelist_set_status_service = WhitelistSetStatusService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + whitelist_set_status_service.execute, + self.request_data.get('item'), + True + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) + +class SetStatusNonActiveWhitelistItemHandler(ProtectedHandler): + + """ + Handles the status of a whitelist item. + """ + + required_fields = [ + 'item' + ] + + async def post(self): + """ + Handles the whitelist item non active status. + """ + + if self.initialize_account() == False: + return + + if self.handle_post(self.required_fields) == False: + return + + try: + self.permission_service.can_edit_whitelist_item() + + if self.account_data.get('role') == AccountRoleModel.INTERNAL.value: + whitelist_set_status_service = WhitelistSetStatusService() + + await tornado.ioloop.IOLoop.current().run_in_executor( + None, + whitelist_set_status_service.execute, + self.request_data.get('item'), + False + ) + + self.success() + + except ApplicationException as e: + self.error(status_code = 400, error_code = e.code, message = e.message) diff --git a/v1/routes.py b/v1/routes.py new file mode 100644 index 0000000..13c9cd0 --- /dev/null +++ b/v1/routes.py @@ -0,0 +1,219 @@ +from .handlers.authentication.login import AuthenticationLoginHandler +from .handlers.authentication.refresh import AuthenticationRefreshHandler +from .handlers.authentication.logout import AuthenticationLogoutHandler + +from .handlers.account.get import GetGeneralAccountHandler +from .handlers.account.get_all import GetAllGeneralAccountHandler + +from .handlers.account.guest.create import CreateGuestAccountHandler +from .handlers.account.guest.get import GetGuestAccountHandler +from .handlers.account.guest.get_all import GetAllGuestAccountHandler +from .handlers.account.guest.remove import RemoveGuestAccountHandler + +from .handlers.account.internal.create import CreateInternalAccountHandler +from .handlers.account.internal.get import GetInternalAccountHandler +from .handlers.account.internal.get_all import GetAllInternalAccountHandler +from .handlers.account.internal.set_status import SetStatusActiveInternalAccountHandler, SetStatusNonActiveInternalAccountHandler +from .handlers.account.internal.change_password import ChangePasswordInternalAccountHandler +from .handlers.account.internal.remove import RemoveInternalAccountHandler + +from .handlers.account.reporter.create import CreateReporterAccountHandler +from .handlers.account.reporter.get import GetReporterAccountHandler +from .handlers.account.reporter.get_all import GetAllReporterAccountHandler +from .handlers.account.reporter.set_status import SetStatusActiveReporterAccountHandler, SetStatusNonActiveReporterAccountHandler +from .handlers.account.reporter.change_password import ChangePasswordReporterAccountHandler +from .handlers.account.reporter.remove import RemoveReporterAccountHandler + +from .handlers.account.provider.create import CreateProviderAccountHandler +from .handlers.account.provider.get import GetProviderAccountHandler +from .handlers.account.provider.get_all import GetAllProviderAccountHandler +from .handlers.account.provider.set_status import SetStatusActiveProviderAccountHandler, SetStatusNonActiveProviderAccountHandler +from .handlers.account.provider.change_password import ChangePasswordProviderAccountHandler +from .handlers.account.provider.remove import RemoveProviderAccountHandler + +from .handlers.ticket.create import CreateTicketHandler +from .handlers.ticket.get import GetTicketHandler +from .handlers.ticket.get_all import GetAllTicketHandler +from .handlers.ticket.get_total import GetTotalTicketHandler +from .handlers.ticket.remove import RemoveTicketHandler + +from .handlers.ticket.error.create import CreateTicketErrorHandler +from .handlers.ticket.error.get_by_ticket import GetByTicketTicketErrorHandler +from .handlers.ticket.error.get_by_account import GetByReporterTicketErrorHandler + +from .handlers.forensic.upload import UploadForensicHandler +from .handlers.forensic.get_by_ticket import GetByTicketForensicHandler +from .handlers.forensic.get_supported_formats import GetSupportedFormatsForensicHandler +from .handlers.forensic.get_supported_hashes import GetSupportedHashesForensicHandler + +from .handlers.ticket.item.set_processed import SetTicketItemProcessedHandler +from .handlers.ticket.item.set_unprocessed import SetTicketItemUnprocessedHandler + +from .handlers.ticket.item.set_flag_active import SetFlagActiveTicketItemHandler, SetFlagNonActiveTicketItemHandler + +from .handlers.ticket.item.get_all_status import GetAllStatusTicketItemHandler +from .handlers.ticket.item.get_all import GetAllTicketItemHandler +from .handlers.ticket.item.get_available_by_ticket import GetAvailableByTicketTicketItemHandler +from .handlers.ticket.item.get_details import GetDetailsTicketItemHandler + +from .handlers.ticket.item.fqdn.get_all import GetAllFQDNHandler +from .handlers.ticket.item.fqdn.get_all_txt import GetAllFQDNTXTHandler +from .handlers.ticket.item.fqdn.get_all_by_ticket import GetTicketFQDNHandler +from .handlers.ticket.item.fqdn.get_all_by_ticket_txt import GetTicketFQDNTXTHandler +from .handlers.ticket.item.fqdn.get_all_by_ticket_checksum_txt import GetTicketFQDNTXTChecksumHandler +from .handlers.ticket.item.fqdn.get_all_checksum_txt import GetAllFQDNTXTChecksumHandler + +from .handlers.ticket.item.ipv4.get_all import GetAllIPv4Handler +from .handlers.ticket.item.ipv4.get_all_txt import GetAllIPv4TXTHandler +from .handlers.ticket.item.ipv4.get_all_by_ticket import GetTicketIPv4Handler +from .handlers.ticket.item.ipv4.get_all_by_ticket_txt import GetTicketIPv4TXTHandler +from .handlers.ticket.item.ipv4.get_all_by_ticket_checksum_txt import GetTicketIPv4TXTChecksumHandler +from .handlers.ticket.item.ipv4.get_all_checksum_txt import GetAllIPv4TXTChecksumHandler + +from .handlers.ticket.item.ipv6.get_all import GetAllIPv6Handler +from .handlers.ticket.item.ipv6.get_all_txt import GetAllIPv6TXTHandler +from .handlers.ticket.item.ipv6.get_all_by_ticket import GetTicketIPv6Handler +from .handlers.ticket.item.ipv6.get_all_by_ticket_txt import GetTicketIPv6TXTHandler +from .handlers.ticket.item.ipv6.get_all_by_ticket_checksum_txt import GetTicketIPv6TXTChecksumHandler +from .handlers.ticket.item.ipv6.get_all_checksum_txt import GetAllIPv6TXTChecksumHandler + +from .handlers.whitelist.create import CreateWhitelistItemHandler +from .handlers.whitelist.get_all import GetAllWhitelistItemHandler +from .handlers.whitelist.get_all_by_account import GetAllByAccountWhitelistItemHandler +from .handlers.whitelist.get_global import GetGlobalWhitelistItemHandler +from .handlers.whitelist.set_status import SetStatusActiveWhitelistItemHandler, SetStatusNonActiveWhitelistItemHandler +from .handlers.whitelist.remove import RemoveWhitelistItemHandler + +from .handlers.dda.create import CreateDDAHandler +from .handlers.dda.get_all import GetAllDDAHandler +from .handlers.dda.get_all_by_account import GetAllByAccountDDAHandler +from .handlers.dda.get_global import GetGlobalDDAHandler +from .handlers.dda.set_status import SetStatusActiveDDAHandler, SetStatusNonActiveDDAHandler +from .handlers.dda.remove import RemoveDDAHandler + +from .handlers.log.ticket.get_all import GetAllTicketLogHandler +from .handlers.log.ticket.item.get_all import GetAllTicketItemLogHandler + +class APIv1: + + routes = [ + # authentication + (r"/authentication/login", AuthenticationLoginHandler), + (r"/authentication/refresh", AuthenticationRefreshHandler), + (r"/authentication/logout", AuthenticationLogoutHandler), + + # global account management + (r"/account/get", GetGeneralAccountHandler), + (r"/account/get/all", GetAllGeneralAccountHandler), + + # guest account management + (r"/account/guest/create", CreateGuestAccountHandler), + (r"/account/guest/get", GetGuestAccountHandler), + (r"/account/guest/get/all", GetAllGuestAccountHandler), + (r"/account/guest/remove", RemoveGuestAccountHandler), + + # internal account management + (r"/account/internal/create", CreateInternalAccountHandler), + (r"/account/internal/get", GetInternalAccountHandler), + (r"/account/internal/get/all", GetAllInternalAccountHandler), + (r"/account/internal/set/status/active", SetStatusActiveInternalAccountHandler), + (r"/account/internal/set/status/non_active", SetStatusNonActiveInternalAccountHandler), + (r"/account/internal/change_password", ChangePasswordInternalAccountHandler), + (r"/account/internal/remove", RemoveInternalAccountHandler), + + # reporter account management + (r"/account/reporter/create", CreateReporterAccountHandler), + (r"/account/reporter/get", GetReporterAccountHandler), + (r"/account/reporter/get/all", GetAllReporterAccountHandler), + (r"/account/reporter/set/status/active", SetStatusActiveReporterAccountHandler), + (r"/account/reporter/set/status/non_active", SetStatusNonActiveReporterAccountHandler), + (r"/account/reporter/change_password", ChangePasswordReporterAccountHandler), + (r"/account/reporter/remove", RemoveReporterAccountHandler), + + # provider account management + (r"/account/provider/create", CreateProviderAccountHandler), + (r"/account/provider/get", GetProviderAccountHandler), + (r"/account/provider/get/all", GetAllProviderAccountHandler), + (r"/account/provider/set/status/active", SetStatusActiveProviderAccountHandler), + (r"/account/provider/set/status/non_active", SetStatusNonActiveProviderAccountHandler), + (r"/account/provider/change_password", ChangePasswordProviderAccountHandler), + (r"/account/provider/remove", RemoveProviderAccountHandler), + + # blocking ticket management + (r"/ticket/create", CreateTicketHandler), + (r"/ticket/get", GetTicketHandler), + (r"/ticket/get/all", GetAllTicketHandler), + (r"/ticket/remove", RemoveTicketHandler), + (r"/ticket/item/get/all", GetAllTicketItemHandler), + (r"/ticket/item/get/available/by_ticket", GetAvailableByTicketTicketItemHandler), + + # error ticket management + (r"/ticket/error/create", CreateTicketErrorHandler), + (r"/ticket/error/get/by_ticket", GetByTicketTicketErrorHandler), + (r"/ticket/error/get", GetByReporterTicketErrorHandler), + + # internal use only + (r"/ticket/get/total", GetTotalTicketHandler), + (r"/ticket/item/status/get/all", GetAllStatusTicketItemHandler), + (r"/ticket/item/get/details", GetDetailsTicketItemHandler), + + (r"/ticket/get/fqdn", GetTicketFQDNHandler), + (r"/ticket/get/fqdn/txt", GetTicketFQDNTXTHandler), + (r"/ticket/get/fqdn/txt/checksum", GetTicketFQDNTXTChecksumHandler), + + (r"/ticket/get/ipv4", GetTicketIPv4Handler), + (r"/ticket/get/ipv4/txt", GetTicketIPv4TXTHandler), + (r"/ticket/get/ipv4/txt/checksum", GetTicketIPv4TXTChecksumHandler), + + (r"/ticket/get/ipv6", GetTicketIPv6Handler), + (r"/ticket/get/ipv6/txt", GetTicketIPv6TXTHandler), + (r"/ticket/get/ipv6/txt/checksum", GetTicketIPv6TXTChecksumHandler), + + (r"/ticket/item/set/processed", SetTicketItemProcessedHandler), + (r"/ticket/item/set/unprocessed", SetTicketItemUnprocessedHandler), + + (r"/ticket/item/set/active", SetFlagActiveTicketItemHandler), + (r"/ticket/item/set/non_active", SetFlagNonActiveTicketItemHandler), + + # FQDN item management + (r"/fqdn/get/all", GetAllFQDNHandler), + (r"/fqdn/get/all/txt", GetAllFQDNTXTHandler), + (r"/fqdn/get/all/txt/checksum", GetAllFQDNTXTChecksumHandler), + + # IPv4 item management + (r"/ipv4/get/all", GetAllIPv4Handler), + (r"/ipv4/get/all/txt", GetAllIPv4TXTHandler), + (r"/ipv4/get/all/txt/checksum", GetAllIPv4TXTChecksumHandler), + + # IPv6 item management + (r"/ipv6/get/all", GetAllIPv6Handler), + (r"/ipv6/get/all/txt", GetAllIPv6TXTHandler), + (r"/ipv6/get/all/txt/checksum", GetAllIPv6TXTChecksumHandler), + + # forensic evidence management + (r"/forensic/upload/([a-zA-Z0-9]+)", UploadForensicHandler), + (r"/forensic/get/by_ticket", GetByTicketForensicHandler), + (r"/forensic/get/supported_formats", GetSupportedFormatsForensicHandler), + (r"/forensic/get/supported_hashes", GetSupportedHashesForensicHandler), + + # whitelist management + (r"/whitelist/item/create", CreateWhitelistItemHandler), + (r"/whitelist/item/get/all", GetAllWhitelistItemHandler), + (r"/whitelist/item/get/all/by_account", GetAllByAccountWhitelistItemHandler), + (r"/whitelist/item/get/global", GetGlobalWhitelistItemHandler), + (r"/whitelist/item/set/status/active", SetStatusActiveWhitelistItemHandler), + (r"/whitelist/item/set/status/non_active", SetStatusNonActiveWhitelistItemHandler), + (r"/whitelist/item/remove", RemoveWhitelistItemHandler), + + # DDA management + (r"/dda/create", CreateDDAHandler), + (r"/dda/get/all", GetAllDDAHandler), + (r"/dda/get/all/by_account", GetAllByAccountDDAHandler), + (r"/dda/get/global", GetGlobalDDAHandler), + (r"/dda/set/status/active", SetStatusActiveDDAHandler), + (r"/dda/set/status/non_active", SetStatusNonActiveDDAHandler), + (r"/dda/remove", RemoveDDAHandler), + + # ticket logging management + (r"/log/ticket/get/all", GetAllTicketLogHandler) + ]