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

Spreedly: Scrub sensitive transaction data #2781

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion lib/active_merchant/billing/gateways/spreedly_core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@ def unstore(authorization, options={})
commit("payment_methods/#{authorization}/redact.xml", '', :put)
end

def supports_scrubbing?
true
end

def scrub(transcript)
transcript.
gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
gsub(%r((<number>).+(</number>)), '\1[FILTERED]\2').
gsub(%r((<verification_value>).+(</verification_value>)), '\1[FILTERED]\2').
gsub(%r((<payment_method_token>).+(</payment_method_token>)), '\1[FILTERED]\2')
end

private

def save_card(retain, credit_card, options)
Expand Down Expand Up @@ -244,4 +256,3 @@ def headers
end
end
end

27 changes: 25 additions & 2 deletions test/remote/gateways/remote_spreedly_core_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ def setup
@amount = 100
@credit_card = credit_card('5555555555554444')
@declined_card = credit_card('4012888888881881')
@existing_payment_method = '9AjLflWs7SOKuqJLveOZya9bixa'
@declined_payment_method = 'n3JElNt9joT1mJ3CxvWjyEN39N'
@existing_payment_method = 'WQ9zJ1UOgak8BrNEi3g5RCianlY'
@declined_payment_method = 'AMc22hrKtQFpYHTvjNx0lGRWZVv'
end

def test_successful_purchase_with_token
Expand Down Expand Up @@ -245,4 +245,27 @@ def test_invalid_login
assert_failure response
assert_match %r{Unable to authenticate}, response.message
end

def test_scrubbing_purchase
transcript = capture_transcript(@gateway) do
@gateway.purchase(@amount, @credit_card)
end
transcript = @gateway.scrub(transcript)

assert_scrubbed(@credit_card.number, transcript)
assert_scrubbed(@credit_card.verification_value, transcript)
assert_scrubbed(@gateway.options[:login], transcript)
assert_scrubbed(@gateway.options[:password], transcript)
end

def test_scrubbing_purchase_with_token
transcript = capture_transcript(@gateway) do
@gateway.purchase(@amount, @existing_payment_method)
end
transcript = @gateway.scrub(transcript)

assert_scrubbed(@existing_payment_method, transcript)
assert_scrubbed(@gateway.options[:login], transcript)
assert_scrubbed(@gateway.options[:password], transcript)
end
end
62 changes: 62 additions & 0 deletions test/unit/gateways/spreedly_core_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,13 @@ def test_successful_unstore
assert_equal "Succeeded!", response.message
end

def test_scrubbing
assert @gateway.supports_scrubbing?
assert_equal @gateway.scrub(pre_scrubbed), post_scrubbed
end

private

def successful_purchase_response
MockResponse.succeeded <<-XML
<transaction>
Expand Down Expand Up @@ -799,4 +804,61 @@ def successful_unstore_response
XML
end

