nicepay_ruby 1.0.0 → 1.1.0
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/lib/builder_file.rb +1 -0
- data/lib/nicepay_ruby/Builder/SNAP/Ewallet.rb +190 -0
- data/lib/nicepay_ruby/Builder/SNAP/Payout.rb +100 -0
- data/lib/nicepay_ruby/Builder/SNAP/QRIS.rb +75 -0
- data/lib/nicepay_ruby/Builder/SNAP/VA.rb +67 -0
- data/lib/nicepay_ruby/Builder/V2/CC.rb +69 -0
- data/lib/nicepay_ruby/Builder/V2/Cancel.rb +33 -0
- data/lib/nicepay_ruby/Builder/V2/Ewallet.rb +107 -0
- data/lib/nicepay_ruby/Builder/V2/Inquiry.rb +29 -0
- data/lib/nicepay_ruby/Builder/V2/Payout.rb +233 -0
- data/lib/nicepay_ruby/Builder/V2/QRIS.rb +98 -0
- data/lib/nicepay_ruby/Builder/V2/Redirect.rb +121 -0
- data/lib/nicepay_ruby/Builder/V2/VA.rb +42 -0
- data/lib/nicepay_ruby/Utils/accessToken.rb +63 -0
- data/lib/nicepay_ruby/Utils/configuration.rb +27 -0
- data/lib/nicepay_ruby/Utils/merchantToken.rb +63 -0
- data/lib/nicepay_ruby/Utils/nicepayConstant.rb +99 -0
- data/lib/nicepay_ruby/Utils/serviceUtils.rb +122 -0
- data/lib/nicepay_ruby/Utils/signatureUtils.rb +100 -0
- data/lib/nicepay_ruby.rb +34 -0
- metadata +20 -1
@@ -0,0 +1,99 @@
|
|
1
|
+
module NicepayRuby
|
2
|
+
class Config
|
3
|
+
@is_production = false
|
4
|
+
@is_cloud_server = false
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :is_production, :is_cloud_server
|
8
|
+
|
9
|
+
def get_sandbox_cloud
|
10
|
+
"https://dev-services.nicepay.co.id/"
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_production_cloud
|
14
|
+
"https://services.nicepay.co.id/"
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_sandbox_base_url
|
18
|
+
"https://dev.nicepay.co.id/"
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_production_base_url
|
22
|
+
"https://www.nicepay.co.id/"
|
23
|
+
end
|
24
|
+
|
25
|
+
def base_url
|
26
|
+
if @is_cloud_server
|
27
|
+
@is_production ? get_production_cloud : get_sandbox_cloud
|
28
|
+
else
|
29
|
+
@is_production ? get_production_base_url : get_sandbox_base_url
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_environment(production:, cloud_server:)
|
34
|
+
@is_production = production
|
35
|
+
@is_cloud_server = cloud_server
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class ApiEndpoints
|
41
|
+
attr_reader :create_va, :inquiry_va, :delete_va,
|
42
|
+
:payment_ewallet, :status_ewallet, :refund_ewallet,
|
43
|
+
:access_token,
|
44
|
+
:generate_qris, :status_qris, :refund_qris,
|
45
|
+
:create_payout, :approve_payout, :inquiry_payout,
|
46
|
+
:cancel_payout, :reject_payout, :balance_payout,
|
47
|
+
:regist_v2, :inquiry_v2, :cancel_v2,
|
48
|
+
:regist_payout_v2, :inquiry_payout_v2, :reject_payout_v2,
|
49
|
+
:approve_payout_v2, :balance_inquiry_v2,
|
50
|
+
:regist_redirect_v2
|
51
|
+
|
52
|
+
def initialize
|
53
|
+
# VA
|
54
|
+
@create_va = "nicepay/api/v1.0/transfer-va/create-va"
|
55
|
+
@inquiry_va = "nicepay/api/v1.0/transfer-va/status"
|
56
|
+
@delete_va = "nicepay/api/v1.0/transfer-va/delete-va"
|
57
|
+
|
58
|
+
# Ewallet
|
59
|
+
@payment_ewallet = "nicepay/api/v1.0/debit/payment-host-to-host"
|
60
|
+
@status_ewallet = "nicepay/api/v1.0/debit/status"
|
61
|
+
@refund_ewallet = "nicepay/api/v1.0/debit/refund"
|
62
|
+
|
63
|
+
# Auth
|
64
|
+
@access_token = "nicepay/v1.0/access-token/b2b"
|
65
|
+
|
66
|
+
# QRIS
|
67
|
+
@generate_qris = "nicepay/api/v1.0/qr/qr-mpm-generate"
|
68
|
+
@status_qris = "nicepay/api/v1.0/qr/qr-mpm-query"
|
69
|
+
@refund_qris = "nicepay/api/v1.0/qr/qr-mpm-refund"
|
70
|
+
|
71
|
+
# Payout V1
|
72
|
+
@create_payout = "nicepay/api/v1.0/transfer/registration"
|
73
|
+
@approve_payout = "nicepay/api/v1.0/transfer/approve"
|
74
|
+
@inquiry_payout = "nicepay/api/v1.0/transfer/inquiry"
|
75
|
+
@cancel_payout = "nicepay/api/v1.0/transfer/cancel"
|
76
|
+
@reject_payout = "nicepay/api/v1.0/transfer/reject"
|
77
|
+
@balance_payout = "nicepay/api/v1.0/balance-inquiry"
|
78
|
+
|
79
|
+
# Direct V2
|
80
|
+
@regist_v2 = "nicepay/direct/v2/registration"
|
81
|
+
@inquiry_v2 = "nicepay/direct/v2/inquiry"
|
82
|
+
@cancel_v2 = "nicepay/direct/v2/cancel"
|
83
|
+
@regist_payout_v2 = "nicepay/api/direct/v2/requestPayout"
|
84
|
+
@inquiry_payout_v2 = "nicepay/api/direct/v2/inquiryPayout"
|
85
|
+
@reject_payout_v2 = "nicepay/api/direct/v2/rejectPayout"
|
86
|
+
@approve_payout_v2 = "nicepay/api/direct/v2/approvePayout"
|
87
|
+
@balance_inquiry_v2 = "nicepay/api/direct/v2/balanceInquiry"
|
88
|
+
|
89
|
+
# Redirect
|
90
|
+
@regist_redirect_v2 = "nicepay/redirect/v2/registration"
|
91
|
+
end
|
92
|
+
|
93
|
+
# helper buat gabung base_url + endpoint
|
94
|
+
def full_url(path)
|
95
|
+
"#{NicepayRuby::Config.base_url}#{path}"
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'json'
|
4
|
+
require_relative 'signatureUtils'
|
5
|
+
|
6
|
+
module NicepayRuby
|
7
|
+
class ServiceApi
|
8
|
+
def initialize(endpoints: nil, client_id: nil, client_secret: nil, channel_id: nil, is_production:, is_cloud_server:)
|
9
|
+
@endpoints = endpoints
|
10
|
+
@client_id = client_id
|
11
|
+
@client_secret = client_secret
|
12
|
+
@channel_id = channel_id
|
13
|
+
@is_production = is_production
|
14
|
+
@is_cloud_server = is_cloud_server
|
15
|
+
|
16
|
+
# Set environment global
|
17
|
+
NicepayRuby::Config.set_environment(
|
18
|
+
production: is_production,
|
19
|
+
cloud_server: is_cloud_server
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
# ==============================
|
24
|
+
# NON-SNAP (simple POST request)
|
25
|
+
# ==============================
|
26
|
+
def send_post(endpoint, request_body)
|
27
|
+
return "Error: Request body is null or empty." if request_body.nil? || request_body.empty?
|
28
|
+
|
29
|
+
full_url = build_url(endpoint)
|
30
|
+
puts "[DEBUG] endpoint: #{full_url}"
|
31
|
+
|
32
|
+
begin
|
33
|
+
json_body = request_body.to_json
|
34
|
+
uri = URI(full_url)
|
35
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
36
|
+
http.use_ssl = uri.scheme == "https"
|
37
|
+
|
38
|
+
headers = { "Content-Type" => "application/json" }
|
39
|
+
request = Net::HTTP::Post.new(uri.request_uri, headers)
|
40
|
+
request.body = json_body
|
41
|
+
|
42
|
+
response = http.request(request)
|
43
|
+
body = response.body
|
44
|
+
|
45
|
+
response.is_a?(Net::HTTPSuccess) ? body : "Error: #{response.code} - #{response.message}\nResponse: #{body}"
|
46
|
+
rescue => e
|
47
|
+
"Exception occurred: #{e.message}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# ==============================
|
52
|
+
# SNAP (secure request w/ signature)
|
53
|
+
# ==============================
|
54
|
+
def send_post_request(endpoint, access_token, timestamp, request_body, external_id)
|
55
|
+
signature = SignatureGeneratorUtils.get_signature(
|
56
|
+
"POST", access_token, request_body, endpoint, timestamp, @client_secret
|
57
|
+
)
|
58
|
+
full_url = build_full_url(endpoint)
|
59
|
+
puts "[DEBUG][SNAP POST] #{full_url}"
|
60
|
+
|
61
|
+
uri = URI(full_url)
|
62
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
63
|
+
http.use_ssl = true
|
64
|
+
|
65
|
+
headers = build_snap_headers(signature, access_token, timestamp, external_id)
|
66
|
+
request = Net::HTTP::Post.new(uri.path, headers)
|
67
|
+
request.body = request_body.to_json
|
68
|
+
|
69
|
+
response = http.request(request)
|
70
|
+
response.body
|
71
|
+
end
|
72
|
+
|
73
|
+
def send_delete_request(endpoint, access_token, timestamp, request_body, external_id)
|
74
|
+
signature = SignatureGeneratorUtils.get_signature(
|
75
|
+
"DELETE", access_token, request_body, endpoint, timestamp, @client_secret
|
76
|
+
)
|
77
|
+
full_url = build_full_url(endpoint)
|
78
|
+
puts "[DEBUG][SNAP DELETE] #{full_url}"
|
79
|
+
|
80
|
+
uri = URI(full_url)
|
81
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
82
|
+
http.use_ssl = true
|
83
|
+
|
84
|
+
headers = build_snap_headers(signature, access_token, timestamp, external_id)
|
85
|
+
request = Net::HTTP::Delete.new(uri.path, headers)
|
86
|
+
request.body = request_body.to_json
|
87
|
+
|
88
|
+
response = http.request(request)
|
89
|
+
response.body
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# ===== Non-snap builder =====
|
95
|
+
def build_url(endpoint)
|
96
|
+
base_url = if @is_cloud_server
|
97
|
+
@is_production ? NicepayRuby::Config.get_production_cloud : NicepayRuby::Config.get_sandbox_cloud
|
98
|
+
else
|
99
|
+
@is_production ? NicepayRuby::Config.get_production_base_url : NicepayRuby::Config.get_sandbox_base_url
|
100
|
+
end
|
101
|
+
URI.join(base_url, endpoint).to_s
|
102
|
+
end
|
103
|
+
|
104
|
+
# ===== Snap builder =====
|
105
|
+
def build_full_url(endpoint)
|
106
|
+
base_url = NicepayRuby::Config.base_url
|
107
|
+
URI.join(base_url, endpoint).to_s
|
108
|
+
end
|
109
|
+
|
110
|
+
def build_snap_headers(signature, access_token, timestamp, external_id)
|
111
|
+
{
|
112
|
+
"X-TIMESTAMP" => timestamp,
|
113
|
+
"X-SIGNATURE" => signature,
|
114
|
+
"Authorization" => "Bearer #{access_token}",
|
115
|
+
"X-PARTNER-ID" => @client_id,
|
116
|
+
"X-EXTERNAL-ID" => external_id,
|
117
|
+
"CHANNEL-ID" => @channel_id,
|
118
|
+
"Content-Type" => "application/json"
|
119
|
+
}
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
|
2
|
+
require 'openssl'
|
3
|
+
require 'base64'
|
4
|
+
require 'json'
|
5
|
+
require 'digest'
|
6
|
+
|
7
|
+
module NicepayRuby
|
8
|
+
class SignatureGeneratorUtils
|
9
|
+
def initialize
|
10
|
+
@client_id = NicepayRuby.configuration.client_id
|
11
|
+
@private_key = OpenSSL::PKey::RSA.new(NicepayRuby.configuration.private_key)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.generate_string_to_sign(client_id, timestamp)
|
15
|
+
"#{client_id}|#{timestamp}"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Generate signature for access token (SHA256withRSA)
|
19
|
+
def self.generate_signature(private_key_base64, client_id, timestamp)
|
20
|
+
string_to_sign = generate_string_to_sign(client_id, timestamp)
|
21
|
+
private_key_der = Base64.decode64(private_key_base64)
|
22
|
+
|
23
|
+
rsa = OpenSSL::PKey::RSA.new(private_key_der)
|
24
|
+
signature = rsa.sign(OpenSSL::Digest::SHA256.new, string_to_sign)
|
25
|
+
Base64.strict_encode64(signature)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Generate API signature using HMAC-SHA512
|
29
|
+
def self.get_signature(http_method, access_token, request_body, endpoint, timestamp, client_secret)
|
30
|
+
json_body = JSON.generate(request_body)
|
31
|
+
hashed_body = sha256_encode_hex(json_body)
|
32
|
+
endpoint_sign = endpoint.sub(/^nicepay/, '')
|
33
|
+
|
34
|
+
string_to_sign = "#{http_method}:#{endpoint_sign}:#{access_token}:#{hashed_body}:#{timestamp}"
|
35
|
+
puts "String to Sign: #{string_to_sign}"
|
36
|
+
|
37
|
+
hmac_sha512_encode_base64(client_secret, string_to_sign)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# HMAC SHA512 encoding (for API signature)
|
42
|
+
def self.hmac_sha512_encode_base64(key, data)
|
43
|
+
hmac = OpenSSL::HMAC.digest('sha512', key, data)
|
44
|
+
Base64.strict_encode64(hmac)
|
45
|
+
end
|
46
|
+
|
47
|
+
# SHA256 in hex string
|
48
|
+
def self.sha256_encode_hex(data)
|
49
|
+
Digest::SHA256.hexdigest(data)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Generate random numeric string
|
53
|
+
def self.generate_random_number_string(length)
|
54
|
+
Array.new(length) { rand(0..9) }.join
|
55
|
+
end
|
56
|
+
|
57
|
+
# Optional: SHA256 encrypt utility
|
58
|
+
def self.sha256_encrypt(value)
|
59
|
+
Digest::SHA256.hexdigest(value)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Parse JSON and generate payment URL from response
|
63
|
+
def self.generate_payment_url(json_response)
|
64
|
+
begin
|
65
|
+
json = JSON.parse(json_response)
|
66
|
+
txid = json["tXid"]
|
67
|
+
payment_url = json["paymentURL"]
|
68
|
+
return "#{payment_url}?tXid=#{txid}" if txid && payment_url
|
69
|
+
rescue => e
|
70
|
+
puts "Error parsing payment URL: #{e.message}"
|
71
|
+
end
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
|
75
|
+
# Optional: Verify signature (public key based)
|
76
|
+
def self.verify_sha256_rsa(string_to_sign, public_key_base64, signature_base64)
|
77
|
+
public_key_der = Base64.decode64(public_key_base64)
|
78
|
+
public_key = OpenSSL::PKey::RSA.new(public_key_der)
|
79
|
+
signature = Base64.decode64(signature_base64)
|
80
|
+
|
81
|
+
is_valid = public_key.verify(OpenSSL::Digest::SHA256.new, signature, string_to_sign)
|
82
|
+
puts "Signature is #{is_valid ? 'valid' : 'invalid'}"
|
83
|
+
is_valid
|
84
|
+
rescue => e
|
85
|
+
puts "Error verifying signature: #{e.message}"
|
86
|
+
false
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
def sha256_hex_minified(json_body)
|
91
|
+
minified = JSON.generate(JSON.parse(json_body)) # ensure no spaces, sorted
|
92
|
+
Digest::SHA256.hexdigest(minified)
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.encrypt(value)
|
96
|
+
Digest::SHA256.hexdigest(value)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
data/lib/nicepay_ruby.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
# lib/nicepay_ruby.rb
|
2
|
+
require_relative "nicepay_ruby/Utils/configuration"
|
3
|
+
require_relative "nicepay_ruby/Utils/signatureUtils"
|
4
|
+
require_relative "nicepay_ruby/Utils/accessToken"
|
5
|
+
require_relative "nicepay_ruby/Utils/merchantToken"
|
6
|
+
require_relative "nicepay_ruby/Utils/nicepayConstant"
|
7
|
+
require_relative "nicepay_ruby/Utils/serviceUtils"
|
8
|
+
require_relative "builder_file"
|
9
|
+
|
10
|
+
require_relative "nicepay_ruby/Builder/SNAP/VA"
|
11
|
+
require_relative "nicepay_ruby/Builder/SNAP/Ewallet"
|
12
|
+
require_relative "nicepay_ruby/Builder/SNAP/QRIS"
|
13
|
+
require_relative "nicepay_ruby/Builder/SNAP/Payout"
|
14
|
+
|
15
|
+
require_relative "nicepay_ruby/Builder/V2/VA"
|
16
|
+
require_relative "nicepay_ruby/Builder/V2/Ewallet"
|
17
|
+
require_relative "nicepay_ruby/Builder/V2/QRIS"
|
18
|
+
require_relative "nicepay_ruby/Builder/V2/Payout"
|
19
|
+
require_relative "nicepay_ruby/Builder/V2/CC"
|
20
|
+
require_relative "nicepay_ruby/Builder/V2/Inquiry"
|
21
|
+
require_relative "nicepay_ruby/Builder/V2/Cancel"
|
22
|
+
require_relative "nicepay_ruby/Builder/V2/Redirect"
|
23
|
+
|
24
|
+
|
25
|
+
module NicepayRuby
|
26
|
+
class << self
|
27
|
+
attr_accessor :configuration
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.configure
|
31
|
+
self.configuration ||= Configuration.new
|
32
|
+
yield(configuration)
|
33
|
+
end
|
34
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nicepay_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- NICEPay_Integration
|
@@ -18,7 +18,26 @@ extensions: []
|
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
20
|
- README.md
|
21
|
+
- lib/builder_file.rb
|
21
22
|
- lib/nicepay_ruby.rb
|
23
|
+
- lib/nicepay_ruby/Builder/SNAP/Ewallet.rb
|
24
|
+
- lib/nicepay_ruby/Builder/SNAP/Payout.rb
|
25
|
+
- lib/nicepay_ruby/Builder/SNAP/QRIS.rb
|
26
|
+
- lib/nicepay_ruby/Builder/SNAP/VA.rb
|
27
|
+
- lib/nicepay_ruby/Builder/V2/CC.rb
|
28
|
+
- lib/nicepay_ruby/Builder/V2/Cancel.rb
|
29
|
+
- lib/nicepay_ruby/Builder/V2/Ewallet.rb
|
30
|
+
- lib/nicepay_ruby/Builder/V2/Inquiry.rb
|
31
|
+
- lib/nicepay_ruby/Builder/V2/Payout.rb
|
32
|
+
- lib/nicepay_ruby/Builder/V2/QRIS.rb
|
33
|
+
- lib/nicepay_ruby/Builder/V2/Redirect.rb
|
34
|
+
- lib/nicepay_ruby/Builder/V2/VA.rb
|
35
|
+
- lib/nicepay_ruby/Utils/accessToken.rb
|
36
|
+
- lib/nicepay_ruby/Utils/configuration.rb
|
37
|
+
- lib/nicepay_ruby/Utils/merchantToken.rb
|
38
|
+
- lib/nicepay_ruby/Utils/nicepayConstant.rb
|
39
|
+
- lib/nicepay_ruby/Utils/serviceUtils.rb
|
40
|
+
- lib/nicepay_ruby/Utils/signatureUtils.rb
|
22
41
|
homepage: https://github.com/nicepay-dev/ruby-nicepay.git
|
23
42
|
licenses:
|
24
43
|
- MIT
|