forked from Mapan/odoo17e
98 lines
3.8 KiB
Python
98 lines
3.8 KiB
Python
import hashlib
|
|
import hmac
|
|
import json
|
|
import logging
|
|
import pprint
|
|
|
|
from werkzeug.exceptions import Forbidden
|
|
from werkzeug.urls import url_encode
|
|
|
|
from odoo import _, http
|
|
from odoo.exceptions import UserError, ValidationError
|
|
from odoo.http import request
|
|
from odoo.tools import hmac as hmac_tool
|
|
|
|
from odoo.addons.sale_amazon import utils as amazon_utils
|
|
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
def compute_oauth_signature(account_id):
|
|
""" Compute a signature for the OAuth flow.
|
|
|
|
:param int account_id: The account being authorized, as an `amazon.account` id.
|
|
:param odoo.api.Environment env: The current environment.
|
|
:return: The computed signature.
|
|
:rtype: str
|
|
"""
|
|
secret = request.env['ir.config_parameter'].sudo().get_param('database.secret')
|
|
message = repr(('amazon_compute_oauth_signature', str(account_id)))
|
|
return hmac_tool(request.env(su=True), secret.encode(), message.encode(), hashlib.sha256)
|
|
|
|
|
|
class AmazonController(http.Controller):
|
|
|
|
@http.route('/amazon/return', type='http', methods=['GET'], auth='user')
|
|
def amazon_return_from_authorization(self, **data):
|
|
""" Request a refresh token from the OAuth token and redirect to the account form.
|
|
|
|
:param dict data: The authorization data provided by Amazon upon redirection, including the
|
|
custom `state` parameter.
|
|
:raise Forbidden: If the received signature does not match the expected signature.
|
|
:raise ValidationError: If the account id does not match any Amazon account.
|
|
"""
|
|
_logger.info("Returning from authorization with data:\n%s", pprint.pformat(data))
|
|
|
|
# Retrieve the Amazon data and Odoo metadata from the redirect data.
|
|
seller_key = data['selling_partner_id']
|
|
authorization_code = data['spapi_oauth_code']
|
|
state = json.loads(data['state'])
|
|
account_id = state['account_id']
|
|
received_signature = state['signature']
|
|
|
|
# Compare the received signature with the expected signature.
|
|
expected_signature = compute_oauth_signature(account_id)
|
|
if not hmac.compare_digest(received_signature, expected_signature):
|
|
_logger.warning("Signature computed from data does not match the expected signature.")
|
|
raise Forbidden()
|
|
|
|
# Store the Amazon data on the account.
|
|
account = request.env['amazon.account'].browse(account_id).exists()
|
|
if not account:
|
|
raise ValidationError(_("Could not find Amazon account with id %s", account_id))
|
|
account.seller_key = seller_key
|
|
|
|
# Craft the URL of the Amazon account.
|
|
account_url = self._compute_account_url(account_id)
|
|
|
|
# Request and set the refresh token on the account and finalize the set up.
|
|
try:
|
|
amazon_utils.exchange_authorization_code(authorization_code, account)
|
|
account.action_update_available_marketplaces()
|
|
except (UserError, ValidationError) as e:
|
|
return request.render(
|
|
'sale_amazon.authorization_error',
|
|
qcontext={'error_message': e['name'], 'account_url': account_url},
|
|
)
|
|
|
|
return request.redirect(account_url, local=False)
|
|
|
|
@staticmethod
|
|
def _compute_account_url(account_id):
|
|
""" Craft the URL of the account's form view.
|
|
|
|
:param int account_id: The account for which the URL must be computed, as an
|
|
`amazon.account` id.
|
|
:return: The URL of the account's form view.
|
|
:rtype: str
|
|
"""
|
|
action = request.env.ref('sale_amazon.list_amazon_account_action', raise_if_not_found=False)
|
|
get_params_string = url_encode({
|
|
'id': account_id,
|
|
'model': 'amazon.account',
|
|
'view_type': 'form',
|
|
'action': action and action.id,
|
|
})
|
|
return f'/web#{get_params_string}'
|