diff --git a/CHANGELOG b/CHANGELOG index b09602200ba..8988b783944 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,7 @@ * MercadoPago: Add remote and unit tests for Naranja card [hdeters] #3345 * CyberSource: Pass commerce indicator if present [curiousepic] #3350 * Worldpay: Add 3DS2 Support [nfarve] #3344 +* Credorax: Add 3DS 2.0 [nfarve] #3342 == Version 1.98.0 (Sep 9, 2019) * Stripe Payment Intents: Add new gateway [britth] #3290 diff --git a/lib/active_merchant/billing/gateways/credorax.rb b/lib/active_merchant/billing/gateways/credorax.rb index 6f28d82f259..94bae1251a3 100644 --- a/lib/active_merchant/billing/gateways/credorax.rb +++ b/lib/active_merchant/billing/gateways/credorax.rb @@ -270,6 +270,30 @@ def add_email(post, options) def add_3d_secure(post, options) if options[:eci] && options[:xid] add_3d_secure_1_data(post, options) + elsif options[:execute_threed] && options[:three_ds_2] + three_ds_2_options = options[:three_ds_2] + browser_info = three_ds_2_options[:browser_info] + post[:'3ds_initiate'] = options[:three_ds_initiate] || '01' + post[:'3ds_purchasedate'] = Time.now.utc.strftime('%Y%m%d%I%M%S') + post[:'3ds_channel'] = '02' + post[:'3ds_redirect_url'] = three_ds_2_options[:notification_url] + post[:'3ds_challengewindowsize'] = options[:three_ds_challenge_window_size] || '03' + post[:d5] = browser_info[:user_agent] + post[:'3ds_browsertz'] = browser_info[:timezone] + post[:'3ds_browserscreenwidth'] = browser_info[:width] + post[:'3ds_browserscreenheight'] = browser_info[:height] + post[:'3ds_browsercolordepth'] = browser_info[:depth] + post[:d6] = browser_info[:language] + post[:'3ds_browserjavaenabled'] = browser_info[:java] + post[:'3ds_browseracceptheader'] = browser_info[:accept_header] + if (shipping_address = options[:shipping_address]) + post[:'3ds_shipaddrstate'] = shipping_address[:state] + post[:'3ds_shipaddrpostcode'] = shipping_address[:zip] + post[:'3ds_shipaddrline2'] = shipping_address[:address2] + post[:'3ds_shipaddrline1'] = shipping_address[:address1] + post[:'3ds_shipaddrcountry'] = shipping_address[:country] + post[:'3ds_shipaddrcity'] = shipping_address[:city] + end elsif options[:three_d_secure] add_normalized_3d_secure_2_data(post, options) end @@ -277,6 +301,7 @@ def add_3d_secure(post, options) def add_3d_secure_1_data(post, options) post[:i8] = build_i8(options[:eci], options[:cavv], options[:xid]) + post[:r1] = 'CREDORAX' end def add_normalized_3d_secure_2_data(post, options) @@ -288,6 +313,7 @@ def add_normalized_3d_secure_2_data(post, options) ) post[:'3ds_version'] = three_d_secure_options[:version] post[:'3ds_dstrxid'] = three_d_secure_options[:ds_transaction_id] + post[:r1] = 'CREDORAX' end def build_i8(eci, cavv=nil, xid=nil) @@ -317,7 +343,8 @@ def add_transaction_type(post, options) credit: '6', purchase_void: '7', refund_void: '8', - capture_void: '9' + capture_void: '9', + threeds_completion: '92' } def commit(action, params, reference_action = nil) diff --git a/test/remote/gateways/remote_credorax_test.rb b/test/remote/gateways/remote_credorax_test.rb index f826f157987..7997fc593b8 100644 --- a/test/remote/gateways/remote_credorax_test.rb +++ b/test/remote/gateways/remote_credorax_test.rb @@ -8,12 +8,39 @@ def setup @credit_card = credit_card('4176661000001015', verification_value: '281', month: '12', year: '2022') @fully_auth_card = credit_card('5223450000000007', brand: 'mastercard', verification_value: '090', month: '12', year: '2025') @declined_card = credit_card('4176661000001111', verification_value: '681', month: '12', year: '2022') + @three_ds_card = credit_card('5185520050000010', verification_value: '737', month: '12', year: '2022') @options = { order_id: '1', currency: 'EUR', billing_address: address, description: 'Store Purchase' } + @normalized_3ds_2_options = { + reference: '345123', + shopper_email: 'john.smith@test.com', + shopper_ip: '77.110.174.153', + shopper_reference: 'John Smith', + billing_address: address(), + shipping_address: address(), + order_id: '123', + execute_threed: true, + three_ds_challenge_window_size: '01', + stored_credential: {reason_type: 'unscheduled'}, + three_ds_2: { + channel: 'browser', + notification_url: 'www.example.com', + browser_info: { + accept_header: 'unknown', + depth: 24, + java: false, + language: 'US', + height: 1000, + width: 500, + timezone: '-120', + user_agent: 'unknown' + } + } + } end def test_invalid_login @@ -49,6 +76,12 @@ def test_successful_purchase_with_auth_data_via_3ds1_fields assert_equal 'Succeeded', response.message end + def test_successful_purchase_with_3ds2_fields + options = @options.merge(@normalized_3ds_2_options) + response = @gateway.purchase(@amount, @three_ds_card, options) + assert_equal 'Transaction pending cardholder authentication.', response.message + end + def test_successful_purchase_with_auth_data_via_normalized_3ds2_options version = '2.0' eci = '02' @@ -91,7 +124,7 @@ def test_failed_purchase_invalid_auth_data_via_3ds1_fields def test_failed_purchase_invalid_auth_data_via_normalized_3ds2_options version = '2.0' eci = '02' - cavv = 'BOGUS' + cavv = 'BOGUS;:' ds_transaction_id = '97267598-FAE6-48F2-8083-C23433990FBC' options = @options.merge( three_d_secure: { diff --git a/test/unit/gateways/credorax_test.rb b/test/unit/gateways/credorax_test.rb index f353c0297fb..06955aa118c 100644 --- a/test/unit/gateways/credorax_test.rb +++ b/test/unit/gateways/credorax_test.rb @@ -12,6 +12,33 @@ def setup billing_address: address, description: 'Store Purchase' } + + @normalized_3ds_2_options = { + reference: '345123', + shopper_email: 'john.smith@test.com', + shopper_ip: '77.110.174.153', + shopper_reference: 'John Smith', + billing_address: address(), + shipping_address: address(), + order_id: '123', + execute_threed: true, + three_ds_challenge_window_size: '01', + stored_credential: {reason_type: 'unscheduled'}, + three_ds_2: { + channel: 'browser', + notification_url: 'www.example.com', + browser_info: { + accept_header: 'unknown', + depth: 100, + java: false, + language: 'US', + height: 1000, + width: 500, + timezone: '-120', + user_agent: 'unknown' + } + } + } end def test_successful_purchase @@ -174,6 +201,37 @@ def test_transcript_scrubbing assert_equal scrubbed_transcript, @gateway.scrub(transcript) end + def test_adds_3d2_secure_fields + options_with_3ds = @normalized_3ds_2_options + + response = stub_comms do + @gateway.purchase(@amount, @credit_card, options_with_3ds) + end.check_request do |endpoint, data, headers| + assert_match(/3ds_channel=02/, data) + assert_match(/3ds_redirect_url=www.example.com/, data) + assert_match(/3ds_challengewindowsize=01/, data) + assert_match(/d5=unknown/, data) + assert_match(/3ds_browsertz=-120/, data) + assert_match(/3ds_browserscreenwidth=500/, data) + assert_match(/3ds_browserscreenheight=1000/, data) + assert_match(/3ds_browsercolordepth=100/, data) + assert_match(/d6=US/, data) + assert_match(/3ds_browserjavaenabled=false/, data) + assert_match(/3ds_browseracceptheader=unknown/, data) + assert_match(/3ds_shipaddrstate=ON/, data) + assert_match(/3ds_shipaddrpostcode=K1C2N6/, data) + assert_match(/3ds_shipaddrline2=Apt\+1/, data) + assert_match(/3ds_shipaddrline1=456\+My\+Street/, data) + assert_match(/3ds_shipaddrcountry=CA/, data) + assert_match(/3ds_shipaddrcity=Ottawa/, data) + end.respond_with(successful_purchase_response) + + assert_success response + + assert_equal '8a82944a5351570601535955efeb513c;006596;02617cf5f02ccaed239b6521748298c5;purchase', response.authorization + assert response.test? + end + def test_adds_3d_secure_fields options_with_3ds = @options.merge({eci: 'sample-eci', cavv: 'sample-cavv', xid: 'sample-xid'})