#!/usr/bin/perl # A script to accept a POST response from Authorize.Net and pass the data to Xerox use strict; use CGI; use Digest::MD5 qw/md5_hex/; use LWP; use Config::YAML; use CGI::Carp qw(fatalsToBrowser); use POSIX qw/strftime/; use Time::HiRes qw/time/; use Data::Dumper; my $configFile = 'adn_helper.yaml'; for (0..$#ARGV) { $configFile = $ARGV[$_ + 1] and last if /--config/; } my $config = Config::YAML->new( config => $configFile, timeout => 60, db_host => q/localhost/, db_name => q/adn_passthrough_log/, ); for (qw/salt loginID postURL/) { die "Missing required key \"$_\" in configuration file" unless $config->{$_}; } my $query = new CGI; $query->import_names('Q'); my $t0 = time; my $old_handle = select(STDOUT); local $| = 1; select($old_handle); syswrite STDOUT, "Content-type: text/html\n\n"; my $md5 = md5_hex($config->{salt}, $config->{loginID}, $Q::x_trans_id, $Q::x_amount); if (lc($md5) eq lc($Q::x_MD5_Hash)) { my $browser = getBrowser($Q::sid); my %hash; $hash{$_} = $query->param($_) for $query->param; logline(" params: ", Dumper [$query->param]); logline(" ", Dumper \%hash); syswrite STDOUT, "Your card was successfully charged for \$$Q::x_amount
\n" if $Q::x_response_reason_code == 1; syswrite STDOUT, "Your card could not be charged. $Q::x_response_reason_text
\n" if $Q::x_response_reason_code == 2; syswrite STDOUT, "There was an error processing your card: $Q::x_response_reason_text
\n" if $Q::x_response_reason_code > 2; my $pid = fork; my $elapsed = time - $t0; if ($pid) { # parent logline(" time elapsed in responding to Authorize.Net and forking: $elapsed"); logline(" forked, child pid $pid"); close STDOUT; exit; } open STDIN, "/dev/null"; $t0 = time; my $response = $browser->post($config->{postURL}, [%hash]); $elapsed = time - $t0; logline(" time elapsed in waiting for response from Xerox: $elapsed"); logline(" query: ", Dumper $query); logline(" response: ", Dumper $response); } else { logger($query, undef); print "This transaction could not be processed due to a checksum mismatch.
"; # possible spoofing attack } sub logger { use DBI; my ($query, $response, $elapsed) = @_; my $dbh = DBI->connect("DBI:mysql:$config->{db_name};host=$config->{db_host}", $config->{db_username}, $config->{db_password}, { RaiseError => 1 }) || die "Could not connect to logging database: $DBI::errstr"; open my $out, ">>/tmp/passthrough.log"; print $out strftime("%Y-%m-%d %T\n", localtime(time)); print $out "Elapsed: $elapsed\n"; print $out "Query\n"; print $out Dumper $query, "\n"; print $out "Response\n"; print $out Dumper $response, "\n"; close $out; } sub logline { open my $out, ">>/tmp/passthrough.log"; print $out strftime("%Y-%m-%d %T", localtime(time)), @_, "\n"; } sub getBrowser { my $sid = shift; open my $out, ">>/tmp/passthrough.log"; print $out strftime("%Y-%m-%d %T: ", localtime(time)), "Creating LWP::UserAgent with Session ID $sid, user-agent $ENV{HTTP_USER_AGENT}\n"; close $out; my $browser = LWP::UserAgent->new(); $browser->timeout($config->{timeout}); $browser->cookie_jar({}); $browser->agent($ENV{HTTP_USER_AGENT}); # $cookie_jar->set_cookie( $version, $key, $val, $path, $domain, $port, $path_spec, $secure, $maxage, $discard, \%rest ) $browser->cookie_jar->set_cookie(1, 'SessionID', "SessionID=$sid", '/'); return $browser; }