Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 60 additions & 34 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from base64 import b64encode
from flask import Flask, request, jsonify
from flask import Flask, g, request, jsonify
from functools import wraps
import json
import os
import tempfile
from werkzeug.exceptions import (BadRequest,
NotFound)
NotFound,
Unauthorized)
from werkzeug.security import safe_str_cmp

app = Flask(__name__)

Expand Down Expand Up @@ -43,17 +46,10 @@ def read_metadata_file(filepath):
return json.loads(content)


def write_metadata_file(filepath, metadata):
metadata_file = os.path.join(filepath, metadata_filename)

with open(metadata_file, 'wb') as f:
f.write(json.dumps(metadata))


def read_properties_file(filepath):
with open(os.path.join(filepath, properties_filename), 'r') as f:
content = f.read()
return json.loads(content)
def read_properties_file(file_id):
file_path = os.path.join(DATA_PATH, file_id, properties_filename)
with open(file_path, 'r') as f:
return json.load(f)


def write_properties_file(filepath, properties):
Expand All @@ -63,8 +59,10 @@ def write_properties_file(filepath, properties):
f.write(json.dumps(properties))


def parse_request_data(request):
return request.get_json() or request.form
@app.before_request
def parse_request_data():
if request.method in ['POST', 'PUT']:
g.payload = request.get_json() or request.form


def not_implemented():
Expand All @@ -73,20 +71,10 @@ def not_implemented():

@app.route('/api/file', methods=['POST'])
def post_file():
payload = parse_request_data(request)

if not payload['metadata']:
app.logger.error("Parsing of request failed")
raise BadRequest()
payload = g.payload

fileid, filepath = create_new_file(DATA_PATH)

write_metadata_file(filepath,
{
'metadata': payload['metadata'],
'mac': payload['mac']
})

uploadpassword = generate_password()
properties = {
'uploadpassword': uploadpassword,
Expand All @@ -104,25 +92,63 @@ def post_file():
})


def assert_file_exists(id):
if not os.path.isdir(os.path.join(DATA_PATH, id)):
raise NotFound("The requested file could not be found")
def require_file_exists(f):
@wraps(f)
def check_file_exists(*args, **kwargs):
dirname = os.path.join(DATA_PATH, kwargs['id'])
if not os.path.isdir(dirname):
raise NotFound("The requested file could not be found")
app.logger.info("Found file %s", kwargs['id'])
return f(*args, **kwargs)
return check_file_exists


@app.route('/api/file/<id>', methods=['PUT'])
def put_file(id):
return not_implemented()
def require_uploadpassword(f):
@require_file_exists
@wraps(f)
def check_uploadpassword(*args, **kwargs):
properties = read_properties_file(kwargs['id'])
payload = g.payload
comparison = safe_str_cmp(
payload['uploadpassword'],
properties['uploadpassword'])

if not comparison:
raise Unauthorized()
return f(*args, **kwargs)
return check_uploadpassword


@app.route('/api/file/<string:id>/metadata', methods=['PUT'])
@require_uploadpassword
def put_file_metadata(id):
payload = g.payload

if 'metadata' not in payload:
app.logger.error("Parsing of request failed")
raise BadRequest()

metadata = payload.copy()
del metadata['uploadpassword']

metadata_file = os.path.join(DATA_PATH, id, metadata_filename)

app.logger.debug("Writing metadata to %s", metadata_file)
with open(metadata_file, 'wb') as f:
json.dump(metadata, f)

return jsonify({})


@app.route('/api/file/<id>/exists', methods=['GET'])
@require_file_exists
def get_file_exists(id):
assert_file_exists(id)
return ""


@app.route('/api/file/<id>/info', methods=['GET'])
@require_file_exists
def get_file_info(id):
assert_file_exists(id)
'''Return public information about the file'''
return not_implemented()

Expand Down
59 changes: 52 additions & 7 deletions test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ def setUp(self):
def tearDown(self):
shutil.rmtree(self.tmp_dir)

def setup_mockfile(self, file_id, uploadpassword='1234'):
filepath = os.path.join(self.tmp_dir, file_id)
os.makedirs(filepath)
with open(os.path.join(filepath, 'properties.json'), 'w') as f:
json.dump({
'uploadpassword': uploadpassword
}, f)
return filepath

def api_upload_success(self, wrap_func=lambda x: x, headers={}):
payload = {
'metadata': b64encode(os.urandom(42)),
Expand Down Expand Up @@ -56,13 +65,6 @@ def test_post_file_json(self):
def test_post_file_multipart(self):
self.api_upload_success()

def test_post_file_no_meta(self):
payload = {
'mac': '1234'
}
resp = self.app.post('/api/file', data=payload)
self.assertEqual(resp.status_code, 400)

def test_get_serverinfo(self):
config_location = os.path.join(files, 'config.json')

Expand All @@ -72,3 +74,46 @@ def test_get_serverinfo(self):
self.status_code(resp, 200)

assert json.loads(resp.get_data()) == expected

def test_put_metadata_success(self):
with patch('main.DATA_PATH', self.tmp_dir):
filepath = self.setup_mockfile('foobar')
payload = {
'uploadpassword': '1234',
'metadata': 'encryptedtexthere'
}
resp = self.app.put('/api/file/foobar/metadata', data=payload)
self.status_code(resp, 200)

with open(os.path.join(filepath, 'metadata.json')) as f:
j = json.load(f)
assert 'uploadpassword' not in j

def test_put_metadata_not_exists(self):
resp = self.app.put('/api/file/fewfsadgsg/metadata', data={})
self.status_code(resp, 404)

def test_put_file_no_meta(self):
with patch('main.DATA_PATH', self.tmp_dir):
filepath = self.setup_mockfile('1234')
payload = {
'uploadpassword': '1234',
}
resp = self.app.put('/api/file/1234/metadata', data=payload)
self.assertEqual(resp.status_code, 400)
metadata_file = os.path.join(filepath, 'metadata.json')
assert not os.path.exists(metadata_file)

def test_put_file_unauthorized(self):
with patch('main.DATA_PATH', self.tmp_dir):
filepath = self.setup_mockfile('weggkgelg')
payload = {
'uploadpassword': '2wefegf',
'metadata': 'encryptedtexthere'
}

resp = self.app.put('/api/file/weggkgelg/metadata', data=payload)
self.status_code(resp, 401)

metadata_file = os.path.join(filepath, 'metadata.json')
assert not os.path.exists(metadata_file)