razorpay 3.2.1 → 3.2.2

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: 5cd01ee8ed4e390a472e9054a4383fde2482eea27f29992bf7d7fc39f33b24c9
4
- data.tar.gz: b099a18ac979054c0862c1bdfbb643cb997d42cd5b8bb73c034811109793537e
3
+ metadata.gz: 0f1899756cb2c34271a9cd8167029bb2aa56d3a07094df776feab8de024aa69b
4
+ data.tar.gz: daf3f8a28f3d5f211a1f83de9772d4f71fa3aa8b0b415bb0731846930584e11a
5
5
  SHA512:
6
- metadata.gz: 726a001671bd021fb23623a05bcda7a952ee618b4b327d45643dddbe3feae613069aa0abb83fb695b798b759638ba5073cfa50711162dc2077c14e462221fd9b
7
- data.tar.gz: 1fe13db4f2ace27314ccc8601e7679289ad1f3fb02ee150fced0c1c192e8727e01c1922c883bf66d627c10997a635de0b81b1ab51f0f859d650391a3fe01dbe9
6
+ metadata.gz: 9458dcd7356a9017800f5ec4cdae747f17e4595ab7b9f194cb8f14c617f41b8c077497b4438afbd559ecd2f6c0f580f4de5ca5935ed7d7aa6de05679e27be535
7
+ data.tar.gz: 3377a46637db6e97d2c2435818de9d8b4782aac20d72adf4721e149c9fff2b7fbe41a83a0374090d2556cec2b996438160850d95ffa3b7f0d92a6f99d22aa024
data/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@ Changelog for Razorpay-Ruby SDK.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## [3.2.2] - 2024-04-16
8
+
9
+ feat: Added oauth APIs and support for access token based authentication mechanism
10
+ * Added oauth APIs (getAuthURL, getAccessToken, refreshToken, revokeToken)
11
+ * Added support for access token based authentication mechanism
12
+ * Added support for onboarding signature generation
13
+
7
14
  ## [3.2.1] - 2023-12-19
8
15
 
9
16
  Rollback: Generic access point due to some performance concern
data/README.md CHANGED
@@ -27,7 +27,11 @@ Ruby 2.6.8 or later
27
27
 
28
28
  Remember to `require 'razorpay'` before anything else.
29
29
 
30
- Next, you need to setup your key and secret using the following:
30
+ Next, you need to setup your auth details. This setup can be done via two ways:
31
+
32
+ ### Using Private Auth
33
+
34
+ you need to setup your key and secret using the following:
31
35
 
32
36
  ```rb
33
37
  Razorpay.setup('key_id', 'key_secret')
@@ -38,6 +42,16 @@ You can set customer headers for your requests using the following:
38
42
  Razorpay.headers = {"CUSTOM_APP_HEADER" => "CUSTOM_VALUE"}
39
43
  ```
40
44
 
45
+ ### Using Access Token
46
+ you need to setup your access token using the following
47
+ ```rb
48
+ Razorpay.setup_with_oauth('access_token')
49
+ ```
50
+ You can set customer headers for your requests using the following:
51
+ ```rb
52
+ Razorpay.headers = {"CUSTOM_APP_HEADER" => "CUSTOM_VALUE"}
53
+ ```
54
+
41
55
  You can find your API keys at <https://dashboard.razorpay.com/#/app/keys>.
42
56
 
43
57
  If you are using rails, the right place to do this might be `config/initializers/razorpay.rb`.
