~ubuntu-branches/ubuntu/trusty/python-boto/trusty

« back to all changes in this revision

Viewing changes to boto/fps/connection.py

  • Committer: Package Import Robot
  • Author(s): Eric Evans
  • Date: 2011-11-13 11:58:40 UTC
  • mfrom: (14.1.1 experimental)
  • Revision ID: package-import@ubuntu.com-20111113115840-ckzyt3h17uh8s41y
Tags: 2.0-2
Promote new upstream to unstable (Closes: #638931).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (c) 2008 Chris Moyer http://coredumped.org/
 
2
# Copyringt (c) 2010 Jason R. Coombs http://www.jaraco.com/
2
3
#
3
4
# Permission is hereby granted, free of charge, to any person obtaining a
4
5
# copy of this software and associated documentation files (the
19
20
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20
21
# IN THE SOFTWARE.
21
22
 
 
23
import base64
 
24
import hmac
 
25
import hashlib
22
26
import urllib
23
27
import xml.sax
24
28
import uuid
25
29
import boto
26
30
import boto.utils
27
 
import urllib
28
31
from boto import handler
29
32
from boto.connection import AWSQueryConnection
30
33
from boto.resultset import ResultSet
32
35
 
33
36
class FPSConnection(AWSQueryConnection):
34
37
 
35
 
        APIVersion = '2007-01-08'
36
 
        SignatureVersion = '1'
37
 
 
38
 
        def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
39
 
                                                is_secure=True, port=None, proxy=None, proxy_port=None,
40
 
                                                host='fps.sandbox.amazonaws.com', debug=0,
41
 
                                                https_connection_factory=None):
42
 
                AWSQueryConnection.__init__(self, aws_access_key_id,
43
 
                                                                                                aws_secret_access_key,
44
 
                                                                                                is_secure, port, proxy, proxy_port,
45
 
                                                                                                host, debug, https_connection_factory)
46
 
        
47
 
        def install_payment_instruction(self, instruction, token_type="Unrestricted", transaction_id=None):
48
 
                """
49
 
                InstallPaymentInstruction
50
 
                instruction: The PaymentInstruction to send, for example: 
51
 
                
52
 
                        MyRole=='Caller' orSay 'Roles do not match';
53
 
                
54
 
                token_type: Defaults to "Unrestricted"
55
 
                transaction_id: Defaults to a new ID
56
 
                """
57
 
 
58
 
                if(transaction_id == None):
59
 
                        transaction_id = uuid.uuid4()
60
 
                params = {}
61
 
                params['PaymentInstruction'] = instruction
62
 
                params['TokenType'] = token_type
63
 
                params['CallerReference'] = transaction_id
64
 
                response = self.make_request("InstallPaymentInstruction", params)
65
 
                return response
66
 
        
67
 
        def install_caller_instruction(self, token_type="Unrestricted", transaction_id=None):
68
 
                """
69
 
                Set us up as a caller
70
 
                This will install a new caller_token into the FPS section.
71
 
                This should really only be called to regenerate the caller token.
72
 
                """
73
 
                response = self.install_payment_instruction("MyRole=='Caller';", token_type=token_type, transaction_id=transaction_id)
74
 
                body = response.read()
75
 
                if(response.status == 200):
76
 
                        rs = ResultSet()
77
 
                        h = handler.XmlHandler(rs, self)
78
 
                        xml.sax.parseString(body, h)
79
 
                        caller_token = rs.TokenId
80
 
                        try:
81
 
                                boto.config.save_system_option("FPS", "caller_token", caller_token)
82
 
                        except(IOError):
83
 
                                boto.config.save_user_option("FPS", "caller_token", caller_token)
84
 
                        return caller_token
85
 
                else:
86
 
                        raise FPSResponseError(response.status, respons.reason, body)
87
 
 
88
 
        def install_recipient_instruction(self, token_type="Unrestricted", transaction_id=None):
89
 
                """
90
 
                Set us up as a Recipient
91
 
                This will install a new caller_token into the FPS section.
92
 
                This should really only be called to regenerate the recipient token.
93
 
                """
