コード例 #1
0
def _check_special_access(res_model, res_id, token='', _hash='', pid=False):
    record = request.env[res_model].browse(res_id).sudo()
    if token:  # Token Case: token is the global one of the document
        token_field = request.env[res_model]._mail_post_token_field
        return (token and record and consteq(record[token_field], token))
    elif _hash and pid:  # Signed Token Case: hash implies token is signed by partner pid
        return consteq(_hash, record._sign_token(pid))
    else:
        raise Forbidden()
コード例 #2
0
    def _get_record_and_check(self,
                              xmlid=None,
                              model=None,
                              id=None,
                              field='datas',
                              access_token=None):
        # get object and content
        record = None
        if xmlid:
            record = self._xmlid_to_obj(self.env, xmlid)
        elif id and model in self.env:
            record = self.env[model].browse(int(id))

        # obj exists
        if not record or field not in record:
            return None, 404

        try:
            if model == 'ir.attachment':
                record_sudo = record.sudo()
                if access_token and not consteq(record_sudo.access_token or '',
                                                access_token):
                    return None, 403
                elif (access_token and consteq(record_sudo.access_token or '',
                                               access_token)):
                    record = record_sudo
                elif record_sudo.public:
                    record = record_sudo
                elif self.env.user.has_group('base.group_portal'):
                    # Check the read access on the record linked to the attachment
                    # eg: Allow to download an attachment on a task from /my/task/task_id
                    record.check('read')
                    record = record_sudo

            # check read access
            try:
                # We have prefetched some fields of record, among which the field
                # 'write_date' used by '__last_update' below. In order to check
                # access on record, we have to invalidate its cache first.
                if not record.env.su:
                    record._cache.clear()
                record['__last_update']
            except AccessError:
                return None, 403

            return record, 200
        except MissingError:
            return None, 404
コード例 #3
0
 def check_token(self, access_token, partner_id, amount, currency_id):
     secret = self.env['ir.config_parameter'].sudo().get_param('database.secret')
     token_str = '%s%s%s' % (partner_id, amount, currency_id)
     correct_token = hmac.new(secret.encode('utf-8'), token_str.encode('utf-8'), hashlib.sha256).hexdigest()
     if consteq(ustr(access_token), correct_token):
         return True
     return False 
コード例 #4
0
ファイル: main.py プロジェクト: mausvt/flectra
 def _check_token(cls, token):
     base_link = request.httprequest.path
     params = dict(request.params)
     params.pop('token', '')
     valid_token = request.env['mail.thread']._notify_encode_link(
         base_link, params)
     return consteq(valid_token, str(token))
コード例 #5
0
    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
コード例 #6
0
    def _redirect_to_record(cls, model, res_id, access_token=None, **kwargs):
        """ If the current user doesn't have access to the document, but provided
        a valid access token, redirect him to the front-end view.
        If the partner_id and hash parameters are given, add those parameters to the redirect url
        to authentify the recipient in the chatter, if any.

        :param model: the model name of the record that will be visualized
        :param res_id: the id of the record
        :param access_token: token that gives access to the record
            bypassing the rights and rules restriction of the user.
        :param kwargs: Typically, it can receive a partner_id and a hash (sign_token).
            If so, those two parameters are used to authentify the recipient in the chatter, if any.
        :return:
        """
        if issubclass(type(request.env[model]), request.env.registry['portal.mixin']):
            uid = request.session.uid or request.env.ref('base.public_user').id
            record_sudo = request.env[model].sudo().browse(res_id).exists()
            try:
                record_sudo.with_user(uid).check_access_rights('read')
                record_sudo.with_user(uid).check_access_rule('read')
            except AccessError:
                if record_sudo.access_token and access_token and consteq(record_sudo.access_token, access_token):
                    record_action = record_sudo.with_context(force_website=True).get_access_action()
                    if record_action['type'] == 'ir.actions.act_url':
                        pid = kwargs.get('pid')
                        hash = kwargs.get('hash')
                        url = record_action['url']
                        if pid and hash:
                            url = urls.url_parse(url)
                            url_params = url.decode_query()
                            url_params.update([("pid", pid), ("hash", hash)])
                            url = url.replace(query=urls.url_encode(url_params)).to_url()
                        return werkzeug.utils.redirect(url)
        return super(MailController, cls)._redirect_to_record(model, res_id, access_token=access_token)
