From d8a1293c21b122228aeb32d965ae6f793e7c6d59 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Thu, 24 Jan 2013 16:51:46 -0800 Subject: [PATCH] start --- .gitignore | 6 ++ CardFortress.pm | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Changes | 5 ++ MANIFEST | 8 ++ Makefile.PL | 20 +++++ README | 55 ++++++++++++++ ignore.txt | 12 +++ t/00-load.t | 9 +++ t/manifest.t | 13 ++++ t/pod.t | 12 +++ 10 files changed, 363 insertions(+) create mode 100644 .gitignore create mode 100644 CardFortress.pm create mode 100644 Changes create mode 100644 MANIFEST create mode 100644 Makefile.PL create mode 100644 README create mode 100644 ignore.txt create mode 100644 t/00-load.t create mode 100644 t/manifest.t create mode 100644 t/pod.t diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9788afa --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +blib/ +*.sw? +Makefile +Makefile.old +MYMETA.yml +pm_to_blib diff --git a/CardFortress.pm b/CardFortress.pm new file mode 100644 index 0000000..3690f1c --- /dev/null +++ b/CardFortress.pm @@ -0,0 +1,223 @@ +package Business::BatchPayment::CardFortress; + +use 5.006; +use strict; +use warnings; +our $VERSION = '0.01'; + +=head1 NAME + +Business::BatchPayment::CardFortress + +=head1 DESCRIPTION + +Batch payment processing via the CardFortress secure payment proxy service. + +=head1 USAGE + +See Business::BatchPayment for general usage information. + +=head2 PROCESSOR ATTRIBUTES + +=over 4 + +=item login, password + +Your login credentials for CardFortress. + +=item gateway + +The L module to use for upstream processing. You +don't need to have this module installed, but the proxy server does. + +=item gateway_* + +Processor options to pass along to the gateway module. The 'gateway_' prefix +will be stripped. + +=back + +=cut + +use Business::BatchPayment; +use Moose; +with 'Business::BatchPayment::Processor'; +with 'Business::BatchPayment::TestMode'; +with 'Business::BatchPayment::Debug'; + +use Data::Serializer; + +has [ qw(login password private_key gateway) ] => ( + is => 'ro', + isa => 'Str', + required => 1, +); + +has 'gateway_opts' => ( + is => 'ro', + isa => 'HashRef', + default => sub { {login => ''} }, +); + +has 'serializer' => ( + is => 'ro', + lazy => 1, + handles => [qw(serialize deserialize)], + default => sub { +# doesn't have to be Storable, but it must support blessed objects + Data::Serializer->new(serializer => 'Storable', encoding => 'b64') + }, +); + +# pull any arg named "gateway_foo" into gateway_opts +around 'BUILDARGS' => sub { + my ($orig, $class, %args) = @_; + foreach (keys %args) { + if (/^gateway_(.*)/) { + $args{'gateway_opts'}->{$1} = delete $args{$_}; + } + } + $class->$orig(%args); +}; + +sub default_transport { + my $self = shift; + Business::BatchPayment->create('CardFortress::Transport', + login => $self->login, + password => $self->password, + debug => $self->debug, + test_mode => $self->test_mode, + private_key => $self->private_key, + serializer => $self->serializer, + ); +} + +sub format_request { + my $self = shift; + my $batch = shift; + bless $batch, 'Business::BatchPayment::CardFortress::Batch'; + # things that get encoded in the batch: + $batch->gateway($self->gateway); + $batch->gateway_opts($self->gateway_opts); + $self->serialize($batch); # that's all folks +} + +sub parse_response { + my $self = shift; + my $input = shift; + my $batch = $self->deserialize($input); +} + +package Business::BatchPayment::CardFortress::Batch; + +use Moose; +extends 'Business::BatchPayment::Batch'; + +has 'gateway' => ( + is => 'rw', + isa => 'Str', +); +has 'gateway_opts' => ( + is => 'rw', + isa => 'HashRef', +); + +package Business::BatchPayment::CardFortress::Transport; + +use Moose; +use Moose::Util::TypeConstraints; +extends 'Business::BatchPayment::Transport::HTTPS'; +with 'Business::BatchPayment::TestMode'; + +use File::Slurp; +use MIME::Base64; +use Crypt::OpenSSL::RSA; + +has '+host' => ( + default => sub { + my $self = shift; + $self->test_mode ? 'gw.cardfortress.com' + : 'test.cardfortress.com' + }, + lazy => 1, +); + +has ['login', 'password', 'private_key'] => (isa => 'Str', is => 'rw'); + +has 'serializer' => ( handles => [qw(serialize deserialize)] ); + +sub upload { + my ($self, $content) = @_; + warn "Sending batch...\n" if $self->debug; + my ($page, $response, %reply_headers) = + $self->https_post('/batch/submit', { + login => $self->login, + password => $self->password, + content => $content, + }); + $page = $self->deserialize($page); + die $page->{error} if $page->{error}; + my $batchid = $page->{batchid}; + + my $private_key = read_file($self->private_key) + or die "No private key available"; + my $rsa = Crypt::OpenSSL::RSA->new_private_key($private_key); + + my %answers; + foreach my $item (@{ $page->{items} }) { + if ( $item->{error} ) { + # We have no reliable way to report an error in a specific transaction + # at this stage. The server will send the error in the reply batch. + # For now do nothing. + } elsif ( $item->{challenge} ) { + my $challenge = $item->{challenge}; + $answers{ $item->{tid} } = $rsa->decrypt( decode_base64($challenge) ); + } else { + # newly created card--doesn't have a challenge, so do nothing + } + } + # post the response + warn "Answering cryptographic challenge...\n" if $self->debug; + my $answer_content = + $self->serialize({ batchid => $batchid, answers => \%answers }); + ($page, $response, %reply_headers) = + $self->https_post('/batch/run', { + login => $self->login, + password => $self->password, + content => $answer_content, + }); + $page = $self->deserialize($page); + die $page->{error} if $page->{error}; + return; +} + +=head1 AUTHOR + +Mark Wells, C<< >> + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc Business::BatchPayment::CardFortress + +Commercial support is available from Freeside Internet Services, Inc. + +L + +=head1 ACKNOWLEDGEMENTS + +=head1 LICENSE AND COPYRIGHT + +Copyright 2012 Mark Wells. + +This program is free software; you can redistribute it and/or modify it +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. + +See http://dev.perl.org/licenses/ for more information. + + +=cut + +1; # End of Business::BatchPayment::Paymentech diff --git a/Changes b/Changes new file mode 100644 index 0000000..8e4fd70 --- /dev/null +++ b/Changes @@ -0,0 +1,5 @@ +Revision history for Business-BatchPayment-CardFortress + +0.01 Date/time + First version, released on an unsuspecting world. + diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..fae5736 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,8 @@ +Changes +CardFortress.pm +Makefile.PL +MANIFEST This list of files +README +t/00-load.t +t/manifest.t +t/pod.t diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..cbe9f6c --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,20 @@ +use 5.006; +use strict; +use warnings; +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => 'Business::BatchPayment::CardFortress', + AUTHOR => q{Mark Wells }, + VERSION_FROM => 'CardFortress.pm', + ABSTRACT_FROM => 'CardFortress.pm', + ($ExtUtils::MakeMaker::VERSION >= 6.3002 + ? ('LICENSE'=> 'perl') + : ()), + PL_FILES => {}, + PREREQ_PM => { + 'Test::More' => 0, + }, + dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, + clean => { FILES => 'Business-BatchPayment-CardFortress-*' }, +); diff --git a/README b/README new file mode 100644 index 0000000..151bdb7 --- /dev/null +++ b/README @@ -0,0 +1,55 @@ +Business-BatchPayment-CardFortress + +The README is used to introduce the module and provide instructions on +how to install the module, any machine dependencies it may have (for +example C compilers and installed libraries) and any other information +that should be provided before the module is installed. + +A README file is required for CPAN modules since CPAN extracts the README +file from a module distribution so that people browsing the archive +can use it to get an idea of the module's uses. It is usually a good idea +to provide version information here so that people can decide whether +fixes for the module are worth downloading. + + +INSTALLATION + +To install this module, run the following commands: + + perl Makefile.PL + make + make test + make install + +SUPPORT AND DOCUMENTATION + +After installing, you can find documentation for this module with the +perldoc command. + + perldoc Business::BatchPayment::CardFortress + +You can also look for information at: + + RT, CPAN's request tracker (report bugs here) + http://rt.cpan.org/NoAuth/Bugs.html?Dist=Business-BatchPayment-CardFortress + + AnnoCPAN, Annotated CPAN documentation + http://annocpan.org/dist/Business-BatchPayment-CardFortress + + CPAN Ratings + http://cpanratings.perl.org/d/Business-BatchPayment-CardFortress + + Search CPAN + http://search.cpan.org/dist/Business-BatchPayment-CardFortress/ + + +LICENSE AND COPYRIGHT + +Copyright (C) 2013 Mark Wells + +This program is free software; you can redistribute it and/or modify it +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. + +See http://dev.perl.org/licenses/ for more information. + diff --git a/ignore.txt b/ignore.txt new file mode 100644 index 0000000..8237b6b --- /dev/null +++ b/ignore.txt @@ -0,0 +1,12 @@ +blib* +Makefile +Makefile.old +Build +Build.bat +_build* +pm_to_blib* +*.tar.gz +.lwpcookies +cover_db +pod2htm*.tmp +Business-BatchPayment-CardFortress-* diff --git a/t/00-load.t b/t/00-load.t new file mode 100644 index 0000000..54a65c1 --- /dev/null +++ b/t/00-load.t @@ -0,0 +1,9 @@ +#!perl -T + +use Test::More tests => 1; + +BEGIN { + use_ok( 'Business::BatchPayment::CardFortress' ) || print "Bail out!\n"; +} + +diag( "Testing Business::BatchPayment::CardFortress $Business::BatchPayment::CardFortress::VERSION, Perl $], $^X" ); diff --git a/t/manifest.t b/t/manifest.t new file mode 100644 index 0000000..45eb83f --- /dev/null +++ b/t/manifest.t @@ -0,0 +1,13 @@ +#!perl -T + +use strict; +use warnings; +use Test::More; + +unless ( $ENV{RELEASE_TESTING} ) { + plan( skip_all => "Author tests not required for installation" ); +} + +eval "use Test::CheckManifest 0.9"; +plan skip_all => "Test::CheckManifest 0.9 required" if $@; +ok_manifest(); diff --git a/t/pod.t b/t/pod.t new file mode 100644 index 0000000..ee8b18a --- /dev/null +++ b/t/pod.t @@ -0,0 +1,12 @@ +#!perl -T + +use strict; +use warnings; +use Test::More; + +# Ensure a recent version of Test::Pod +my $min_tp = 1.22; +eval "use Test::Pod $min_tp"; +plan skip_all => "Test::Pod $min_tp required for testing POD" if $@; + +all_pod_files_ok(); -- 2.11.0