def _check_token(cls, token): base_link = request.httprequest.path params = dict(request.params) params.pop('token', '') valid_token = request.env['mail.thread']._generate_notification_token( base_link, params) return consteq(valid_token, str(token))
def execute_callback(self): res = None for transaction in self: # limited sudo env, only for checking callback presence, not for running it! # manual transactions have no callback, and can pass without being run by admin user tx_sudo = transaction.sudo() if not (tx_sudo.callback_model_id and tx_sudo.callback_res_id and tx_sudo.callback_method): continue valid_token = transaction._generate_callback_hash() if not consteq(ustr(valid_token), transaction.callback_hash): _logger.warning( "Invalid callback signature for transaction %d" % (transaction.id)) continue record = self.env[transaction.callback_model_id.model].browse( transaction.callback_res_id).exists() if record: res = getattr(record, transaction.callback_method)(transaction) else: _logger.warning( "Did not found record %s.%s for callback of transaction %d" % (transaction.callback_model_id.model, transaction.callback_res_id, transaction.id)) return res
def _invoice_check_access(self, invoice_id, access_token=None): invoice = request.env['account.invoice'].browse([invoice_id]) invoice_sudo = invoice.sudo() try: invoice.check_access_rights('read') invoice.check_access_rule('read') except AccessError: if not access_token or not consteq(invoice_sudo.access_token, access_token): raise return invoice_sudo
def _order_check_access(self, order_id, access_token=None): order = request.env['sale.order'].browse([order_id]) order_sudo = order.sudo() try: order.check_access_rights('read') order.check_access_rule('read') except AccessError: if not access_token or not consteq(order_sudo.access_token, access_token): raise return order_sudo
def _stock_picking_check_access(self, picking_id, access_token=None): picking = request.env['stock.picking'].browse([picking_id]) picking_sudo = picking.sudo() try: picking.check_access_rights('read') picking.check_access_rule('read') except exceptions.AccessError: if not access_token or not consteq( picking_sudo.sale_id.access_token, access_token): raise return picking_sudo
def mailing(self, mailing_id, email=None, res_id=None, token="", **post): mailing = request.env['mail.mass_mailing'].sudo().browse(mailing_id) if mailing.exists(): res_id = res_id and int(res_id) res_ids = [] if mailing.mailing_model_name == 'mail.mass_mailing.list': contacts = request.env['mail.mass_mailing.contact'].sudo().search([ ('email', '=', email), ('list_ids', 'in', [mailing_list.id for mailing_list in mailing.contact_list_ids]) ]) res_ids = contacts.ids else: res_ids = [res_id] right_token = mailing._unsubscribe_token(res_id, email) if not consteq(str(token), right_token): raise exceptions.AccessDenied() mailing.update_opt_out(email, res_ids, True) return _('You have been unsubscribed successfully')
def _has_token_access(res_model, res_id, token=''): record = request.env[res_model].browse(res_id).sudo() token_field = request.env[res_model]._mail_post_token_field return (token and record and consteq(record[token_field], token))
def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas', unique=False, filename=None, filename_field='datas_fname', download=False, mimetype=None, default_mimetype='application/octet-stream', access_token=None, env=None): """ Get file, attachment or downloadable content If the ``xmlid`` and ``id`` parameter is omitted, fetches the default value for the binary field (via ``default_get``), otherwise fetches the field for that precise record. :param str xmlid: xmlid of the record :param str model: name of the model to fetch the binary from :param int id: id of the record from which to fetch the binary :param str field: binary field :param bool unique: add a max-age for the cache control :param str filename: choose a filename :param str filename_field: if not create an filename with model-id-field :param bool download: apply headers to download the file :param str mimetype: mintype of the field (for headers) :param str default_mimetype: default mintype if no mintype found :param str access_token: optional token for unauthenticated access only available for ir.attachment :param Environment env: by default use request.env :returns: (status, headers, content) """ env = env or request.env # get object and content obj = None if xmlid: obj = env.ref(xmlid, False) elif id and model == 'ir.attachment' and access_token: obj = env[model].sudo().browse(int(id)) if not consteq(obj.access_token, access_token): return (403, [], None) elif id and model in env.registry: obj = env[model].browse(int(id)) # obj exists if not obj or not obj.exists() or field not in obj: return (404, [], None) # check read access try: last_update = obj['__last_update'] except AccessError: return (403, [], None) status, headers, content = None, [], None # attachment by url check module_resource_path = None if model == 'ir.attachment' and obj.type == 'url' and obj.url: url_match = re.match("^/(\w+)/(.+)$", obj.url) if url_match: module = url_match.group(1) module_path = get_module_path(module) module_resource_path = get_resource_path(module, url_match.group(2)) if module_path and module_resource_path: module_path = os.path.join(os.path.normpath(module_path), '') # join ensures the path ends with '/' module_resource_path = os.path.normpath(module_resource_path) if module_resource_path.startswith(module_path): with open(module_resource_path, 'rb') as f: content = base64.b64encode(f.read()) last_update = pycompat.text_type(os.path.getmtime(module_resource_path)) if not module_resource_path: module_resource_path = obj.url if not content: status = 301 content = module_resource_path else: content = obj[field] or '' # filename if not filename: if filename_field in obj: filename = obj[filename_field] elif module_resource_path: filename = os.path.basename(module_resource_path) else: filename = "%s-%s-%s" % (obj._name, obj.id, field) # mimetype mimetype = 'mimetype' in obj and obj.mimetype or False if not mimetype: if filename: mimetype = mimetypes.guess_type(filename)[0] if not mimetype and getattr(env[model]._fields[field], 'attachment', False): # for binary fields, fetch the ir_attachement for mimetype check attach_mimetype = env['ir.attachment'].search_read(domain=[('res_model', '=', model), ('res_id', '=', id), ('res_field', '=', field)], fields=['mimetype'], limit=1) mimetype = attach_mimetype and attach_mimetype[0]['mimetype'] if not mimetype: mimetype = guess_mimetype(base64.b64decode(content), default=default_mimetype) headers += [('Content-Type', mimetype), ('X-Content-Type-Options', 'nosniff')] # cache etag = bool(request) and request.httprequest.headers.get('If-None-Match') retag = '"%s"' % hashlib.md5(pycompat.to_text(content).encode('utf-8')).hexdigest() status = status or (304 if etag == retag else 200) headers.append(('ETag', retag)) headers.append(('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0))) # content-disposition default name if download: headers.append(('Content-Disposition', cls.content_disposition(filename))) return (status, headers, content)