94
 
                response = self.install_payment_instruction("MyRole=='Recipient';", token_type=token_type, transaction_id=transaction_id)
95
 
                body = response.read()
96
 
                if(response.status == 200):
97
 
                        rs = ResultSet()
98
 
                        h = handler.XmlHandler(rs, self)
99
 
                        xml.sax.parseString(body, h)
100
 
                        recipient_token = rs.TokenId
101
 
                        try:
102
 
                                boto.config.save_system_option("FPS", "recipient_token", recipient_token)
103
 
                        except(IOError):
104
 
                                boto.config.save_user_option("FPS", "recipient_token", recipient_token)
105
 
 
106
 
                        return recipient_token
107
 
                else:
108
 
                        raise FPSResponseError(response.status, respons.reason, body)
109
 
 
110
 
        def make_url(self, returnURL, paymentReason, pipelineName, **params):
111
 
                """
112
 
                Generate the URL with the signature required for a transaction
113
 
                """
114
 
                params['callerKey'] = str(self.aws_access_key_id)
115
 
                params['returnURL'] = str(returnURL)
116
 
                params['paymentReason'] = str(paymentReason)
117
 
                params['pipelineName'] = pipelineName
118
 
 
119
 
                if(not params.has_key('callerReference')):
120
 
                        params['callerReference'] = str(uuid.uuid4())
121
 
 
122
 
                url = ""
123
 
                keys = params.keys()
124
 
                keys.sort()
125
 
                for k in keys:
126
 
                        url += "&%s=%s" % (k, urllib.quote_plus(str(params[k])))
127
 
 
128
 
                url = "/cobranded-ui/actions/start?%s" % ( url[1:])
129
 
                signature= boto.utils.encode(self.aws_secret_access_key, url, True)
130
 
                return "https://authorize.payments-sandbox.amazon.com%s&awsSignature=%s" % (url, signature)
131
 
 
132
 
        def make_payment(self, amount, sender_token, charge_fee_to="Recipient", reference=None, senderReference=None, recipientReference=None, senderDescription=None, recipientDescription=None, callerDescription=None, metadata=None, transactionDate=None):
133
 
                """
134
 
                Make a payment transaction
135
 
                You must specify the amount and the sender token.
136
 
                """
137
 
                params = {}
138
 
                params['RecipientTokenId'] = boto.config.get("FPS", "recipient_token")
139
 
                params['CallerTokenId'] = boto.config.get("FPS", "caller_token")
140
 
                params['SenderTokenId'] = sender_token
141
 
                params['TransactionAmount.Amount'] = str(amount)
142
 
                params['TransactionAmount.CurrencyCode'] = "USD"
143
 
                params['ChargeFeeTo'] = charge_fee_to
144
 
 
145
 
                if(transactionDate != None):
146
 
                        params['TransactionDate'] = transactionDate
147
 
                if(senderReference != None):
148
 
                        params['SenderReference'] = senderReference
149
 
                if(recipientReference != None):
150
 
                        params['RecipientReference'] = recipientReference
151
 
                if(senderDescription != None):
152
 
                        params['SenderDescription'] = senderDescription
153
 
                if(recipientDescription != None):
154
 
                        params['RecipientDescription'] = recipientDescription
155
 
                if(callerDescription != None):
156
 
                        params['CallerDescription'] = callerDescription
157
 
                if(metadata != None):
158
 
                        params['MetaData'] = metadata
159
 
                if(transactionDate != None):
160
 
                        params['TransactionDate'] = transactionDate
161
 
                if(reference == None):
162
 
                        reference = uuid.uuid4()
163
 
                params['CallerReference'] = reference
164
 
 
165
 
                response = self.make_request("Pay", params)
166
 
                body = response.read()
167
 
                if(response.status == 200):
168
 
                        rs = ResultSet()
169
 
                        h = handler.XmlHandler(rs, self)
170
 
                        xml.sax.parseString(body, h)
171
 
                        return rs
172
 
                else:
173
 
                        raise FPSResponseError(response.status, response.reason, body)
 
