From d7efed8c1d1fbdaee36ad215d2150694ec20303a Mon Sep 17 00:00:00 2001 From: Robert Putt Date: Fri, 1 Dec 2017 20:43:13 +0000 Subject: [PATCH] Add starter routes and db methods. Add starter routes and db methods. Change-Id: I1e5c3d59cdbac17c6bb11a7886026bb58856cc9c --- python_nemesis/api/v1/__init__.py | 31 +++++++++++++++++++++ python_nemesis/db/models.py | 15 ++++++++++- python_nemesis/db/utilities.py | 45 +++++++++++++++++++++++++++++++ python_nemesis/exceptions.py | 11 ++++++-- 4 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 python_nemesis/db/utilities.py diff --git a/python_nemesis/api/v1/__init__.py b/python_nemesis/api/v1/__init__.py index 4ba0d2a..6fd2195 100644 --- a/python_nemesis/api/v1/__init__.py +++ b/python_nemesis/api/v1/__init__.py @@ -13,8 +13,13 @@ # under the License. from flask import Blueprint +from flask import jsonify +from python_nemesis.db.utilities import add_request +from python_nemesis.db.utilities import search_by_hash from python_nemesis.exceptions import general_handler from python_nemesis.exceptions import NemesisException +from python_nemesis.exceptions import NotFoundException +from python_nemesis.extensions import log V1_API = Blueprint('v1_api', __name__) @@ -28,3 +33,29 @@ def handle_exception(error): @V1_API.route('/v1') def api_definition(): return "" + + +@V1_API.route('/v1/file/') +def lookup_hash(req_hash): + try: + result = search_by_hash(req_hash) + except Exception as err: + log.logger.error(str(err)) + raise NemesisException(str(err)) + + if len(result) == 0: + add_request(req_hash, 'not_found') + raise NotFoundException("Unable to find file with hash %s." % req_hash) + + elif len(result) == 1: + add_request(req_hash, 'found', file_id=result[0]['file_id']) + + else: + add_request(req_hash, 'multiple_found') + + return jsonify(result) + + +@V1_API.route('/v1/file', methods=['POST']) +def post_file(): + return "" diff --git a/python_nemesis/db/models.py b/python_nemesis/db/models.py index f796f57..b758cc1 100644 --- a/python_nemesis/db/models.py +++ b/python_nemesis/db/models.py @@ -27,7 +27,20 @@ class Files(db.Model): status = db.Column(db.String(20), nullable=False) last_updated = db.Column(db.DateTime, nullable=False) first_seen = db.Column(db.DateTime, nullable=False) - role_function = db.relationship("FileLookupRequest") + file_lookup = db.relationship("FileLookupRequest") + + def to_dict(self): + return {"file_id": self.file_id, + "sha512": self.sha512_hash, + "sha256": self.sha256_hash, + "sha1": self.sha1_hash, + "md5": self.md5_hash, + "crc32": self.crc32, + "size": self.size, + "mime_type": self.mime_type, + "status": self.status, + "last_updated": self.last_updated, + "first_seen": self.first_seen} class FileLookupRequest(db.Model): diff --git a/python_nemesis/db/utilities.py b/python_nemesis/db/utilities.py new file mode 100644 index 0000000..5fb682d --- /dev/null +++ b/python_nemesis/db/utilities.py @@ -0,0 +1,45 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +import datetime +from flask_keystone import current_user +from python_nemesis.db.models import FileLookupRequest +from python_nemesis.db.models import Files +from python_nemesis.extensions import db +from sqlalchemy import or_ + + +def add_request(lookup_hash, result, file_id=None): + now = datetime.datetime.now() + nreq = FileLookupRequest(requested_at=now, + requestor=current_user.user_id, + file_id=file_id, + lookup_hash=lookup_hash, + result=result) + db.session.add(nreq) + db.session.commit() + + +def search_by_hash(lookup_hash): + results = db.session.query(Files). \ + filter(or_(Files.sha512_hash == lookup_hash, + Files.sha256_hash == lookup_hash, + Files.sha1_hash == lookup_hash, + Files.md5_hash == lookup_hash, + Files.crc32 == lookup_hash)) + + ret_results = [] + for file in results: + ret_results.append(file.to_dict()) + + return ret_results diff --git a/python_nemesis/exceptions.py b/python_nemesis/exceptions.py index 929ae53..625009f 100644 --- a/python_nemesis/exceptions.py +++ b/python_nemesis/exceptions.py @@ -38,10 +38,11 @@ class NemesisException(Exception): title = "Internal Server Error" message = "" - def __init__(self, title, message, status_code=None, payload=None): + def __init__(self, message, title=None, status_code=None, payload=None): Exception.__init__(self) - self.title = title self.message = message + if title: + self.title = title if status_code is not None: self.status_code = status_code @@ -53,3 +54,9 @@ class NemesisException(Exception): rv['title'] = self.title rv['message'] = self.message return rv + + +class NotFoundException(NemesisException): + status_code = 404 + title = "Not Found" + message = ""