def pre_scrubbed
<<-EOS
opening connection to core.spreedly.com:443...
opened
starting SSL for core.spreedly.com:443...
SSL established
<- "POST /v1/payment_methods.xml HTTP/1.1\r\nContent-Type: text/xml\r\nAuthorization: Basic NFk5YlZrT0NwWWVzUFFPZkRpN1RYUXlVdzUwOlkyaTdBamdVMDNTVWp3WTR4bk9QcXpkc3Y0ZE1iUERDUXpvckFrOEJjb3kwVThFSVZFNGlubkdqdW9NUXY3TU4=\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: core.spreedly.com\r\nContent-Length: 404\r\n\r\n"
<- "<?xml version=\"1.0\"?>\n<payment_method>\n <credit_card>\n <number>5555555555554444</number>\n <verification_value>123</verification_value>\n <first_name>Longbob</first_name>\n <last_name>Longsen</last_name>\n <month>9</month>\n <year>2019</year>\n <email/>\n <address1/>\n <address2/>\n <city/>\n <state/>\n <zip/>\n <country/>\n </credit_card>\n <data></data>\n</payment_method>\n"
-> "HTTP/1.1 201 Created\r\n"
-> "Date: Sat, 10 Mar 2018 22:04:06 GMT\r\n"
-> "Content-Type: application/xml; charset=utf-8\r\n"
-> "Content-Length: 1875\r\n"
-> "Connection: close\r\n"
-> "X-Frame-Options: SAMEORIGIN\r\n"
-> "X-XSS-Protection: 1; mode=block\r\n"
-> "X-Content-Type-Options: nosniff\r\n"
-> "ETag: W/\"c4ef6dfc389a5514d6b6ffd8bac8786c\"\r\n"
-> "Cache-Control: max-age=0, private, must-revalidate\r\n"
-> "X-Request-Id: b227ok4du2hrj7mrtt10.core_dcaa82760687b3ef\r\n"
-> "Server: nginx\r\n"
-> "Strict-Transport-Security: max-age=31536000; includeSubdomains;\r\n"
-> "\r\n"
reading 1875 bytes...
-> "<transaction>\n <token>NRBpydUCWn658GHV8h2kVlUzB0i</token>\n <created_at type=\"dateTime\">2018-03-10T22:04:06Z</created_at>\n <updated_at type=\"dateTime\">2018-03-10T22:04:06Z</updated_at>\n <succeeded type=\"boolean\">true</succeeded>\n <transaction_type>AddPaymentMethod</transaction_type>\n <retained type=\"boolean\">false</retained>\n <state>succeeded</state>\n <message key=\"messages.transaction_succeeded\">Succeeded!</message>\n <payment_method>\n <token>Wd25UIrH1uopTkZZ4UDdb5XmSDd</token>\n <created_at type=\"dateTime\">2018-03-10T22:04:06Z</created_at>\n <updated_at type=\"dateTime\">2018-03-10T22:04:06Z</updated_at>\n <email nil=\"true\"/>\n <data nil=\"true\"/>\n <storage_state>cached</storage_state>\n <test type=\"boolean\">true</test>\n <last_four_digits>4444</last_four_digits>\n <first_six_digits>555555</first_six_digits>\n <card_type>master</card_type>\n <first_name>Longbob</first_name>\n <last_name>Longsen</last_name>\n <month type=\"integer\">9</month>\n <year type=\"integer\">2019</year>\n <address1 nil=\"true\"/>\n <address2 nil=\"true\"/>\n <city nil=\"true\"/>\n <state nil=\"true\"/>\n <zip nil=\"true\"/>\n <country nil=\"true\"/>\n <phone_number nil=\"true\"/>\n <company nil=\"true\"/>\n <full_name>Longbob Longsen</full_name>\n <eligible_for_card_updater type=\"boolean\">true</eligible_for_card_updater>\n <shipping_address1 nil=\"true\"/>\n <shipping_address2 nil=\"true\"/>\n <shipping_city nil=\"true\"/>\n <shipping_state nil=\"true\"/>\n <shipping_zip nil=\"true\"/>\n <shipping_country nil=\"true\"/>\n <shipping_phone_number nil=\"true\"/>\n <payment_method_type>credit_card</payment_method_type>\n <errors>\n </errors>\n <verification_value>XXX</verification_value>\n <number>XXXX-XXXX-XXXX-4444</number>\n <fingerprint>125370bb396dff6fed4f581f85a91a9e5317</fingerprint>\n </payment_method>\n</transaction>\n"
read 1875 bytes
Conn close
EOS
end