@@ -70,6 +84,7 @@ If you are using rails, the right place to do this might be `config/initializers
70
84
  - [Register NACH and Charge First Payment Together](documents/registerNach.md)
71
85
  - [Payment Verification](documents/paymentVerification.md)
72
86
  - [Webhook](documents/webhook.md)
87
+ - [OAuthToken](documents/oauth_token.md)
73
88
 
74
89
  ## Development
75
90
 
@@ -0,0 +1,142 @@
1
+ ### OAuthToken
2
+
3
+ ```rb
4
+ require "razorpay"
5
+ ```
6
+
7
+ ### Generate Authorize Url
8
+ ```rb
9
+ body = {
10
+ submerchant_id: '<SUBMERCHANT_MID>',
11
+ timestamp: Time.now.to_i
12
+ }
13
+ onboarding_signature = Razorpay::Utility.generate_onboarding_signature(body, '<YOUR_CLIENT_SECRET>')
14
+
15
+ options = {
16
+ 'client_id' => '<YOUR_CLIENT_ID>',
17
+ 'redirect_uri' => 'https://example.com/razorpay_callback',
18
+ 'scopes' => ["read_write"],
19
+ 'state' => 'NOBYtv8r6c75ex6WZ',
20
+ 'onboarding_signature' => onboarding_signature
21
+ }
22
+ authorize_url = Razorpay::OAuthToken.get_auth_url(options)
23
+ ```
24
+
25
+ **Parameters:**
26
+
27
+ | Name | Type | Description |
28
+ |----------------------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------|
29
+ | client_id* | string | Unique client identifier. |
30
+ | redirect_uri* | string | Callback URL used by Razorpay to redirect after the user approves or denies the authorisation request. The client should whitelist the 'redirect_uri'. |
31
+ | scopes* | array | Defines what access your application is requesting from the user. You can request one or multiple scopes by adding them to an array as indicated above. |
32
+ | state* | string | A random string generated by your service. This parameter helps prevent cross-site request forgery (CSRF) attacks. |
33
+ | onboarding_signature | string | A cryptographic string generated by your service using generateOnboardingSignature method in Utils class. Only applicable for accounts created with pre-fill KYC |
34
+
35
+ **Response:**
36
+ ```
37
+ "https://auth.razorpay.com/authorize?response_type=code&client_id=<YOUR_CLIENT_ID>&redirect_uri=https:%2F%2Fexample.com%2Frazorpay_callback&scope[]=read_only&scope[]=rx_read_write&state=NOBYtv8r6c75ex6WZ&onboarding_signature=<GENERATED_ONBOARDING_SIGNATURE>"
38
+ ```
39
+
40
+ -------------------------------------------------------------------------------------------------------
41
+ ### Get Access token
42
+ ```rb
43
+ options = {
44
+ 'client_id' => '<YOUR_CLIENT_ID>',
45
+ 'client_secret' => '<YOUR_CLIENT_SECRET>',
46
+ 'redirect_uri' => 'https://example.com/razorpay_callback',
47
+ 'grant_type' => 'authorization_code',
48
+ 'code' => '<AUTHORIZATION_CODE>',
49
+ 'mode' => 'test'
50
+ }
51
+ oauth_token = Razorpay::OAuthToken.get_access_token(options)
52
+ ```
53
+
54
+ **Parameters:**
55
+
56
+ | Name | Type | Description |
57
+ |----------------|--------|------------------------------------------------------------------------------------------------------------------------------|
58
+ | client_id* | string | Unique client identifier. |
59
+ | client_secret* | string | Client secret string. |
60
+ | redirect_uri* | string | Specifies the same redirect_uri used in the authorisation request. |
61
+ | grant_type* | string | Defines the grant type for the request. Possible value are:<ul><li>authorization_code</li><li>client_credentials</li></ul> |
62
+ | code* | string | Decoded authorisation code received in the last step. Note: Pass this parameter only when grant_type is 'authorization_code' |
63
+ | mode | string | The type of mode. Possible values: <ul><li>test</li><li>live (default)</li></ul> |
64
+
65
+ **Response:**
66
+ ```json
67
+ {
68
+ "public_token": "rzp_test_oauth_9xu1rkZqoXlClS",
69
+ "token_type": "Bearer",
70
+ "expires_in": 7862400,
71
+ "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IkY1Z0NQYkhhRzRjcUpnIn0.eyJhdWQiOiJGNFNNeEgxanMxbkpPZiIsImp0aSI6IkY1Z0NQYkhhRzRjcUpnIiwiaWF0IjoxNTkyODMxMDExLCJuYmYiOjE1OTI4MzEwMTEsInN1YiI6IiIsImV4cCI6MTYwMDc3OTgxMSwidXNlcl9pZCI6IkYycVBpejJEdzRPRVFwIiwibWVyY2hhbnRfaWQiOiJGMnFQaVZ3N0lNV01GSyIsInNjb3BlcyI6WyJyZWFkX29ubHkiXX0.Wwqt5czhoWpVzP5_aoiymKXoGj-ydo-4A_X2jf_7rrSvk4pXdqzbA5BMrHxPdPbeFQWV6vsnsgbf99Q3g-W4kalHyH67LfAzc3qnJ-mkYDkFY93tkeG-MCco6GJW-Jm8xhaV9EPUak7z9J9jcdluu9rNXYMtd5qxD8auyRYhEgs",
72
+ "refresh_token": "def50200f42e07aded65a323f6c53181d802cc797b62cc5e78dd8038d6dff253e5877da9ad32f463a4da0ad895e3de298cbce40e162202170e763754122a6cb97910a1f58e2378ee3492dc295e1525009cccc45635308cce8575bdf373606c453ebb5eb2bec062ca197ac23810cf9d6cf31fbb9fcf5b7d4de9bf524c89a4aa90599b0151c9e4e2fa08acb6d2fe17f30a6cfecdfd671f090787e821f844e5d36f5eacb7dfb33d91e83b18216ad0ebeba2bef7721e10d436c3984daafd8654ed881c581d6be0bdc9ebfaee0dc5f9374d7184d60aae5aa85385690220690e21bc93209fb8a8cc25a6abf1108d8277f7c3d38217b47744d7",
73
+ "razorpay_account_id": "acc_Dhk2qDbmu6FwZH"
74
+ }
75
+ ```
76
+
77
+ -------------------------------------------------------------------------------------------------------
78
+
79
+ ### Get Access token using refresh token
80
+ ```rb
81
+ options = {
82
+ 'client_id' => '<YOUR_CLIENT_ID>',
83
+ 'client_secret' => '<YOUR_CLIENT_SECRET>',
84
+ 'refresh_token' => 'def5020096e1c470c901d34cd60fa53abdaf3662sa0'
85
+ }
86
+ oauth_token = Razorpay::OAuthToken.refresh_token(options)
87
+ ```
88
+
89
+ **Parameters:**
90
+
91
+ | Name | Type | Description |
92
+ |----------------|-----------|--------------------------------------------|
93
+ | client_id* | string | Unique client identifier. |
94
+ | client_secret* | string | Client secret string. |
95
+ | refresh_token* | string | The previously-stored refresh token value. |
96
+
97
+ **Response:**
98
+ ```json
99
+ {
100
+ "public_token": "rzp_test_oauth_9xu1rkZqoXlClS",
101
+ "token_type": "Bearer",
102
+ "expires_in": 7862400,
103
+ "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6Ijl4dTF",
104
+ "refresh_token": "def5020096e1c470c901d34cd60fa53abdaf36620e823ffa53"
105
+ }
106
+ ```
107
+
108
+ -------------------------------------------------------------------------------------------------------
109
+
110
+ ### Revoke a token
111
+ ```rb
112
+ options = {
113
+ 'client_id' => '<YOUR_CLIENT_ID>',
114
+ 'client_secret' => '<YOUR_CLIENT_SECRET>',
115
+ 'token' => 'def5020096e1c470c901d34cd60fa53abdaf36620e823ffa53'
116
+ 'token_type_hint' => 'access_token'
117
+ }
118
+ response = Razorpay::OAuthToken.revoke_token(options)
119
+ ```
120
+
121
+ **Parameters:**
122
+
123
+ | Name | Type | Description |
124
+ |------------------|----------|----------------------------------------------------------------------------------------------------------|
125
+ | client_id* | string | Unique client identifier. |
126
+ | client_secret* | string | Client secret string. |
127
+ | token_type_hint* | string | The type of token for the request. Possible values: <ul><li>access_token</li><li>refresh_token</li></ul> |
128
+ | token* | string | The token whose access should be revoked. |
129
+
130
+ **Response:**
131
+ ```json
132
+ {
133
+ "message": "Token Revoked"
134
+ }
135
+ ```
136
+ -------------------------------------------------------------------------------------------------------
137
+
138
+ **PN: * indicates mandatory fields**
139
+ <br>
140
+ <br>
141
+ **For reference click [here](https://razorpay.com/docs/partners/platform/onboard-businesses/integrate-oauth/integration-steps)**
142
+
@@ -2,5 +2,10 @@
2
2
  module Razorpay
3
3
  BASE_URI = 'https://api.razorpay.com'.freeze
4
4
  TEST_URL = 'https://api.razorpay.com/'.freeze
5
- VERSION = '3.2.1'.freeze
5
+ VERSION = '3.2.2'.freeze
6
+ AUTH_URL = 'https://auth.razorpay.com'.freeze
7
+ API_HOST = 'API'.freeze
8
+ AUTH_HOST = 'AUTH'.freeze
9
+ PRIVATE_AUTH = 'Private'.freeze
10
+ OAUTH = 'OAuth'.freeze
6
11
  end
@@ -0,0 +1,109 @@
1
+ require 'razorpay/request'
2
+ require 'razorpay/entity'
3
+ require 'razorpay/payload_validator'
4
+ require 'razorpay/validation_config'
5
+
6
+ module Razorpay
7
+ # OAuth APIs allow to you create and manage access tokens
8
+ class OAuthToken < Entity
9
+ def self.request
10
+ Razorpay::Request.new('token', Razorpay::AUTH_HOST)
11
+ end
12
+
13
+ def self.get_auth_url(options)
14
+ validate_auth_url_request(options)
15
+ uri = URI.join(Razorpay::AUTH_URL, '/authorize')
16
+
17
+ query_params = {
18
+ 'response_type' => 'code',
19
+ 'client_id' => options['client_id'],
20
+ 'redirect_uri' => options['redirect_uri'],
21
+ 'state' => options['state']
22
+ }
23
+
24
+ options['scopes'].each { |scope| query_params["scope[]"] = scope }
25
+
26
+ if options.has_key?('onboarding_signature')
27
+ query_params['onboarding_signature'] = options['onboarding_signature']
28
+ end
29
+ uri.query = URI.encode_www_form(query_params)
30
+ uri.to_s
31
+ end
32
+
33
+ def self.get_access_token(options)
34
+ validate_access_token_request(options)
35
+ r = request
36
+ r.request :post, "/token", options
37
+ end
38
+
39
+ def self.refresh_token(options)
40
+ options['grant_type'] = 'refresh_token'
41
+ validate_refresh_token_request(options)
42
+ r = request
43
+ r.request :post, "/token", options
44
+ end
45
+
46
+ def self.revoke_token(options)
47
+ validate_revoke_token_request(options)
48
+ r = request
49
+ r.request :post, "/revoke", options
50
+ end
51
+
52
+ class << self
53
+
54
+ private
55
+
56
+ def validate_auth_url_request(options)
57
+ Razorpay::PayloadValidator.validate(options, get_validations_for_auth_request_url)
58
+ end
59
+
60
+ def validate_access_token_request(options)
61
+ Razorpay::PayloadValidator.validate(options, get_validations_for_access_token_request)
62
+ end
63
+
64
+ def validate_refresh_token_request(options)
65
+ Razorpay::PayloadValidator.validate(options, get_validations_for_refresh_token_request)
66
+ end
67
+
68
+ def validate_revoke_token_request(options)
69
+ Razorpay::PayloadValidator.validate(options, get_validations_for_revoke_token_request)
70
+ end
71
+
72
+ def get_validations_for_auth_request_url
73
+ [
74
+ Razorpay::ValidationConfig.new('client_id', [:id]),
75
+ Razorpay::ValidationConfig.new('redirect_uri', [:non_empty_string, :url]),
76
+ Razorpay::ValidationConfig.new('scopes', [:non_null]),
77
+ Razorpay::ValidationConfig.new('state', [:non_empty_string])
78
+ ]
79
+ end
80
+
81
+ def get_validations_for_access_token_request
82
+ [
83
+ Razorpay::ValidationConfig.new('client_id', [:id]),
84
+ Razorpay::ValidationConfig.new('client_secret', [:non_empty_string]),
85
+ Razorpay::ValidationConfig.new('redirect_uri', [:non_empty_string, :url]),
86
+ Razorpay::ValidationConfig.new('grant_type', [:token_grant])
87
+ ]
88
+ end
89
+
90
+ def get_validations_for_refresh_token_request
91
+ [
92
+ Razorpay::ValidationConfig.new('client_id', [:id]),
93
+ Razorpay::ValidationConfig.new('client_secret', [:non_empty_string]),
94
+ Razorpay::ValidationConfig.new('refresh_token', [:non_empty_string]),
95
+ Razorpay::ValidationConfig.new('grant_type', [:token_grant])
96
+ ]
97
+ end
98
+
99
+ def get_validations_for_revoke_token_request
100
+ [
101
+ Razorpay::ValidationConfig.new('client_id', [:id]),
102
+ Razorpay::ValidationConfig.new('client_secret', [:non_empty_string]),
103
+ Razorpay::ValidationConfig.new('token', [:non_empty_string]),
104
+ Razorpay::ValidationConfig.new('token_type_hint', [:non_empty_string])
105
+ ]
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,93 @@
1
+ module Razorpay
2
+
3
+ ValidationType = {
4
+ non_null: :non_null,
5
+ non_empty_string: :non_empty_string,
6
+ url: :url,
7
+ id: :id,
8
+ mode: :mode,
9
+ token_grant: :token_grant
10
+ }
11
+
12
+ # PayloadValidator allows to perform basic validations
13
+ class PayloadValidator
14
+ def self.validate(request, validation_configs)
15
+ validation_configs.each do |config|
16
+ field_name = config.field_name
17
+ config.validations.each do |validation_type|
18
+ apply_validation(request, field_name, validation_type)
19
+ end
20
+ end
21
+ end
22
+
23
+ class << self
24
+
25
+ private
26
+
27
+ def apply_validation(payload, field, validation_type)
28
+ case validation_type
29
+ when ValidationType[:non_null]
30
+ validate_non_null(payload, field)
31
+ when ValidationType[:non_empty_string]
32
+ validate_non_empty_string(payload, field)
33
+ when ValidationType[:url]
34
+ validate_url(payload, field)
35
+ when ValidationType[:id]
36
+ validate_id(payload, field)
37
+ when ValidationType[:mode]
38
+ validate_mode(payload, field)
39
+ when ValidationType[:token_grant]
40
+ validate_grant_type(payload, field)
41
+ end
42
+ end
43
+
44
+ def validate_non_null(payload, field)
45
+ raise Razorpay::Error.new, "Field #{field} cannot be null" unless payload.key?(field) && !payload[field].nil?
46
+ end
47
+
48
+ def validate_non_empty_string(payload, field)
49
+ raise Razorpay::Error.new, "Field #{field} cannot be empty" if payload[field].to_s.strip.empty?
50
+ end
51
+
52
+ def validate_url(payload, field)
53
+ url = payload[field]
54
+ url_regex = /^(http[s]?):\/\/[^\s\/$.?#].[^\s]*$/
55
+
56
+ unless url_regex.match?(url)
57
+ error_message = "Field #{field} is not a valid URL"
58
+ raise Razorpay::Error.new, error_message
59
+ end
60
+ end
61
+
62
+ def validate_id(payload, field)
63
+ validate_non_null(payload, field)
64
+ validate_non_empty_string(payload, field)
65
+ value = payload[field]
66
+ id_regex = /^[A-Za-z0-9]{1,14}$/
67
+
68
+ unless value.match?(id_regex)
69
+ error_message = "Field #{field} is not a valid ID"
70
+ raise Razorpay::Error.new, error_message
71
+ end
72
+ end
73
+
74
+ def validate_mode(payload, field)
75
+ validate_non_null(payload, field)
76
+ unless ["test", "live"].include?(payload[field])
77
+ error_message = "Invalid value provided for field #{field}"
78
+ raise Razorpay::Error.new, error_message
79
+ end
80
+ end
81
+
82
+ def validate_grant_type(payload, field)
83
+ validate_non_null(payload, field)
84
+ case payload[field]
85
+ when 'authorization_code'
86
+ validate_non_null(payload, 'code');
87
+ when 'refresh_token'
88
+ validate_non_null(payload, 'refresh_token');
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -11,20 +11,30 @@ module Razorpay
11
11
 
12
12
  ssl_ca_file File.dirname(__FILE__) + '/../ca-bundle.crt'
13
13
 
14
- def initialize(entity_name = nil)
15
- self.class.base_uri(Razorpay::BASE_URI)
14
+ def initialize(entity_name = nil, host = Razorpay::API_HOST)
15
+ self.class.base_uri(get_base_url(host))
16
16
  @entity_name = entity_name
17
17
  custom_headers = Razorpay.custom_headers || {}
18
18
  predefined_headers = {
19
19
  'User-Agent' => "Razorpay-Ruby/#{Razorpay::VERSION}; Ruby/#{RUBY_VERSION}"
20
20
  }
21
+
21
22
  # Order is important to give precedence to predefined headers
22
23
  headers = custom_headers.merge(predefined_headers)
23
- @options = {
24
- basic_auth: Razorpay.auth,
25
- timeout: 30,
26
- headers: headers
27
- }
24
+
25
+ if Razorpay.auth_type == Razorpay::OAUTH
26
+ @options = {
27
+ timeout: 30,
28
+ headers: headers
29
+ }
30
+ headers['Authorization'] = 'Bearer ' + Razorpay.access_token
31
+ else
32
+ @options = {
33
+ basic_auth: Razorpay.auth,
34
+ timeout: 30,
35
+ headers: headers
36
+ }
37
+ end
28
38
  end
29
39
 
30
40
  def fetch(id, version="v1")
@@ -74,6 +84,13 @@ module Razorpay
74
84
  self.class.send(method, url, @options)
75
85
  end
76
86
 
87
+ def get_base_url(host)
88
+ if host == Razorpay::AUTH_HOST
89
+ return Razorpay::AUTH_URL
90
+ end
91
+ Razorpay::BASE_URI
92
+ end
93
+
77
94
  # Since we need to change the base route
78
95
  def make_test_request
79
96
  self.class.get Razorpay::TEST_URL, @options
@@ -26,6 +26,11 @@ module Razorpay
26
26
  verify_signature(body, signature, secret)
27
27
  end
28
28
 
29
+ def self.generate_onboarding_signature(body, secret)
30
+ json_data = body.to_json
31
+ encrypt(json_data, secret);
32
+ end
33
+
29
34
  class << self
30
35
  private
31
36
 
@@ -52,6 +57,25 @@ module Razorpay
52
57
 
53
58
  r.zero?
54
59
  end
60
+
61
+ def encrypt(data, secret)
62
+ iv = secret[0, 12]
63
+ key = secret[0, 16]
64
+
65
+ cipher = OpenSSL::Cipher.new('aes-128-gcm')
66
+ cipher.encrypt
67
+ cipher.key = key
68
+ cipher.iv = iv
69
+
70
+ cipher.auth_data = ""
71
+
72
+ encrypted = cipher.update(data) + cipher.final
73
+
74
+ tag = cipher.auth_tag
75
+ combined_encrypted_data = encrypted + tag
76
+
77
+ encrypted_data_hex = combined_encrypted_data.unpack1("H*")
78
+ end
55
79
  end
56
80
  end
57
81
  end
@@ -0,0 +1,11 @@
1
+ module Razorpay
2
+
3
+ class ValidationConfig
4
+ attr_reader :field_name, :validations
5
+
6
+ def initialize(field_name, validations)
7
+ @field_name = field_name
8
+ @validations = validations
9
+ end
10
+ end
11
+ end
data/lib/razorpay.rb CHANGED
@@ -26,15 +26,22 @@ require 'razorpay/token'
26
26
  require 'razorpay/product'
27
27
  require 'razorpay/stakeholder'
28
28
  require 'razorpay/account'
29
+ require 'razorpay/oauth_token'
29
30
 
30
31
  # Base Razorpay module
31
32
  module Razorpay
32
33
  class << self
33
- attr_accessor :auth, :custom_headers
34
+ attr_accessor :auth, :custom_headers, :access_token, :auth_type
34
35
  end
35
36
 
36
37
  def self.setup(key_id, key_secret)
37
38
  self.auth = { username: key_id, password: key_secret }
39
+ self.auth_type = Razorpay::PRIVATE_AUTH
40
+ end
41
+
42
+ def self.setup_with_oauth(access_token)
43
+ self.access_token = access_token
44
+ self.auth_type = Razorpay::OAUTH
38
45
  end
39
46
 
40
47
  def self.headers=(headers = {})
@@ -0,0 +1,8 @@
1
+ {
2
+ "public_token": "rzp_test_oauth_9xu1rkZqoXlClS",
3
+ "token_type": "Bearer",
4
+ "expires_in": 7862400,
5
+ "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IkY1Z0NQYkhhRzRjcUpnIn0.eyJhdWQiOiJGNFNNeEgxanMxbkpPZiIsImp0aSI6IkY1Z0NQYkhhRzRjcUpnIiwiaWF0IjoxNTkyODMxMDExLCJuYmYiOjE1OTI4MzEwMTEsInN1YiI6IiIsImV4cCI6MTYwMDc3OTgxMSwidXNlcl9pZCI6IkYycVBpejJEdzRPRVFwIiwibWVyY2hhbnRfaWQiOiJGMnFQaVZ3N0lNV01GSyIsInNjb3BlcyI6WyJyZWFkX29ubHkiXX0.Wwqt5czhoWpVzP5_aoiymKXoGj-ydo-4A_X2jf_7rrSvk4pXdqzbA5BMrHxPdPbeFQWV6vsnsgbf99Q3g-W4kalHyH67LfAzc3qnJ-mkYDkFY93tkeG-MCco6GJW-Jm8xhaV9EPUak7z9J9jcdluu9rNXYMtd5qxD8auyRYhEgs",
6
+ "refresh_token": "def50200f42e07aded65a323f6c53181d802cc797b62cc5e78dd8038d6dff253e5877da9ad32f463a4da0ad895e3de298cbce40e162202170e763754122a6cb97910a1f58e2378ee3492dc295e1525009cccc45635308cce8575bdf373606c453ebb5eb2bec062ca197ac23810cf9d6cf31fbb9fcf5b7d4de9bf524c89a4aa90599b0151c9e4e2fa08acb6d2fe17f30a6cfecdfd671f090787e821f844e5d36f5eacb7dfb33d91e83b18216ad0ebeba2bef7721e10d436c3984daafd8654ed881c581d6be0bdc9ebfaee0dc5f9374d7184d60aae5aa85385690220690e21bc93209fb8a8cc25a6abf1108d8277f7c3d38217b47744d7",
7
+ "razorpay_account_id": "acc_Dhk2qDbmu6FwZH"
8
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "message": "Token Revoked"
3
+ }
@@ -0,0 +1,105 @@
1
+ require 'test_helper'
2
+
3
+ module Razorpay
4
+ # Tests for Razorpay::OauthToken
5
+ class RazorpayOAuthTokenTest < Minitest::Test
6
+ class OAuthToken < Razorpay::Entity; end
7
+
8
+ def test_get_auth_url
9
+ options = {
10
+ 'client_id' => '8DXCMTshWSWECc',
11
+ 'redirect_uri' => 'https://example.com/razorpay_callback',
12
+ 'state' => 'NOBYtv8r6c75ex6WZ',
13
+ 'scopes' => ["read_write"]
14
+ }
15
+
16
+ expected_auth_url = "https://auth.razorpay.com/authorize?response_type=code&client_id=8DXCMTshWSWECc&redirect_uri=https%3A%2F%2Fexample.com%2Frazorpay_callback&state=NOBYtv8r6c75ex6WZ&scope%5B%5D=read_write"
17
+ auth_url = Razorpay::OAuthToken.get_auth_url(options)
18
+ assert_equal expected_auth_url, auth_url
19
+ end
20
+
21
+ def test_request_validation_for_get_auth_url
22
+ options = {
23
+ 'client_id' => '8DXCMTshWSWECc',
24
+ 'redirect_uri' => 'https://example.com/razorpay_callback',
25
+ 'scopes' => ["read_write"]
26
+ }
27
+ assert_raises(Razorpay::Error) do
28
+ Razorpay::OAuthToken.get_auth_url(options)
29
+ end
30
+ end
31
+
32
+ def test_get_access_token
33
+ options = {
34
+ 'client_id' => '8DXCMTshWSWECc',
35
+ 'client_secret' => 'AESSECRETKEY',
36
+ 'grant_type' => 'client_credentials',
37
+ 'redirect_uri' => 'http://example.com/razorpay_callback',
38
+ 'mode' => 'test'
39
+ }
40
+ stub_post(/token$/,'fake_oauth_token',options)
41
+ oauth_token = Razorpay::OAuthToken.get_access_token(options)
42
+ assert_instance_of Razorpay::Entity, oauth_token, 'OAuthToken not an instance of Entity class'
43
+ assert_equal 'rzp_test_oauth_9xu1rkZqoXlClS', oauth_token.public_token, 'Public Tokens do not match'
44
+ end
45
+
46
+ def test_get_access_token_validation_failure
47
+ options = {
48
+ 'client_id' => '8DXCMTshWSWECc',
49
+ 'grant_type' => 'client_credentials',
50
+ 'redirect_uri' => 'http://example.com/razorpay_callback',
51
+ 'mode' => 'test'
52
+ }
53
+ assert_raises(Razorpay::Error) do
54
+ Razorpay::OAuthToken.get_access_token(options)
55
+ end
56
+ end
57
+
58
+ def test_refresh_token
59
+ options = {
60
+ 'client_id' => '8DXCMTshWSWECc',
61
+ 'client_secret' => 'AESSECRETKEY',
62
+ 'refresh_token' => 'def5020096e1c470c901d34cd60fa53abdaf3662sa0'
63
+ }
64
+ expected_request_payload = options.merge('grant_type': 'refresh_token')
65
+ stub_post(/token$/,'fake_oauth_token',expected_request_payload)
66
+ oauth_token = Razorpay::OAuthToken.refresh_token(options)
67
+ assert_instance_of Razorpay::Entity, oauth_token, 'OAuthToken not an instance of Entity class'
68
+ assert_equal 'rzp_test_oauth_9xu1rkZqoXlClS', oauth_token.public_token, 'Public Tokens do not match'
69
+ end
70
+
71
+ def test_refresh_token_validation_failure
72
+ options = {
73
+ 'client_id' => '8DXCMTshWSWECc',
74
+ 'refresh_token' => 'def5020096e1c470c901d34cd60fa53abdaf3662sa0'
75
+ }
76
+ assert_raises(Razorpay::Error) do
77
+ Razorpay::OAuthToken.refresh_token(options)
78
+ end
79
+ end
80
+
81
+ def test_revoke_token
82
+ options = {
83
+ 'client_id' => '8DXCMTshWSWECc',
84
+ 'client_secret' => 'AESSECRETKEY',
85
+ 'token_type_hint' => 'access_token',
86
+ 'token' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJKQTFwODVudE1ySEpoQSIsImp0aSI6IkpPZkd0aHFDTmhqQUhTIiwiaWF0IjoxNjUxMTI0NTU0LCJuYmYiOjE2NTExMjQ1NTQsInN1YiI6IiIsImV4cCI6MTY1ODk4Njk1Miw'
87
+ }
88
+ stub_post(/revoke$/,'fake_revoke_token',options)
89
+ oauth_token = Razorpay::OAuthToken.revoke_token(options)
90
+ assert_instance_of Razorpay::Entity, oauth_token, 'OAuthToken not an instance of Entity class'
91
+ assert_equal 'Token Revoked', oauth_token.message, 'Messages do not match'
92
+ end
93
+
94
+ def test_revoke_token_validation_failure
95
+ options = {
96
+ 'client_id' => '8DXCMTshWSWECc',
97
+ 'client_secret' => 'AESSECRETKEY',
98
+ 'token_type_hint' => 'access_token'
99
+ }
100
+ assert_raises(Razorpay::Error) do
101
+ Razorpay::OAuthToken.revoke_token(options)
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,61 @@
1
+ require 'test_helper'
2
+ require 'razorpay/validation_config'
3
+
4
+ module Razorpay
5
+ # Tests for Razorpay::PayloadValidator
6
+ class RazorpayPayloadValidatorTest < Minitest::Test
7
+ def test_validate_mode
8
+ payload = {
9
+ 'mode1' => 'test',
10
+ 'mode2' => 'live'
11
+ }
12
+ assert_silent do
13
+ Razorpay::PayloadValidator.validate(payload, [
14
+ Razorpay::ValidationConfig.new('mode1', [:mode]),
15
+ Razorpay::ValidationConfig.new('mode2', [:mode]),
16
+ ])
17
+ end
18
+ end
19
+
20
+ def test_mode_validation_failure
21
+ payload = {
22
+ 'mode' => 'testvalue'
23
+ }
24
+ assert_raises(Razorpay::Error) do
25
+ Razorpay::PayloadValidator.validate(payload, [
26
+ Razorpay::ValidationConfig.new('mode', [:mode])
27
+ ])
28
+ end
29
+ end
30
+
31
+ def test_url_validation_failure
32
+ payload = {
33
+ 'redirect_uri' => 'test.com'
34
+ }
35
+ assert_raises(Razorpay::Error) do
36
+ Razorpay::PayloadValidator.validate(payload, [
37
+ Razorpay::ValidationConfig.new('redirect_uri', [:url])
38
+ ])
39
+ end
40
+ end
41
+
42
+ def test_non_null_validation_failure
43
+ assert_raises(Razorpay::Error) do
44
+ Razorpay::PayloadValidator.validate({}, [
45
+ Razorpay::ValidationConfig.new('redirect_uri', [:non_null])
46
+ ])
47
+ end
48
+ end
49
+
50
+ def test_id_validation_failure
51
+ payload = {
52
+ 'client_id' => 'fjidhf'
53
+ }
54
+ assert_raises(Razorpay::Error) do
55
+ Razorpay::PayloadValidator.validate({}, [
56
+ Razorpay::ValidationConfig.new('client_id', [:id])
57
+ ])
58
+ end
59
+ end
60
+ end
61
+ end
@@ -49,5 +49,22 @@ module Razorpay
49
49
  headers: headers,
50
50
  times: 1
51
51
  end
52
+
53
+ def test_oauth_setup
54
+ Razorpay.setup_with_oauth('access_token')
55
+ assert_equal 'access_token', Razorpay.access_token
56
+ end
57
+
58
+ # # We mock this request
59
+ def test_auth_header_and_user_agent_for_oauth
60
+ stub_get(/$/, 'hello_response')
61
+ Razorpay.setup_with_oauth('access_token')
62
+ Razorpay::Request.new('dummy').make_test_request
63
+ user_agent = "Razorpay-Ruby/#{Razorpay::VERSION}; Ruby/#{RUBY_VERSION}"
64
+ headers = { 'User-Agent' => user_agent, 'Authorization' => 'Bearer access_token' }
65
+ assert_requested :get, 'https://api.razorpay.com/',
66
+ headers: headers,
67
+ times: 1
68
+ end
52
69
  end
53
70
  end
@@ -1,4 +1,5 @@
1
1
  require 'test_helper'
2
+ require 'json'
2
3
 
3
4
  module Razorpay
4
5
  # Tests for Razorpay::Utility
@@ -80,5 +81,38 @@ module Razorpay
80
81
  Razorpay::Utility.verify_webhook_signature(webhook_body, signature, secret)
81
82
  end
82
83
  end
84
+
85
+ def test_generate_onboarding_signature
86
+ secret = "EnLs21M47BllR3X8PSFtjtbd"
87
+ timestamp = Time.now.to_i
88
+ body = {
89
+ submerchant_id: 'NSgKfYIR2f9v2y',
90
+ timestamp: timestamp
91
+ }
92
+ encryptedData = Razorpay::Utility.generate_onboarding_signature(body, secret)
93
+ json_data = decrypt(encryptedData, secret)
94
+ body = JSON.parse(json_data)
95
+ assert_equal 'NSgKfYIR2f9v2y', body['submerchant_id'], 'Submerchant IDs do not match'
96
+ assert_equal timestamp, body['timestamp'], 'Timestamps do not match'
97
+ end
98
+
99
+ def decrypt(data, secret)
100
+ combined_encrypted_data = [data].pack("H*")
101
+
102
+ iv = secret[0, 12]
103
+ key = secret[0, 16]
104
+ tag = combined_encrypted_data[-16..]
105
+
106
+ encrypted_data = combined_encrypted_data[0...-16]
107
+
108
+ cipher = OpenSSL::Cipher.new('aes-128-gcm')
109
+ cipher.decrypt
110
+ cipher.key = key
111
+ cipher.iv = iv
112
+ cipher.auth_tag = tag
113
+ cipher.auth_data = ""
114
+
115
+ cipher.update(encrypted_data) + cipher.final
116
+ end
83
117
  end
84
118
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: razorpay
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.1
4
+ version: 3.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abhay Rana
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-12-19 00:00:00.000000000 Z
12
+ date: 2024-04-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
@@ -138,6 +138,7 @@ files:
138
138
  - documents/emandate.md
139
139
  - documents/fund.md
140
140
  - documents/items.md
141
+ - documents/oauth_token.md
141
142
  - documents/order.md
142
143
  - documents/papernach.md
143
144
  - documents/payment.md
@@ -176,7 +177,9 @@ files:
176
177
  - lib/razorpay/iin.rb
177
178
  - lib/razorpay/invoice.rb
178
179
  - lib/razorpay/item.rb
180
+ - lib/razorpay/oauth_token.rb
179
181
  - lib/razorpay/order.rb
182
+ - lib/razorpay/payload_validator.rb
180
183
  - lib/razorpay/payment.rb
181
184
  - lib/razorpay/payment_link.rb
182
185
  - lib/razorpay/payment_method.rb
@@ -192,6 +195,7 @@ files:
192
195
  - lib/razorpay/token.rb
193
196
  - lib/razorpay/transfer.rb
194
197
  - lib/razorpay/utility.rb
198
+ - lib/razorpay/validation_config.rb
195
199
  - lib/razorpay/virtual_account.rb
196
200
  - lib/razorpay/webhook.rb
197
201
  - razorpay-ruby.gemspec
@@ -219,6 +223,7 @@ files:
219
223
  - test/fixtures/fake_instant_settlement.json
220
224
  - test/fixtures/fake_invoice.json
221
225
  - test/fixtures/fake_item.json
226
+ - test/fixtures/fake_oauth_token.json
222
227
  - test/fixtures/fake_order.json
223
228
  - test/fixtures/fake_order_transfers.json
224
229
  - test/fixtures/fake_otp_generate.json
@@ -236,6 +241,7 @@ files:
236
241
  - test/fixtures/fake_recurring.json
237
242
  - test/fixtures/fake_refund.json
238
243
  - test/fixtures/fake_refunded_payment.json
244
+ - test/fixtures/fake_revoke_token.json
239
245
  - test/fixtures/fake_settlement.json
240
246
  - test/fixtures/fake_settlement_on_demand.json
241
247
  - test/fixtures/fake_stakeholder.json
@@ -296,7 +302,9 @@ files:
296
302
  - test/razorpay/test_iin.rb
297
303
  - test/razorpay/test_invoice.rb
298
304
  - test/razorpay/test_item.rb
305
+ - test/razorpay/test_oauth_token.rb
299
306
  - test/razorpay/test_order.rb
307
+ - test/razorpay/test_payload_validator.rb
300
308
  - test/razorpay/test_payment.rb
301
309
  - test/razorpay/test_payment_link.rb
302
310
  - test/razorpay/test_plan.rb
@@ -363,6 +371,7 @@ test_files:
363
371
  - test/fixtures/fake_instant_settlement.json
364
372
  - test/fixtures/fake_invoice.json
365
373
  - test/fixtures/fake_item.json
374
+ - test/fixtures/fake_oauth_token.json
366
375
  - test/fixtures/fake_order.json
367
376
  - test/fixtures/fake_order_transfers.json
368
377
  - test/fixtures/fake_otp_generate.json
@@ -380,6 +389,7 @@ test_files:
380
389
  - test/fixtures/fake_recurring.json
381
390
  - test/fixtures/fake_refund.json
382
391
  - test/fixtures/fake_refunded_payment.json
392
+ - test/fixtures/fake_revoke_token.json
383
393
  - test/fixtures/fake_settlement.json
384
394
  - test/fixtures/fake_settlement_on_demand.json
385
395
  - test/fixtures/fake_stakeholder.json
@@ -440,7 +450,9 @@ test_files:
440
450
  - test/razorpay/test_iin.rb
441
451
  - test/razorpay/test_invoice.rb
442
452
  - test/razorpay/test_item.rb
453
+ - test/razorpay/test_oauth_token.rb
443
454
  - test/razorpay/test_order.rb
455
+ - test/razorpay/test_payload_validator.rb
444
456
  - test/razorpay/test_payment.rb
445
457
  - test/razorpay/test_payment_link.rb
446
458
  - test/razorpay/test_plan.rb