paymob_accept 0.2.1 → 0.3.1

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
  SHA256:
3
- metadata.gz: a6ebddca8de134c54bbf5d5f8dceecde5ae4f65cc735f403e40c04afa13e3f5e
4
- data.tar.gz: f635a17547b178a9ed8428d1fccf8a8157440e1656b6808375d5984b4e26a8e4
3
+ metadata.gz: 3f07b80f4fe23b6ca6da25649d650917ebf48802ce93903ca44dde300acf0f89
4
+ data.tar.gz: 4238ee5fa6e5267b27deac4b3f45701759515420ae4cfc255621691ef8f9b616
5
5
  SHA512:
6
- metadata.gz: 3925164b5d6519cf7216d719222c79c3882a70e88d56b1227c59a9c6bec93e4c9e499f22a7351620eb66c320550104615dddd2bc99b9da03fc82335c41d0c3b1
7
- data.tar.gz: 6009edcbbbc9f9feeaad04f26169cd14b9131102fb651944fee152b4c8c2b2bd62e109a1030b87ee5be5831faea4f0077bff157add1535a0cd87e5d9343616b1
6
+ metadata.gz: f29651bddc3f492f908304e0aa1f552b597ba9e8feeaff5f67f1bb045b2b8791f5bf66cf72a16291ae43b7036da4277dc5276dd75550351a4fe476396e7af127
7
+ data.tar.gz: f761e0b4eb1faafd6688beafdf195416ec2db6160265d9227b3e94c332bddf5c4f493965d2a3ce2767c0f9622ad36b90a5e699e21b7d1307f7c85c1ebe499d91
data/Gemfile.lock CHANGED
@@ -1,15 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- paymob_accept (0.2.0)
4
+ paymob_accept (0.3.1)
5
5
  faraday
6
6
  json-schema
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- addressable (2.8.0)
12
- public_suffix (>= 2.0.2, < 5.0)
11
+ addressable (2.8.1)
12
+ public_suffix (>= 2.0.2, < 6.0)
13
13
  diff-lcs (1.5.0)
14
14
  faraday (2.5.2)
15
15
  faraday-net_http (>= 2.0, < 3.1)
@@ -17,7 +17,7 @@ GEM
17
17
  faraday-net_http (3.0.0)
18
18
  json-schema (3.0.0)
19
19
  addressable (>= 2.8)
20
- public_suffix (4.0.7)
20
+ public_suffix (5.0.0)
21
21
  rake (13.0.6)
22
22
  rspec (3.11.0)
23
23
  rspec-core (~> 3.11.0)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # PaymobAccept
1
+ # Paymob Accept
2
2
 
