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 +4 -4
- data/CHANGELOG.md +8 -0
- data/CONTRIBUTING.md +4 -12
- data/Gemfile +5 -1
- data/Gemfile.lock +35 -20
- data/README.md +2 -2
- data/bitbucket-pipelines.yml +3 -1
- data/lib/pixelpay_sdk/base/Helpers.rb +55 -2
- data/lib/pixelpay_sdk/base/RequestBehaviour.rb +21 -2
- data/lib/pixelpay_sdk/base/ServiceBehaviour.rb +86 -1
- data/lib/pixelpay_sdk/exceptions/FailedEncryptionException.rb +6 -0
- data/lib/pixelpay_sdk/models/Settings.rb +3 -1
- data/lib/pixelpay_sdk/request/CardTokenization.rb +63 -0
- data/lib/pixelpay_sdk/request/PaymentTransaction.rb +61 -0
- data/lib/pixelpay_sdk/services/Transaction.rb +2 -7
- data/lib/pixelpay_sdk/version.rb +1 -1
- metadata +8 -8
- data/lib/pixelpay_sdk/libraries/RouterManager.rb +0 -52
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d53ee74ca8bbed17b4bec55f9fe0061cdd14f841b5450d7ec8b5aed23b6a974a
|
|
4
|
+
data.tar.gz: a9835dec0d92cc864ec02b694c4b3f7de62345055f0db1529de31b00fe0e2e87
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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
|
|
49
|
-
3. rbenv global
|
|
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.
|
|
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
|
+
pixelpay_sdk (1.0.5)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
|
-
ast (2.4.
|
|
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 (
|
|
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.
|
|
17
|
-
parser (3.
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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 (>=
|
|
29
|
-
|
|
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, <
|
|
33
|
-
rubocop-ast (1.
|
|
34
|
-
parser (>= 3.
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
13
|
+
gem 'pixelpay_sdk', '~> 1.0.5'
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
Y luego ejecutar:
|
data/bitbucket-pipelines.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
image: ruby:2.
|
|
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
|
|
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
|
-
|
|
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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
data/lib/pixelpay_sdk/version.rb
CHANGED
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
|
+
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-
|
|
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.
|
|
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
|