Beispiel #1
0
 def test_post_update_existing(self, scan_and_complete_patch):
     """
     The uploaded file should be saved to quarantine in spite
     of having the same name as an previously uploaded file.
     """
     os.mkdir(self.upload_basepath)
     rf = RequestsFactory(self.request_id)
     rf.add_file(self.upload_path)
     file_contents = b"contents"
     with scan_and_complete_patch:
         response = self.client.post(
             '/upload/' + self.request_id,
             data={
                 "file": (BytesIO(file_contents), self.filename),
                 "update": True
             }
         )
         self.assertEqual(
             json.loads(response.data.decode()),
             {
                 "files": [{
                     "name": self.filename_secure,
                     "original_name": self.filename,
                     "size": len(file_contents)
                 }]
             }
         )
         # checked mocked call (is_update = True)
         scan_and_complete_patch.assert_called_once_with(
             self.request_id, self.quarantine_path, True)
     # check redis key set
     self.assertEqual(redis.get(self.key_update).decode(), upload_status.PROCESSING)
     # check file saved
     self.assertTrue(os.path.exists(self.quarantine_path))
Beispiel #2
0
def status():
    """
    Check the status of an upload.

    Request Parameters:
        - request_id
        - filename
        - for_update (bool, optional)

    :returns: {
        "status": upload status
    }
    """
    try:
        status = redis.get(
            get_upload_key(request.args['request_id'],
                           secure_filename(request.args['filename']),
                           eval_request_bool(request.args.get('for_update'))))
        if status is not None:
            response = {"status": status.decode("utf-8")}
        else:
            response = {"error": "Upload status not found."}
        status_code = 200
    except KeyError:
        response = {}
        status_code = 422

    return jsonify(response), status_code
Beispiel #3
0
def status():
    """
    Check the status of an upload.

    Request Parameters:
        - request_id
        - filename
        - for_update (bool, optional)

    :returns: {
        "status": upload status
    }
    """
    try:
        status = redis.get(
            get_upload_key(
                request.args['request_id'],
                secure_filename(request.args['filename']),
                eval_request_bool(request.args.get('for_update'))
            )
        )
        if status is not None:
            response = {"status": status.decode("utf-8")}
        else:
            response = {"error": "Upload status not found."}
        status_code = 200
    except KeyError:
        sentry.captureException()
        response = {}
        status_code = 422

    return jsonify(response), status_code
Beispiel #4
0
 def test_post(self, scan_and_complete_patch):
     file_contents = b"contents"
     with scan_and_complete_patch:
         # make request
         response = self.client.post(
             '/upload/' + self.request_id,
             data={
                 "file": (BytesIO(file_contents), self.filename)
             }
         )
         # check response
         self.assertEqual(
             json.loads(response.data.decode()),
             {
                 "files" : [{
                     "name": self.filename_secure,
                     "original_name": self.filename,
                     "size": len(file_contents)
                 }]
             }
         )
         # checked mocked call (is_update = False)
         scan_and_complete_patch.assert_called_once_with(
             self.request_id, self.quarantine_path, False)
     # check redis key set
     self.assertEqual(redis.get(self.key).decode(), upload_status.PROCESSING)
     # check file saved
     self.assertTrue(os.path.exists(self.quarantine_path))
Beispiel #5
0
 def test_good_file_update(self):
     with patch(
         'app.upload.utils.scan_file'
     ):
         scan_and_complete_upload(self.request_id, self.quarantine_path, is_update=True)
         self.assertFalse(os.path.exists(self.quarantine_path))
         self.assertFalse(os.path.exists(self.upload_path))
         self.assertTrue(os.path.exists(self.update_path))
         self.assertEqual(redis.get(self.key_update).decode(), upload_status.READY)
def redis_get_file_metadata(request_or_response_id, filepath, is_update=False):
    """
    Returns a tuple containing a file's
        ( size (int), mime type (str), and hash (str) ).
    """
    data = redis.get(_get_file_metadata_key(
        request_or_response_id, filepath, is_update)).decode().split(':')
    data[0] = int(data[0])  # size
    return tuple(data)
Beispiel #7
0
def redis_get_file_metadata(request_or_response_id, filepath, is_update=False):
    """
    Returns a tuple containing a file's
        ( size (int), mime type (str), and hash (str) ).
    """
    data = redis.get(
        _get_file_metadata_key(request_or_response_id, filepath,
                               is_update)).decode().split(':')
    data[0] = int(data[0])  # size
    return tuple(data)
