[IMP] web, *: remove explicit references to session_id
Before this rev. the `session_id` was provided by the server to the webclient (in session_info, mostly) and was stored and accessible. This made XSS injection more dangerous than they should be as it was very easy to steal the `session_id`. As the browser automatically set the `session_id` on every request to the server, the webclient shouldn't need any explicit reference. Since rev. odoo/odoo@f4d541e the `session_id` cookie uses the `httponly` flag so it cannot be accessed through client side script. Task 1905359 closes odoo/odoo#30098
This commit is contained in:
@@ -3,8 +3,6 @@
|
||||
<t t-set="_id" t-value="_.uniqueId('export')"/>
|
||||
<form action="" method="post" enctype="multipart/form-data" class="oe_import">
|
||||
<input type="hidden" name="csrf_token" t-att-value="csrf_token"/>
|
||||
<input type="hidden" name="session_id"
|
||||
t-att-value="widget.session.session_id"/>
|
||||
<input type="hidden" name="import_id"/>
|
||||
<div class="oe_import_box col-lg-12 d-none">
|
||||
<input accept=".csv, .xls, .xlsx, .xlsm, .ods" t-attf-id="file_#{_id}"
|
||||
|
||||
@@ -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 = {}
|
||||
|
||||
@@ -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.<any(css,js):ext>', 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/<int:channel_id>', 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -194,7 +194,7 @@
|
||||
odoo.define('web.session', function (require) {
|
||||
var Session = require('web.Session');
|
||||
var modules = odoo._modules;
|
||||
return new Session(undefined, "<t t-esc="info['server_url']"/>", {modules:modules, use_cors: false});
|
||||
return new Session(undefined, "<t t-esc="info['server_url']"/>", {modules:modules, use_cors: true});
|
||||
});
|
||||
</t>
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -98,7 +98,6 @@
|
||||
<t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t>
|
||||
<input type="hidden" name="model" t-att-value="activity.res_model"/>
|
||||
<input type="hidden" name="id" t-att-value="activity.res_id"/>
|
||||
<input type="hidden" name="session_id" t-att-value="session.session_id"/>
|
||||
</t>
|
||||
</span>
|
||||
<a role="button" href="#" class="btn btn-link btn-secondary text-muted o_edit_activity o_activity_link" t-att-data-activity-id="activity.id">
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
<t t-set="multi_upload" t-value="true"/>
|
||||
<input type="hidden" name="model" value="mail.compose.message"/>
|
||||
<input type="hidden" name="id" value="0"/>
|
||||
<input type="hidden" name="session_id" t-att-value="widget.getSession().session_id"/>
|
||||
</t>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -92,7 +92,6 @@
|
||||
<t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t>
|
||||
<input type="hidden" name="model" t-att-value="log.res_model"/>
|
||||
<input type="hidden" name="id" t-att-value="log.res_id"/>
|
||||
<input type="hidden" name="session_id" t-att-value="session.session_id"/>
|
||||
</t>
|
||||
</span>
|
||||
</t>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t>
|
||||
<input type="hidden" name="model" t-att-value="widget.modelName" />
|
||||
<input type="hidden" name="id" t-att-value="widget.id" />
|
||||
<input type="hidden" name="session_id" t-att-value="widget.getSession().session_id" />
|
||||
</t>
|
||||
</span>
|
||||
</t>
|
||||
|
||||
@@ -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/<path:path>', type='http', auth='user', methods=['GET'])
|
||||
def post(self, path):
|
||||
"""Effectively execute a POST request that was hooked through user login"""
|
||||
|
||||
@@ -23,7 +23,6 @@ class Http(models.AbstractModel):
|
||||
display_switch_company_menu = user.has_group('base.group_multi_company') and len(user.company_ids) > 1
|
||||
version_info = odoo.service.common.exp_version()
|
||||
return {
|
||||
"session_id": request.session.sid,
|
||||
"uid": request.session.uid,
|
||||
"is_system": user._is_system() if request.session.uid else False,
|
||||
"is_admin": user._is_admin() if request.session.uid else False,
|
||||
|
||||
@@ -45,7 +45,6 @@ function genericJsonRpc (fct_name, params, settings, fct) {
|
||||
var def = $.Deferred();
|
||||
return def.reject.apply(def, ["communication"].concat(_.toArray(arguments)));
|
||||
});
|
||||
// FIXME: jsonp?
|
||||
deferred.abort = function () {
|
||||
deferred.reject({message: "XmlHttpRequestError abort"}, $.Event('abort'));
|
||||
if (xhr.abort) {
|
||||
@@ -106,80 +105,6 @@ function jsonRpc(url, fct_name, params, settings) {
|
||||
});
|
||||
}
|
||||
|
||||
function jsonpRpc(url, fct_name, params, settings) {
|
||||
settings = settings || {};
|
||||
return genericJsonRpc(fct_name, params, settings, function(data) {
|
||||
var payload_str = JSON.stringify(data, time.date_to_utc);
|
||||
var payload_url = $.param({r:payload_str});
|
||||
var force2step = settings.force2step || false;
|
||||
delete settings.force2step;
|
||||
var session_id = settings.session_id || null;
|
||||
delete settings.session_id;
|
||||
if (payload_url.length < 2000 && ! force2step) {
|
||||
return $.ajax(url, _.extend({}, settings, {
|
||||
url: url,
|
||||
dataType: 'jsonp',
|
||||
jsonp: 'jsonp',
|
||||
type: 'GET',
|
||||
cache: false,
|
||||
data: {r: payload_str, session_id: session_id}
|
||||
}));
|
||||
} else {
|
||||
var args = {session_id: session_id, id: data.id};
|
||||
var ifid = _.uniqueId('oe_rpc_iframe');
|
||||
var html = "<iframe src='javascript:false;' name='" + ifid + "' id='" + ifid + "' style='display:none'></iframe>";
|
||||
var $iframe = $(html);
|
||||
var nurl = 'jsonp=1&' + $.param(args);
|
||||
nurl = url.indexOf("?") !== -1 ? url + "&" + nurl : url + "?" + nurl;
|
||||
var $form = $('<form>')
|
||||
.attr('method', 'POST')
|
||||
.attr('target', ifid)
|
||||
.attr('enctype', "multipart/form-data")
|
||||
.attr('action', nurl)
|
||||
.append($('<input type="hidden" name="r" />').attr('value', payload_str))
|
||||
.hide()
|
||||
.appendTo($('body'));
|
||||
var cleanUp = function() {
|
||||
if ($iframe) {
|
||||
$iframe.unbind("load").remove();
|
||||
}
|
||||
$form.remove();
|
||||
};
|
||||
var deferred = $.Deferred();
|
||||
// the first bind is fired up when the iframe is added to the DOM
|
||||
$iframe.bind('load', function() {
|
||||
// the second bind is fired up when the result of the form submission is received
|
||||
$iframe.unbind('load').bind('load', function() {
|
||||
$.ajax({
|
||||
url: url,
|
||||
dataType: 'jsonp',
|
||||
jsonp: 'jsonp',
|
||||
type: 'GET',
|
||||
cache: false,
|
||||
data: {session_id: session_id, id: data.id}
|
||||
}).always(function() {
|
||||
cleanUp();
|
||||
}).done(function() {
|
||||
deferred.resolve.apply(deferred, arguments);
|
||||
}).fail(function() {
|
||||
deferred.reject.apply(deferred, arguments);
|
||||
});
|
||||
});
|
||||
// now that the iframe can receive data, we fill and submit the form
|
||||
$form.submit();
|
||||
});
|
||||
// append the iframe to the DOM (will trigger the first load)
|
||||
$form.after($iframe);
|
||||
if (settings.timeout) {
|
||||
realSetTimeout(function() {
|
||||
deferred.reject({});
|
||||
}, settings.timeout);
|
||||
}
|
||||
return deferred;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// helper function to make a rpc with a function name hardcoded to 'call'
|
||||
function rpc(url, params, settings) {
|
||||
return jsonRpc(url, 'call', params, settings);
|
||||
@@ -312,7 +237,7 @@ function get_file(options) {
|
||||
xhr.open('POST', options.url);
|
||||
data = new FormData();
|
||||
_.each(options.data || {}, function (v, k) {
|
||||
data.append(k, v)
|
||||
data.append(k, v);
|
||||
});
|
||||
}
|
||||
data.append('token', 'dummy-because-api-expects-one');
|
||||
@@ -360,7 +285,7 @@ function get_file(options) {
|
||||
name: String(xhr.status),
|
||||
title: nodes.length > 0 ? nodes[0].textContent : '',
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
options.error(err);
|
||||
};
|
||||
@@ -375,7 +300,7 @@ function get_file(options) {
|
||||
}
|
||||
};
|
||||
if (options.complete) {
|
||||
xhr.onloadend = function () { options.complete(); }
|
||||
xhr.onloadend = function () { options.complete(); };
|
||||
}
|
||||
|
||||
xhr.send(data);
|
||||
@@ -596,7 +521,6 @@ function loadLibs (libs) {
|
||||
|
||||
var ajax = {
|
||||
jsonRpc: jsonRpc,
|
||||
jsonpRpc: jsonpRpc,
|
||||
rpc: rpc,
|
||||
loadCSS: loadCSS,
|
||||
loadJS: loadJS,
|
||||
|
||||
@@ -22,11 +22,8 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
or `null` if the server to contact is the origin server.
|
||||
@param {Dict} options A dictionary that can contain the following options:
|
||||
|
||||
* "override_session": Default to false. If true, the current session object will
|
||||
not try to re-use a previously created session id stored in a cookie.
|
||||
* "session_id": Default to null. If specified, the specified session_id will be used
|
||||
by this session object. Specifying this option automatically implies that the option
|
||||
"override_session" is set to true.
|
||||
* "modules"
|
||||
* "use_cors"
|
||||
*/
|
||||
init: function (parent, origin, options) {
|
||||
mixins.EventDispatcherMixin.init.call(this);
|
||||
@@ -34,8 +31,6 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
options = options || {};
|
||||
this.module_list = (options.modules && options.modules.slice()) || (window.odoo._modules && window.odoo._modules.slice()) || [];
|
||||
this.server = null;
|
||||
this.session_id = options.session_id || null;
|
||||
this.override_session = options.override_session || !!options.session_id || false;
|
||||
this.avoid_recursion = false;
|
||||
this.use_cors = options.use_cors || false;
|
||||
this.setup(origin);
|
||||
@@ -61,7 +56,6 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
this.origin = origin;
|
||||
this.prefix = this.origin;
|
||||
this.server = this.origin; // keep chs happy
|
||||
this.origin_server = this.origin === window_origin;
|
||||
options = options || {};
|
||||
if ('use_cors' in options) {
|
||||
this.use_cors = options.use_cors;
|
||||
@@ -139,7 +133,6 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
if (!result.uid) {
|
||||
return $.Deferred().reject();
|
||||
}
|
||||
delete result.session_id;
|
||||
_.extend(self, result);
|
||||
});
|
||||
},
|
||||
@@ -276,9 +269,6 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
return this.currencies[currency_id];
|
||||
},
|
||||
get_file: function (options) {
|
||||
if (this.override_session){
|
||||
options.data.session_id = this.session_id;
|
||||
}
|
||||
options.session = this;
|
||||
return ajax.get_file(options);
|
||||
},
|
||||
@@ -290,29 +280,9 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
*/
|
||||
session_reload: function () {
|
||||
var result = _.extend({}, window.odoo.session_info);
|
||||
delete result.session_id;
|
||||
_.extend(this, result);
|
||||
return $.when();
|
||||
},
|
||||
check_session_id: function () {
|
||||
var self = this;
|
||||
if (this.avoid_recursion)
|
||||
return $.when();
|
||||
if (this.session_id)
|
||||
return $.when(); // we already have the session id
|
||||
if (!this.use_cors && (this.override_session || ! this.origin_server)) {
|
||||
// If we don't use the origin server we consider we should always create a new session.
|
||||
// Even if some browsers could support cookies when using jsonp that behavior is
|
||||
// not consistent and the browser creators are tending to removing that feature.
|
||||
this.avoid_recursion = true;
|
||||
return this.rpc("/gen_session_id", {}).then(function (result) {
|
||||
self.session_id = result;
|
||||
}).always(function () {
|
||||
self.avoid_recursion = false;
|
||||
});
|
||||
}
|
||||
return $.when();
|
||||
},
|
||||
/**
|
||||
* Executes an RPC call, registering the provided callbacks.
|
||||
*
|
||||
@@ -333,57 +303,19 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
||||
options.headers["X-Debug-Mode"] = $.deparam($.param.querystring()).debug;
|
||||
}
|
||||
|
||||
var deferred = self.check_session_id();
|
||||
var aborted = false;
|
||||
var xhrDef;
|
||||
deferred.abort = function () {
|
||||
if (xhrDef) {
|
||||
xhrDef.abort();
|
||||
} else {
|
||||
aborted = true;
|
||||
}
|
||||
};
|
||||
// TODO: remove
|
||||
if (! _.isString(url)) {
|
||||
_.extend(options, url);
|
||||
url = url.url;
|
||||
}
|
||||
if (self.use_cors) {
|
||||
url = self.url(url, null);
|
||||
}
|
||||
|
||||
var promise = deferred.then(function () {
|
||||
if (aborted) {
|
||||
var def = $.Deferred().reject({message: "XmlHttpRequestError abort"}, $.Event('abort'));
|
||||
def.abort = function () {};
|
||||
return def;
|
||||
}
|
||||
// TODO: remove
|
||||
if (! _.isString(url)) {
|
||||
_.extend(options, url);
|
||||
url = url.url;
|
||||
}
|
||||
var fct;
|
||||
if (self.origin_server) {
|
||||
fct = ajax.jsonRpc;
|
||||
if (self.override_session) {
|
||||
options.headers["X-Openerp-Session-Id"] = self.session_id || '';
|
||||
}
|
||||
} else if (self.use_cors) {
|
||||
fct = ajax.jsonRpc;
|
||||
url = self.url(url, null);
|
||||
options.session_id = self.session_id || '';
|
||||
if (self.override_session) {
|
||||
options.headers["X-Openerp-Session-Id"] = self.session_id || '';
|
||||
}
|
||||
} else {
|
||||
fct = ajax.jsonpRpc;
|
||||
url = self.url(url, null);
|
||||
options.session_id = self.session_id || '';
|
||||
}
|
||||
xhrDef = fct(url, "call", params, options);
|
||||
return xhrDef;
|
||||
});
|
||||
|
||||
promise.abort = deferred.abort;
|
||||
return promise;
|
||||
return ajax.jsonRpc(url, "call", params, options);
|
||||
},
|
||||
url: function (path, params) {
|
||||
params = _.extend(params || {});
|
||||
if (this.override_session || (! this.origin_server))
|
||||
params.session_id = this.session_id;
|
||||
var qs = $.param(params);
|
||||
if (qs.length > 0)
|
||||
qs = "?" + qs;
|
||||
|
||||
@@ -1446,7 +1446,6 @@ var AbstractFieldBinary = AbstractField.extend({
|
||||
self.on_file_uploaded(file.size, file.name, file.type, data);
|
||||
};
|
||||
} else {
|
||||
this.$('form.o_form_binary_form input[name=session_id]').val(this.getSession().session_id);
|
||||
this.$('form.o_form_binary_form').submit();
|
||||
}
|
||||
this.$('.o_form_binary_progress').show();
|
||||
|
||||
@@ -378,7 +378,6 @@
|
||||
<t t-set="multi_upload" t-value="true"/>
|
||||
<input type="hidden" name="model" t-att-value="widget.env and widget.env.model"/>
|
||||
<input type="hidden" name="id" t-att-value="widget.env.activeIds[0]"/>
|
||||
<input type="hidden" name="session_id" t-att-value="widget.getSession().session_id" t-if="widget.getSession().override_session"/>
|
||||
<span>Add...</span>
|
||||
</t>
|
||||
</div>
|
||||
@@ -998,7 +997,6 @@
|
||||
<form class="o_form_binary_form" t-att-target="fileupload_id"
|
||||
method="post" enctype="multipart/form-data" t-att-action="fileupload_action || '/web/binary/upload'">
|
||||
<input type="hidden" name="csrf_token" t-att-value="csrf_token"/>
|
||||
<input type="hidden" name="session_id" value="" t-if="widget.getSession().override_session"/>
|
||||
<input type="hidden" name="callback" t-att-value="fileupload_id"/>
|
||||
<input t-if="widget.image_only" type="file" class="o_input_file" name="ufile" accept="image/*"/>
|
||||
<input t-if="!widget.image_only" type="file" class="o_input_file" name="ufile" t-att="{'multiple': multi_upload ? 'multiple' : null}"/>
|
||||
@@ -1042,7 +1040,6 @@
|
||||
<t t-set="multi_upload" t-value="true"/>
|
||||
<input type="hidden" name="model" t-att-value="widget.model"/>
|
||||
<input type="hidden" name="id" value="0"/>
|
||||
<input t-if="widget.getSession().override_session" type="hidden" name="session_id" t-att-value="widget.getSession().session_id"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1567,7 +1564,6 @@
|
||||
<t t-set="multi_upload" t-value="true"/>
|
||||
<input type="hidden" name="model" t-att-value="widget.res_model"/>
|
||||
<input type="hidden" name="id" t-att-value="widget.res_id"/>
|
||||
<input type="hidden" name="session_id" t-att-value="widget.getSession().session_id"/>
|
||||
</t>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
@@ -47,8 +47,8 @@ odoo.define('website_sale.tour_shop_customize', function (require) {
|
||||
args: ['product.group_product_variant', false],
|
||||
kwargs: {}
|
||||
};
|
||||
ajax.jsonpRpc('/web/dataset/call_kw', 'call', get_group_payload).then(function(group_id) {
|
||||
ajax.jsonpRpc('/web/dataset/call_kw', 'call', {
|
||||
ajax.jsonRpc('/web/dataset/call_kw', 'call', get_group_payload).then(function(group_id) {
|
||||
ajax.jsonRpc('/web/dataset/call_kw', 'call', {
|
||||
model: 'res.groups',
|
||||
method: 'write',
|
||||
args: [group_id, {'users': [[4, 1]]}],
|
||||
|
||||
+6
-48
@@ -302,7 +302,7 @@ class WebRequest(object):
|
||||
def _handle_exception(self, exception):
|
||||
"""Called within an except block to allow converting exceptions
|
||||
to abitrary responses. Anything returned (except None) will
|
||||
be used as response."""
|
||||
be used as response."""
|
||||
self._failed = exception # prevent tx commit
|
||||
if not isinstance(exception, NO_POSTMORTEM) \
|
||||
and not isinstance(exception, werkzeug.exceptions.HTTPException):
|
||||
@@ -579,34 +579,14 @@ class JsonRequest(WebRequest):
|
||||
def __init__(self, *args):
|
||||
super(JsonRequest, self).__init__(*args)
|
||||
|
||||
self.jsonp_handler = None
|
||||
self.params = {}
|
||||
|
||||
args = self.httprequest.args
|
||||
jsonp = args.get('jsonp')
|
||||
self.jsonp = jsonp
|
||||
request = None
|
||||
request_id = args.get('id')
|
||||
|
||||
if jsonp and self.httprequest.method == 'POST':
|
||||
# jsonp 2 steps step1 POST: save call
|
||||
def handler():
|
||||
self.session['jsonp_request_%s' % (request_id,)] = self.httprequest.form['r']
|
||||
self.session.modified = True
|
||||
headers=[('Content-Type', 'text/plain; charset=utf-8')]
|
||||
r = werkzeug.wrappers.Response(request_id, headers=headers)
|
||||
return r
|
||||
self.jsonp_handler = handler
|
||||
return
|
||||
elif jsonp and args.get('r'):
|
||||
# jsonp method GET
|
||||
request = args.get('r')
|
||||
elif jsonp and request_id:
|
||||
# jsonp 2 steps step2 GET: run and return result
|
||||
request = self.session.pop('jsonp_request_%s' % (request_id,), '{}')
|
||||
else:
|
||||
# regular jsonrpc2
|
||||
request = self.httprequest.get_data().decode(self.httprequest.charset)
|
||||
|
||||
# regular jsonrpc2
|
||||
request = self.httprequest.get_data().decode(self.httprequest.charset)
|
||||
|
||||
# Read POST content or POST Form Data named "request"
|
||||
try:
|
||||
@@ -630,16 +610,8 @@ class JsonRequest(WebRequest):
|
||||
if result is not None:
|
||||
response['result'] = result
|
||||
|
||||
if self.jsonp:
|
||||
# If we use jsonp, that's mean we are called from another host
|
||||
# Some browser (IE and Safari) do no allow third party cookies
|
||||
# We need then to manage http sessions manually.
|
||||
response['session_id'] = self.session.sid
|
||||
mime = 'application/javascript'
|
||||
body = "%s(%s);" % (self.jsonp, json.dumps(response, default=date_utils.json_default))
|
||||
else:
|
||||
mime = 'application/json'
|
||||
body = json.dumps(response, default=date_utils.json_default)
|
||||
mime = 'application/json'
|
||||
body = json.dumps(response, default=date_utils.json_default)
|
||||
|
||||
return Response(
|
||||
body, status=error and error.pop('http_status', 200) or 200,
|
||||
@@ -674,8 +646,6 @@ class JsonRequest(WebRequest):
|
||||
return self._json_response(error=error)
|
||||
|
||||
def dispatch(self):
|
||||
if self.jsonp_handler:
|
||||
return self.jsonp_handler()
|
||||
try:
|
||||
rpc_request_flag = rpc_request.isEnabledFor(logging.DEBUG)
|
||||
rpc_response_flag = rpc_response.isEnabledFor(logging.DEBUG)
|
||||
@@ -1388,8 +1358,6 @@ class Root(object):
|
||||
|
||||
def get_request(self, httprequest):
|
||||
# deduce type of request
|
||||
if httprequest.args.get('jsonp'):
|
||||
return JsonRequest(httprequest)
|
||||
if httprequest.mimetype in ("application/json", "application/json-rpc"):
|
||||
return JsonRequest(httprequest)
|
||||
else:
|
||||
@@ -1647,15 +1615,5 @@ def content_disposition(filename):
|
||||
|
||||
return "attachment; filename*=UTF-8''%s" % escaped
|
||||
|
||||
#----------------------------------------------------------
|
||||
# RPC controller
|
||||
#----------------------------------------------------------
|
||||
class CommonController(Controller):
|
||||
|
||||
@route('/gen_session_id', type='json', auth="none")
|
||||
def gen_session_id(self):
|
||||
nsession = root.session_store.new()
|
||||
return nsession.sid
|
||||
|
||||
# main wsgi handler
|
||||
root = Root()
|
||||
|
||||
Reference in New Issue
Block a user