From 376b23e122427cef6e0e95b0053d09cfec1eeee4 Mon Sep 17 00:00:00 2001 From: Christophe Monniez Date: Thu, 29 Feb 2024 16:15:11 +0100 Subject: [PATCH] [IMP] runbot: handle exceptions in web_search_read --- runbot/controllers/api.py | 42 +++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/runbot/controllers/api.py b/runbot/controllers/api.py index 8ff065f9..86e6833d 100644 --- a/runbot/controllers/api.py +++ b/runbot/controllers/api.py @@ -2,16 +2,40 @@ import json import logging import time +from functools import wraps + from odoo import http from odoo.http import request +from odoo.exceptions import AccessError, AccessDenied, UserError from odoo.tools import consteq _logger = logging.getLogger(__name__) +def to_json(fn): + @wraps(fn) + def decorator(*args, **kwargs): + headers = [('Content-Type', 'application/json'), + ('Cache-Control', 'no-store')] + try: + return request.make_response(json.dumps(fn(*args, **kwargs), indent=4, default=str), headers) + except AccessError: + response = request.make_response(json.dumps('unauthorized'), headers) + response.status = 401 + return response + except AccessDenied as e: + response = request.make_response(json.dumps(e.args[0]), headers) + response.status = 403 + return response + except UserError as e: + response = request.make_response(json.dumps(e.args[0]), headers) + response.status = 400 + return response + return decorator class RunbotController(http.Controller): @http.route('/runbot/api/web_search_read', type='http', auth='public', csrf=False) + @to_json def api_web_search_read(self, uid=None, token=None, model=None, specification=None, id=None, ids=None, domain=None, limit=200, offset=0, order=None): """ model: the model to read @@ -43,13 +67,19 @@ class RunbotController(http.Controller): ).json() """ user = request.env['res.users'].sudo().browse(int(uid)) - if not user or not token or len(token) < 32 or not consteq(user.runbot_api_token, token): + try: + assert user.active # handle unexisting user, accessing a field raises a user error + except UserError: time.sleep(1) - return json.dumps({'error': 'Invalid user or token'}) + raise AccessDenied(message={'error': 'Unauthorized'}) + + if not user or not user.runbot_api_token or not token or len(token) < 32 or not consteq(user.runbot_api_token, token): + time.sleep(1) + raise AccessDenied(message={'error': 'Invalid user or token'}) request.env.cache.clear() limit = max(min(2000, limit), 1) if not model.startswith('runbot.'): - return json.dumps({'error': 'Invalid model'}) + raise UserError({'error': 'Invalid model'}) if id: ids = [id] if ids: @@ -57,13 +87,13 @@ class RunbotController(http.Controller): else: domain = json.loads(domain) if not domain: - return json.dumps({'error': 'Invalid domain'}) + raise UserError({'error': 'Invalid domain'}) specification = json.loads(specification) try: user_env = request.env(user=user) result = user_env[model].web_search_read(domain, specification, limit=limit, offset=offset, order=order) - return json.dumps(result) + return result except Exception: _logger.exception('Something went wrong reading %s %s %s', model, specification, domain) - return json.dumps({'error': 'Something went wrong'}) + raise UserError({'error': 'Something went wrong'})