3
3
  `paymob_accept` is a Ruby gem created by [OneOrder](https://www.oneorder.net/) for integrating [Paymob](https://paymob.com/en) payment solutions with your Ruby application.
4
4
 
@@ -26,13 +26,14 @@ Configure the gem with your configuration
26
26
 
27
27
  ```ruby
28
28
  PaymobAccept.configure do |config|
29
- config.api_key = "######"
30
- config.online_integration_id = "######"
31
- config.kiosk_integration_id = "######"
32
- config.cash_integration_id = "######"
33
- config.wallet_integration_id = "######"
34
- config.auth_integration_id = "######"
35
- config.moto_integration_id = "######"
29
+ config.api_key = "######"
30
+ config.hmac_key = "######"
31
+ config.online_integration_id = "######"
32
+ config.kiosk_integration_id = "######"
33
+ config.cash_integration_id = "######"
34
+ config.wallet_integration_id = "######"
35
+ config.auth_integration_id = "######"
36
+ config.moto_integration_id = "######"
36
37
  end
37
38
  ```
38
39
 
@@ -111,11 +112,15 @@ The `:method` key in the `charge` method could be one of the following:
111
112
 
112
113
  Please refer to the official Paymob documentation for in-depth explanation about each payment method.
113
114
 
114
- The return value of the `charge` method in general is the response of Paymob's server which varies according to the payment method except in `:online`. In an `:online` payment if an `iframe_id` is provided, the return value is an iFrame URL with an embedded payment token. If the `iframe_id` is not provided, only the payment token is returned
115
+ The return value of the `charge` method in general is the response of Paymob's server which varies according to the payment method except in `:online`. In an `:online` payment if an `iframe_id` is provided, the return value is an iFrame URL with an embedded payment token. If the `iframe_id` is not provided, only the payment token and order_id is returned
115
116
 
116
117
  ### Paying with a saved card token
117
118
 
118
- To pre-fill an iFrame with a customer card data or process a MOTO charge, make sure the `customer_data` hash has a `cc_token` key in addition to the fields mentioned above.
119
+ ```ruby
120
+ def pay_moto(customer:, address:, cc_token:, amount_cents:, amount_currency:)
121
+ ```
122
+
123
+ - To pre-fill an iFrame with a customer card data or process a MOTO charge, make sure to pass the `cc_token` key in addition to the fields mentioned above.
119
124
 
120
125
  ## Dealing with charges
121
126
 
@@ -130,9 +135,16 @@ To pre-fill an iFrame with a customer card data or process a MOTO charge, make s
130
135
  - Void a transaction: `service.void!(transaction_id: transaction_id)`
131
136
  - Capture an auth transaction: `service.capture!(transaction_id: transaction_id, amount_cents: amount_cents)`
132
137
 
138
+ ## HMAC validation
139
+
140
+ `PaymobAccept::Hmac.validate(paymob_response: , hmac_key:)`
141
+
142
+ `hmac_key` can be either passed once to the configuration block, otherwise, it must be passed to the `validate` function.
143
+
144
+
133
145
  ## Roadmap
134
146
 
135
- - [ ] HMAC validation
147
+ - [x] HMAC validation
136
148
 
137
149
  ## Contributing
138
150
 
@@ -28,20 +28,20 @@ module PaymobAccept
28
28
  end
29
29
 
30
30
  # 3. Payment Key Request
31
- def generate_payment_intent(customer:, address:, integration_id:, amount_cents:, amount_currency:, iframe_id: nil, order_id: nil, auth_token: get_auth_token)
31
+ def generate_payment_intent(customer:, address:, integration_id:, amount_cents:, amount_currency:, cc_token: nil, iframe_id: nil, order_id: nil, auth_token: get_auth_token)
32
32
  if order_id.nil?
33
33
  order = create_order(amount_cents: amount_cents, amount_currency: amount_currency)
34
34
  order_id = order['id']
35
35
  end
36
36
  payment_token = generate_payment_key(auth_token: auth_token, customer: customer, address: address, order_id: order_id, amount_cents: amount_cents, amount_currency: amount_currency,
37
- integration_id: integration_id)
37
+ integration_id: integration_id, cc_token: cc_token)
38
38
 
39
- format_bill_reference(payment_token, iframe_id)
39
+ { token: format_bill_reference(payment_token, iframe_id), order_id: order_id }
40
40
  end
41
41
 
42
42
  private
43
43
 
44
- def generate_payment_key(customer:, address:, amount_cents:, amount_currency:, integration_id:, order_id: nil, auth_token: get_auth_token)
44
+ def generate_payment_key(customer:, address:, amount_cents:, amount_currency:, integration_id:, cc_token: nil, order_id: nil, auth_token: get_auth_token)
45
45
  body = {
46
46
  "auth_token": auth_token,
47
47
  "amount_cents": amount_cents.to_i,
@@ -65,7 +65,7 @@ module PaymobAccept
65
65
  },
66
66
  "integration_id": integration_id
67
67
  }
68
- body['token'] = customer[:cc_token] unless customer[:cc_token].nil?
68
+ body['token'] = cc_token unless cc_token.nil?
69
69
 
70
70
  response = @client.request('/acceptance/payment_keys', body)
71
71
 
@@ -98,7 +98,6 @@ module PaymobAccept
98
98
  "last_name": { "type": 'string' },
99
99
  "email": { "type": 'string' },
100
100
  "phone_number": { "type": 'string' },
101
- "cc_token": { "type": 'string' },
102
101
  "wallet_mobile_number": { "type": 'string' }
103
102
  },
104
103
  "required": %w[email phone_number]
@@ -36,15 +36,15 @@ module PaymobAccept
36
36
  end
37
37
 
38
38
  # Return an iFrame URL if an iframe_id is provided. Otherwise, returns a payment token
