Skip to content

Commit

Permalink
Mercury: Stripping the start and end sentinels on card-present track …
Browse files Browse the repository at this point in the history
…data for max-length track1 requests

Closes #2026
  • Loading branch information
ryanbalsdon authored and Ryan Balsdon committed Feb 24, 2016
1 parent ca6aa89 commit 033f2fc
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
* Clearhaus: Make request signing more transparent & robust [sdball]
* Cashnet: Default custcode option and proper redirect handling [hoenth]
* SagePay: Properly detect Electron brand [sdball]
* Mercury: Fix for max-length track 1 [ryanbalsdon]


== Version 1.56.0 (December 1, 2015)
Expand Down
16 changes: 12 additions & 4 deletions lib/active_merchant/billing/gateways/mercury.rb
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,20 @@ def add_credit_card(xml, credit_card, action)
if credit_card.track_data.present?
# Track 1 has a start sentinel (STX) of '%' and track 2 is ';'
# Track 1 and 2 have identical end sentinels (ETX) of '?'
# Tracks may or may not have checksum (LRC) after the ETX
# If the track has no STX or is corrupt, we send it as track 1, to let Mercury
#handle with the validation error as it sees fit.
# Track 2 requires having the start and end sentinels stripped. Track 1 does not.
if credit_card.track_data[0] == ';' # track 2 start sentinel (STX)
xml.tag! 'Track2', credit_card.track_data[1..-2]
else # track 1 or a corrupt track
# Track 2 requires having the STX and ETX stripped. Track 1 does not.
# Max-length track 1s require having the STX and ETX stripped. Max is 79 bytes including LRC.
is_track_2 = credit_card.track_data[0] == ';'
etx_index = credit_card.track_data.rindex('?') || credit_card.track_data.length
is_max_track1 = etx_index >= 77

if is_track_2
xml.tag! 'Track2', credit_card.track_data[1...etx_index]
elsif is_max_track1
xml.tag! 'Track1', credit_card.track_data[1...etx_index]
else
xml.tag! 'Track1', credit_card.track_data
end
else
Expand Down
14 changes: 14 additions & 0 deletions test/unit/gateways/mercury_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ def test_card_present_with_track_2_data
assert_success response
end

def test_card_present_with_max_length_track_1_data
track_data = "%B373953192351004^CARDUSER/JOHN^200910100000019301000000877000000930001234567?"
stripped_data = "B373953192351004^CARDUSER/JOHN^200910100000019301000000877000000930001234567"
@credit_card.track_data = track_data
response = stub_comms do
@gateway.purchase(@amount, @credit_card, @options)
end.check_request do |endpoint, data, headers|
assert_match(/<Track1>#{Regexp.escape(stripped_data)}<\/Track1>/, data)
end.respond_with(successful_purchase_response)

assert_instance_of Response, response
assert_success response
end

def test_card_present_with_invalid_data
track_data = "this is not valid track data"
@credit_card.track_data = track_data
Expand Down

0 comments on commit 033f2fc

Please sign in to comment.