pixelpay_sdk 1.0.4 → 1.0.5

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: 594dac058ce11835e6f1999b2214753ac5cb7ff8d47caeb628be1640bba2d749
4
- data.tar.gz: cd484011f1f79aad821c0fe61d8dd182bd128d2e78fd3dbed3641ef53e9d19d9
3
+ metadata.gz: d53ee74ca8bbed17b4bec55f9fe0061cdd14f841b5450d7ec8b5aed23b6a974a
4
+ data.tar.gz: a9835dec0d92cc864ec02b694c4b3f7de62345055f0db1529de31b00fe0e2e87
5
5
  SHA512:
6
- metadata.gz: 5b9e99e31e44d377952e0fd2d83de94ec2a4c9dde06054d209b66542db75b13575d2a8a10241e70037cbede8dd2c97f2b8d9c42059ece7532fb193c4062ff345
7
- data.tar.gz: 5f18ccc435f62eb9a65506d8605b45f8895a3d3df4c662117c5f31a1d365f8dca7f966afe426d34386587dd19c699243a288d862b72868a1cea5da78278df0ce
6
+ metadata.gz: 511b116d1b5281bf5009cce39f0c8cf6456b0faa34abc3e99a473e3e400c03b35e784450fc12612350fcf9272de3c49a953854d64e2f3b19e23d33f617f3a2ab
7
+ data.tar.gz: 53c3ad088779920e9842a187c15b006ce794836ce132242d7030b25f5b0c3b12c784cabb816d4e2fb7ce23f08ce0fa55fdf8a267f1f05d3641f0f6aa0b16338a
data/CHANGELOG.md CHANGED
@@ -5,7 +5,15 @@ El formato se basa en [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  y este proyecto se adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
  Tipos de cambios: `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`.
7
7
 
8
+ ## [v1.0.5] - 2026-10-30
9
+ ### Added
10
+ - Se restauro lógica de encriptación de datos de tarjeta
11
+
12
+ ### Removed
13
+ - Se elimina lógica de enrutador de transacción.
14
+
8
15
  ## [v1.0.4] - 2025-12-23
16
+ ### Added
9
17
  - Se agregó headers a settings
10
18
 
11
19
  ## [v1.0.3] - 2025-06-04
data/CONTRIBUTING.md CHANGED
@@ -33,19 +33,11 @@ ruby test/services/test_transaction.rb -n test_success_sale_transaction
33
33
 
34
34
  El sistema macOS ya trae una versión de **Ruby** instalada, pero es posible que no sea completamente compatible con el **SDK**. Por ello, es mejor instalar otra versión.
35
35
 
36
- 1. Instalar Ruby Version Manager para gestionar versiones de Ruby: [RVM](https://rvm.io/).
37
- 2. Instalar la versión de ruby: ```rvm install 2.7.6 --with-openssl-dir=$(brew --prefix openssl@1.1) ```
38
- 3. Correr ```gem install bundler```
39
-
40
- **Nota**: ```openssl@1.1``` ya deberia estar en homebrew. Revisar con ```brew list```. Si no está, instalarlo antes de ejecutar el paso 2.
41
-
42
- **Opción alternativa**
43
- Es posible que no se permita instalar ```openssl@1.1``` ya que fue deshabilitado por homebrew. En ese caso se puede utilizar otro manejador de versiones de **Ruby** como [rbenv](https://github.com/rbenv/rbenv).
36
+ Utilizar manejador de versiones de **Ruby** como [rbenv](https://github.com/rbenv/rbenv).
44
37
 
45
38
  Pasos de instalación:
46
39
 
47
40
  1. brew install rbenv
48
- 2. rbenv install 2.7.6
49
- 3. rbenv global 2.7.6 (Configura la versión de Ruby por defecto de la computadora)
50
-
51
- **Nota** Si se intento la instalación previa de RVM y no se puedo debido al elemento de **openssl@1.1**, comentar en archivo de variables de entorno .zshrc los elementos de RVM.
41
+ 2. rbenv install 3.7.2
42
+ 3. rbenv global 3.7.2 (Configura la versión de Ruby por defecto de la computadora)
43
+ 4. rbenv local 3.7.2 (Configura la versión de Ruby local en el proyecto)
data/Gemfile CHANGED
@@ -9,8 +9,12 @@ gem "rake", "~> 13.0"
9
9
 
10
10
  gem "minitest", "~> 5.0"
11
11
 
12
- gem "rubocop", "~> 1.21"
12
+ gem "rubocop", "~> 1.51", ">= 1.51.0"
13
13
 
14
14
  gem "i18n", "~> 1.13"
15
15
 
16
+ gem "rbnacl", "~> 7.1"
17
+
16
18
  gem "simplecov", require: false, group: :test
19
+
20
+ gem 'dotenv'
data/Gemfile.lock CHANGED
@@ -1,37 +1,47 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pixelpay_sdk (1.0.4)
4
+ pixelpay_sdk (1.0.5)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- ast (2.4.2)
9
+ ast (2.4.3)
10
10
  concurrent-ruby (1.2.2)
11
11
  docile (1.4.0)
12
+ dotenv (3.2.0)
13
+ ffi (1.17.4)
12
14
  i18n (1.13.0)
13
15
  concurrent-ruby (~> 1.0)
14
- json (2.6.3)
16
+ json (3.1.0)
17
+ language_server-protocol (3.17.0.6)
18
+ lint_roller (1.1.0)
15
19
  minitest (5.18.0)
16
- parallel (1.23.0)
17
- parser (3.2.2.1)
20
+ parallel (1.28.0)
21
+ parser (3.3.13.0)
18
22
  ast (~> 2.4.1)
23
+ racc
24
+ prism (1.9.0)
25
+ racc (1.8.1)
19
26
  rainbow (3.1.1)
20
27
  rake (13.0.6)
21
- regexp_parser (2.8.0)
22
- rexml (3.2.5)
23
- rubocop (1.50.2)
24
- json (~> 2.3)
25
- parallel (~> 1.10)
26
- parser (>= 3.2.0.0)
28
+ rbnacl (7.1.2)
29
+ ffi (~> 1)
30
+ regexp_parser (2.13.1)
31
+ rubocop (1.92.2)
32
+ json (>= 2.3)
33
+ language_server-protocol (~> 3.17.0.2)
34
+ lint_roller (~> 1.1.0)
35
+ parallel (>= 1.10)
36
+ parser (>= 3.3.0.2)
27
37
  rainbow (>= 2.2.2, < 4.0)
28
- regexp_parser (>= 1.8, < 3.0)
29
- rexml (>= 3.2.5, < 4.0)
30
- rubocop-ast (>= 1.28.0, < 2.0)
38
+ regexp_parser (>= 2.11.3, < 3.0)
39
+ rubocop-ast (>= 1.49.0, < 2.0)
31
40
  ruby-progressbar (~> 1.7)
32
- unicode-display_width (>= 2.4.0, < 3.0)
33
- rubocop-ast (1.28.0)
34
- parser (>= 3.2.1.0)
41
+ unicode-display_width (>= 2.4.0, < 4.0)
42
+ rubocop-ast (1.50.0)
43
+ parser (>= 3.3.7.2)
44
+ prism (~> 1.7)
35
45
  ruby-progressbar (1.13.0)
36
46
  simplecov (0.22.0)
37
47
  docile (~> 1.1)
@@ -39,20 +49,25 @@ GEM
39
49
  simplecov_json_formatter (~> 0.1)
40
50
  simplecov-html (0.12.3)
41
51
  simplecov_json_formatter (0.1.4)
42
- unicode-display_width (2.4.2)
52
+ unicode-display_width (3.3.0)
53
+ unicode-emoji (~> 4.3)
54
+ unicode-emoji (4.3.0)
43
55
 
44
56
  PLATFORMS
45
57
  arm64-darwin-22
46
58
  arm64-darwin-23
47
- ruby
59
+ arm64-darwin-25
48
60
  x64-mingw32
61
+ x86_64-linux
49
62
 
50
63
  DEPENDENCIES
64
+ dotenv
51
65
  i18n (~> 1.13)
52
66
  minitest (~> 5.0)
53
67
  pixelpay_sdk!
54
68
  rake (~> 13.0)
55
- rubocop (~> 1.21)
69
+ rbnacl (~> 7.1)
70
+ rubocop (~> 1.51, >= 1.51.0)
56
71
  simplecov
57
72
 
58
73
  BUNDLED WITH
data/README.md CHANGED
@@ -5,12 +5,12 @@
5
5
  Para obtener la versión del SDK de PixelPay con Ruby puedes utilizar este comando para instalar directamente:
6
6
 
7
7
  ``` bash
8
- gem install pixelpay_sdk-1.0.4
8
+ gem install pixelpay_sdk-1.0.5
9
9
  ```
10
10
 
11
11
  O puedes colocar en el archivo Gemfile la siguiente línea:
12
12
  ``` bash
13
- gem 'pixelpay_sdk', '~> 1.0.4'
13
+ gem 'pixelpay_sdk', '~> 1.0.5'
14
14
  ```
15
15
 
16
16
  Y luego ejecutar:
@@ -1,4 +1,4 @@
1
- image: ruby:2.7
1
+ image: ruby:3.2.6
2
2
 
3
3
  pipelines:
4
4
  tags:
@@ -6,6 +6,8 @@ pipelines:
6
6
  - step:
7
7
  name: Build and test
8
8
  script:
9
+ # Install system dependency required by rbnacl
10
+ - apt-get update && apt-get install -y libsodium23
9
11
  # Install gems
10
12
  - bundle install
11
13
  # Run tests
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rbnacl"
4
+ require "base64"
3
5
  require "digest"
4
6
  require "json"
5
7
  # Helpers
@@ -7,13 +9,17 @@ module Helpers
7
9
  # Serialize object to JSON string without empties.
8
10
  # Args:
9
11
  # value (object): object to serialize.
12
+ # ignore (array): key values that will be excluded from final JSON.
10
13
  # Returns
11
14
  # string: JSON string.
12
- def self.object_to_json(value)
15
+ def self.object_to_json(value, ignore = [])
13
16
  verify_type(Object, value.is_a?(Object))
14
17
 
15
18
  hash = {}
16
- value.instance_variables.each { |var| hash[var.to_s.delete("@")] = value.instance_variable_get(var) }
19
+ value.instance_variables.each do |var|
20
+ var_name = var.to_s.delete("@")
21
+ hash[var_name] = value.instance_variable_get(var) unless ignore.include?(var_name)
22
+ end
17
23
 
18
24
  hash.each do |attr_name, attr_value|
19
25
  if hash[attr_name].nil? || hash[attr_name].to_s.empty? || (attr_value.is_a?(Array) && attr_value.empty?) || (attr_value.is_a?(Hash) && attr_value.empty?)
@@ -95,4 +101,51 @@ module Helpers
95
101
  def self.verify_type(expected, flag)
96
102
  raise TypeError, "This function only accepts parameters of type #{expected}." unless flag
97
103
  end
104
+
105
+ # Generate encryption key pair.
106
+ # Returns:
107
+ # Hash: encryption key pair.
108
+ def self.get_key_pair
109
+ private_key = RbNaCl::PrivateKey.generate
110
+ public_key = private_key.public_key
111
+
112
+ {
113
+ private_key: private_key,
114
+ public_key: public_key
115
+ }
116
+ end
117
+
118
+ # Encrypt message.
119
+ # Args:
120
+ # message (string): raw message.
121
+ # public_key (string): merchant public key.
122
+ # key_pair (hash): encryption key pair
123
+ # Returns:
124
+ # string: encrypted value concatenated with base64 nonce.
125
+ def self.encrypt(message, public_key, key_pair)
126
+ verify_type(Hash, key_pair.is_a?(Hash))
127
+
128
+ return nil if message.nil? || message.empty?
129
+
130
+ return message if message.include?("|")
131
+
132
+ return message if public_key.nil? || public_key.empty?
133
+
134
+ merchant_public_key = Base64.strict_decode64(public_key)
135
+
136
+ return message if merchant_public_key.bytesize != 32
137
+
138
+ sdk_private_key = key_pair[:private_key]
139
+
140
+ box = RbNaCl::Box.new(merchant_public_key, sdk_private_key)
141
+
142
+ nonce = RbNaCl::Random.random_bytes(box.nonce_bytes)
143
+
144
+ encrypted_message = box.encrypt(nonce, message)
145
+
146
+ box_b64 = Base64.strict_encode64(encrypted_message)
147
+ nonce_b64 = Base64.strict_encode64(nonce)
148
+
149
+ "#{box_b64}|#{nonce_b64}"
150
+ end
98
151
  end
@@ -6,7 +6,7 @@ require_relative "../version"
6
6
 
7
7
  # RequestBehaviour defines the structure for the request behaviour.
8
8
  class RequestBehaviour
9
- attr_accessor :env, :lang, :from, :sdk_version
9
+ attr_accessor :env, :lang, :from, :sdk_version, :sdk_key_pair
10
10
 
11
11
  # Initialize request
12
12
  def initialize
@@ -23,12 +23,31 @@ class RequestBehaviour
23
23
  @sdk_version = PixelpaySdk::VERSION
24
24
 
25
25
  @lang = "es" if @lang != "es" && @lang != "en"
26
+
27
+ # For internal use to prevent encrypting same request instance twice
28
+ @sdk_key_pair = nil
26
29
  end
27
30
 
28
31
  # Serialize object to JSON string.
29
32
  # Returns:
30
33
  # string: JSON string.
31
34
  def object_to_json
32
- Helpers.object_to_json(self)
35
+ Helpers.object_to_json(self, ["sdk_key_pair"])
36
+ end
37
+
38
+ # Check if current request needs encryption, must be overriden by inherited classes.
39
+ # Returns:
40
+ # bool: true if request contains parameters that mush be encrypted.
41
+ def is_encryptable?
42
+ false
43
+ end
44
+
45
+ # Encrypt fields with sensitive data, must be overriden by inherited classes.
46
+ # Args:
47
+ # public_key (string): merchant public key.
48
+ # Returns:
49
+ # nil: this base method always returns nil.
50
+ def with_encryption(public_key)
51
+ nil
33
52
  end
34
53
  end
@@ -7,6 +7,7 @@ require "uri"
7
7
  require_relative "../base/Helpers"
8
8
  require_relative "../base/RequestBehaviour"
9
9
  require_relative "../exceptions/InvalidCredentialsException"
10
+ require_relative "../exceptions/FailedEncryptionException"
10
11
  require_relative "../responses/ErrorResponse"
11
12
  require_relative "../responses/FailureResponse"
12
13
  require_relative "../responses/InputErrorResponse"
@@ -21,7 +22,9 @@ require_relative "../responses/TimeoutResponse"
21
22
 
22
23
  # ServiceBehaviour defines the structure for the service behaviour.
23
24
  class ServiceBehaviour
24
- attr_accessor :settings
25
+ PUBLIC_KEY_PATH = "api/v2/merchant/public_key"
26
+
27
+ attr_accessor :settings, :sdk_public_key
25
28
 
26
29
  # Initialize service.
27
30
  def initialize(settings)
@@ -29,6 +32,9 @@ class ServiceBehaviour
29
32
 
30
33
  # Settings service model
31
34
  @settings = settings
35
+
36
+ # Public key from pair generated by current instance.
37
+ @sdk_public_key = nil
32
38
  rescue StandardError => e
33
39
  warn("An exception occurred: #{e.message}")
34
40
  end
@@ -136,6 +142,8 @@ class ServiceBehaviour
136
142
 
137
143
  request["x-auth-user"] = @settings.auth_user if @settings.auth_user != ""
138
144
 
145
+ request["x-auth-secure"] = @sdk_public_key if @sdk_public_key
146
+
139
147
  if @settings.headers
140
148
  @settings.headers.each do |key, value|
141
149
  request[key] = value
@@ -167,6 +175,7 @@ class ServiceBehaviour
167
175
  raise TypeError, "This function only accepts parameters of type RequestBehaviour."
168
176
  end
169
177
 
178
+ validate_encryption(body)
170
179
  uri = get_route(url)
171
180
  req = build_request(uri, "POST", body)
172
181
 
@@ -190,6 +199,7 @@ class ServiceBehaviour
190
199
  def put(url, body)
191
200
  Helpers.verify_type(RequestBehaviour, body.is_a?(RequestBehaviour))
192
201
 
202
+ validate_encryption(body)
193
203
  uri = get_route(url)
194
204
  req = build_request(uri, "PUT", body)
195
205
 
@@ -211,6 +221,7 @@ class ServiceBehaviour
211
221
  def delete(url, body)
212
222
  Helpers.verify_type(RequestBehaviour, body.is_a?(RequestBehaviour))
213
223
 
224
+ validate_encryption(body)
214
225
  uri = get_route(url)
215
226
  req = build_request(uri, "DELETE", body)
216
227
 
@@ -232,6 +243,7 @@ class ServiceBehaviour
232
243
  def get(url, body)
233
244
  Helpers.verify_type(RequestBehaviour, body.is_a?(RequestBehaviour))
234
245
 
246
+ validate_encryption(body) if url != PUBLIC_KEY_PATH
235
247
  uri = get_route(url)
236
248
  req = build_request(uri, "GET", body)
237
249
 
@@ -243,4 +255,77 @@ class ServiceBehaviour
243
255
  rescue StandardError => e
244
256
  exception_response(e)
245
257
  end
258
+
259
+ # Verify and set request encryption values.
260
+ # Args:
261
+ # request (RequestBehaviour): unencrypted request.
262
+ # Raises:
263
+ # InvalidCredentialsException: When invalid or no credentials are provided.
264
+ # FailedEncryptionException: When encryption process fails.
265
+ def validate_encryption(request)
266
+ Helpers.verify_type(RequestBehaviour, request.is_a?(RequestBehaviour))
267
+
268
+ return unless request.is_encryptable?
269
+
270
+ validate_merchant_public_key
271
+ validate_sdk_public_key(request)
272
+ end
273
+
274
+ # Resiliently fetch merchant public key, trying at least 3 times before failing.
275
+ # Raises:
276
+ # InvalidCredentialsException: When invalid or no credentials are provided.
277
+ def validate_merchant_public_key
278
+ tries = 0
279
+
280
+ while @settings.public_key.nil? && tries < 3
281
+ @settings.public_key = fetch_merchant_public_key
282
+ tries += 1
283
+ end
284
+
285
+ if @settings.public_key.nil?
286
+ raise InvalidCredentialsException, "Could not obtain necessary credentials for transaction."
287
+ end
288
+ end
289
+
290
+ # Resiliently generate keys and encrypt request, trying at least 3 times before failing.
291
+ # Args:
292
+ # request (RequestBehaviour): unencrypted request.
293
+ # Raises:
294
+ # FailedEncryptionException: When encryption process fails.
295
+ def validate_sdk_public_key(request)
296
+
297
+ Helpers.verify_type(RequestBehaviour, request.is_a?(RequestBehaviour))
298
+
299
+ tries = 0
300
+ last_error = nil
301
+
302
+ while @sdk_public_key.nil? && tries < 3 || tries.zero?
303
+ begin
304
+ @sdk_public_key = request.with_encryption(@settings.public_key)
305
+ rescue StandardError => e
306
+ last_error = e
307
+ ensure
308
+ tries += 1
309
+ end
310
+ end
311
+
312
+ raise last_error if @sdk_public_key.nil? && last_error
313
+
314
+ if @sdk_public_key.nil?
315
+ raise FailedEncryptionException, "Could not process encryption, please try again."
316
+ end
317
+ end
318
+
319
+ # Fetch merchant public key for encryption.
320
+ # Returns:
321
+ # string: merchant public key or None.
322
+ # Raises:
323
+ # InvalidCredentialsException: When no credentials are provided.
324
+ def fetch_merchant_public_key
325
+ response = get(PUBLIC_KEY_PATH, RequestBehaviour.new)
326
+
327
+ return response.get_data("public_key") if response.success
328
+
329
+ nil
330
+ end
246
331
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # FailedEncryptionException provides the possibility to create an exception of
4
+ # it's type
5
+ class FailedEncryptionException < StandardError
6
+ end
@@ -4,7 +4,7 @@ require_relative "../base/Helpers"
4
4
  require_relative "../resources/Environment"
5
5
  # Settings represents the settings information for a request.
6
6
  class Settings
7
- attr_accessor :auth_key, :auth_hash, :auth_user, :endpoint, :environment, :lang, :headers
7
+ attr_accessor :auth_key, :auth_hash, :auth_user, :endpoint, :environment, :lang, :headers, :public_key
8
8
 
9
9
  # Initialize model
10
10
  def initialize
@@ -29,6 +29,8 @@ class Settings
29
29
  # Request headers
30
30
  @headers = nil
31
31
 
32
+ # Public encryption key
33
+ @public_key = nil
32
34
  end
33
35
 
34
36
  # Setup API endpoint URL.
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "base64"
3
4
  require_relative "../base/Helpers"
4
5
  require_relative "../base/RequestBehaviour"
6
+ require_relative "../exceptions/FailedEncryptionException"
5
7
 
6
8
  # CardTokenization defines a card tokenization request.
7
9
  class CardTokenization < RequestBehaviour
@@ -94,4 +96,65 @@ class CardTokenization < RequestBehaviour
94
96
 
95
97
  self
96
98
  end
99
+
100
+ # Check if current request needs encryption.
101
+ # Returns:
102
+ # bool: true if request contains parameters that must be encrypted.
103
+ def is_encryptable?
104
+ !(@number.nil? || @number.empty?) ||
105
+ !(@cvv2.nil? || @cvv2.empty?) ||
106
+ !(@expire_month.nil? || @expire_month.empty?) ||
107
+ !(@expire_year.nil? || @expire_year.empty?) ||
108
+ !(@cardholder.nil? || @ardholder.empty?) ||
109
+ !(@email.nil? || @email.empty?)
110
+ end
111
+
112
+ # Encrypt fields with sensitive data.
113
+ # Args:
114
+ # public_key (string): merchant public key.
115
+ # Returns:
116
+ # string: SDK public key.
117
+ # Raises:
118
+ # FailedEncryptionException: When public key is empty or encryption fails.
119
+ def with_encryption(public_key)
120
+ if public_key.nil? || public_key.empty?
121
+ raise FailedEncryptionException, "Could not process transaction without merchant public key."
122
+ end
123
+
124
+ begin
125
+ key_pair = !@sdk_key_pair.nil? ? @sdk_key_pair : Helpers.get_key_pair
126
+
127
+ if !(@number.nil? || @number.empty?)
128
+ @number = Helpers.encrypt(@number, public_key, key_pair)
129
+ end
130
+
131
+ if !(@cvv2.nil? || @cvv2.empty?)
132
+ @cvv2 = Helpers.encrypt(@cvv2, public_key, key_pair)
133
+ end
134
+
135
+ if !(@expire_month.nil? || @expire_month.empty?)
136
+ @expire_month = Helpers.encrypt(@expire_month, public_key, key_pair)
137
+ end
138
+
139
+ if !(@expire_year.nil? || @expire_year.empty?)
140
+ @expire_year = Helpers.encrypt(@expire_year, public_key, key_pair)
141
+ end
142
+
143
+ if !(@cardholder.nil? || @cardholder.empty?)
144
+ @cardholder = Helpers.encrypt(@cardholder, public_key, key_pair)
145
+ end
146
+
147
+ if !(@email.nil? || @email.empty?)
148
+ @email = Helpers.encrypt(@email, public_key, key_pair)
149
+ end
150
+
151
+ sdk_public_key = Base64.strict_encode64(key_pair[:public_key])
152
+
153
+ @sdk_key_pair = key_pair
154
+
155
+ sdk_public_key
156
+ rescue StandardError
157
+ raise FailedEncryptionException, "Could not process transaction without merchant public key."
158
+ end
159
+ end
97
160
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "base64"
3
4
  require_relative "../base/Helpers"
4
5
  require_relative "../base/RequestBehaviour"
6
+ require_relative "../exceptions/FailedEncryptionException"
5
7
 
6
8
  # PaymentTransaction defines the structure for a payment transaction request.
7
9
  class PaymentTransaction < RequestBehaviour
@@ -179,4 +181,63 @@ class PaymentTransaction < RequestBehaviour
179
181
  def with_authentication_request
180
182
  @authentication_request = true
181
183
  end
184
+
185
+ # Check if current request needs encryption.
186
+ # Returns:
187
+ # bool: true if request contains parameters that must be encrypted.
188
+ def is_encryptable?
189
+ !(@card_number.nil? || @card_number.empty?) ||
190
+ !(@card_cvv.nil? || @card_cvv.empty?) ||
191
+ !(@card_expire.nil? || @card_expire.empty?) ||
192
+ !(@card_holder.nil? || @card_holder.empty?) ||
193
+ !(@customer_name.nil? || @customer_name.empty?) ||
194
+ !(@customer_email.nil? || @customer_email.empty?)
195
+ end
196
+
197
+ # Encrypt fields with sensitive data.
198
+ # Args:
199
+ # public_key (string): merchant public key.
200
+ # Returns:
201
+ # string: SDK public key or nil.
202
+ def with_encryption(public_key)
203
+ if public_key.nil? || public_key.empty?
204
+ raise FailedEncryptionException, "Could not process transaction without merchant public key."
205
+ end
206
+
207
+ begin
208
+ key_pair = !@sdk_key_pair.nil? ? @sdk_key_pair : Helpers.get_key_pair
209
+
210
+ if !(@card_number.nil? || @card_number.empty?)
211
+ @card_number = Helpers.encrypt(@card_number, public_key, key_pair)
212
+ end
213
+
214
+ if !(@card_cvv.nil? || @card_cvv.empty?)
215
+ @card_cvv = Helpers.encrypt(@card_cvv, public_key, key_pair)
216
+ end
217
+
218
+ if !(@card_expire.nil? || @card_expire.empty?)
219
+ @card_expire = Helpers.encrypt(@card_expire, public_key, key_pair)
220
+ end
221
+
222
+ if !(@card_holder.nil? || @card_holder.empty?)
223
+ @card_holder = Helpers.encrypt(@card_holder, public_key, key_pair)
224
+ end
225
+
226
+ if !(@customer_name.nil? || @customer_name.empty?)
227
+ @customer_name = Helpers.encrypt(@customer_name, public_key, key_pair)
228
+ end
229
+
230
+ if !(@customer_email.nil? || @customer_email.empty?)
231
+ @customer_email = Helpers.encrypt(@customer_email, public_key, key_pair)
232
+ end
233
+
234
+ sdk_public_key = Base64.strict_encode64(key_pair[:public_key])
235
+
236
+ @sdk_key_pair = key_pair
237
+
238
+ sdk_public_key
239
+ rescue StandardError
240
+ raise FailedEncryptionException, "Could not process transaction without merchant public key."
241
+ end
242
+ end
182
243
  end
@@ -6,7 +6,6 @@ require_relative "../request/StatusTransaction"
6
6
  require_relative "../request/AuthTransaction"
7
7
  require_relative "../request/CaptureTransaction"
8
8
  require_relative "../request/VoidTransaction"
9
- require_relative "../libraries/RouterManager"
10
9
  require_relative "../exceptions/InvalidTransactionTypeException"
11
10
  require_relative "../exceptions/RunningTransactionException"
12
11
 
@@ -39,9 +38,7 @@ class Transaction < ServiceBehaviour
39
38
  response = post("api/v2/transaction/sale", transaction)
40
39
 
41
40
  if response.instance_of?(PayloadResponse)
42
- if response.data["transaction_type"] == "router"
43
- return RouterManager.new(transaction).init_manager(response.data["payload"])
44
- end
41
+ raise RunningTransactionException, "This type of transaction is invalid."
45
42
  end
46
43
 
47
44
  return response
@@ -63,9 +60,7 @@ class Transaction < ServiceBehaviour
63
60
  response = post("api/v2/transaction/auth", transaction)
64
61
 
65
62
  if response.instance_of?(PayloadResponse)
66
- if response.data["transaction_type"] == "router"
67
- return RouterManager.new(transaction).init_manager(response.data["payload"])
68
- end
63
+ raise RunningTransactionException, "This type of transaction is invalid"
69
64
  end
70
65
 
71
66
  return response
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PixelpaySdk
4
- VERSION = "1.0.4"
4
+ VERSION = "1.0.5"
5
5
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pixelpay_sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sonia Villeda
8
8
  - Oscar Gómez
9
- autorequire:
9
+ autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2026-01-05 00:00:00.000000000 Z
12
+ date: 2026-10-31 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description:
14
+ description:
15
15
  email:
16
16
  - sonia@pixel.hn
17
17
  - oscar@pixel.hn
@@ -38,10 +38,10 @@ files:
38
38
  - lib/pixelpay_sdk/base/ServiceBehaviour.rb
39
39
  - lib/pixelpay_sdk/entities/CardResult.rb
40
40
  - lib/pixelpay_sdk/entities/TransactionResult.rb
41
+ - lib/pixelpay_sdk/exceptions/FailedEncryptionException.rb
41
42
  - lib/pixelpay_sdk/exceptions/InvalidCredentialsException.rb
42
43
  - lib/pixelpay_sdk/exceptions/InvalidTransactionTypeException.rb
43
44
  - lib/pixelpay_sdk/exceptions/RunningTransactionException.rb
44
- - lib/pixelpay_sdk/libraries/RouterManager.rb
45
45
  - lib/pixelpay_sdk/models/Billing.rb
46
46
  - lib/pixelpay_sdk/models/Card.rb
47
47
  - lib/pixelpay_sdk/models/Item.rb
@@ -77,7 +77,7 @@ licenses:
77
77
  - MIT
78
78
  metadata:
79
79
  homepage_uri: https://pixel.hn
80
- post_install_message:
80
+ post_install_message:
81
81
  rdoc_options: []
82
82
  require_paths:
83
83
  - lib
@@ -92,8 +92,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
92
  - !ruby/object:Gem::Version
93
93
  version: '0'
94
94
  requirements: []
95
- rubygems_version: 3.1.6
96
- signing_key:
95
+ rubygems_version: 3.4.19
96
+ signing_key:
97
97
  specification_version: 4
98
98
  summary: PixelPay SDK toolkit.
99
99
  test_files: []
@@ -1,52 +0,0 @@
1
- require "json"
2
- require "base64"
3
-
4
- require_relative "../services/Transaction"
5
- require_relative "../request/PaymentTransaction"
6
- require_relative "../request/SaleTransaction"
7
- require_relative "../models/Settings"
8
-
9
- class RouterManager
10
- attr_accessor :transaction, :identifier
11
-
12
- def initialize(request)
13
- # Payment transaction
14
- @transaction = request
15
-
16
- #Payment transaction source
17
- @transaction.source = 'router'
18
-
19
- # PixelPay transaction authentication identifier
20
- @identifier = nil
21
- end
22
-
23
- # Initialize manager
24
- def init_manager(payload)
25
- service = Transaction.new(parse_payload(payload))
26
-
27
- if @transaction.is_a?(SaleTransaction)
28
- return service.do_sale(@transaction);
29
- else
30
- return service.do_auth(@transaction)
31
- end
32
- end
33
-
34
- # Parse the payload string to Object Settings
35
- def parse_payload(payload)
36
- decoded_payload = Base64.decode64(payload)
37
- obj_payload = JSON.parse(decoded_payload)
38
-
39
- settings = Settings.new
40
-
41
- settings.setup_environment(obj_payload["env"])
42
- settings.setup_credentials(obj_payload["auth_key"], obj_payload["auth_hash"])
43
- settings.setup_endpoint(obj_payload["endpoint"]);
44
- settings.setup_language(@transaction.lang);
45
-
46
- if obj_payload["auth_user"]
47
- settings.setup_platform_user(obj_payload["auth_user"])
48
- end
49
-
50
- return settings
51
- end
52
- end