payOS 0.1.0 → 0.2.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: 6bb1ea8be43cc547a8501508fa27eb6b0ff6362b4435057c6c4f2a68dc0f523f
4
- data.tar.gz: 30e5e2a4c6b1677025061307e362dfd4556effc1a501ae1294511ac93f8f65f5
3
+ metadata.gz: 155bba52879e7a7743cd447a86317e58e08d7150d5dd9be896f59aee21b355cb
4
+ data.tar.gz: 87b95d58cb37ee032a4c65312ce80968733685e9e57243680946118119413ae1
5
5
  SHA512:
6
- metadata.gz: 65b2c71bdf2feb5353a24ad9ff53f3d3b47464b7eade0fc8a3501189922ccb4b11df342ed085aef2de081c5950e0470760a52008471d09e64cb1757205d90c12
7
- data.tar.gz: 7a718232722397c9573563096ba404046c5f7af01fba605000bb194ef178a0369c8de9f1b5a9611053f8c433ac1a2090f6ef1f959954a4684c2d9b61ad296a18
6
+ metadata.gz: b1eae46715429d9b6d01ca48b9614b80a7b60d840363400092e8fd8b142e3a028209677b1db099413700f5fd5375df43074757e43a9cbfbd5904dcaf17136812
7
+ data.tar.gz: 2486c99e721df4abab4397f0d31cdc2e11f201c359b0c36184aa67206c50e1068f41e89bc3518e67fe0d8652f5df4900f65a5efaf85db3eee03bbe15cef1a0d4
data/CHANGELOG.md CHANGED
@@ -3,3 +3,7 @@
3
3
  ## [0.1.0] - 2024-12-25
4
4
 
5
5
  - Initial release
6
+
7
+ ## [0.2.1] - 2025-02-22
8
+
9
+ - Fix nil value in query string
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # PayOS
2
2
 