def post_scrubbed
<<-EOS
opening connection to core.spreedly.com:443...
opened
starting SSL for core.spreedly.com:443...
SSL established
<- "POST /v1/payment_methods.xml HTTP/1.1\r\nContent-Type: text/xml\r\nAuthorization: Basic [FILTERED]=\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: core.spreedly.com\r\nContent-Length: 404\r\n\r\n"
<- "<?xml version=\"1.0\"?>\n<payment_method>\n <credit_card>\n <number>[FILTERED]</number>\n <verification_value>[FILTERED]</verification_value>\n <first_name>Longbob</first_name>\n <last_name>Longsen</last_name>\n <month>9</month>\n <year>2019</year>\n <email/>\n <address1/>\n <address2/>\n <city/>\n <state/>\n <zip/>\n <country/>\n </credit_card>\n <data></data>\n</payment_method>\n"
-> "HTTP/1.1 201 Created\r\n"
-> "Date: Sat, 10 Mar 2018 22:04:06 GMT\r\n"
-> "Content-Type: application/xml; charset=utf-8\r\n"
-> "Content-Length: 1875\r\n"
-> "Connection: close\r\n"
-> "X-Frame-Options: SAMEORIGIN\r\n"
-> "X-XSS-Protection: 1; mode=block\r\n"
-> "X-Content-Type-Options: nosniff\r\n"
-> "ETag: W/\"c4ef6dfc389a5514d6b6ffd8bac8786c\"\r\n"
-> "Cache-Control: max-age=0, private, must-revalidate\r\n"
-> "X-Request-Id: b227ok4du2hrj7mrtt10.core_dcaa82760687b3ef\r\n"
-> "Server: nginx\r\n"
-> "Strict-Transport-Security: max-age=31536000; includeSubdomains;\r\n"
-> "\r\n"
reading 1875 bytes...
-> "<transaction>\n <token>NRBpydUCWn658GHV8h2kVlUzB0i</token>\n <created_at type=\"dateTime\">2018-03-10T22:04:06Z</created_at>\n <updated_at type=\"dateTime\">2018-03-10T22:04:06Z</updated_at>\n <succeeded type=\"boolean\">true</succeeded>\n <transaction_type>AddPaymentMethod</transaction_type>\n <retained type=\"boolean\">false</retained>\n <state>succeeded</state>\n <message key=\"messages.transaction_succeeded\">Succeeded!</message>\n <payment_method>\n <token>Wd25UIrH1uopTkZZ4UDdb5XmSDd</token>\n <created_at type=\"dateTime\">2018-03-10T22:04:06Z</created_at>\n <updated_at type=\"dateTime\">2018-03-10T22:04:06Z</updated_at>\n <email nil=\"true\"/>\n <data nil=\"true\"/>\n <storage_state>cached</storage_state>\n <test type=\"boolean\">true</test>\n <last_four_digits>4444</last_four_digits>\n <first_six_digits>555555</first_six_digits>\n <card_type>master</card_type>\n <first_name>Longbob</first_name>\n <last_name>Longsen</last_name>\n <month type=\"integer\">9</month>\n <year type=\"integer\">2019</year>\n <address1 nil=\"true\"/>\n <address2 nil=\"true\"/>\n <city nil=\"true\"/>\n <state nil=\"true\"/>\n <zip nil=\"true\"/>\n <country nil=\"true\"/>\n <phone_number nil=\"true\"/>\n <company nil=\"true\"/>\n <full_name>Longbob Longsen</full_name>\n <eligible_for_card_updater type=\"boolean\">true</eligible_for_card_updater>\n <shipping_address1 nil=\"true\"/>\n <shipping_address2 nil=\"true\"/>\n <shipping_city nil=\"true\"/>\n <shipping_state nil=\"true\"/>\n <shipping_zip nil=\"true\"/>\n <shipping_country nil=\"true\"/>\n <shipping_phone_number nil=\"true\"/>\n <payment_method_type>credit_card</payment_method_type>\n <errors>\n </errors>\n <verification_value>[FILTERED]</verification_value>\n <number>[FILTERED]</number>\n <fingerprint>125370bb396dff6fed4f581f85a91a9e5317</fingerprint>\n </payment_method>\n</transaction>\n"
read 1875 bytes
Conn close
EOS
end
end