38
    APIVersion = '2007-01-08'
 
39
 
 
40
    def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
 
41
                 is_secure=True, port=None, proxy=None, proxy_port=None,
 
42
                 proxy_user=None, proxy_pass=None,
 
43
                 host='fps.sandbox.amazonaws.com', debug=0,
 
44
                 https_connection_factory=None, path="/"):
 
45
        AWSQueryConnection.__init__(self, aws_access_key_id, aws_secret_access_key,
 
46
                                    is_secure, port, proxy, proxy_port,
 
47
                                    proxy_user, proxy_pass, host, debug,
 
48
                                    https_connection_factory, path)
 
49
    
 
50
    def _required_auth_capability(self):
 
51
        return ['fps']
 
52
 
 
53
    def install_payment_instruction(self, instruction, token_type="Unrestricted", transaction_id=None):
 
54
        """
 
55
        InstallPaymentInstruction
 
56
        instruction: The PaymentInstruction to send, for example: 
 
57
        
 
58
            MyRole=='Caller' orSay 'Roles do not match';
 
59
        
 
60
        token_type: Defaults to "Unrestricted"
 
61
        transaction_id: Defaults to a new ID
 
62
        """
 
63
 
 
64
        if(transaction_id == None):
 
65
            transaction_id = uuid.uuid4()
 
66
        params = {}
 
67
        params['PaymentInstruction'] = instruction
 
68
        params['TokenType'] = token_type
 
69
        params['CallerReference'] = transaction_id
 
70
        response = self.make_request("InstallPaymentInstruction", params)
 
71
        return response
 
72
    
 
73
    def install_caller_instruction(self, token_type="Unrestricted", transaction_id=None):
 
74
        """
 
75
        Set us up as a caller
 
76
        This will install a new caller_token into the FPS section.
 
77
        This should really only be called to regenerate the caller token.
 
78
        """
 
79
        response = self.install_payment_instruction("MyRole=='Caller';", token_type=token_type, transaction_id=transaction_id)
 
80
        body = response.read()
 
81
        if(response.status == 200):
 
82
            rs = ResultSet()
 
83
            h = handler.XmlHandler(rs, self)
 
84
            xml.sax.parseString(body, h)
 
85
            caller_token = rs.TokenId
 
86
            try:
 
87
                boto.config.save_system_option("FPS", "caller_token", caller_token)
 
88
            except(IOError):
 
89
                boto.config.save_user_option("FPS", "caller_token", caller_token)
 
90
            return caller_token
 
91
        else:
 
92
            raise FPSResponseError(response.status, response.reason, body)
 
93
 
 
94
    def install_recipient_instruction(self, token_type="Unrestricted", transaction_id=None):
 
95
        """
 
96
        Set us up as a Recipient
 
97
        This will install a new caller_token into the FPS section.
 
98
        This should really only be called to regenerate the recipient token.
 
99
        """
 
100
        response = self.install_payment_instruction("MyRole=='Recipient';", token_type=token_type, transaction_id=transaction_id)
 
101
        body = response.read()
 
102
        if(response.status == 200):
 
103
            rs = ResultSet()
 
104
            h = handler.XmlHandler(rs, self)
 
105
            xml.sax.parseString(body, h)
 
106
            recipient_token = rs.TokenId
 
107
            try:
 
108
                boto.config.save_system_option("FPS", "recipient_token", recipient_token)
 
109
            except(IOError):
 
110
                boto.config.save_user_option("FPS", "recipient_token", recipient_token)
 
111
 
 
112
            return recipient_token
 
113
        else:
 
114
            raise FPSResponseError(response.status, response.reason, body)
 
115
 
 
116
    def make_marketplace_registration_url(self, returnURL, pipelineName, maxFixedFee=0.0, maxVariableFee=0.0, recipientPaysFee=True, **params):  
 
117
        """
 
118
        Generate the URL with the signature required for signing up a recipient
 
119
        """
 
120
        # use the sandbox authorization endpoint if we're using the
 
121
        #  sandbox for API calls.
 