Beispiel #8
0
def delete(r_id_type, r_id, filecode):
    """
    Removes an uploaded file.

    :param r_id_type: "response" or "request"
    :param r_id: the Response or Request identifier
    :param filecode: the encoded name of the uploaded file
        (base64 without padding)

    Optional request body parameters:
    - quarantined_only (bool)
        only delete the file if it is quarantined
        (beware: takes precedence over 'updated_only')
    - updated_only (bool)
        only delete the file if it is in the 'updated' directory

    :returns:
        On success:
            { "deleted": filename }
        On failure:
            { "error": error message }
    """
    filename = secure_filename(b64decode_lenient(filecode))
    if r_id_type not in ["request", "response"]:
        response = {"error": "Invalid ID type."}
    else:
        try:
            if r_id_type == "response":
                response = Responses.query.filter_by(id=r_id, deleted=False)
                r_id = response.request_id

            path = ''
            quarantined_only = eval_request_bool(
                request.form.get('quarantined_only'))
            has_add_edit = (is_allowed(user=current_user,
                                       request_id=r_id,
                                       permission=permission.ADD_FILE)
                            or is_allowed(user=current_user,
                                          request_id=r_id,
                                          permission=permission.EDIT_FILE))
            if quarantined_only and has_add_edit:
                path = os.path.join(
                    current_app.config['UPLOAD_QUARANTINE_DIRECTORY'], r_id)
            elif eval_request_bool(request.form.get('updated_only')) and \
                    is_allowed(user=current_user, request_id=r_id, permission=permission.EDIT_FILE):
                path = os.path.join(current_app.config['UPLOAD_DIRECTORY'],
                                    r_id, UPDATED_FILE_DIRNAME)
            else:
                path_for_status = {
                    upload_status.PROCESSING:
                    current_app.config['UPLOAD_QUARANTINE_DIRECTORY'],
                    upload_status.SCANNING:
                    current_app.config['UPLOAD_QUARANTINE_DIRECTORY'],
                    upload_status.READY:
                    current_app.config['UPLOAD_DIRECTORY']
                }
                status = redis.get(get_upload_key(r_id, filename))
                if status is not None:
                    dest_path = path_for_status[status.decode("utf-8")]
                    if (dest_path ==
                            current_app.config['UPLOAD_QUARANTINE_DIRECTORY']
                            and has_add_edit
                        ) or (dest_path
                              == current_app.config['UPLOAD_DIRECTORY']
                              and is_allowed(user=current_user,
                                             request_id=r_id,
                                             permission=permission.ADD_FILE)):
                        path = os.path.join(dest_path, r_id)
            filepath = os.path.join(path, filename)
            found = False
            if path != '':
                if quarantined_only:
                    if os.path.exists(filepath):
                        os.remove(filepath)
                        found = True
                else:
                    if fu.exists(filepath):
                        fu.remove(filepath)
                        found = True
            if found:
                response = {"deleted": filename}
            else:
                response = {"error": "Upload not found."}
        except Exception as e:
            current_app.logger.exception(
                "Error on DELETE /upload/: {}".format(e))
            response = {"error": "Failed to delete '{}'".format(filename)}

    return jsonify(response), 200
Beispiel #9
0
def delete(r_id_type, r_id, filecode):
    """
    Removes an uploaded file.

    :param r_id_type: "response" or "request"
    :param r_id: the Response or Request identifier
    :param filecode: the encoded name of the uploaded file
        (base64 without padding)

    Optional request body parameters:
    - quarantined_only (bool)
        only delete the file if it is quarantined
        (beware: takes precedence over 'updated_only')
    - updated_only (bool)
        only delete the file if it is in the 'updated' directory

    :returns:
        On success:
            { "deleted": filename }
        On failure:
            { "error": error message }
    """
    filename = secure_filename(b64decode_lenient(filecode))
    if r_id_type not in ["request", "response"]:
        response = {"error": "Invalid ID type."}
    else:
        try:
            if r_id_type == "response":
                response = Responses.query.filter_by(id=r_id, deleted=False)
                r_id = response.request_id

            path = ''
            quarantined_only = eval_request_bool(request.form.get('quarantined_only'))
            has_add_edit = (is_allowed(user=current_user, request_id=r_id, permission=permission.ADD_FILE) or
                            is_allowed(user=current_user, request_id=r_id, permission=permission.EDIT_FILE))
            if quarantined_only and has_add_edit:
                path = os.path.join(
                    current_app.config['UPLOAD_QUARANTINE_DIRECTORY'],
                    r_id
                )
            elif eval_request_bool(request.form.get('updated_only')) and \
                    is_allowed(user=current_user, request_id=r_id, permission=permission.EDIT_FILE):
                path = os.path.join(
                    current_app.config['UPLOAD_DIRECTORY'],
                    r_id,
                    UPDATED_FILE_DIRNAME
                )
            else:
                path_for_status = {
                    upload_status.PROCESSING: current_app.config['UPLOAD_QUARANTINE_DIRECTORY'],
                    upload_status.SCANNING: current_app.config['UPLOAD_QUARANTINE_DIRECTORY'],
                    upload_status.READY: current_app.config['UPLOAD_DIRECTORY']
                }
                status = redis.get(get_upload_key(r_id, filename))
                if status is not None:
                    dest_path = path_for_status[status.decode("utf-8")]
                    if (dest_path == current_app.config['UPLOAD_QUARANTINE_DIRECTORY'] and has_add_edit) or (
                        dest_path == current_app.config['UPLOAD_DIRECTORY'] and
                            is_allowed(user=current_user, request_id=r_id, permission=permission.ADD_FILE)
                    ):
                        path = os.path.join(
                            dest_path,
                            r_id
                        )
            filepath = os.path.join(path, filename)
            found = False
            if path != '':
                if quarantined_only:
                    if os.path.exists(filepath):
                        os.remove(filepath)
                        found = True
                else:
                    if fu.exists(filepath):
                        fu.remove(filepath)
                        found = True
            if found:
                response = {"deleted": filename}
            else:
                response = {"error": "Upload not found."}
        except Exception as e:
            sentry.captureException()
            current_app.logger.exception("Error on DELETE /upload/: {}".format(e))
            response = {"error": "Failed to delete '{}'".format(filename)}

    return jsonify(response), 200
Beispiel #10
0
 def test_scan_good_file(self):
     scan_and_complete_upload(self.request_id, self.quarantine_path)
     self.assertFalse(os.path.exists(self.quarantine_path))
     self.assertTrue(os.path.exists(self.upload_path))
     self.assertEqual(redis.get(self.key).decode(), upload_status.READY)