39
- # The iFrame will be prepoulated with the credit card info if customer[cc_token] is present and is valid stored credit card token on Paymob's server
40
- def pay_online(customer:, address:, amount_cents:, amount_currency:, iframe_id: nil)
39
+ # The iFrame will be prepoulated with the credit card info if cc_token is present and is valid stored credit card token on Paymob's server
40
+ def pay_online(customer:, address:, amount_cents:, amount_currency:, cc_token: nil, iframe_id: nil)
41
41
  generate_payment_intent(customer: customer, address: address, amount_cents: amount_cents, amount_currency: amount_currency,
42
- integration_id: online_integration_id, iframe_id: iframe_id)
42
+ integration_id: online_integration_id, iframe_id: iframe_id, cc_token: cc_token)
43
43
  end
44
44
 
45
45
  # Paying MOTO (ie. with a saved card token)
46
- def pay_moto(customer:, address:, amount_cents:, amount_currency:)
47
- if customer[:cc_token].nil?
46
+ def pay_moto(customer:, address:, cc_token:, amount_cents:, amount_currency:)
47
+ if cc_token.nil?
48
48
  raise ArgumentError,
49
49
  'You need to provide a credit card token for MOTO payments'
50
50
  end
@@ -52,7 +52,7 @@ module PaymobAccept
52
52
  bill_reference = generate_payment_intent(customer: customer, address: address, amount_cents: amount_cents, amount_currency: amount_currency,
53
53
  integration_id: auth_integration_id)
54
54
  body = {
55
- "source": { "subtype": 'TOKEN', "identifier": customer[:cc_token] },
55
+ "source": { "subtype": 'TOKEN', "identifier": cc_token },
56
56
  "payment_token": bill_reference
57
57
  }
58
58
  @client.request('/acceptance/payments/pay', body)
@@ -1,7 +1,7 @@
1
1
  module PaymobAccept
2
2
  class Configuration
3
3
  attr_accessor :api_key, :online_integration_id, :cash_integration_id, :kiosk_integration_id,
4
- :auth_integration_id, :wallet_integration_id, :moto_integration_id
4
+ :auth_integration_id, :wallet_integration_id, :moto_integration_id, :hmac_key
5
5
  end
6
6
 
7
7
  class ConfigurationMissingError < StandardError; end
@@ -0,0 +1,21 @@
1
+ module PaymobAccept
2
+ module Hmac
3
+ FILTERED_KEYS = %w[amount_cents created_at currency error_occured has_parent_transaction id
4
+ integration_id is_3d_secure is_auth is_capture is_refunded is_standalone_payment
5
+ is_voided order.id owner
6
+ pending source_data.pan source_data.sub_type source_data.type success].freeze
7
+
8
+ class << self
9
+ def validate(paymob_response:, hmac_key: PaymobAccept.configuration.hmac_key)
10
+ raise ArgumentError, 'hmac_key is required' if hmac_key.nil?
11
+
12
+ digest = OpenSSL::Digest.new('sha512')
13
+ concatenated_str = FILTERED_KEYS.map do |element|
14
+ paymob_response.dig('obj', *element.split('.'))
15
+ end.join
16
+ secure_hash = OpenSSL::HMAC.hexdigest(digest, hmac_key, concatenated_str)
17
+ secure_hash == paymob_response['hmac']
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PaymobAccept
4
- VERSION = '0.2.1'
4
+ VERSION = '0.3.1'
5
5
  end
data/lib/paymob_accept.rb CHANGED
@@ -9,6 +9,7 @@ require 'paymob_accept/api/pay'
9
9
  require 'paymob_accept/api/client'
10
10
  require 'paymob_accept/api/charge'
11
11
 
12
+ require 'paymob_accept/hmac'
12
13
  require 'json'
13
14
  require 'faraday'
14
15
  require 'faraday/net_http'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paymob_accept
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - OneOrder
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-02 00:00:00.000000000 Z
11
+ date: 2022-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -63,6 +63,7 @@ files:
63
63
  - lib/paymob_accept/api/pay.rb
64
64
  - lib/paymob_accept/configuration.rb
65
65
  - lib/paymob_accept/errors/bad_gateway.rb
66
+ - lib/paymob_accept/hmac.rb
66
67
  - lib/paymob_accept/version.rb
67
68
  - paymob_accept.gemspec
68
69
  homepage: https://github.com/oneorder-tech/paymob-accept