122
        endpoint_host = 'authorize.payments.amazon.com'
 
123
        if 'sandbox' in self.host:
 
124
            endpoint_host = 'authorize.payments-sandbox.amazon.com'
 
125
        base = "/cobranded-ui/actions/start"
 
126
 
 
127
        params['callerKey'] = str(self.aws_access_key_id)
 
128
        params['returnURL'] = str(returnURL)
 
129
        params['pipelineName'] = str(pipelineName)
 
130
        params['maxFixedFee'] = str(maxFixedFee)
 
131
        params['maxVariableFee'] = str(maxVariableFee)
 
132
        params['recipientPaysFee'] = str(recipientPaysFee)
 
133
        params["signatureMethod"] = 'HmacSHA256'
 
134
        params["signatureVersion"] = '2'
 
135
 
 
136
        if(not params.has_key('callerReference')):
 
137
            params['callerReference'] = str(uuid.uuid4())
 
138
 
 
139
        parts = ''
 
140
        for k in sorted(params.keys()):
 
141
            parts += "&%s=%s" % (k, urllib.quote(params[k], '~'))
 
142
 
 
143
        canonical = '\n'.join(['GET',
 
144
                               str(endpoint_host).lower(),
 
145
                               base,
 
146
                               parts[1:]])
 
147
 
 
148
        signature = self._auth_handler.sign_string(canonical)
 
149
        params["signature"] = signature
 
150
 
 
151
        urlsuffix = ''
 
152
        for k in sorted(params.keys()):
 
153
            urlsuffix += "&%s=%s" % (k, urllib.quote(params[k], '~'))
 
154
        urlsuffix = urlsuffix[1:] # strip the first &
 
155
        
 
156
        fmt = "https://%(endpoint_host)s%(base)s?%(urlsuffix)s"
 
157
        final = fmt % vars()
 
158
        return final
 
159
 
 
160
 
 
161
    def make_url(self, returnURL, paymentReason, pipelineName, transactionAmount, **params):
 
162
        """
 
163
        Generate the URL with the signature required for a transaction
 
164
        """
 
165
        # use the sandbox authorization endpoint if we're using the
 
166
        #  sandbox for API calls.
 
167
        endpoint_host = 'authorize.payments.amazon.com'
 
168
        if 'sandbox' in self.host:
 
169
            endpoint_host = 'authorize.payments-sandbox.amazon.com'
 
170
        base = "/cobranded-ui/actions/start"
 
171
 
 
172
        params['callerKey'] = str(self.aws_access_key_id)
 
173
        params['returnURL'] = str(returnURL)
 
174
        params['paymentReason'] = str(paymentReason)
 
175
        params['pipelineName'] = pipelineName
 
176
        params['transactionAmount'] = transactionAmount
 
177
        params["signatureMethod"] = 'HmacSHA256'
 
178
        params["signatureVersion"] = '2'
 
179
        
 
180
        if(not params.has_key('callerReference')):
 
181
            params['callerReference'] = str(uuid.uuid4())
 
182
 
 
183
        parts = ''
 
184
        for k in sorted(params.keys()):
 
185
            parts += "&%s=%s" % (k, urllib.quote(params[k], '~'))
 
186
 
 
187
        canonical = '\n'.join(['GET',
 
188
                               str(endpoint_host).lower(),
 
189
                               base,
 
190
                               parts[1:]])
 
191
 
 
192
        signature = self._auth_handler.sign_string(canonical)
 
193
        params["signature"] = signature
 
194
 
 
195
        urlsuffix = ''
 
196
        for k in sorted(params.keys()):
 
197
            urlsuffix += "&%s=%s" % (k, urllib.quote(params[k], '~'))
 
198
        urlsuffix = urlsuffix[1:] # strip the first &
 
199
        
 
200
        fmt = "https://%(endpoint_host)s%(base)s?%(urlsuffix)s"
 
201
        final = fmt % vars()
 
202
        return final
 
