diff --git a/api_views/books.py b/api_views/books.py index f153b1c..c53dc2c 100644 --- a/api_views/books.py +++ b/api_views/books.py @@ -47,26 +47,16 @@ def get_by_title(book_title): if "error" in resp: return Response(error_message_helper(resp), 401, mimetype="application/json") else: - if vuln: # Broken Object Level Authorization - book = Book.query.filter_by(book_title=str(book_title)).first() - if book: - responseObject = { - 'book_title': book.book_title, - 'secret': book.secret_content, - 'owner': book.user.username - } - return Response(json.dumps(responseObject), 200, mimetype="application/json") - else: - return Response(error_message_helper("Book not found!"), 404, mimetype="application/json") - else: - user = User.query.filter_by(username=resp['sub']).first() - book = Book.query.filter_by(user=user, book_title=str(book_title)).first() - if book: - responseObject = { - 'book_title': book.book_title, - 'secret': book.secret_content, - 'owner': book.user.username - } - return Response(json.dumps(responseObject), 200, mimetype="application/json") - else: - return Response(error_message_helper("Book not found!"), 404, mimetype="application/json") \ No newline at end of file + # Object-level authorization is enforced unconditionally here: a book's secret + # content must only ever be returned to the authenticated caller that owns it, + # regardless of the legacy `vuln` toggle used elsewhere in this app. + requesting_user = User.query.filter_by(username=resp['sub']).first() + candidate_book = Book.query.filter_by(book_title=str(book_title)).first() + if candidate_book is None or requesting_user is None or candidate_book.user_id != requesting_user.id: + return Response(error_message_helper("Book not found!"), 404, mimetype="application/json") + responseObject = { + 'book_title': candidate_book.book_title, + 'secret': candidate_book.secret_content, + 'owner': candidate_book.user.username + } + return Response(json.dumps(responseObject), 200, mimetype="application/json") \ No newline at end of file