| OLD | NEW |
| 1 # Copyright (c) 2008 Chris Moyer http://coredumped.org/ | 1 # Copyright (c) 2008 Chris Moyer http://coredumped.org/ |
| 2 # Copyringt (c) 2010 Jason R. Coombs http://www.jaraco.com/ | 2 # Copyringt (c) 2010 Jason R. Coombs http://www.jaraco.com/ |
| 3 # | 3 # |
| 4 # Permission is hereby granted, free of charge, to any person obtaining a | 4 # Permission is hereby granted, free of charge, to any person obtaining a |
| 5 # copy of this software and associated documentation files (the | 5 # copy of this software and associated documentation files (the |
| 6 # "Software"), to deal in the Software without restriction, including | 6 # "Software"), to deal in the Software without restriction, including |
| 7 # without limitation the rights to use, copy, modify, merge, publish, dis- | 7 # without limitation the rights to use, copy, modify, merge, publish, dis- |
| 8 # tribute, sublicense, and/or sell copies of the Software, and to permit | 8 # tribute, sublicense, and/or sell copies of the Software, and to permit |
| 9 # persons to whom the Software is furnished to do so, subject to the fol- | 9 # persons to whom the Software is furnished to do so, subject to the fol- |
| 10 # lowing conditions: | 10 # lowing conditions: |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 | 35 |
| 36 class FPSConnection(AWSQueryConnection): | 36 class FPSConnection(AWSQueryConnection): |
| 37 | 37 |
| 38 APIVersion = '2007-01-08' | 38 APIVersion = '2007-01-08' |
| 39 | 39 |
| 40 def __init__(self, aws_access_key_id=None, aws_secret_access_key=None, | 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, | 41 is_secure=True, port=None, proxy=None, proxy_port=None, |
| 42 proxy_user=None, proxy_pass=None, | 42 proxy_user=None, proxy_pass=None, |
| 43 host='fps.sandbox.amazonaws.com', debug=0, | 43 host='fps.sandbox.amazonaws.com', debug=0, |
| 44 https_connection_factory=None, path="/"): | 44 https_connection_factory=None, path="/"): |
| 45 AWSQueryConnection.__init__(self, aws_access_key_id, aws_secret_access_k
ey, | 45 AWSQueryConnection.__init__(self, aws_access_key_id, |
| 46 aws_secret_access_key, |
| 46 is_secure, port, proxy, proxy_port, | 47 is_secure, port, proxy, proxy_port, |
| 47 proxy_user, proxy_pass, host, debug, | 48 proxy_user, proxy_pass, host, debug, |
| 48 https_connection_factory, path) | 49 https_connection_factory, path) |
| 49 | 50 |
| 50 def _required_auth_capability(self): | 51 def _required_auth_capability(self): |
| 51 return ['fps'] | 52 return ['fps'] |
| 52 | 53 |
| 53 def install_payment_instruction(self, instruction, token_type="Unrestricted"
, transaction_id=None): | 54 def install_payment_instruction(self, instruction, |
| 55 token_type="Unrestricted", |
| 56 transaction_id=None): |
| 54 """ | 57 """ |
| 55 InstallPaymentInstruction | 58 InstallPaymentInstruction |
| 56 instruction: The PaymentInstruction to send, for example: | 59 instruction: The PaymentInstruction to send, for example: |
| 57 | 60 |
| 58 MyRole=='Caller' orSay 'Roles do not match'; | 61 MyRole=='Caller' orSay 'Roles do not match'; |
| 59 | 62 |
| 60 token_type: Defaults to "Unrestricted" | 63 token_type: Defaults to "Unrestricted" |
| 61 transaction_id: Defaults to a new ID | 64 transaction_id: Defaults to a new ID |
| 62 """ | 65 """ |
| 63 | 66 |
| 64 if(transaction_id == None): | 67 if(transaction_id == None): |
| 65 transaction_id = uuid.uuid4() | 68 transaction_id = uuid.uuid4() |
| 66 params = {} | 69 params = {} |
| 67 params['PaymentInstruction'] = instruction | 70 params['PaymentInstruction'] = instruction |
| 68 params['TokenType'] = token_type | 71 params['TokenType'] = token_type |
| 69 params['CallerReference'] = transaction_id | 72 params['CallerReference'] = transaction_id |
| 70 response = self.make_request("InstallPaymentInstruction", params) | 73 response = self.make_request("InstallPaymentInstruction", params) |
| 71 return response | 74 return response |
| 72 | 75 |
| 73 def install_caller_instruction(self, token_type="Unrestricted", transaction_
id=None): | 76 def install_caller_instruction(self, token_type="Unrestricted", |
| 77 transaction_id=None): |
| 74 """ | 78 """ |
| 75 Set us up as a caller | 79 Set us up as a caller |
| 76 This will install a new caller_token into the FPS section. | 80 This will install a new caller_token into the FPS section. |
| 77 This should really only be called to regenerate the caller token. | 81 This should really only be called to regenerate the caller token. |
| 78 """ | 82 """ |
| 79 response = self.install_payment_instruction("MyRole=='Caller';", token_t
ype=token_type, transaction_id=transaction_id) | 83 response = self.install_payment_instruction("MyRole=='Caller';", |
| 84 token_type=token_type, |
| 85 transaction_id=transaction_i
d) |
| 80 body = response.read() | 86 body = response.read() |
| 81 if(response.status == 200): | 87 if(response.status == 200): |
| 82 rs = ResultSet() | 88 rs = ResultSet() |
| 83 h = handler.XmlHandler(rs, self) | 89 h = handler.XmlHandler(rs, self) |
| 84 xml.sax.parseString(body, h) | 90 xml.sax.parseString(body, h) |
| 85 caller_token = rs.TokenId | 91 caller_token = rs.TokenId |
| 86 try: | 92 try: |
| 87 boto.config.save_system_option("FPS", "caller_token", caller_tok
en) | 93 boto.config.save_system_option("FPS", "caller_token", |
| 94 caller_token) |
| 88 except(IOError): | 95 except(IOError): |
| 89 boto.config.save_user_option("FPS", "caller_token", caller_token
) | 96 boto.config.save_user_option("FPS", "caller_token", |
| 97 caller_token) |
| 90 return caller_token | 98 return caller_token |
| 91 else: | 99 else: |
| 92 raise FPSResponseError(response.status, response.reason, body) | 100 raise FPSResponseError(response.status, response.reason, body) |
| 93 | 101 |
| 94 def install_recipient_instruction(self, token_type="Unrestricted", transacti
on_id=None): | 102 def install_recipient_instruction(self, token_type="Unrestricted", |
| 103 transaction_id=None): |
| 95 """ | 104 """ |
| 96 Set us up as a Recipient | 105 Set us up as a Recipient |
| 97 This will install a new caller_token into the FPS section. | 106 This will install a new caller_token into the FPS section. |
| 98 This should really only be called to regenerate the recipient token. | 107 This should really only be called to regenerate the recipient token. |
| 99 """ | 108 """ |
| 100 response = self.install_payment_instruction("MyRole=='Recipient';", toke
n_type=token_type, transaction_id=transaction_id) | 109 response = self.install_payment_instruction("MyRole=='Recipient';", |
| 110 token_type=token_type, |
| 111 transaction_id=transaction_i
d) |
| 101 body = response.read() | 112 body = response.read() |
| 102 if(response.status == 200): | 113 if(response.status == 200): |
| 103 rs = ResultSet() | 114 rs = ResultSet() |
| 104 h = handler.XmlHandler(rs, self) | 115 h = handler.XmlHandler(rs, self) |
| 105 xml.sax.parseString(body, h) | 116 xml.sax.parseString(body, h) |
| 106 recipient_token = rs.TokenId | 117 recipient_token = rs.TokenId |
| 107 try: | 118 try: |
| 108 boto.config.save_system_option("FPS", "recipient_token", recipie
nt_token) | 119 boto.config.save_system_option("FPS", "recipient_token", |
| 120 recipient_token) |
| 109 except(IOError): | 121 except(IOError): |
| 110 boto.config.save_user_option("FPS", "recipient_token", recipient
_token) | 122 boto.config.save_user_option("FPS", "recipient_token", |
| 123 recipient_token) |
| 111 | 124 |
| 112 return recipient_token | 125 return recipient_token |
| 113 else: | 126 else: |
| 114 raise FPSResponseError(response.status, response.reason, body) | 127 raise FPSResponseError(response.status, response.reason, body) |
| 115 | 128 |
| 116 def make_url(self, returnURL, paymentReason, pipelineName, transactionAmount
, **params): | 129 def make_marketplace_registration_url(self, returnURL, pipelineName, |
| 130 maxFixedFee=0.0, maxVariableFee=0.0, |
| 131 recipientPaysFee=True, **params): |
| 117 """ | 132 """ |
| 118 Generate the URL with the signature required for a transaction | 133 Generate the URL with the signature required for signing up a recipient |
| 119 """ | 134 """ |
| 120 # use the sandbox authorization endpoint if we're using the | 135 # use the sandbox authorization endpoint if we're using the |
| 121 # sandbox for API calls. | 136 # sandbox for API calls. |
| 122 endpoint_host = 'authorize.payments.amazon.com' | 137 endpoint_host = 'authorize.payments.amazon.com' |
| 123 if 'sandbox' in self.host: | 138 if 'sandbox' in self.host: |
| 124 endpoint_host = 'authorize.payments-sandbox.amazon.com' | 139 endpoint_host = 'authorize.payments-sandbox.amazon.com' |
| 125 base = "/cobranded-ui/actions/start" | 140 base = "/cobranded-ui/actions/start" |
| 126 | 141 |
| 142 params['callerKey'] = str(self.aws_access_key_id) |
| 143 params['returnURL'] = str(returnURL) |
| 144 params['pipelineName'] = str(pipelineName) |
| 145 params['maxFixedFee'] = str(maxFixedFee) |
| 146 params['maxVariableFee'] = str(maxVariableFee) |
| 147 params['recipientPaysFee'] = str(recipientPaysFee) |
| 148 params["signatureMethod"] = 'HmacSHA256' |
| 149 params["signatureVersion"] = '2' |
| 150 |
| 151 if(not params.has_key('callerReference')): |
| 152 params['callerReference'] = str(uuid.uuid4()) |
| 153 |
| 154 parts = '' |
| 155 for k in sorted(params.keys()): |
| 156 parts += "&%s=%s" % (k, urllib.quote(params[k], '~')) |
| 157 |
| 158 canonical = '\n'.join(['GET', |
| 159 str(endpoint_host).lower(), |
| 160 base, |
| 161 parts[1:]]) |
| 162 |
| 163 signature = self._auth_handler.sign_string(canonical) |
| 164 params["signature"] = signature |
| 165 |
| 166 urlsuffix = '' |
| 167 for k in sorted(params.keys()): |
| 168 urlsuffix += "&%s=%s" % (k, urllib.quote(params[k], '~')) |
| 169 urlsuffix = urlsuffix[1:] # strip the first & |
| 170 |
| 171 fmt = "https://%(endpoint_host)s%(base)s?%(urlsuffix)s" |
| 172 final = fmt % vars() |
| 173 return final |
| 174 |
| 175 |
| 176 def make_url(self, returnURL, paymentReason, pipelineName, |
| 177 transactionAmount, **params): |
| 178 """ |
| 179 Generate the URL with the signature required for a transaction |
| 180 """ |
| 181 # use the sandbox authorization endpoint if we're using the |
| 182 # sandbox for API calls. |
| 183 endpoint_host = 'authorize.payments.amazon.com' |
| 184 if 'sandbox' in self.host: |
| 185 endpoint_host = 'authorize.payments-sandbox.amazon.com' |
| 186 base = "/cobranded-ui/actions/start" |
| 127 | 187 |
| 128 params['callerKey'] = str(self.aws_access_key_id) | 188 params['callerKey'] = str(self.aws_access_key_id) |
| 129 params['returnURL'] = str(returnURL) | 189 params['returnURL'] = str(returnURL) |
| 130 params['paymentReason'] = str(paymentReason) | 190 params['paymentReason'] = str(paymentReason) |
| 131 params['pipelineName'] = pipelineName | 191 params['pipelineName'] = pipelineName |
| 192 params['transactionAmount'] = transactionAmount |
| 132 params["signatureMethod"] = 'HmacSHA256' | 193 params["signatureMethod"] = 'HmacSHA256' |
| 133 params["signatureVersion"] = '2' | 194 params["signatureVersion"] = '2' |
| 134 params["transactionAmount"] = transactionAmount | 195 |
| 135 | |
| 136 if(not params.has_key('callerReference')): | 196 if(not params.has_key('callerReference')): |
| 137 params['callerReference'] = str(uuid.uuid4()) | 197 params['callerReference'] = str(uuid.uuid4()) |
| 138 | 198 |
| 139 parts = '' | 199 parts = '' |
| 140 for k in sorted(params.keys()): | 200 for k in sorted(params.keys()): |
| 141 parts += "&%s=%s" % (k, urllib.quote(params[k], '~')) | 201 parts += "&%s=%s" % (k, urllib.quote(params[k], '~')) |
| 142 | 202 |
| 143 canonical = '\n'.join(['GET', | 203 canonical = '\n'.join(['GET', |
| 144 str(endpoint_host).lower(), | 204 str(endpoint_host).lower(), |
| 145 base, | 205 base, |
| 146 parts[1:]]) | 206 parts[1:]]) |
| 147 | 207 |
| 148 signature = self._auth_handler.sign_string(canonical) | 208 signature = self._auth_handler.sign_string(canonical) |
| 149 params["signature"] = signature | 209 params["signature"] = signature |
| 150 | 210 |
| 151 urlsuffix = '' | 211 urlsuffix = '' |
| 152 for k in sorted(params.keys()): | 212 for k in sorted(params.keys()): |
| 153 urlsuffix += "&%s=%s" % (k, urllib.quote(params[k], '~')) | 213 urlsuffix += "&%s=%s" % (k, urllib.quote(params[k], '~')) |
| 154 urlsuffix = urlsuffix[1:] # strip the first & | 214 urlsuffix = urlsuffix[1:] # strip the first & |
| 155 | 215 |
| 156 fmt = "https://%(endpoint_host)s%(base)s?%(urlsuffix)s" | 216 fmt = "https://%(endpoint_host)s%(base)s?%(urlsuffix)s" |
| 157 final = fmt % vars() | 217 final = fmt % vars() |
| 158 return final | 218 return final |
| 159 | 219 |
| 160 def pay(self, transactionAmount, senderTokenId, | 220 def pay(self, transactionAmount, senderTokenId, |
| 161 recipientTokenId=None, callerTokenId=None, | 221 recipientTokenId=None, callerTokenId=None, |
| 162 chargeFeeTo="Recipient", | 222 chargeFeeTo="Recipient", |
| 163 callerReference=None, senderReference=None, recipientReference=None, | 223 callerReference=None, senderReference=None, recipientReference=None, |
| 164 senderDescription=None, recipientDescription=None, callerDescription
=None, | 224 senderDescription=None, recipientDescription=None, |
| 165 metadata=None, transactionDate=None, reserve=False): | 225 callerDescription=None, metadata=None, |
| 226 transactionDate=None, reserve=False): |
| 166 """ | 227 """ |
| 167 Make a payment transaction. You must specify the amount. | 228 Make a payment transaction. You must specify the amount. |
| 168 This can also perform a Reserve request if 'reserve' is set to True. | 229 This can also perform a Reserve request if 'reserve' is set to True. |
| 169 """ | 230 """ |
| 170 params = {} | 231 params = {} |
| 171 params['SenderTokenId'] = senderTokenId | 232 params['SenderTokenId'] = senderTokenId |
| 172 # this is for 2008-09-17 specification | 233 # this is for 2008-09-17 specification |
| 173 params['TransactionAmount.Amount'] = str(transactionAmount) | 234 params['TransactionAmount.Amount'] = str(transactionAmount) |
| 174 params['TransactionAmount.CurrencyCode'] = "USD" | 235 params['TransactionAmount.CurrencyCode'] = "USD" |
| 175 #params['TransactionAmount'] = str(transactionAmount) | 236 #params['TransactionAmount'] = str(transactionAmount) |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 response = self.make_request("Settle", params) | 323 response = self.make_request("Settle", params) |
| 263 body = response.read() | 324 body = response.read() |
| 264 if(response.status == 200): | 325 if(response.status == 200): |
| 265 rs = ResultSet() | 326 rs = ResultSet() |
| 266 h = handler.XmlHandler(rs, self) | 327 h = handler.XmlHandler(rs, self) |
| 267 xml.sax.parseString(body, h) | 328 xml.sax.parseString(body, h) |
| 268 return rs | 329 return rs |
| 269 else: | 330 else: |
| 270 raise FPSResponseError(response.status, response.reason, body) | 331 raise FPSResponseError(response.status, response.reason, body) |
| 271 | 332 |
| 272 def refund(self, callerReference, transactionId, refundAmount=None, callerDe
scription=None): | 333 def refund(self, callerReference, transactionId, refundAmount=None, |
| 334 callerDescription=None): |
| 273 """ | 335 """ |
| 274 Refund a transaction. This refunds the full amount by default unless 're
fundAmount' is specified. | 336 Refund a transaction. This refunds the full amount by default |
| 337 unless 'refundAmount' is specified. |
| 275 """ | 338 """ |
| 276 params = {} | 339 params = {} |
| 277 params['CallerReference'] = callerReference | 340 params['CallerReference'] = callerReference |
| 278 params['TransactionId'] = transactionId | 341 params['TransactionId'] = transactionId |
| 279 if(refundAmount != None): | 342 if(refundAmount != None): |
| 280 params['RefundAmount'] = refundAmount | 343 params['RefundAmount'] = refundAmount |
| 281 if(callerDescription != None): | 344 if(callerDescription != None): |
| 282 params['CallerDescription'] = callerDescription | 345 params['CallerDescription'] = callerDescription |
| 283 | 346 |
| 284 response = self.make_request("Refund", params) | 347 response = self.make_request("Refund", params) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 303 if(response.status == 200): | 366 if(response.status == 200): |
| 304 rs = ResultSet() | 367 rs = ResultSet() |
| 305 h = handler.XmlHandler(rs, self) | 368 h = handler.XmlHandler(rs, self) |
| 306 xml.sax.parseString(body, h) | 369 xml.sax.parseString(body, h) |
| 307 return rs | 370 return rs |
| 308 else: | 371 else: |
| 309 raise FPSResponseError(response.status, response.reason, body) | 372 raise FPSResponseError(response.status, response.reason, body) |
| 310 | 373 |
| 311 def get_token_by_caller_reference(self, callerReference): | 374 def get_token_by_caller_reference(self, callerReference): |
| 312 """ | 375 """ |
| 313 Returns details about the token specified by 'callerReference'. | 376 Returns details about the token specified by 'CallerReference'. |
| 314 """ | 377 """ |
| 315 params ={} | 378 params ={} |
| 316 params['callerReference'] = callerReference | 379 params['CallerReference'] = callerReference |
| 317 | 380 |
| 318 response = self.make_request("GetTokenByCaller", params) | 381 response = self.make_request("GetTokenByCaller", params) |
| 319 body = response.read() | 382 body = response.read() |
| 320 if(response.status == 200): | 383 if(response.status == 200): |
| 321 rs = ResultSet() | 384 rs = ResultSet() |
| 322 h = handler.XmlHandler(rs, self) | 385 h = handler.XmlHandler(rs, self) |
| 323 xml.sax.parseString(body, h) | 386 xml.sax.parseString(body, h) |
| 324 return rs | 387 return rs |
| 325 else: | 388 else: |
| 326 raise FPSResponseError(response.status, response.reason, body) | 389 raise FPSResponseError(response.status, response.reason, body) |
| 390 |
| 327 def get_token_by_caller_token(self, tokenId): | 391 def get_token_by_caller_token(self, tokenId): |
| 328 """ | 392 """ |
| 329 Returns details about the token specified by 'callerReference'. | 393 Returns details about the token specified by 'TokenId'. |
| 330 """ | 394 """ |
| 331 params ={} | 395 params ={} |
| 332 params['TokenId'] = tokenId | 396 params['TokenId'] = tokenId |
| 333 | 397 |
| 334 response = self.make_request("GetTokenByCaller", params) | 398 response = self.make_request("GetTokenByCaller", params) |
| 335 body = response.read() | 399 body = response.read() |
| 336 if(response.status == 200): | 400 if(response.status == 200): |
| 337 rs = ResultSet() | 401 rs = ResultSet() |
| 338 h = handler.XmlHandler(rs, self) | 402 h = handler.XmlHandler(rs, self) |
| 339 xml.sax.parseString(body, h) | 403 xml.sax.parseString(body, h) |
| 340 return rs | 404 return rs |
| 341 else: | 405 else: |
| 342 raise FPSResponseError(response.status, response.reason, body) | 406 raise FPSResponseError(response.status, response.reason, body) |
| 343 | 407 |
| 344 def verify_signature(self, end_point_url, http_parameters): | 408 def verify_signature(self, end_point_url, http_parameters): |
| 345 params = dict( | 409 params = dict( |
| 346 UrlEndPoint = end_point_url, | 410 UrlEndPoint = end_point_url, |
| 347 HttpParameters = http_parameters, | 411 HttpParameters = http_parameters, |
| 348 ) | 412 ) |
| 349 response = self.make_request("VerifySignature", params) | 413 response = self.make_request("VerifySignature", params) |
| 350 body = response.read() | 414 body = response.read() |
| 351 if(response.status != 200): | 415 if(response.status != 200): |
| 352 raise FPSResponseError(response.status, response.reason, body) | 416 raise FPSResponseError(response.status, response.reason, body) |
| 353 rs = ResultSet() | 417 rs = ResultSet() |
| 354 h = handler.XmlHandler(rs, self) | 418 h = handler.XmlHandler(rs, self) |
| 355 xml.sax.parseString(body, h) | 419 xml.sax.parseString(body, h) |
| 356 return rs | 420 return rs |
| OLD | NEW |