203
 
 
204
    def pay(self, transactionAmount, senderTokenId,
 
205
            recipientTokenId=None, callerTokenId=None,
 
206
            chargeFeeTo="Recipient",
 
207
            callerReference=None, senderReference=None, recipientReference=None,
 
208
            senderDescription=None, recipientDescription=None, callerDescription=None,
 
209
            metadata=None, transactionDate=None, reserve=False):
 
210
        """
 
211
        Make a payment transaction. You must specify the amount.
 
212
        This can also perform a Reserve request if 'reserve' is set to True.
 
213
        """
 
214
        params = {}
 
215
        params['SenderTokenId'] = senderTokenId
 
216
        # this is for 2008-09-17 specification
 
217
        params['TransactionAmount.Amount'] = str(transactionAmount)
 
218
        params['TransactionAmount.CurrencyCode'] = "USD"
 
219
        #params['TransactionAmount'] = str(transactionAmount)
 
220
        params['ChargeFeeTo'] = chargeFeeTo
 
221
        
 
222
        params['RecipientTokenId'] = (
 
223
            recipientTokenId if recipientTokenId is not None
 
224
            else boto.config.get("FPS", "recipient_token")
 
225
            )
 
226
        params['CallerTokenId'] = (
 
227
            callerTokenId if callerTokenId is not None
 
228
            else boto.config.get("FPS", "caller_token")
 
229
            )
 
230
        if(transactionDate != None):
 
231
            params['TransactionDate'] = transactionDate
 
232
        if(senderReference != None):
 
233
            params['SenderReference'] = senderReference
 
234
        if(recipientReference != None):
 
235
            params['RecipientReference'] = recipientReference
 
236
        if(senderDescription != None):
 
237
            params['SenderDescription'] = senderDescription
 
238
        if(recipientDescription != None):
 
239
            params['RecipientDescription'] = recipientDescription
 
240
        if(callerDescription != None):
 
241
            params['CallerDescription'] = callerDescription
 
242
        if(metadata != None):
 
243
            params['MetaData'] = metadata
 
244
        if(callerReference == None):
 
245
            callerReference = uuid.uuid4()
 
246
        params['CallerReference'] = callerReference
 
247
        
 
248
        if reserve:
 
249
            response = self.make_request("Reserve", params)
 
250
        else:
 
251
            response = self.make_request("Pay", params)
 
252
        body = response.read()
 
253
        if(response.status == 200):
 
254
            rs = ResultSet()
 
255
            h = handler.XmlHandler(rs, self)
 
256
            xml.sax.parseString(body, h)
 
257
            return rs
 
258
        else:
 
259
            raise FPSResponseError(response.status, response.reason, body)
 
260
    
 
261
    def get_transaction_status(self, transactionId):
 
262
        """
 
263
        Returns the status of a given transaction.
 
264
        """
 
265
        params = {}
 
266
        params['TransactionId'] = transactionId
 
267
    
 
268
        response = self.make_request("GetTransactionStatus", params)
 
269
        body = response.read()
 
270
        if(response.status == 200):
 
271
            rs = ResultSet()
 
272
            h = handler.XmlHandler(rs, self)
 
273
            xml.sax.parseString(body, h)
 
274
            return rs
 
275
        else:
 
276
            raise FPSResponseError(response.status, response.reason, body)
 
277
    
 
278
    def cancel(self, transactionId, description=None):
 
279
        """
 
280
        Cancels a reserved or pending transaction.
 
281
        """
 
282
        params = {}
 
283
        params['transactionId'] = transactionId
 
284
        if(description != None):
 
285
            params['description'] = description
 
286
        
 
287
        response = self.make_request("Cancel", params)
 
288
        body = response.read()
 
289
        if(response.status == 200):
 
290
            rs = ResultSet()
 
291
            h = handler.XmlHandler(rs, self)
 
292
            xml.sax.parseString(body, h)
 
293
            return rs
 
294
        else:
 
295
            raise FPSResponseError(response.status, response.reason, body)
 
296
    
 
297
    def settle(self, reserveTransactionId, transactionAmount=None):
 
298
        """
 
299
        Charges for a reserved payment.
 
300
        """
 
301
        params = {}
 
