Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Worldpay: Encyrpted ApplePay and GooglePay #5093

Merged
merged 1 commit into from May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG
Expand Up @@ -163,7 +163,7 @@
* Cybersource Rest: Add support for network tokens [aenand] #5107
* Decidir: Add support for customer object [rachelkirk] #5071
* Worldpay: Add support for stored credentials with network tokens [aenand] #5114

* Worldpay: Encyrpted ApplePay and GooglePay [almalee24] #5093

== Version 1.135.0 (August 24, 2023)
* PaymentExpress: Correct endpoints [steveh] #4827
Expand Down
25 changes: 24 additions & 1 deletion lib/active_merchant/billing/gateways/worldpay.rb
Expand Up @@ -577,6 +577,8 @@ def add_payment_method(xml, amount, payment_method, options)
add_amount_for_pay_as_order(xml, amount, payment_method, options)
when :network_token
add_network_tokenization_card(xml, payment_method, options)
when :encrypted_wallet
add_encrypted_wallet(xml, payment_method, options)
else
add_card_or_token(xml, payment_method, options)
end
Expand Down Expand Up @@ -617,6 +619,23 @@ def add_network_tokenization_card(xml, payment_method, options)
end
end

def add_encrypted_wallet(xml, payment_method, options)
source = payment_method.source == :apple_pay ? 'APPLEPAY' : 'PAYWITHGOOGLE'

xml.paymentDetails do
xml.tag! "#{source}-SSL" do
xml.header do
xml.ephemeralPublicKey payment_method.payment_data.dig(:header, :ephemeralPublicKey)
xml.publicKeyHash payment_method.payment_data.dig(:header, :publicKeyHash)
xml.transactionId payment_method.payment_data.dig(:header, :transactionId)
end
xml.signature payment_method.payment_data[:signature]
xml.version payment_method.payment_data[:version]
xml.data payment_method.payment_data[:data]
end
end
end

def add_card_or_token(xml, payment_method, options)
xml.paymentDetails credit_fund_transfer_attribute(options) do
if options[:payment_type] == :token
Expand Down Expand Up @@ -986,7 +1005,11 @@ def payment_details(payment_method, options = {})
when String
token_type_and_details(payment_method)
else
type = network_token?(payment_method) || options[:wallet_type] == :google_pay ? :network_token : :credit
type = if network_token?(payment_method)
payment_method.payment_data ? :encrypted_wallet : :network_token
else
options[:wallet_type] == :google_pay ? :network_token : :credit
end
Comment on lines +1008 to +1012
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do payment methods with options[:wallet_type] == :google_pay have payment_data? would this work?

Suggested change
type = if network_token?(payment_method)
payment_method.payment_data ? :encrypted_wallet : :network_token
else
options[:wallet_type] == :google_pay ? :network_token : :credit
end
type = if network_token?(payment_method) || options[:wallet_type] == :google_pay
payment_method.payment_data ? :encrypted_wallet : :network_token
else
:credit
end

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't. options[:wallet_type] == :google_pay is for a non-tokenized GooglePay which we treat as a CreditCard


{ payment_type: type }
end
Expand Down
52 changes: 51 additions & 1 deletion test/unit/gateways/worldpay_test.rb
Expand Up @@ -164,7 +164,7 @@ def test_payment_type_for_network_card

def test_payment_type_returns_network_token_if_the_payment_method_responds_to_source_payment_cryptogram_and_eci
payment_method = mock
payment_method.stubs(source: nil, payment_cryptogram: nil, eci: nil)
payment_method.stubs(source: nil, payment_cryptogram: nil, eci: nil, payment_data: nil)
result = @gateway.send(:payment_details, payment_method)
assert_equal({ payment_type: :network_token }, result)
end
Expand Down Expand Up @@ -219,6 +219,56 @@ def test_successful_authorize_without_name
assert_equal 'R50704213207145707', response.authorization
end

def test_successful_authorize_encrypted_apple_pay
apple_pay = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new({
source: :apple_pay,
payment_data: {
version: 'EC_v1',
data: 'QlzLxRFnNP9/GTaMhBwgmZ2ywntbr9',
signature: 'signature',
header: {
ephemeralPublicKey: 'ephemeralPublicKey',
publicKeyHash: 'publicKeyHash',
transactionId: 'transactionId'
}
}
})

stub_comms do
@gateway.authorize(@amount, apple_pay, @options)
end.check_request do |_endpoint, data, _headers|
assert_match(/APPLEPAY-SSL/, data)
assert_match(%r(<version>EC_v1</version>), data)
assert_match(%r(<transactionId>transactionId</transactionId>), data)
assert_match(%r(<data>QlzLxRFnNP9/GTaMhBwgmZ2ywntbr9</data>), data)
end.respond_with(successful_authorize_response)
end

def test_successful_authorize_encrypted_google_pay
google_pay = ActiveMerchant::Billing::NetworkTokenizationCreditCard.new({
source: :google_pay,
payment_data: {
version: 'EC_v1',
data: 'QlzLxRFnNP9/GTaMhBwgmZ2ywntbr9',
signature: 'signature',
header: {
ephemeralPublicKey: 'ephemeralPublicKey',
publicKeyHash: 'publicKeyHash',
transactionId: 'transactionId'
}
}
})

stub_comms do
@gateway.authorize(@amount, google_pay, @options)
end.check_request do |_endpoint, data, _headers|
assert_match(/PAYWITHGOOGLE-SSL/, data)
assert_match(%r(<version>EC_v1</version>), data)
assert_match(%r(<transactionId>transactionId</transactionId>), data)
assert_match(%r(<data>QlzLxRFnNP9/GTaMhBwgmZ2ywntbr9</data>), data)
end.respond_with(successful_authorize_response)
end

def test_successful_authorize_by_reference
response = stub_comms do
@gateway.authorize(@amount, @options[:order_id].to_s, @options)
Expand Down