pci_proxy 1.0.0 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d2e838d63aadc950a829e6d3b50e7c6fddcfffdb216ae9f7646d4dc06fbb930
4
- data.tar.gz: 42b52b3106e60c53a75de4424f445edca6ddc9251c899f12f07dfeadee30b722
3
+ metadata.gz: 91dcc3b1b4d3f7b715bf9b97096e309041e263839f0c98b9b605ed6fa4b652d9
4
+ data.tar.gz: 10fe3831fe0b63dccfa142a21bf91983898574245c2c37ea4f62c2729a4f22ed
5
5
  SHA512:
6
- metadata.gz: e9c4197a8b75b8070f5174d0a64ffd3fdb374ce4e279bc45b0f2386be6ccfdda3172baac6b00c8ac795526ac45e92bd4e19f41a23f959c5df803643d0b46562a
7
- data.tar.gz: 11735efca4a2ce834ea0c6a05906b38649796b999eda37e9f6b697d39bce4b494cc1e92ba376d41a67e5ba270376a91388da925173541c2a46a8b09ec76f3b0f
6
+ metadata.gz: 8a7f74d2b7656f9227f8ead57e15ecbb1abf03ce7b6b0b1e7eedb30c5153571b55b7d7dfc13e41405ff16824ca0257600700fd1ae508c5ff7dd82d2930106f45
7
+ data.tar.gz: 5246d64cea9102600e09adfe254d25ea9368e4b1d91842f7feda9f9997ef426d2377b1403e241d80d6319a2e6d29f236e933c3ca764ad341743ece1e70dff05b
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  .DS_Store
2
+ *.gem
2
3
  /.idea/
3
4
  /.bundle/
4
5
  /.yardoc
@@ -1,7 +1,13 @@
1
- # PciProxy
1
+ # PciProxy Change Log
2
2
 