302
        params['ReserveTransactionId'] = reserveTransactionId
 
303
        if(transactionAmount != None):
 
304
            params['TransactionAmount'] = transactionAmount
 
305
        
 
306
        response = self.make_request("Settle", params)
 
307
        body = response.read()
 
308
        if(response.status == 200):
 
309
            rs = ResultSet()
 
310
            h = handler.XmlHandler(rs, self)
 
311
            xml.sax.parseString(body, h)
 
312
            return rs
 
313
        else:
 
314
            raise FPSResponseError(response.status, response.reason, body)
 
315
    
 
316
    def refund(self, callerReference, transactionId, refundAmount=None, callerDescription=None):
 
317
        """
 
318
        Refund a transaction. This refunds the full amount by default unless 'refundAmount' is specified.
 
319
        """
 
320
        params = {}
 
321
        params['CallerReference'] = callerReference
 
322
        params['TransactionId'] = transactionId
 
323
        if(refundAmount != None):
 
324
            params['RefundAmount'] = refundAmount
 
325
        if(callerDescription != None):
 
326
            params['CallerDescription'] = callerDescription
 
327
        
 
328
        response = self.make_request("Refund", params)
 
329
        body = response.read()
 
330
        if(response.status == 200):
 
331
            rs = ResultSet()
 
332
            h = handler.XmlHandler(rs, self)
 
333
            xml.sax.parseString(body, h)
 
334
            return rs
 
335
        else:
 
336
            raise FPSResponseError(response.status, response.reason, body)
 
337
    
 
338
    def get_recipient_verification_status(self, recipientTokenId):
 
339
        """
 
340
        Test that the intended recipient has a verified Amazon Payments account.
 
341
        """
 
342
        params ={}
 
343
        params['RecipientTokenId'] = recipientTokenId
 
344
        
 
345
        response = self.make_request("GetRecipientVerificationStatus", params)
 
346
        body = response.read()
 
347
        if(response.status == 200):
 
348
            rs = ResultSet()
 
349
            h = handler.XmlHandler(rs, self)
 
350
            xml.sax.parseString(body, h)
 
351
            return rs
 
352
        else:
 
353
            raise FPSResponseError(response.status, response.reason, body)
 
354
    
 
355
    def get_token_by_caller_reference(self, callerReference):
 
356
        """
 
357
        Returns details about the token specified by 'callerReference'.
 
358
        """
 
359
        params ={}
 
360
        params['callerReference'] = callerReference
 
361
        
 
362
        response = self.make_request("GetTokenByCaller", params)
 
363
        body = response.read()
 
364
        if(response.status == 200):
 
365
            rs = ResultSet()
 
366
            h = handler.XmlHandler(rs, self)
 
367
            xml.sax.parseString(body, h)
 
368
            return rs
 
369
        else:
 
370
            raise FPSResponseError(response.status, response.reason, body)
 
371
    def get_token_by_caller_token(self, tokenId):
 
372
        """
 
373
        Returns details about the token specified by 'callerReference'.
 
374
        """
 
375
        params ={}
 
376
        params['TokenId'] = tokenId
 
377
        
 
378
        response = self.make_request("GetTokenByCaller", params)
 
379
        body = response.read()
 
380
        if(response.status == 200):
 
381
            rs = ResultSet()
 
382
            h = handler.XmlHandler(rs, self)
 
383
            xml.sax.parseString(body, h)
 
384
            return rs
 
385
        else:
 
386
            raise FPSResponseError(response.status, response.reason, body)
 
387
 
 
388
    def verify_signature(self, end_point_url, http_parameters):
 
389
        params = dict(
 
390
            UrlEndPoint = end_point_url,
 
391
            HttpParameters = http_parameters,
 
392
            )
 
393
        response = self.make_request("VerifySignature", params)
 
394
        body = response.read()
 
395
        if(response.status != 200):
 
396
            raise FPSResponseError(response.status, response.reason, body)
 
397
        rs = ResultSet()
 
398
        h = handler.XmlHandler(rs, self)
 
399
        xml.sax.parseString(body, h)
 
400
        return rs