1 package Business::OnlinePayment::CardFortress;
3 use base qw( Business::OnlinePayment::HTTPS );
7 #use vars qw( $DEBUG $me );
10 use Crypt::OpenSSL::RSA;
16 'info_compat' => '0.01',
17 'module_version' => $VERSION,
18 'supported_types' => [ 'CC' ],
19 'supported_actions' => { 'CC' => [
20 'Normal Authorization',
29 #need to figure out how to pass through for gateways that do... an option?
30 #'CC_void_requires_card' => 1,
38 $self->server('gw.cardfortress.com') unless $self->server;
40 $self->port('443') unless $self->port;
41 $self->path('/bop/index.html') unless $self->path;
43 $self->build_subs(qw( order_number avs_code cvv2_response
44 response_page response_code response_headers
45 card_token private_key txn_date
52 $self->server('test.cardfortress.com') if $self->test_transaction;
54 my %content = $self->content;
55 $content{$_} = $self->$_() for qw( gateway gateway_login gateway_password );
57 $content{$_} = $self->$_() for grep $self->can($_), qw( bop_options );
59 my ($page,$server_response,%headers) = $self->https_post(%content);
61 die "$server_response\n" unless $server_response =~ /^200/;
64 #this encoding good enough? wfm... if something's easier for other
65 #languages they can always use a different URL
66 foreach my $line ( grep /^\w+=/, split(/\n/, $page) ) {
67 $line =~ /^(\w+)=(.*)$/ or next;
71 foreach (qw( is_success error_message failure_status
72 authorization order_number
73 fraud_score fraud_transaction_id
74 result_code avs_code cvv2_response
78 $self->$_($response{$_});
81 #map these to gateway_response_code, etc?
86 #handle the challenge/response handshake
87 if ( $self->error_message eq '_challenge' ) { #XXX infinite loop protection?
89 my $private_key = $self->private_key
90 or die "no private key available";
92 $private_key = read_file($private_key)
93 if $private_key !~ /-----BEGIN/ && -r $private_key;
95 #decrypt the challenge with the private key
96 my $challenge = decode_base64($response{'card_challenge'});
98 #here is the hardest part to implement at each client side
99 my $rsa_priv = Crypt::OpenSSL::RSA->new_private_key($private_key);
100 my $response = $rsa_priv->decrypt($challenge);
102 #try the transaction again with the challenge response
103 # (B:OP could sure use a better way to alter one value)
104 my %content = $self->content;
105 $content{'card_response'} = encode_base64($response, '');
106 $self->content(%content);
118 Business::OnlinePayment::CardFortress - CardFortress backend for Business::OnlinePayment
122 use Business::OnlinePayment;
124 my $tx = new Business::OnlinePayment(
126 'gateway' => 'ProcessingGateway',
127 'gateway_login' => 'gwlogin',
128 'gateway_password' => 'gwpass',
129 #private_key not necessary
134 login => 'cardfortress_login',
135 password => 'cardfortress_pass',
136 action => 'Normal Authorization',
137 description => 'Business::OnlinePayment test',
139 customer_id => 'tfb',
140 name => 'Tofu Beast',
141 address => '123 Anystreet',
145 card_number => '4007000000027',
146 expiration => '09/02',
147 cvv2 => '1234', #optional (not stored)
151 if($tx->is_success()) {
152 print "Card processed successfully: ".$tx->authorization."\n";
153 $token = $tx->card_token;
154 print "Card token is: $token\n";
156 print "Card was rejected: ".$tx->error_message."\n";
159 # ... time slips by ...
161 my $rx = new Business::OnlinePayment(
163 'gateway' => 'ProcessingGateway',
164 'gateway_login' => 'gwlogin',
165 'gateway_password' => 'gwpass',
166 'private_key' => $private_key_string, #or filename
167 'bop_options' => join('/', map "$_=".$options{$_}, keys %options),
172 login => 'cardfortress_login',
173 password => 'cardfortress_pass',
174 action => 'Normal Authorization',
175 description => 'Business::OnlinePayment test',
177 card_token => $card_token
178 cvv2 => '1234', #optional, typically not necessary w/followup tx
184 This is a Business::OnlinePayment backend module for the gateway-independent
185 CardFortress storage service (http://cardfortress.com/).
187 =head1 SUPPORTED TRANSACTION TYPES
189 =head2 CC, Visa, MasterCard, American Express, Discover
191 Content required: type, login, action, amount, card_number, expiration.
193 =head1 METHODS AND FUNCTIONS
195 See L<Business::OnlinePayment> for the complete list. The following methods either override the methods in L<Business::OnlinePayment> or provide additional functions.
199 Returns the card token for any transaction. The card token can be used in
200 a subsequent transaction as a replacement for the card number and expiration
201 (as well as customer/AVS data).
205 Returns the response error code.
209 Returns the response error description text.
211 =head2 server_response
213 Returns the complete response from the server.
217 Ivan Kohler C<< <ivan-bop-cardfortress at freeside.biz> >>
219 =head1 COPYRIGHT & LICENSE
221 Copyright 2008-2016 Freeside Internet Services, Inc. (http://freeside.biz/)
224 This program is free software; you can redistribute it and/or modify it
225 under the same terms as Perl itself.