Class: AliquotPay
- Inherits:
-
Object
- Object
- AliquotPay
- Defined in:
- lib/aliquot-pay.rb,
lib/aliquot-pay/util.rb
Defined Under Namespace
Constant Summary collapse
- EC_CURVE =
'prime256v1'.freeze
- DEFAULTS =
{ info: 'Google', recipient_id: 'merchant:0123456789', }.freeze
Instance Attribute Summary collapse
-
#auth_method ⇒ Object
Returns the value of attribute auth_method.
-
#cleartext_message ⇒ Object
Returns the value of attribute cleartext_message.
-
#cryptogram ⇒ Object
Returns the value of attribute cryptogram.
-
#eci_indicator ⇒ Object
Returns the value of attribute eci_indicator.
-
#encrypted_message ⇒ Object
Returns the value of attribute encrypted_message.
-
#ephemeral_public_key ⇒ Object
Returns the value of attribute ephemeral_public_key.
-
#expiration_month ⇒ Object
Returns the value of attribute expiration_month.
-
#expiration_year ⇒ Object
Returns the value of attribute expiration_year.
-
#gateway_merchant_id ⇒ Object
Returns the value of attribute gateway_merchant_id.
-
#info ⇒ Object
Returns the value of attribute info.
-
#intermediate_key ⇒ Object
Returns the value of attribute intermediate_key.
-
#intermediate_signing_key ⇒ Object
Returns the value of attribute intermediate_signing_key.
-
#key_expiration ⇒ Object
Returns the value of attribute key_expiration.
-
#key_value ⇒ Object
Returns the value of attribute key_value.
-
#message_expiration ⇒ Object
Returns the value of attribute message_expiration.
-
#message_id ⇒ Object
Returns the value of attribute message_id.
-
#pan ⇒ Object
Returns the value of attribute pan.
-
#payment_method ⇒ Object
Returns the value of attribute payment_method.
-
#payment_method_details ⇒ Object
Returns the value of attribute payment_method_details.
-
#recipient ⇒ Object
Returns the value of attribute recipient.
- #recipient_id ⇒ Object
-
#root_key ⇒ Object
Returns the value of attribute root_key.
- #shared_secret ⇒ Object
-
#signature ⇒ Object
Returns the value of attribute signature.
-
#signatures ⇒ Object
Returns the value of attribute signatures.
-
#signed_key ⇒ Object
Returns the value of attribute signed_key.
- #signed_key_string ⇒ Object
-
#signed_message ⇒ Object
Returns the value of attribute signed_message.
-
#tag ⇒ Object
Returns the value of attribute tag.
- #token ⇒ Object
Instance Method Summary collapse
- #build_cleartext_message ⇒ Object
- #build_payment_method_details ⇒ Object
- #build_signature ⇒ Object
- #build_signatures ⇒ Object
- #build_signed_key ⇒ Object
- #build_signed_message ⇒ Object
- #build_token ⇒ Object
- #encrypt(cleartext_message) ⇒ Object
- #ensure_intermediate_key ⇒ Object
- #ensure_root_key ⇒ Object
- #extract_root_signing_keys ⇒ Object
-
#initialize(protocol_version = :ECv2, root_key = nil) ⇒ AliquotPay
constructor
A new instance of AliquotPay.
- #sign(key, message) ⇒ Object
- #signed_message_string ⇒ Object
Constructor Details
#initialize(protocol_version = :ECv2, root_key = nil) ⇒ AliquotPay
Returns a new instance of AliquotPay.
28 29 30 31 32 33 |
# File 'lib/aliquot-pay.rb', line 28 def initialize(protocol_version = :ECv2, root_key = nil) @protocol_version = protocol_version if root_key @root_key = root_key end end |
Instance Attribute Details
#auth_method ⇒ Object
Returns the value of attribute auth_method.
22 23 24 |
# File 'lib/aliquot-pay.rb', line 22 def auth_method @auth_method end |
#cleartext_message ⇒ Object
Returns the value of attribute cleartext_message.
20 21 22 |
# File 'lib/aliquot-pay.rb', line 20 def end |
#cryptogram ⇒ Object
Returns the value of attribute cryptogram.
23 24 25 |
# File 'lib/aliquot-pay.rb', line 23 def cryptogram @cryptogram end |
#eci_indicator ⇒ Object
Returns the value of attribute eci_indicator.
23 24 25 |
# File 'lib/aliquot-pay.rb', line 23 def eci_indicator @eci_indicator end |
#encrypted_message ⇒ Object
Returns the value of attribute encrypted_message.
20 21 22 |
# File 'lib/aliquot-pay.rb', line 20 def end |
#ephemeral_public_key ⇒ Object
Returns the value of attribute ephemeral_public_key.
20 21 22 |
# File 'lib/aliquot-pay.rb', line 20 def ephemeral_public_key @ephemeral_public_key end |
#expiration_month ⇒ Object
Returns the value of attribute expiration_month.
22 23 24 |
# File 'lib/aliquot-pay.rb', line 22 def expiration_month @expiration_month end |
#expiration_year ⇒ Object
Returns the value of attribute expiration_year.
22 23 24 |
# File 'lib/aliquot-pay.rb', line 22 def expiration_year @expiration_year end |
#gateway_merchant_id ⇒ Object
Returns the value of attribute gateway_merchant_id.
21 22 23 |
# File 'lib/aliquot-pay.rb', line 21 def gateway_merchant_id @gateway_merchant_id end |
#info ⇒ Object
Returns the value of attribute info.
25 26 27 |
# File 'lib/aliquot-pay.rb', line 25 def info @info end |
#intermediate_key ⇒ Object
Returns the value of attribute intermediate_key.
25 26 27 |
# File 'lib/aliquot-pay.rb', line 25 def intermediate_key @intermediate_key end |
#intermediate_signing_key ⇒ Object
Returns the value of attribute intermediate_signing_key.
17 18 19 |
# File 'lib/aliquot-pay.rb', line 17 def intermediate_signing_key @intermediate_signing_key end |
#key_expiration ⇒ Object
Returns the value of attribute key_expiration.
19 20 21 |
# File 'lib/aliquot-pay.rb', line 19 def key_expiration @key_expiration end |
#key_value ⇒ Object
Returns the value of attribute key_value.
19 20 21 |
# File 'lib/aliquot-pay.rb', line 19 def key_value @key_value end |
#message_expiration ⇒ Object
Returns the value of attribute message_expiration.
21 22 23 |
# File 'lib/aliquot-pay.rb', line 21 def end |
#message_id ⇒ Object
Returns the value of attribute message_id.
21 22 23 |
# File 'lib/aliquot-pay.rb', line 21 def end |
#pan ⇒ Object
Returns the value of attribute pan.
22 23 24 |
# File 'lib/aliquot-pay.rb', line 22 def pan @pan end |
#payment_method ⇒ Object
Returns the value of attribute payment_method.
21 22 23 |
# File 'lib/aliquot-pay.rb', line 21 def payment_method @payment_method end |
#payment_method_details ⇒ Object
Returns the value of attribute payment_method_details.
21 22 23 |
# File 'lib/aliquot-pay.rb', line 21 def payment_method_details @payment_method_details end |
#recipient ⇒ Object
Returns the value of attribute recipient.
25 26 27 |
# File 'lib/aliquot-pay.rb', line 25 def recipient @recipient end |
#recipient_id ⇒ Object
227 228 229 |
# File 'lib/aliquot-pay.rb', line 227 def recipient_id @recipient_id ||= DEFAULTS[:recipient_id] end |
#root_key ⇒ Object
Returns the value of attribute root_key.
25 26 27 |
# File 'lib/aliquot-pay.rb', line 25 def root_key @root_key end |
#shared_secret ⇒ Object
231 232 233 234 235 |
# File 'lib/aliquot-pay.rb', line 231 def shared_secret return Base64.strict_encode64(@shared_secret) if @shared_secret @shared_secret ||= Random.new.bytes(32) shared_secret end |
#signature ⇒ Object
Returns the value of attribute signature.
17 18 19 |
# File 'lib/aliquot-pay.rb', line 17 def signature @signature end |
#signatures ⇒ Object
Returns the value of attribute signatures.
18 19 20 |
# File 'lib/aliquot-pay.rb', line 18 def signatures @signatures end |
#signed_key ⇒ Object
Returns the value of attribute signed_key.
18 19 20 |
# File 'lib/aliquot-pay.rb', line 18 def signed_key @signed_key end |
#signed_key_string ⇒ Object
163 164 165 |
# File 'lib/aliquot-pay.rb', line 163 def signed_key_string @signed_key_string ||= build_signed_key.to_json end |
#signed_message ⇒ Object
Returns the value of attribute signed_message.
17 18 19 |
# File 'lib/aliquot-pay.rb', line 17 def end |
#tag ⇒ Object
Returns the value of attribute tag.
20 21 22 |
# File 'lib/aliquot-pay.rb', line 20 def tag @tag end |
#token ⇒ Object
35 36 37 |
# File 'lib/aliquot-pay.rb', line 35 def token build_token end |
Instance Method Details
#build_cleartext_message ⇒ Object
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/aliquot-pay.rb', line 109 def return if = Base64.strict_encode64(OpenSSL::Random.random_bytes(24)) = ((Time.now.to_f + 60 * 5) * 1000).round.to_s = { 'messageExpiration' => || , 'messageId' => || , 'paymentMethod' => @payment_method || 'CARD', 'paymentMethodDetails' => build_payment_method_details } if @protocol_version == :ECv2 .merge!( 'gatewayMerchantId' => @gateway_merchant_id || 'SOME GATEWAY MERCHANT ID' ) end end |
#build_payment_method_details ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/aliquot-pay.rb', line 90 def build_payment_method_details return @payment_method_details if @payment_method_details value = { 'pan' => @pan || '4111111111111111', 'expirationYear' => @expiration_year || Time.now.year + 1, 'expirationMonth' => @expiration_month || 12, 'authMethod' => @auth_method || 'PAN_ONLY', } if @auth_method == 'CRYPTOGRAM_3DS' value.merge!( 'cryptogram' => @cryptogram || 'SOME CRYPTOGRAM', 'eciIndicator' => @eci_indicator || '05' ) end value end |
#build_signature ⇒ Object
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/aliquot-pay.rb', line 175 def build_signature return @signature if @signature key = case @protocol_version when :ECv1 ensure_root_key when :ECv2 ensure_intermediate_key end signature_string = = ['Google', recipient_id, @protocol_version.to_s, ].map do |str| [str.length].pack('V') + str end.join @signature = sign(key, signature_string) end |
#build_signatures ⇒ Object
194 195 196 197 198 199 200 201 202 203 |
# File 'lib/aliquot-pay.rb', line 194 def build_signatures return @signatures if @signatures signature_string = signed_key_signature = ['Google', 'ECv2', signed_key_string].map do |str| [str.to_s.length].pack('V') + str.to_s end.join @signatures = [sign(ensure_root_key, signature_string)] end |
#build_signed_key ⇒ Object
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/aliquot-pay.rb', line 146 def build_signed_key return @signed_key if @signed_key ensure_intermediate_key if !@intermediate_key.private_key? && !@intermediate_key.public_key? fail 'Intermediate key must be public and private key' end default_key_value = Base64.strict_encode64(@intermediate_key.to_der) default_key_expiration = "#{Time.now.to_i + 3600}000" @signed_key = { 'keyExpiration' => @key_expiration || default_key_expiration, 'keyValue' => @key_value || default_key_value, } end |
#build_signed_message ⇒ Object
131 132 133 134 135 136 137 138 139 140 |
# File 'lib/aliquot-pay.rb', line 131 def return if = encrypt(.to_json) ['encryptedMessage'] = if ['ephemeralPublicKey'] = @ephemeral_public_key if @ephemeral_public_key ['tag'] = @tag if @tag = end |
#build_token ⇒ Object
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/aliquot-pay.rb', line 205 def build_token return @token if @token res = { 'protocolVersion' => @protocol_version.to_s, 'signedMessage' => || , 'signature' => build_signature, } if @protocol_version == :ECv2 intermediate = { 'intermediateSigningKey' => @intermediate_signing_key || { 'signedKey' => signed_key_string, 'signatures' => build_signatures, } } res.merge!(intermediate) end @token = res end |
#encrypt(cleartext_message) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/aliquot-pay.rb', line 57 def encrypt() @recipient ||= OpenSSL::PKey::EC.generate('prime256v1') @info ||= 'Google' eph = AliquotPay::Util.generate_ephemeral_key @shared_secret ||= AliquotPay::Util.generate_shared_secret(eph, @recipient.public_key) ss = @shared_secret case @protocol_version when :ECv1 cipher = OpenSSL::Cipher::AES128.new(:CTR) when :ECv2 cipher = OpenSSL::Cipher::AES256.new(:CTR) else raise StandardError, "Invalid protocol_version #{protocol_version}" end keys = AliquotPay::Util.derive_keys(eph.public_key.to_bn.to_s(2), ss, @info, @protocol_version) cipher.encrypt cipher.key = keys[:aes_key] = cipher.update() + cipher.final tag = AliquotPay::Util.calculate_tag(keys[:mac_key], ) { 'encryptedMessage' => Base64.strict_encode64(), 'ephemeralPublicKey' => Base64.strict_encode64(eph.public_key.to_bn.to_s(2)), 'tag' => Base64.strict_encode64(tag), } end |
#ensure_intermediate_key ⇒ Object
171 172 173 |
# File 'lib/aliquot-pay.rb', line 171 def ensure_intermediate_key @intermediate_key ||= OpenSSL::PKey::EC.generate(EC_CURVE) end |
#ensure_root_key ⇒ Object
167 168 169 |
# File 'lib/aliquot-pay.rb', line 167 def ensure_root_key @root_key ||= OpenSSL::PKey::EC.generate(EC_CURVE) end |
#extract_root_signing_keys ⇒ Object
39 40 41 42 43 44 45 46 47 |
# File 'lib/aliquot-pay.rb', line 39 def extract_root_signing_keys key = Base64.strict_encode64(ensure_root_key.to_der) { 'keys' => [ 'protocolVersion' => @protocol_version, 'keyValue' => key, ] }.to_json end |
#sign(key, message) ⇒ Object
49 50 51 52 53 54 55 |
# File 'lib/aliquot-pay.rb', line 49 def sign(key, ) d = OpenSSL::Digest::SHA256.new def key.private? private_key? end Base64.strict_encode64(key.sign(d, )) end |
#signed_message_string ⇒ Object
142 143 144 |
# File 'lib/aliquot-pay.rb', line 142 def ||= .to_json end |