fixes #16: remove unwanted keys in PUT/POST requests

This commit is contained in:
Davide Alberani 2017-01-28 10:35:14 +01:00
parent f57923f0e9
commit e4355a8ff2

67
ibt2.py
View file

@ -84,7 +84,9 @@ class BaseHandler(tornado.web.RequestHandler):
:type data: dict""" :type data: dict"""
if isinstance(data, dict): if isinstance(data, dict):
for key in data.keys(): for key in data.keys():
if isinstance(key, (str, unicode)) and key.startswith('$'): if (isinstance(key, (str, unicode)) and key.startswith('$')) or key in ('_id', 'created_by',
'created_at', 'updated_by',
'updated_at'):
del data[key] del data[key]
return data return data
@ -168,7 +170,15 @@ class BaseHandler(tornado.web.RequestHandler):
self.write({'error': True, 'message': message}) self.write({'error': True, 'message': message})
def has_permission(self, owner_id): def has_permission(self, owner_id):
if (owner_id and str(self.current_user_info.get('_id')) != str(owner_id) and not """Check if the given owner_id matches with the current user or the logged in user is an admin; if not,
build an error reply.
:param owner_id: owner ID to check against
:type owner_id: str, ObjectId, None
:returns: if the logged in user has the permission
:rtype: bool"""
if (owner_id and str(self.current_user) != str(owner_id) and not
self.current_user_info.get('isAdmin')): self.current_user_info.get('isAdmin')):
self.build_error(status=401, message='insufficient permissions: must be the owner or admin') self.build_error(status=401, message='insufficient permissions: must be the owner or admin')
return False return False
@ -180,6 +190,23 @@ class BaseHandler(tornado.web.RequestHandler):
del self._users_cache[self.current_user] del self._users_cache[self.current_user]
self.clear_cookie("user") self.clear_cookie("user")
def add_access_info(self, doc):
"""Add created/updated by/at to a document (modified in place and returned).
:param doc: the doc to be updated
:type doc: dict
:returns: the updated document
:rtype: dict"""
user_id = self.current_user
now = datetime.datetime.now()
if 'created_by' not in doc:
doc['created_by'] = user_id
if 'created_at' not in doc:
doc['created_at'] = now
doc['updated_by'] = user_id
doc['updated_at'] = now
return doc
class RootHandler(BaseHandler): class RootHandler(BaseHandler):
"""Handler for the / path.""" """Handler for the / path."""
@ -212,30 +239,19 @@ class AttendeesHandler(BaseHandler):
if not value: if not value:
return self.build_error(status=404, message="%s can't be empty" % key) return self.build_error(status=404, message="%s can't be empty" % key)
data[key] = value data[key] = value
user_id = self.current_user_info.get('_id') self.add_access_info(data)
now = datetime.datetime.now()
data['created_by'] = user_id
data['created_at'] = now
data['updated_by'] = user_id
data['updated_at'] = now
doc = self.db.add(self.collection, data) doc = self.db.add(self.collection, data)
self.write(doc) self.write(doc)
@gen.coroutine @gen.coroutine
def put(self, id_, **kwargs): def put(self, id_, **kwargs):
data = self.clean_body data = self.clean_body
if '_id' in data:
del data['_id']
doc = self.db.getOne(self.collection, {'_id': id_}) or {} doc = self.db.getOne(self.collection, {'_id': id_}) or {}
if not doc: if not doc:
return self.build_error(status=404, message='unable to access the resource') return self.build_error(status=404, message='unable to access the resource')
owner_id = doc.get('created_by') if not self.has_permission(doc.get('created_by')):
if not self.has_permission(owner_id):
return return
user_id = self.current_user_info.get('_id') self.add_access_info(data)
now = datetime.datetime.now()
data['updated_by'] = user_id
data['updated_at'] = now
merged, doc = self.db.update(self.collection, {'_id': id_}, data) merged, doc = self.db.update(self.collection, {'_id': id_}, data)
self.write(doc) self.write(doc)
@ -247,8 +263,7 @@ class AttendeesHandler(BaseHandler):
doc = self.db.getOne(self.collection, {'_id': id_}) or {} doc = self.db.getOne(self.collection, {'_id': id_}) or {}
if not doc: if not doc:
return self.build_error(status=404, message='unable to access the resource') return self.build_error(status=404, message='unable to access the resource')
owner_id = doc.get('created_by') if not self.has_permission(doc.get('created_by')):
if not self.has_permission(owner_id):
return return
howMany = self.db.delete(self.collection, id_) howMany = self.db.delete(self.collection, id_)
self.write({'success': True, 'deleted entries': howMany.get('n')}) self.write({'success': True, 'deleted entries': howMany.get('n')})
@ -327,13 +342,11 @@ class DaysHandler(BaseHandler):
@gen.coroutine @gen.coroutine
def put(self, **kwargs): def put(self, **kwargs):
data = self.clean_body data = self.clean_body
now = datetime.datetime.now()
data['updated_by'] = self.current_user_info.get('_id')
data['updated_at'] = now
day = (data.get('day') or '').strip() day = (data.get('day') or '').strip()
if not day: if not day:
return self.build_error(status=404, message='unable to access the resource') return self.build_error(status=404, message='unable to access the resource')
data['day'] = day data['day'] = day
self.add_access_info(data)
merged, doc = self.db.update('days', {'day': day}, data) merged, doc = self.db.update('days', {'day': day}, data)
self.write(doc) self.write(doc)
@ -343,15 +356,13 @@ class GroupsHandler(BaseHandler):
@gen.coroutine @gen.coroutine
def put(self, **kwargs): def put(self, **kwargs):
data = self.clean_body data = self.clean_body
now = datetime.datetime.now()
data['updated_by'] = self.current_user_info.get('_id')
data['updated_at'] = now
day = (data.get('day') or '').strip() day = (data.get('day') or '').strip()
group = (data.get('group') or '').strip() group = (data.get('group') or '').strip()
if not (day and group): if not (day and group):
return self.build_error(status=404, message='unable to access the resource') return self.build_error(status=404, message='unable to access the resource')
data['day'] = day data['day'] = day
data['group'] = group data['group'] = group
self.add_access_info(data)
merged, doc = self.db.update('groups', {'day': day, 'group': group}, data) merged, doc = self.db.update('groups', {'day': day, 'group': group}, data)
self.write(doc) self.write(doc)
@ -381,8 +392,6 @@ class UsersHandler(BaseHandler):
@gen.coroutine @gen.coroutine
def post(self, **kwargs): def post(self, **kwargs):
data = self.clean_body data = self.clean_body
if '_id' in data:
del data['_id']
username = (data.get('username') or '').strip() username = (data.get('username') or '').strip()
password = (data.get('password') or '').strip() password = (data.get('password') or '').strip()
email = (data.get('email') or '').strip() email = (data.get('email') or '').strip()
@ -392,8 +401,9 @@ class UsersHandler(BaseHandler):
if res: if res:
raise InputException('username already exists') raise InputException('username already exists')
data['username'] = username data['username'] = username
data['email'] = email
data['password'] = utils.hash_password(password) data['password'] = utils.hash_password(password)
data['email'] = email
self.add_access_info(data)
if 'isAdmin' in data and not self.current_user_info.get('isAdmin'): if 'isAdmin' in data and not self.current_user_info.get('isAdmin'):
del data['isAdmin'] del data['isAdmin']
doc = self.db.add(self.collection, data) doc = self.db.add(self.collection, data)
@ -408,8 +418,6 @@ class UsersHandler(BaseHandler):
return self.build_error(status=404, message='unable to access the resource') return self.build_error(status=404, message='unable to access the resource')
if not self.has_permission(id_): if not self.has_permission(id_):
return return
if '_id' in data:
del data['_id']
if 'username' in data: if 'username' in data:
del data['username'] del data['username']
if 'isAdmin' in data and (str(self.current_user) == id_ or not self.current_user_info.get('isAdmin')): if 'isAdmin' in data and (str(self.current_user) == id_ or not self.current_user_info.get('isAdmin')):
@ -420,6 +428,7 @@ class UsersHandler(BaseHandler):
data['password'] = utils.hash_password(password) data['password'] = utils.hash_password(password)
else: else:
del data['password'] del data['password']
self.add_access_info(data)
merged, doc = self.db.update(self.collection, {'_id': id_}, data) merged, doc = self.db.update(self.collection, {'_id': id_}, data)
if 'password' in doc: if 'password' in doc:
del doc['password'] del doc['password']