3
3
  A simple client library for [PCI Proxy](https://pci-proxy.com)'s API
4
4
 
5
- #CHANGE LOG
5
+ v1.2.1 - 30th January 2020 - Minor tweaks; cleanups; update documentation
6
6
 
7
- v1.0.0 - 14th January 2020 - Initial release - covers the [Token API](https://docs.pci-proxy.com/collect-and-store-cards/capture-iframes/token-api)
7
+ v1.2.0 - 30th January 2020 - Add support for the [Check API](https://docs.pci-proxy.com/use-stored-cards/check)
8
+
9
+ v1.1.0 - 17th January 2020 - Return an instance of PciProxy::Model::TokenisedCard instead of plain Hash
10
+
11
+ v1.0.1 - 14th January 2020 - Relax dependency version requirements
12
+
13
+ v1.0.0 - 14th January 2020 - Initial release - covering the [Token API](https://docs.pci-proxy.com/collect-and-store-cards/capture-iframes/token-api)
@@ -1,19 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pci_proxy (1.0.0)
5
- faraday (~> 0.17.3)
6
- multi_json (~> 1.14.1)
4
+ pci_proxy (1.2.2)
5
+ faraday (>= 0.8.9)
6
+ multi_json (>= 1.10.0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- faraday (0.17.3)
11
+ faraday (1.0.1)
12
12
  multipart-post (>= 1.2, < 3)
13
13
  minitest (5.13.0)
14
14
  multi_json (1.14.1)
15
15
  multipart-post (2.1.1)
16
- rake (10.5.0)
16
+ rake (13.0.1)
17
17
 
18
18
  PLATFORMS
19
19
  java
@@ -23,7 +23,7 @@ DEPENDENCIES
23
23
  bundler (~> 2.0)
24
24
  minitest (~> 5.0)
25
25
  pci_proxy!
26
- rake (~> 10.0)
26
+ rake (~> 13.0)
27
27
 
28
28
  BUNDLED WITH
29
- 2.1.2
29
+ 2.1.4
data/README.md CHANGED
@@ -20,7 +20,7 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- Initially, this gem only covers the [Token API](https://docs.pci-proxy.com/collect-and-store-cards/capture-iframes/token-api), which converts a transactionId from the [secure fields](https://docs.pci-proxy.com/collect-and-store-cards/capture-iframes) mechanism into tokenised card PAN and CVV.
23
+ Initially, this gem only covers the [Token API](https://docs.pci-proxy.com/collect-and-store-cards/capture-iframes/token-api), which converts a transactionId from the [secure fields](https://docs.pci-proxy.com/collect-and-store-cards/capture-iframes) mechanism into tokenised card PAN and CVV, and the [Check API](https://docs.pci-proxy.com/use-stored-cards/check) which allows verification of a card token.
24
24
 
25
25
  Pull requests are most welcome for coverage of other PCI Proxy APIs :)
26
26
  ### Token API - Usage
@@ -35,20 +35,61 @@ And execute a token exchange like so:
35
35
  client.execute(transaction_id: '1234567890')
36
36
  ```
37
37
 
38
- In the event of a 200 OK response, the JSON response body is returned as a hash, for example:
38
+ In the event of a 200 OK response, an instance of PciProxy::Model::TokenisedCard is returned:
39
39
 
40
40
  ```ruby
41
- {"aliasCC"=>"411111GGCMUJ1111", "aliasCVV"=>"vCslSwP0SQ9JXJy-nDzLKHaS"}
41
+ #<PciProxy::Model::TokenisedCard:0x00007fda073453f8 @pan_token="411111GGCMUJ1111", @cvv_token="b8XeAbhQQES6OVWTpOCaAscj", @type_slug=:visa>
42
42
  ```
43
+ (```response``` attr_reader value omitted for clarity)
44
+
45
+ This object has attr_readers for ```pan_token```, ```cvv_token``` and ```type_slug``` which will return one of the following symbols:
46
+
47
+ ```ruby
48
+ [:visa, :mastercard, :amex, :diners, :discovery, :jcb, :elo, :cup, :unknown]
49
+ ```
50
+
51
+ It also has an attr_reader for ```response``` which is the raw parsed JSON response, as a hash.
43
52
 
44
53
  In the event of an error, a subclass of ```PciProxyAPIError``` will be raised.
45
54
 
46
55
  The most likely error is that the transactionId temporary token has expired, resulting in:
47
56
 
48
- ```ruby
57
+ ```
49
58
  PciProxy::BadRequestError (HTTP status: 400, Response: Tokenization not found)
50
59
  ```
51
60
 
61
+ ### Check API - Usage
62
+
63
+ Create an instance of ```PciProxy::Check``` and call ```execute``` as follows:
64
+
65
+ ```ruby
66
+ client = PciProxy::Check.new(api_username: 'username', api_password: 'password')
67
+ ```
68
+
69
+ And execute a card verification like so:
70
+
71
+ ```ruby
72
+ client.execute(reference: 'foo', card_token: '411111GGCMUJ1111', card_type: :visa, expiry_month: 1, expiry_year: 2022)
73
+ ```
74
+
75
+ In all cases (success, denoted by 200 OK from the API, or error, denoted by non-200 response), an instance of ```PciProxy::Model::CheckResult``` is returned.
76
+
77
+ This object has attr_readers for ```auth_code```, ```transaction_id```, ```status``` and ```error```
78
+
79
+ It also has an attr_reader for ```response``` which is the raw parsed JSON response, as a hash.
80
+
81
+ With a successful response, the object's ```status``` attribute will have the value ```:success```, and the ```auth_code``` and ```transaction_id``` values will be available:
82
+ ```ruby
83
+ #<PciProxy::Model::CheckResult:0x00007fbda2186fe8 @auth_code="124101", @transaction_id="190828124101219812", @error=nil, @status=:success>
84
+ ```
85
+ (```response``` attr_reader value omitted for clarity)
86
+
87
+ With an unsuccessful response, the object's ```status``` attribute will have the value ```:error```:
88
+ ```ruby
89
+ #<PciProxy::Model::CheckResult:0x00007fbda2186fe8 @auth_code=nil, @transaction_id=nil, @error={"code"=>"UNAUTHORIZED", "message"=>"The account is not configured to use this API."}, @status=:error>
90
+ ```
91
+ (```response``` attr_reader value omitted for clarity)
92
+
52
93
  ## Changes
53
94
  See [Changelog](CHANGELOG.md)
54
95
 
@@ -2,7 +2,10 @@ require 'bundler'
2
2
  require "pci_proxy/version"
3
3
 
4
4
  require 'pci_proxy/base'
5
+ require 'pci_proxy/check'
5
6
  require 'pci_proxy/token'
7
+ require 'pci_proxy/model/check_result'
8
+ require 'pci_proxy/model/tokenised_card'
6
9
 
7
10
  module PciProxy
8
11
  PciProxyAPIError = Class.new(StandardError)
@@ -19,4 +22,5 @@ module PciProxy
19
22
  HTTP_FORBIDDEN_CODE = 403
20
23
  HTTP_NOT_FOUND_CODE = 404
21
24
  HTTP_UNPROCESSABLE_ENTITY_CODE = 429
25
+
22
26
  end
@@ -4,6 +4,8 @@ require 'multi_json'
4
4
  module PciProxy
5
5
  class Base
6
6
 
7
+ JSON_UTF8_CONTENT_TYPE = 'application/json; charset=UTF-8'.freeze
8
+
7
9
  attr_reader :api_endpoint, :api_username, :api_password
8
10
 
9
11
  ##
@@ -17,19 +19,35 @@ module PciProxy
17
19
  end
18
20
 
19
21
  ##
20
- # Perform the API request
22
+ # Perform an API request via HTTP GET
21
23
  #
22
24
  # @param +endpoint+ [String] (Optional) - the API endpoint to hit - defaults to the value of the api_endpoint reader
23
- # @param +http_method+ [Symbol] (Optional) - the HTTP method to use - defaults to GET
24
- # @param +params+ [Hash] (Optional) - any parameters to supply to the API call
25
+ # @param +params+ [Hash] (Optional) - any URL parameters to supply to the API call
25
26
  #
26
27
  # @raise [PciProxyAPIError] in cases where the API responds with a non-200 response code
27
28
  # @return [Hash] parsed JSON response
29
+ def api_get(endpoint: @api_endpoint, params: {}, raise_on_error: true)
30
+ response = client.get(endpoint, params)
31
+
32
+ if raise_on_error == false || response.status == HTTP_OK_CODE
33
+ return MultiJson.load(response.body)
34
+ end
35
+
36
+ raise error_class(response), "HTTP status: #{response.status}, Response: #{response.body}"
37
+ end
38
+
39
+ ##
40
+ # Perform an API request via HTTP POST
41
+ #
42
+ # @param +endpoint+ [String] (Optional) - the API endpoint to hit - defaults to the value of the api_endpoint reader
43
+ # @param +body+ [Hash] (Optional) - the API request payload (will be converted to JSON)
28
44
  #
29
- def request(endpoint: @api_endpoint, http_method: :get, params: {})
30
- response = client.public_send(http_method, endpoint, params)
45
+ # @raise [PciProxyAPIError] in cases where the API responds with a non-200 response code
46
+ # @return [Hash] parsed JSON response
47
+ def api_post(endpoint: @api_endpoint, body: {}, raise_on_error: true)
48
+ response = client.post(endpoint, MultiJson.dump(body), "Content-Type" => JSON_UTF8_CONTENT_TYPE)
31
49
 
32
- if response.status == HTTP_OK_CODE
50
+ if raise_on_error == false || response.status == HTTP_OK_CODE
33
51
  return MultiJson.load(response.body)
34
52
  end
35
53
 
@@ -0,0 +1,62 @@
1
+ module PciProxy
2
+ class Check < Base
3
+
4
+ SANDBOX_ENDPOINT = 'https://api.sandbox.datatrans.com/v1/transactions/validate'.freeze
5
+ LIVE_ENDPOINT = 'https://api.datatrans.com/v1/transactions/validate'.freeze
6
+
7
+ CHF = 'CHF'.freeze
8
+ EUR = 'EUR'.freeze
9
+
10
+ # error codes
11
+ # "UNKNOWN_ERROR", "UNRECOGNIZED_PROPERTY", "INVALID_PROPERTY", "INVALID_TRANSACTION_STATUS", "TRANSACTION_NOT_FOUND", "INVALID_JSON_PAYLOAD", "UNAUTHORIZED", "EXPIRED_CARD", "INVALID_CARD", "UNSUPPORTED_CARD", "DUPLICATED_REFNO", "DECLINED", "BLOCKED_BY_VELOCITY_CHECKER", "CLIENT_ERROR" , "SERVER_ERROR"
12
+
13
+ ##
14
+ # Initialise with the specified +api_username+ and +api_password+ from PCI Proxy.
15
+ #
16
+ # Defaults to the sandbox API endpoint - to use the live environment,
17
+ # supply the LIVE_ENDPOINT constant as the value of the +endpoint+ kwarg
18
+ def initialize(api_username:, api_password:, endpoint: SANDBOX_ENDPOINT)
19
+ @api_endpoint = endpoint
20
+ @api_username = api_username
21
+ @api_password = api_password
22
+ end
23
+
24
+ ##
25
+ # Perform a check API request to verify the card token
26
+ #
27
+ # @param +reference+ [String] - caller's unique reference (any non-empty string value)
28
+ # @param +card_token+ [String] - card token obtained from the Token API - see PciProxy::Token
29
+ # @param +card_type+ [Symbol / String] - one of 'visa', 'mastercard' or 'amex'
30
+ # @param +expiry_month+ [Integer / String] - integer 1-12, or string '01' - '12'
31
+ # @param +expiry_year+ [Integer / String] - two or four digit year as a string or integer
32
+ # @param +currency+ [Integer / String] (Optional) - one of 'CHF' or 'EUR' - will default by card type where not specified
33
+ #
34
+ # @raise [PciProxyAPIError] in cases where the API responds with a non-200 response code
35
+ # @return [Hash] result from PCI Proxy, decoded from JSON
36
+ def execute(reference:, card_token:, card_type:, expiry_month:, expiry_year:, currency: nil)
37
+ raise "reference is required" if reference.empty?
38
+ raise "card_token is required" unless card_token && !card_token.empty?
39
+ raise "card_type must be one of 'visa', 'mastercard' or 'amex'" unless [:visa, :mastercard, :amex].include?(card_type.to_sym)
40
+ raise "invalid expiry_month" unless (1..12).include?(expiry_month.to_i)
41
+ raise "invalid expiry_year" unless expiry_year.to_i > 0
42
+
43
+ # default the currency where not specified - according to the documentation Amex should use EUR, Visa and MC should use CHF
44
+ currency ||= :amex == card_type.to_sym ? EUR : CHF
45
+
46
+ card = {
47
+ alias: card_token,
48
+ expiryMonth: expiry_month.to_s,
49
+ expiryYear: expiry_year.to_s.chars.last(2).join
50
+ }
51
+
52
+ body = {
53
+ refno: reference,
54
+ currency: currency,
55
+ card: card
56
+ }
57
+
58
+ PciProxy::Model::CheckResult.new(api_post(endpoint: @api_endpoint, body: body, raise_on_error: false))
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,18 @@
1
+ module PciProxy
2
+ module Model
3
+ class CheckResult
4
+
5
+ attr_reader :response, :status, :error, :auth_code, :transaction_id
6
+
7
+ def initialize(response)
8
+ @response = response
9
+ @auth_code = response["acquirerAuthorizationCode"]
10
+ @transaction_id = response["transactionId"]
11
+ @error = response["error"]
12
+
13
+ @status = @auth_code && @transaction_id && !@error ? :success : :error
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,43 @@
1
+ module PciProxy
2
+ module Model
3
+ class TokenisedCard
4
+
5
+ attr_reader :response, :pan_token, :cvv_token, :type_slug
6
+
7
+ def initialize(response)
8
+ @response = response
9
+ @pan_token = response["aliasCC"]
10
+ @cvv_token = response["aliasCVV"]
11
+ @type_slug = slug_for(response["paymentMethod"])
12
+ end
13
+
14
+ private
15
+
16
+ def slug_for(payment_method)
17
+ return nil if payment_method.nil?
18
+
19
+ case payment_method
20
+ when 'VIS'
21
+ :visa
22
+ when 'ECA'
23
+ :mastercard
24
+ when 'AMX'
25
+ :amex
26
+ when 'DIN'
27
+ :diners
28
+ when 'DIS'
29
+ :discovery
30
+ when 'JCB'
31
+ :jcb
32
+ when 'ELO'
33
+ :elo
34
+ when 'CUP'
35
+ :cup
36
+ else
37
+ :unknown
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,24 +1,35 @@
1
1
  module PciProxy
2
2
  class Token < Base
3
3
 
4
+ SANDBOX_ENDPOINT = 'https://api.sandbox.datatrans.com/upp/services/v1/inline/token'.freeze
5
+ LIVE_ENDPOINT = 'https://api.datatrans.com/upp/services/v1/inline/token'.freeze
6
+
4
7
  ##
5
8
  # Initialise with the specified +api_username+ and +api_password+ from PCI Proxy.
6
- def initialize(api_username:, api_password:)
7
- @api_endpoint = 'https://api.sandbox.datatrans.com/upp/services/v1/inline/token'.freeze
9
+ #
10
+ # Defaults to the sandbox API endpoint - to use the live environment,
11
+ # supply the LIVE_ENDPOINT constant as the value of the +endpoint+ kwarg
12
+ def initialize(api_username:, api_password:, endpoint: SANDBOX_ENDPOINT)
13
+ @api_endpoint = endpoint
8
14
  @api_username = api_username
9
15
  @api_password = api_password
10
16
  end
11
17
 
12
18
  ##
13
- # Perform a token request to turn the specified +transaction_id+ into card and CVV tokens
19
+ # Perform a token API request to turn the specified +transaction_id+ into card and CVV tokens
14
20
  #
15
21
  # @param +return_payment_method+ (true/false) - whether or not to return the identified payment method (default: true)
16
22
  # @param +cvv_mandatory+ (true/false) - whether or not to consider the CVV alias should be mandatory (default: false)
17
23
  #
18
24
  # @raise [PciProxyAPIError] in cases where the API responds with a non-200 response code
19
- # @return [Hash] result from PCI Proxy, decoded from JSON
25
+ # @return [PciProxy::Model::TokenisedCard] wrapper object around the JSON response
20
26
  def execute(transaction_id:, return_payment_method: true, cvv_mandatory: false)
21
- request(params: { transactionId: transaction_id, returnPaymentMethod: return_payment_method, mandatoryAliasCVV: cvv_mandatory })
27
+ raise "transaction_id is required" unless transaction_id && !transaction_id.empty?
28
+
29
+ PciProxy::Model::TokenisedCard.new(api_get(params: {
30
+ transactionId: transaction_id,
31
+ returnPaymentMethod: return_payment_method,
32
+ mandatoryAliasCVV: cvv_mandatory }))
22
33
  end
23
34
 
24
35
  end
@@ -1,3 +1,3 @@
1
1
  module PciProxy
2
- VERSION = "1.0.0"
2
+ VERSION = "1.2.2"
3
3
  end
@@ -27,9 +27,9 @@ Gem::Specification.new do |spec|
27
27
  spec.require_paths = ["lib"]
28
28
 
29
29
  spec.add_development_dependency "bundler", "~> 2.0"
30
- spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "rake", "~> 13.0"
31
31
  spec.add_development_dependency "minitest", "~> 5.0"
32
32
 
33
- spec.add_dependency "faraday", "~> 0.17.3"
34
- spec.add_dependency "multi_json", "~> 1.14.1"
33
+ spec.add_dependency "faraday", ">= 0.8.9"
34
+ spec.add_dependency "multi_json", ">= 1.10.0"
35
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pci_proxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rory Sinclair
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-14 00:00:00.000000000 Z
11
+ date: 2020-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -56,30 +56,30 @@ dependencies:
56
56
  name: faraday
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 0.17.3
61
+ version: 0.8.9
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 0.17.3
68
+ version: 0.8.9
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: multi_json
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: 1.14.1
75
+ version: 1.10.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: 1.14.1
82
+ version: 1.10.0
83
83
  description: A ruby library covering the server-server aspects of the PCI-Proxy API
84
84
  email:
85
85
  - rory@mungler.com
@@ -100,6 +100,9 @@ files:
100
100
  - bin/setup
101
101
  - lib/pci_proxy.rb
102
102
  - lib/pci_proxy/base.rb
103
+ - lib/pci_proxy/check.rb
104
+ - lib/pci_proxy/model/check_result.rb
105
+ - lib/pci_proxy/model/tokenised_card.rb
103
106
  - lib/pci_proxy/token.rb
104
107
  - lib/pci_proxy/version.rb
105
108
  - pci_proxy.gemspec