From 7abeaf56b3ae544dbe24c4a9fe4fa6d919582aba Mon Sep 17 00:00:00 2001 From: Martin Geubelle Date: Tue, 15 Jan 2019 15:04:03 +0000 Subject: [PATCH] [REF] im_livechat, *: remove JSONP in favor of CORS When embedding the livechat on an external website, we used to make JSONP calls. As the support of JSONP calls has been dropped, we now use the CORS mechanism instead. --- addons/bus/controllers/main.py | 2 +- addons/im_livechat/controllers/main.py | 26 ++++++++++++++----- .../im_livechat/static/src/js/im_livechat.js | 10 +++---- .../views/im_livechat_channel_templates.xml | 2 +- addons/mail/controllers/bus.py | 4 +-- addons/web/controllers/main.py | 16 ------------ 6 files changed, 27 insertions(+), 33 deletions(-) diff --git a/addons/bus/controllers/main.py b/addons/bus/controllers/main.py index a5a0e3e189b..6ff4d7ac8e0 100644 --- a/addons/bus/controllers/main.py +++ b/addons/bus/controllers/main.py @@ -27,7 +27,7 @@ class BusController(Controller): request._cr = None return dispatch.poll(dbname, channels, last, options) - @route('/longpolling/poll', type="json", auth="public") + @route('/longpolling/poll', type="json", auth="public", cors="*") def poll(self, channels, last, options=None): if options is None: options = {} diff --git a/addons/im_livechat/controllers/main.py b/addons/im_livechat/controllers/main.py index 86553625f4d..b3783d2f59d 100644 --- a/addons/im_livechat/controllers/main.py +++ b/addons/im_livechat/controllers/main.py @@ -3,13 +3,16 @@ import base64 -from odoo import http, _ +from odoo import http,tools, _ from odoo.http import request from odoo.addons.base.models.assetsbundle import AssetsBundle class LivechatController(http.Controller): + # Note: the `cors` attribute on many routes is meant to allow the livechat + # to be embedded in an external website. + @http.route('/im_livechat/external_lib.', type='http', auth='none') def livechat_lib(self, ext, **kwargs): # _get_asset return the bundle html code (script and link list) but we want to use the attachment content @@ -26,6 +29,17 @@ class LivechatController(http.Controller): headers.append(('Content-Length', len(content_base64))) return request.make_response(content_base64, headers) + @http.route('/im_livechat/load_templates', type='json', auth='none', cors="*") + def load_templates(self, **kwargs): + base_url = request.httprequest.base_url + templates = [ + 'mail/static/src/xml/abstract_thread_window.xml', + 'mail/static/src/xml/discuss.xml', + 'mail/static/src/xml/thread.xml', + 'im_livechat/static/src/xml/im_livechat.xml', + ] + return [tools.file_open(tmpl, 'rb').read() for tmpl in templates] + @http.route('/im_livechat/support/', type='http', auth='public') def support_page(self, channel_id, **kwargs): channel = request.env['im_livechat.channel'].sudo().browse(channel_id) @@ -38,7 +52,7 @@ class LivechatController(http.Controller): info = request.env['im_livechat.channel'].get_livechat_info(channel.id, username=username) return request.render('im_livechat.loader', {'info': info, 'web_session_required': True}, headers=[('Content-Type', 'application/javascript')]) - @http.route('/im_livechat/init', type='json', auth="public") + @http.route('/im_livechat/init', type='json', auth="public", cors="*") def livechat_init(self, channel_id): LivechatChannel = request.env['im_livechat.channel'] available = len(LivechatChannel.browse(channel_id).get_available_users()) @@ -66,7 +80,7 @@ class LivechatController(http.Controller): 'rule': rule, } - @http.route('/im_livechat/get_session', type="json", auth='public') + @http.route('/im_livechat/get_session', type="json", auth='public', cors="*") def get_session(self, channel_id, anonymous_name, **kwargs): user_id = None country_id = None @@ -83,7 +97,7 @@ class LivechatController(http.Controller): anonymous_name, country_id = _("%s (%s)") % (anonymous_name, country.name), country.id return request.env["im_livechat.channel"].with_context(lang=False).get_mail_channel(channel_id, anonymous_name, user_id, country_id) - @http.route('/im_livechat/feedback', type='json', auth='public') + @http.route('/im_livechat/feedback', type='json', auth='public', cors="*") def feedback(self, uuid, rate, reason=None, **kwargs): Channel = request.env['mail.channel'] Rating = request.env['rating.rating'] @@ -114,7 +128,7 @@ class LivechatController(http.Controller): return rating.id return False - @http.route('/im_livechat/history', type="json", auth="public") + @http.route('/im_livechat/history', type="json", auth="public", cors="*") def history_pages(self, pid, channel_uuid, page_history=None): partner_ids = (pid, request.env.user.partner_id.id) channel = request.env['mail.channel'].sudo().search([('uuid', '=', channel_uuid), ('channel_partner_ids', 'in', partner_ids)]) @@ -122,7 +136,7 @@ class LivechatController(http.Controller): channel._send_history_message(pid, page_history) return True - @http.route('/im_livechat/notify_typing', type='json', auth='public') + @http.route('/im_livechat/notify_typing', type='json', auth='public', cors="*") def notify_typing(self, uuid, is_typing): """ Broadcast the typing notification of the website user to other channel members :param uuid: (string) the UUID of the livechat channel diff --git a/addons/im_livechat/static/src/js/im_livechat.js b/addons/im_livechat/static/src/js/im_livechat.js index f59a03e2040..964e9ef5d3e 100644 --- a/addons/im_livechat/static/src/js/im_livechat.js +++ b/addons/im_livechat/static/src/js/im_livechat.js @@ -190,15 +190,11 @@ var LivechatButton = Widget.extend({ * @private */ _loadQWebTemplate: function () { - var xml_files = ['/mail/static/src/xml/abstract_thread_window.xml', - '/mail/static/src/xml/thread.xml', - '/im_livechat/static/src/xml/im_livechat.xml']; - var defs = _.map(xml_files, function (tmpl) { - return session.rpc('/web/proxy/load', { path: tmpl }).then(function (xml) { - QWeb.add_template(xml); + return session.rpc('/im_livechat/load_templates').then(function (templates) { + _.each(templates, function (template) { + QWeb.add_template(template); }); }); - return $.when.apply($, defs); }, /** * @private diff --git a/addons/im_livechat/views/im_livechat_channel_templates.xml b/addons/im_livechat/views/im_livechat_channel_templates.xml index 85861a185fa..d029ae32478 100644 --- a/addons/im_livechat/views/im_livechat_channel_templates.xml +++ b/addons/im_livechat/views/im_livechat_channel_templates.xml @@ -194,7 +194,7 @@ odoo.define('web.session', function (require) { var Session = require('web.Session'); var modules = odoo._modules; - return new Session(undefined, "", {modules:modules, use_cors: false}); + return new Session(undefined, "", {modules:modules, use_cors: true}); }); diff --git a/addons/mail/controllers/bus.py b/addons/mail/controllers/bus.py index c900604ab06..912aae3cacd 100644 --- a/addons/mail/controllers/bus.py +++ b/addons/mail/controllers/bus.py @@ -34,7 +34,7 @@ class MailChatController(BusController): # -------------------------- # Anonymous routes (Common Methods) # -------------------------- - @route('/mail/chat_post', type="json", auth="none") + @route('/mail/chat_post', type="json", auth="none", cors="*") def mail_chat_post(self, uuid, message_content, **kwargs): # find the author from the user session, which can be None author_id = False # message_post accept 'False' author_id, but not 'None' @@ -46,7 +46,7 @@ class MailChatController(BusController): message = mail_channel.sudo().with_context(mail_create_nosubscribe=True).message_post(author_id=author_id, email_from=False, body=body, message_type='comment', subtype='mail.mt_comment') return message and message.id or False - @route(['/mail/chat_history'], type="json", auth="none") + @route(['/mail/chat_history'], type="json", auth="none", cors="*") def mail_chat_history(self, uuid, last_id=False, limit=20): channel = request.env["mail.channel"].sudo().search([('uuid', '=', uuid)], limit=1) if not channel: diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 59b427cfe65..cf87240484c 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -640,22 +640,6 @@ class WebClient(http.Controller): class Proxy(http.Controller): - @http.route('/web/proxy/load', type='json', auth="none") - def load(self, path): - """ Proxies an HTTP request through a JSON request. - - It is strongly recommended to not request binary files through this, - as the result will be a binary data blob as well. - - :param path: actual request path - :return: file content - """ - from werkzeug.test import Client - from werkzeug.wrappers import BaseResponse - - base_url = request.httprequest.base_url - return Client(request.httprequest.app, BaseResponse).get(path, base_url=base_url).data - @http.route('/web/proxy/post/', type='http', auth='user', methods=['GET']) def post(self, path): """Effectively execute a POST request that was hooked through user login"""