#!/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;
}