3
- PayOS is a Ruby library that provides a simple and elegant way to integrate with the PayOS payment gateway services.
3
+ PayOS is a Ruby library that provides a simple and elegant way to integrate with the [PayOS payment gateway services](https://payos.vn/docs/).
4
4
 
5
5
  ## Installation
6
6
 
@@ -58,6 +58,14 @@ To cancel a payment:
58
58
  PayOS.cancel_payment('4573928465')
59
59
  ```
60
60
 
61
+ ### Confirming a Webhook
62
+
63
+ To confirm a webhook:
64
+
65
+ ```ruby
66
+ PayOS.confirm_webhook('https://example.com/webhook')
67
+ ```
68
+
61
69
  ## Development
62
70
 
63
71
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -4,4 +4,5 @@ module PayOS
4
4
  BASE_URL = "https://api-merchant.payos.vn"
5
5
  API_VERSION = "v2"
6
6
  PAYMENT_URL_PATH = "payment-requests"
7
+ CONFIRM_WEBHOOK_PATH = "confirm-webhook"
7
8
  end
data/lib/payOS/errors.rb CHANGED
@@ -5,4 +5,5 @@ module PayOS
5
5
  class SignatureVerificationError < Error; end
6
6
  class RateLimitError < Error; end
7
7
  class APIError < Error; end
8
+ class ForbiddenError < Error; end
8
9
  end
@@ -23,25 +23,9 @@ module PayOS
23
23
  def verify_signature!
24
24
  return true if @data.nil? || @data["signature"].nil?
25
25
 
26
- # Remove signature from data before verification
27
- data_without_signature = @data.reject { |k, _| k == "signature" }
26
+ string_to_sign = Utils::Formater.params_to_string(@data.reject { |k, _| k == "signature" })
28
27
 
29
- # Sort parameters alphabetically and create string to verify
30
- string_to_verify = data_without_signature.sort.to_h
31
- .map { |k, v| "#{k}=#{v}" }
32
- .join("&")
33
-
34
- # Generate signature
35
- expected_signature = OpenSSL::HMAC.hexdigest(
36
- "SHA256",
37
- @checksum_secret,
38
- string_to_verify
39
- )
40
-
41
- return true if expected_signature == @signature
42
-
43
- raise SignatureVerificationError,
44
- "Invalid signature!"
28
+ Utils::Signature.verify!(string_to_sign, @checksum_secret, @signature)
45
29
  end
46
30
  end
47
31
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "../constants"
4
4
  require_relative "../utils/signature"
5
+ require_relative "../utils/formater"
5
6
 
6
7
  module PayOS
7
8
  module Services
@@ -22,20 +23,17 @@ module PayOS
22
23
  @client.post("#{PayOS::API_VERSION}/#{PayOS::PAYMENT_URL_PATH}/#{payment_url_id}/cancel", {})
23
24
  end
24
25
 
26
+ def confirm_webhook(webhook_url)
27
+ @client.post(PayOS::CONFIRM_WEBHOOK_PATH, { "webhookUrl" => webhook_url })
28
+ end
29
+
25
30
  private
26
31
 
27
32
  def params_with_signature(params)
28
- # Generate signature from the formatted params
29
- formatted_params = params.sort_by { |key, _| key.to_s }.map do |key, value|
30
- formatted_key = key.to_s.split("_").map.with_index do |word, i|
31
- i.zero? ? word : word.capitalize
32
- end.join
33
- [formatted_key, value]
34
- end.to_h
35
-
36
- formatted_params["signature"] = Utils::Signature.generate(formatted_params.map do |k, v|
37
- "#{k}=#{v}"
38
- end.join("&"), PayOS.configuration.checksum_secret)
33
+ formatted_params = Utils::Formater.format_params(params)
34
+ string_to_sign = Utils::Formater.params_to_string(formatted_params)
35
+
36
+ formatted_params["signature"] = Utils::Signature.generate(string_to_sign, PayOS.configuration.checksum_secret)
39
37
 
40
38
  formatted_params
41
39
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PayOS
4
+ module Utils
5
+ class Formater
6
+ def self.format_params(params)
7
+ params.sort_by { |key, _| key.to_s }.map do |key, value|
8
+ formatted_key = key.to_s.split("_").map.with_index do |word, i|
9
+ i.zero? ? word : word.capitalize
10
+ end.join
11
+ [formatted_key, value]
12
+ end.to_h
13
+ end
14
+
15
+ def self.params_to_string(params)
16
+ params.reject { |k, _| k == "signature" }.sort_by { |key, _| key.to_s }.map { |k, v| "#{k}=#{v}" }.join("&")
17
+ end
18
+
19
+ def self.webhook_data_to_string(data)
20
+ sorted_data_by_key = sort_obj_data_by_key(data)
21
+ convert_data_to_query_str(sorted_data_by_key)
22
+ end
23
+
24
+ def self.snake_to_camel(str)
25
+ str.to_s.split("_").map.with_index { |word, i| i.zero? ? word : word.capitalize }.join
26
+ end
27
+
28
+ def self.sort_obj_data_by_key(object)
29
+ object.transform_keys { |key| snake_to_camel(key) }
30
+ .sort
31
+ .to_h
32
+ end
33
+
34
+ def self.convert_data_to_query_str(object)
35
+ object.map do |key, value|
36
+ camel_key = snake_to_camel(key)
37
+ formatted_value = case value
38
+ when Array
39
+ JSON.generate(value.map { |val| sort_obj_data_by_key(val) })
40
+ when nil, "undefined", "null"
41
+ ""
42
+ else
43
+ value.to_s
44
+ end
45
+
46
+ "#{camel_key}=#{formatted_value}"
47
+ end
48
+ .join("&")
49
+ end
50
+ end
51
+ end
52
+ end
@@ -6,6 +6,14 @@ module PayOS
6
6
  def self.generate(data, secret_key)
7
7
  OpenSSL::HMAC.hexdigest("SHA256", secret_key, data)
8
8
  end
9
+
10
+ def self.verify!(data, secret_key, signature)
11
+ raise SignatureVerificationError, "Invalid signature!" if signature.nil?
12
+
13
+ return true if OpenSSL::HMAC.hexdigest("SHA256", secret_key, data) == signature
14
+
15
+ raise SignatureVerificationError, "Invalid signature!"
16
+ end
9
17
  end
10
18
  end
11
19
  end
data/lib/payOS/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PayOS
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.1"
5
5
  end
data/lib/payOS.rb CHANGED
@@ -9,6 +9,8 @@ require_relative "payOS/errors"
9
9
  require_relative "payOS/models/response"
10
10
  require_relative "payOS/client"
11
11
  require_relative "payOS/services/payment_url"
12
+ require_relative "payOS/utils/formater"
13
+ require_relative "payOS/utils/signature"
12
14
 
13
15
  module PayOS
14
16
  class Error < StandardError; end
@@ -42,4 +44,16 @@ module PayOS
42
44
  def self.cancel_payment(payment_url_id)
43
45
  payment_service.cancel(payment_url_id)
44
46
  end
47
+
48
+ def self.confirm_webhook(webhook_url)
49
+ payment_service.confirm_webhook(webhook_url)
50
+ end
51
+
52
+ def self.verify_request!(data, signature)
53
+ # raise ForbiddenError if request_source != PayOS::BASE_URL
54
+
55
+ # verify signature
56
+ string_to_sign = Utils::Formater.webhook_data_to_string(data)
57
+ Utils::Signature.verify!(string_to_sign, PayOS.configuration.checksum_secret, signature)
58
+ end
45
59
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: payOS
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ldhoax
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-12-31 00:00:00.000000000 Z
11
+ date: 2025-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -60,6 +60,7 @@ files:
60
60
  - lib/payOS/errors.rb
61
61
  - lib/payOS/models/response.rb
62
62
  - lib/payOS/services/payment_url.rb
63
+ - lib/payOS/utils/formater.rb
63
64
  - lib/payOS/utils/signature.rb
64
65
  - lib/payOS/version.rb
65
66
  - sig/payOS.rbs