File: transparent_redirect_gateway.py

package info (click to toggle)
python-braintree 3.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,376 kB
  • ctags: 1,998
  • sloc: python: 13,634; makefile: 73; sh: 8
file content (79 lines) | stat: -rw-r--r-- 3,244 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import cgi
from datetime import datetime
import braintree
from braintree.util.crypto import Crypto
from braintree.error_result import ErrorResult
from braintree.exceptions.forged_query_string_error import ForgedQueryStringError
from braintree.util.http import Http
from braintree.signature_service import SignatureService
from braintree.successful_result import SuccessfulResult
from braintree.transparent_redirect import TransparentRedirect

class TransparentRedirectGateway(object):
    def __init__(self, gateway):
        self.gateway = gateway
        self.config = gateway.config

    def confirm(self, query_string):
        """
        Confirms a transparent redirect request. It expects the query string from the
        redirect request. The query string should _not_ include the leading "?" character. ::

            result = braintree.TransparentRedirect.confirm("foo=bar&id=12345")
        """
        parsed_query_string = self._parse_and_validate_query_string(query_string)
        confirmation_gateway = {
            TransparentRedirect.Kind.CreateCustomer: "customer",
            TransparentRedirect.Kind.UpdateCustomer: "customer",
            TransparentRedirect.Kind.CreatePaymentMethod: "credit_card",
            TransparentRedirect.Kind.UpdatePaymentMethod: "credit_card",
            TransparentRedirect.Kind.CreateTransaction: "transaction"
        }[parsed_query_string["kind"][0]]

        return getattr(self.gateway, confirmation_gateway)._post("/transparent_redirect_requests/" + parsed_query_string["id"][0] + "/confirm")

    def tr_data(self, data, redirect_url):
        data = self.__flatten_dictionary(data)
        date_string = datetime.utcnow().strftime("%Y%m%d%H%M%S")
        data["time"] = date_string
        data["redirect_url"] = redirect_url
        data["public_key"] = self.config.public_key
        data["api_version"] = self.config.api_version()

        return SignatureService(self.config.private_key).sign(data)

    def url(self):
        """
        Returns the url for POSTing Transparent Redirect HTML forms
        """
        return self.config.base_merchant_url() + "/transparent_redirect_requests"

    def _parse_and_validate_query_string(self, query_string):
        query_params = cgi.parse_qs(query_string)
        http_status = int(query_params["http_status"][0])
        message = query_params.get("bt_message")
        if message != None:
            message = message[0]

        if Http.is_error_status(http_status):
            Http.raise_exception_from_status(http_status, message)

        if not self._is_valid_tr_query_string(query_string):
            raise ForgedQueryStringError

        return query_params

    def _is_valid_tr_query_string(self, query_string):
        content, hash = query_string.split("&hash=")
        return hash == Crypto.sha1_hmac_hash(self.config.private_key, content)

    def __flatten_dictionary(self, params, parent=None):
        data = {}
        for key, val in params.items():
            full_key = parent + "[" + key + "]" if parent else key
            if isinstance(val, dict):
                data.update(self.__flatten_dictionary(val, full_key))
            else:
                data[full_key] = val
        return data