razorpay 3.2.1 → 3.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: 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