cardinity 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f11054ae9a4a74c663c741d1d6e53cc679b9684b
4
- data.tar.gz: ed309c4fd81fbdd4f3af840e8e0e619855933167
3
+ metadata.gz: 1792daaf31ee88c7c270dc6e00bd625007923fe6
4
+ data.tar.gz: e09efc856cd5332d1dadede05177006f5dda970e
5
5
  SHA512:
6
- metadata.gz: 7821197020d3a79e12a511dfe02696a6e5f39a13f87e03f506e6198b33a8c98f08028adf90f5c9f2317ea173b0b1238876b30b9b1e39b0f244698e55768e949e
7
- data.tar.gz: 14516824e4ebe5136e28151004ade1c86fcbc1850b68860f015aae50f63916b5683dd7b779f5e60c950a5adb5cb4b375d512be4f218e5f517bc3c3b6260c5c11
6
+ metadata.gz: b031d6b90c243e431ca5a7e3d957d43f2fd002cce7c630bf15ced922cea8959a71897ab8861613c6afb39996089d4cfe4138f04c5751601872bae0064e55e7fc
7
+ data.tar.gz: 165cfbd858971f0b65d7c89134224889a7cab3ee10fd4c24ce69d765437b69bcbf1f117018f376caf2c90089ecefefa1bcce39cad28fa9b7c4a7c2b5c02a80e7
data/README.md CHANGED
@@ -18,7 +18,33 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- TODO: Write usage instructions here
21
+ ### Configuration
22
+
23
+ Cardinity.configure!(options)
24
+
25
+ Where options should contain:
26
+ - key
27
+ - secret
28
+ - api_base (optional, if you want to point the requests somewhere else than Cardinity servers)
29
+
30
+ ### Creating Payments
31
+
32
+ Cardinity.create_payment(payment_data)
33
+
34
+ Where `payment_data` is a plain `Hash`. See rdoc or [Cardinity API doc](https://developers.cardinity.com/api/v1/) to see
35
+ what attributes are allowed and required.
36
+
37
+ Cardinity.finalize_payment(payment_id, authorization_data)
38
+
39
+ Where `payment_id` is an id of previously created payment and `authorization_data` is
40
+ a `Hash` with single key `authorize_data`.
41
+
42
+ ### Other stuff
43
+
44
+ Cardinity.payments
45
+
46
+ Returns the last 10 payments made.
47
+
22
48
 
23
49
  ## Development
24
50
 
@@ -21,4 +21,6 @@ Gem::Specification.new do |spec|
21
21
  spec.add_development_dependency "bundler", "~> 1.11"
22
22
  spec.add_development_dependency "rake", "~> 10.0"
23
23
  spec.add_development_dependency "minitest", "~> 5.0"
24
+
25
+ spec.add_runtime_dependency 'rest-client', '~> 2.0'
24
26
  end
@@ -1,5 +1,75 @@
1
- require "cardinity/version"
1
+ require 'cardinity/version'
2
+ require 'cardinity/utils'
3
+ require 'cardinity/auth'
4
+ require 'rest-client'
5
+ require 'json'
2
6
 
3
7
  module Cardinity
4
- # Your code goes here...
8
+
9
+ DEFAULT_API_BASE = 'https://api.cardinity.com/v1/'
10
+
11
+ API_PAYMENTS = 'payments'
12
+
13
+ STATUS_PENDING = 'pending'
14
+ STATUS_APPROVED = 'approved'
15
+ STATUS_DECLINED = 'declined'
16
+
17
+ TYPE_AUTHORIZATION = 'authorization'
18
+ TYPE_PURCHASE = 'purchase'
19
+ TYPE_ERROR = 'https://developers.cardinity.com/api/v1/'
20
+
21
+ def self.configure!(options)
22
+ @config = {
23
+ # key and secret to be supplied from outsite
24
+ api_base: DEFAULT_API_BASE
25
+ }
26
+ @config.merge! options
27
+ @auth = Cardinity::Auth.new(@config)
28
+ end
29
+
30
+ # Creates a Payment object
31
+ #
32
+ # Accepted attributes:
33
+ # - amount (#0.00, two decimals required)
34
+ # - currency (EUR,USD)
35
+ # - settle (boolean, default true, false means just pre-authorize and finish later)
36
+ # - order_id (not required)
37
+ # - description (not required)
38
+ # - country (country of customer, required)
39
+ # - payment_method (required, only supported value is card)
40
+ # - payment_instrument (card details)
41
+ # - pan (card number)
42
+ # - exp_year
43
+ # - exp_month
44
+ # - cvc
45
+ # - holder
46
+ #
47
+ # Returns:
48
+ # - updated payment object on success
49
+ # - error object on error
50
+ def self.create_payment(payment_hash)
51
+ checked_payment_data = check_payment_data(payment_hash)
52
+ parse post(payments_uri, serialize(checked_payment_data))
53
+ end
54
+
55
+ # Finalizes a Payment
56
+ #
57
+ # This is necessary for 3D secure payments, when the customer has completed
58
+ # the 3D secure redirects and authorization.
59
+ #
60
+ # Accepted attributes:
61
+ # - authorize_data (PaRes string received from 3D secure)
62
+ #
63
+ # Returns:
64
+ # - updated payment object on success
65
+ # - error object on error
66
+ def self.finalize_payment(payment_id, authorize_hash)
67
+ parse patch(payment_uri(payment_id), serialize(authorize_hash))
68
+ end
69
+
70
+ # Get list of all payments
71
+ def self.payments
72
+ parse get(payments_uri)
73
+ end
74
+
5
75
  end
@@ -0,0 +1,69 @@
1
+ require 'base64'
2
+ require 'openssl/digest'
3
+ require 'uri'
4
+ require 'cgi'
5
+
6
+ class Cardinity::Auth
7
+
8
+ OAUTH_VERSION = '1.0'
9
+ RESERVED_CHARACTERS = /[^a-zA-Z0-9\-._~]/
10
+ SIGNATURE_METHOD = 'HMAC-SHA1'
11
+
12
+ def initialize(config)
13
+ @config = config
14
+ end
15
+
16
+ def sign_request(method, uri)
17
+ params = {
18
+ oauth_consumer_key: @config[:key],
19
+ oauth_nonce: generate_key,
20
+ oauth_signature_method: SIGNATURE_METHOD,
21
+ oauth_timestamp: generate_timestamp,
22
+ oauth_version: OAUTH_VERSION
23
+ }
24
+ params[:oauth_signature] = request_signature(method, uri, params)
25
+ params_str = params.collect { |k, v| "#{k}=\"#{escape(v)}\"" }.join(', ')
26
+ "OAuth #{params_str}"
27
+ end
28
+
29
+ def request_signature(method, uri, params)
30
+ base_str = generate_base_string(method, uri, params)
31
+ encoded_digest(base_str)
32
+ end
33
+
34
+ def encoded_digest(string)
35
+ Base64.strict_encode64(digest(string))
36
+ end
37
+
38
+ def digest(string)
39
+ key = escape(@config[:secret]) + '&'
40
+ OpenSSL::HMAC.digest(
41
+ OpenSSL::Digest.new('sha1'),
42
+ key,
43
+ string)
44
+ end
45
+
46
+ def escape(string)
47
+ URI.escape(string, RESERVED_CHARACTERS)
48
+ end
49
+
50
+ def generate_base_string(method, url, params)
51
+ base = [method.to_s.upcase, url, normalized_params(params)]
52
+ base.map { |v| escape(v) }.join('&')
53
+ end
54
+
55
+ private
56
+
57
+ def generate_key(size=32)
58
+ Base64.strict_encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/, '')
59
+ end
60
+
61
+ def generate_timestamp
62
+ Time.now.to_i.to_s
63
+ end
64
+
65
+ def normalized_params(params)
66
+ params.collect { |k, v| "#{k}=#{v}" }.sort.join("&")
67
+ end
68
+
69
+ end
@@ -0,0 +1,69 @@
1
+ module Cardinity
2
+
3
+ CODES_WITH_RESPONSE = [200, 201, 202, 400, 402]
4
+
5
+ def self.check_payment_data(payment)
6
+ payment = payment.dup
7
+ if payment[:payment_method].nil?
8
+ payment[:payment_method] = 'card'
9
+ end
10
+ if payment[:amount].is_a?(Numeric)
11
+ payment[:amount] = '%.2f' % payment[:amount]
12
+ end
13
+ payment
14
+ end
15
+
16
+ def self.payments_uri
17
+ "#{api_base}#{API_PAYMENTS}"
18
+ end
19
+
20
+ def self.payment_uri(payment_id)
21
+ "#{api_base}#{API_PAYMENTS}/#{payment_id}"
22
+ end
23
+
24
+ def self.parse(response)
25
+ JSON.parse response.body
26
+ end
27
+
28
+ def self.serialize(data)
29
+ JSON.generate(data)
30
+ end
31
+
32
+ def self.handle_error_response(e)
33
+ if CODES_WITH_RESPONSE.index e.response.code
34
+ e.response
35
+ else
36
+ raise e
37
+ end
38
+ end
39
+
40
+ def self.get(uri)
41
+ RestClient.get uri, headers(:get, uri)
42
+ rescue RestClient::ExceptionWithResponse => e
43
+ handle_error_response e
44
+ end
45
+
46
+ def self.post(uri, body)
47
+ RestClient.post uri, body, headers(:post, uri)
48
+ rescue RestClient::ExceptionWithResponse => e
49
+ handle_error_response e
50
+ end
51
+
52
+ def self.patch(uri, body)
53
+ RestClient.patch uri, body, headers(:patch, uri)
54
+ rescue RestClient::ExceptionWithResponse => e
55
+ handle_error_response e
56
+ end
57
+
58
+ def self.headers(method, uri)
59
+ {
60
+ content_type: 'application/json',
61
+ authorization: @auth.sign_request(method, uri)
62
+ }
63
+ end
64
+
65
+ def self.api_base
66
+ @config[:api_base]
67
+ end
68
+
69
+ end
@@ -1,3 +1,3 @@
1
1
  module Cardinity
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cardinity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Sterba
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-10 00:00:00.000000000 Z
11
+ date: 2017-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rest-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.0'
55
69
  description:
56
70
  email:
57
71
  - info@jansterba.com
@@ -70,6 +84,8 @@ files:
70
84
  - bin/setup
71
85
  - cardinity.gemspec
72
86
  - lib/cardinity.rb
87
+ - lib/cardinity/auth.rb
88
+ - lib/cardinity/utils.rb
73
89
  - lib/cardinity/version.rb
74
90
  homepage: https://github.com/honzasterba/cardinity
75
91
  licenses: