Pass bop_options to gateway
[Business-OnlinePayment-CardFortress.git] / lib / Business / OnlinePayment / CardFortress.pm
index 513ed26..1d97d49 100644 (file)
@@ -5,12 +5,15 @@ use base qw( Business::OnlinePayment::HTTPS );
 use warnings;
 use strict;
 #use vars qw( $DEBUG $me );
+use File::Slurp;
+use MIME::Base64;
+use Crypt::OpenSSL::RSA;
 
-our $VERSION = 0.01;
+our $VERSION = 0.03;
 
 sub _info {
   {
-    'info_version'      => '0.01',
+    'info_compat'       => '0.01',
     'module_version'    => $VERSION,
     'supported_types'   => [ 'CC' ],
     'supported_actions' => { 'CC' => [
@@ -19,9 +22,10 @@ sub _info {
                                        'Post Authorization',
                                        'Void',
                                        'Credit',
+                                       'Tokenize',
                                      ],
                            },
-    'token_support'     => 'challenge/response',
+    'token_support'     => 1,
     #need to figure out how to pass through for gateways that do... an option?
     #'CC_void_requires_card' => 1,
   };
@@ -38,20 +42,25 @@ sub set_defaults {
 
   $self->build_subs(qw( order_number avs_code cvv2_response
                         response_page response_code response_headers
-                        card_token
+                        card_token private_key
                    ));
 }
 
 sub submit {
   my $self = shift;
 
-  $self->server('test.cardfortress.com');
+  $self->server('test.cardfortress.com') if $self->test_transaction;
 
-  my ($page,$server_response,%headers) = $self->https_post($self->content);
+  my %content = $self->content;
+  $content{$_} = $self->$_() for qw( gateway gateway_login gateway_password );
 
-  die $server_response unless $server_response =~ /^200/;
+  $content{$_} = $self->$_() for grep $self->can($_), qw( bop_options );
 
-  my %response = {};
+  my ($page,$server_response,%headers) = $self->https_post(%content);
+
+  die "$server_response\n" unless $server_response =~ /^200/;
+
+  my %response = ();
   #this encoding good enough?  wfm... if something's easier for other
   #languages they can always use a different URL
   foreach my $line ( grep /^\w+=/, split(/\n/, $page) ) {
@@ -73,6 +82,30 @@ sub submit {
   # response_headers()
   # response_page()
 
+  #handle the challenge/response handshake
+  if ( $self->error_message eq '_challenge' ) { #XXX infinite loop protection?
+
+    my $private_key = $self->private_key
+      or die "no private key available";
+
+    $private_key = read_file($private_key)
+      if $private_key !~ /-----BEGIN/ && -r $private_key;
+
+    #decrypt the challenge with the private key
+    my $challenge = decode_base64($response{'card_challenge'});
+
+    #here is the hardest part to implement at each client side
+    my $rsa_priv = Crypt::OpenSSL::RSA->new_private_key($private_key);
+    my $response = $rsa_priv->decrypt($challenge);
+
+    #try the transaction again with the challenge response
+    # (B:OP could sure use a better way to alter one value)
+    my %content = $self->content;
+    $content{'card_response'} = encode_base64($response, '');
+    $self->content(%content);
+    $self->submit;
+  }
+
 }
 
 1;
@@ -87,12 +120,13 @@ Business::OnlinePayment::CardFortress - CardFortress backend for Business::Onlin
 
   use Business::OnlinePayment;
 
-  my $tx = new Business::OnlinePayment( 'CardFortress',
-                                          'gateway' => 'ProcessingGateway',
-                                          'gateway_login' => 'gwlogin',
-                                          'gateway_password' => 'gwpass',
-                                          #private_key not necessary
-                                      );
+  my $tx = new Business::OnlinePayment(
+    'CardFortress',
+      'gateway'          => 'ProcessingGateway',
+      'gateway_login'    => 'gwlogin',
+      'gateway_password' => 'gwpass',
+      #private_key not necessary
+  );
 
   $tx->content(
       type           => 'VISA',
@@ -123,12 +157,14 @@ Business::OnlinePayment::CardFortress - CardFortress backend for Business::Onlin
 
   # ... time slips by ...
 
-  my $rx = new Business::OnlinePayment( 'CardFortress',
-                                          'gateway' => 'ProcessingGateway',
-                                          'gateway_login' => 'gwlogin',
-                                          'gateway_password' => 'gwpass',
-                                          'private_key' => '/path/to/keyfile',
-                                      );
+  my $rx = new Business::OnlinePayment(
+    'CardFortress',
+      'gateway'          => 'ProcessingGateway',
+      'gateway_login'    => 'gwlogin',
+      'gateway_password' => 'gwpass',
+      'private_key'      => $private_key_string, #or filename
+      'bop_options'      => join('/', map "$_=".$options{$_}, keys %options),
+  );
 
   $rx->content(
       type           => 'VISA',