コード例 #7
0
ファイル: portal.py プロジェクト: sheetal4123/flectra
 def confirm(self, **kw):
     tx_id = int(kw.get('tx_id', 0))
     access_token = kw.get('access_token')
     if tx_id:
         if access_token:
             tx = request.env['payment.transaction'].sudo().browse(tx_id)
             secret = request.env['ir.config_parameter'].sudo().get_param('database.secret')
             valid_token_str = '%s%s%s' % (tx.id, tx.reference, float_repr(tx.amount, precision_digits=tx.currency_id.decimal_places))
             valid_token = hmac.new(secret.encode('utf-8'), valid_token_str.encode('utf-8'), hashlib.sha256).hexdigest()
             if not consteq(ustr(valid_token), access_token):
                 raise werkzeug.exceptions.NotFound
         else:
             tx = request.env['payment.transaction'].browse(tx_id)
         if tx.state in ['done', 'authorized']:
             status = 'success'
             message = tx.acquirer_id.done_msg
         elif tx.state == 'pending':
             status = 'warning'
             message = tx.acquirer_id.pending_msg
         else:
             status = 'danger'
             message = tx.state_message or _('An error occured during the processing of this payment')
         PaymentProcessing.remove_payment_transaction(tx)
         return request.render('payment.confirm', {'tx': tx, 'status': status, 'message': message})
     else:
         return request.redirect('/my/home')
コード例 #8
0
    def _verify_stripe_signature(self):
        """
        :return: true if and only if signature matches hash of payload calculated with secret
        :raises ValidationError: if signature doesn't match
        """
        if not self.stripe_webhook_secret:
            raise ValidationError('webhook event received but webhook secret is not configured')
        signature = request.httprequest.headers.get('Stripe-Signature')
        body = request.httprequest.data

        sign_data = {k: v for (k, v) in [s.split('=') for s in signature.split(',')]}
        event_timestamp = int(sign_data['t'])
        if datetime.utcnow().timestamp() - event_timestamp > STRIPE_SIGNATURE_AGE_TOLERANCE:
            _logger.error('stripe event is too old, event is discarded')
            raise ValidationError('event timestamp older than tolerance')

        signed_payload = "%s.%s" % (event_timestamp, body.decode('utf-8'))

        actual_signature = sign_data['v1']
        expected_signature = hmac.new(self.stripe_webhook_secret.encode('utf-8'),
                                      signed_payload.encode('utf-8'),
                                      sha256).hexdigest()

        if not consteq(expected_signature, actual_signature):
            _logger.error(
                'incorrect webhook signature from Stripe, check if the webhook signature '
                'in Flectra matches to one in the Stripe dashboard')
            raise ValidationError('incorrect webhook signature')

        return True
コード例 #9
0
ファイル: portal.py プロジェクト: westlyou/flectra-1
 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
コード例 #10
0
ファイル: portal.py プロジェクト: devexpat/kouterp
 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
コード例 #11
0
ファイル: portal.py プロジェクト: devexpat/kouterp
 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
コード例 #12
0
ファイル: portal.py プロジェクト: mausvt/flectra
 def _document_check_access(self, model_name, document_id, access_token=None):
     document = request.env[model_name].browse([document_id])
     document_sudo = document.with_user(SUPERUSER_ID).exists()
     if not document_sudo:
         raise MissingError(_("This document does not exist."))
     try:
         document.check_access_rights('read')
         document.check_access_rule('read')
     except AccessError:
         if not access_token or not document_sudo.access_token or not consteq(document_sudo.access_token, access_token):
             raise
     return document_sudo
コード例 #13
0
ファイル: main.py プロジェクト: yemanadep/Flectra
    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')
コード例 #14
0
ファイル: ir_http.py プロジェクト: yemanadep/Flectra
    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)
コード例 #15
0
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))