package Business::GestPayCrypt; # # Business::GestPayCrypt is Copyright (C) 2002-2004 Open2b Software S.r.l. All Rights Reserved. # # This code is distributed under the same license as Perl 5; you can # redistribute it and/or modify it under the terms of either: # # a) the GNU General Public License # # b) the Artistic License # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either # the GNU General Public License or the Artistic License for more details. # $VERSION = '0.41'; =head1 NAME Business::GestPayCrypt - Perl interface to the italian online payment system GestPay =head1 SYNOPSIS # # Request # use Business::GestPayCrypt; my $obj = new Business::GestPayCrypt; $obj->SetShopLogin($ShopLogin); $obj->SetCurrency($Currency); $obj->SetAmount($Amount); $obj->SetShopTransactionID($ShopTransationID); $obj->SetLanguage($Language); $obj->Encrypt(); if ( $obj->GetErrorCode() ) { print 'Error: ', $obj->GetErrorCode(), ' ', $objCrypt->GetErrorDescription(); } else { my $a = $obj->GetShopLogin(); my $b = $obj->GetEncryptedString(); print qq~
~; } # # Response # use Business::GestPayCrypt; my $obj = new Business::GestPayCrypt; $obj->SetShopLogin($ShopLogin); $obj->SetEncryptedString($b); $obj->Decrypt(); if ( $objCrypt->GetErrorCode() ) { print 'Error: ', $obj->GetErrorCode() , ' ', $objCrypt->GetErrorDescription(); } else { print 'ShopLogin : ', $obj->GetShopLogin(), "\n"; print 'Currency :', $obj->GetCurrency(), "\n"; print 'Amount : ', $obj->GetAmount(), "\n"; print 'ShopTransactionID : ', $obj->GetShopTransactionID(), "\n"; print 'BuyerName : ', $obj->GetBuyerName(), "\n"; print 'BuyerEmail : ', $obj->GetBuyerEmail(), "\n"; print 'TransactionResult : ', $obj->GetTransactionResult(), "\n"; print 'AuthorizationCode : ', $obj->GetAuthorizationCode(), "\n"; print 'BankTransactionID : ', $obj->GetBankTransactionID(), "\n"; print 'ErrorCode : ', $obj->GetErrorCode(), "\n"; print 'ErrorDescription : ', $obj->GetErrorDescription(), "\n"; print 'AlertCode : ', $obj->GetAlertCode(), "\n"; print 'AlertDescription : ', $obj->GetAlertDescription(), "\n"; print 'CustomInfo : ', $obj->GetCustomInfo(), "\n"; } =head1 DESCRIPTION This class implements the italian system for on-line payments GestPay, of Banca Sella, in the cryptography version. The class crypts the data of the transaction and returns the data as an encrypted string to send to the GestPay server for payment. The communication from shop server and the GestPay server is not encrypted and is send with the HTTP protocol. For more information see the reference manual of Banca Sella at http://www.sellanet.it. =cut use Socket; use strict; sub new { my $class = shift; my $self = { # public methods AlertCode => '', AlertDescription => '', Amount => '', AuthorizationCode => '', BankTransactionID => '', BuyerEmail => '', BuyerName => '', CardNumber => '', Country => '', # add 0.30 Currency => '', CustomInfo => '', CVV => '', # add 0.30 EncryptedString => '', Encryption => '', # add 0.30 ErrorCode => '', ErrorDescription => '', ExpMonth => '', ExpYear => '', Language => '', MIN => '', # add 0.30 PasswordEncrypt => '', # add 0.30 ShopLogin => '', ShopTransactionID => '', TransactionResult => '', VBV => '', # add 0.30 VBVrisp => '', # add 0.30 # private methods Decripted => '', DomainName => 'ecomm.sella.it', ScriptEncrypt => '/CryptHTTP/Encrypt.asp', ScriptDecrypt => '/CryptHTTP/Decrypt.asp', ToBeEncript => '', }; return bless $self, $class; } # # implements the Get and Set methods # sub AUTOLOAD { my ($self,$value) = @_; my %permission = ( AlertCode => 'g', AlertDescription => 'g', Amount => 'gs', AuthorizationCode => 'g', BankTransactionID => 'g', BuyerEmail => 'gs', BuyerName => 'gs', CardNumber => 's', Currency => 'gs', Country => 'g', # add 0.30 CustomInfo => 'gs', CVV => 's', # add 0.30 EncryptedString => 'gs', Encryption => 's', # add 0.30 ErrorCode => 'g', ErrorDescription => 'g', ExpMonth => 's', ExpYear => 's', Language => 's', MIN => 's', # add 0.30 PasswordEncrypt => 's', # add 0.30 ShopLogin => 'gs', ShopTransactionID => 'gs', TransactionResult => 'g', VBV => 'g', # add 0.30 VBVrisp => 'g', # add 0.30 ); # my $method = $GestPayCrypt::AUTOLOAD; # add comment 0.40 my $method = $Business::GestPayCrypt::AUTOLOAD; # add 0.40 $method =~ /::(Get|Set)(.*)$/; if ( $1 eq 'Get' && ( $permission{$2} eq 'g' || $permission{$2} eq 'gs' ) ) { return $self->{$2}; } elsif ( $1 eq 'Set' && ( $permission{$2} eq 's' || $permission{$2} eq 'gs' ) ) { $self->{$2} = $value; return; } else { my ($package,$filename,$line) = caller(); # add 0.40 die "The method $method don't exists at $filename line $line\n"; } } # add 0.30 sub SetWithoutEncryption { my $self = shift; $self->{'Encryption'} = 0; return; } # add 0.30 sub SetShopTransactionID { my ($self,$string) = @_; $self->{'ShopTransactionID'} = url_encode(trim($string)); return; } # add 0.30 sub SetBuyerName { my ($self,$string) = @_; $self->{'BuyerName'} = url_encode(trim($string)); return; } # add 0.30 sub SetBuyerEmail { my ($self,$string) = @_; $self->{'BuyerEmail'} = trim($string); return; } # add 0.30 sub SetLanguage { my ($self,$string) = @_; $self->{'Language'} = trim($string); return; } # add 0.30 sub SetCustomInfo { my ($self,$string) = @_; $self->{'CustomInfo'} = url_encode(trim($string)); return; } # add 0.30 sub GetShopTransactionID { my $self = shift; return url_decode($self->{'ShopTransactionID'}); } # add 0.30 sub GetBuyerName { my $self = shift; return url_decode($self->{'BuyerName'}); } # add 0.30 sub GetCustomInfo { my $self = shift; return url_decode($self->{'CustomInfo'}); } sub Encrypt { my $self = shift; $self->{'ErrorCode'} = '0'; $self->{'ErrorDescription'} = ''; # verify the attributes if ( $self->{'ShopLogin'} eq '' ) { $self->{'ErrorCode'} = '546'; $self->{'ErrorDescription'} = 'IDshop not valid'; return 0; } if ( $self->{'Currency'} eq '' ) { $self->{'ErrorCode'} = '552'; $self->{'ErrorDescription'} = 'Currency not valid'; return 0; } if ( $self->{'Amount'} eq '' ) { $self->{'ErrorCode'} = '553'; $self->{'ErrorDescription'} = 'Amount not valid'; return 0; } if ( $self->{'ShopTransactionID'} eq '' ) { $self->{'ErrorCode'} = '551'; $self->{'ErrorDescription'} = 'Shop Transaction ID not valid'; return 0; } # prepare the string to crypt my @to_be_encript = (); push @to_be_encript, ("PAY1_CVV=$self->{'CVV'}") if $self->{'CVV'} ne ''; # add 0.30 push @to_be_encript, ("PAY1_MIN=$self->{'MIN'}") if $self->{'MIN'} ne ''; # add 0.30 push @to_be_encript, ("PAY1_UICCODE=$self->{'Currency'}") if $self->{'Currency'} ne ''; push @to_be_encript, ("PAY1_AMOUNT=$self->{'Amount'}") if $self->{'Amount'} ne ''; push @to_be_encript, ("PAY1_SHOPTRANSACTIONID=$self->{'ShopTransactionID'}") if $self->{'ShopTransactionID'} ne ''; push @to_be_encript, ("PAY1_CHNAME=$self->{'BuyerName'}") if $self->{'BuyerName'} ne ''; push @to_be_encript, ("PAY1_CHEMAIL=$self->{'BuyerEmail'}") if $self->{'BuyerEmail'} ne ''; push @to_be_encript, ("PAY1_IDLANGUAGE=$self->{'Language'}") if $self->{'Language'} ne ''; push @to_be_encript, ($self->{'CustomInfo'}) if $self->{'CustomInfo'} ne ''; $self->{'ToBeEncript'} = join('*P1*',@to_be_encript); # $self->{'ToBeEncript'} =~ s/ /§/g; # add comment 0.30 # crypt the string return $self->query_server(); } sub Decrypt { my $self = shift; $self->{'ErrorCode'} =''; $self->{'ErrorDescription'} = ''; # verify the attributes if ( $self->{'ShopLogin'} eq '' ) { $self->{'ErrorCode'} = '546'; $self->{'ErrorDescription'} = 'IDshop not valid'; return 0; } if ( $self->{'EncryptedString'} eq '' ) { $self->{'ErrorCode'} = '1009'; $self->{'ErrorDescription'} = 'String to Decrypt not valid'; return 0; } # decrypt the string unless ( $self->query_server() ) { return 0; } # get the attributes from the string # $self->{'Decripted'} =~ s/§/ /g; # add comment 0.30 # if ( $self->{'Decripted'} eq '' ) { if ( trim($self->{'Decripted'}) eq '' ) { # set 0.30 $self->{'ErrorCode'} = '99999'; $self->{'ErrorDescription'} = 'Void String'; return 0; } my %fields = ( PAY1_ALERTCODE => 'AlertCode', PAY1_ALERTDESCRIPTION => 'AlertDescription', PAY1_AMOUNT => 'Amount', PAY1_AUTHORIZATIONCODE => 'AuthorizationCode', PAY1_BANKTRANSACTIONID => 'BankTransactionID', PAY1_CARDNUMBER => 'CardNumber', PAY1_CHEMAIL => 'BuyerEmail', PAY1_CHNAME => 'BuyerName', PAY1_COUNTRY => 'Country', # add 0.30 PAY1_ERRORCODE => 'ErrorCode', PAY1_ERRORDESCRIPTION => 'ErrorDescription', PAY1_EXPMONTH => 'ExpMonth', PAY1_EXPYEAR => 'ExpYear', PAY1_IDLANGUAGE => 'Language', PAY1_SHOPTRANSACTIONID => 'ShopTransactionID', PAY1_TRANSACTIONRESULT => 'TransactionResult', PAY1_UICCODE => 'Currency', PAY1_VBV => 'VBV', #add 0.30 PAY1_VBVRISP => 'VBVrisp', #add 0.30 ); foreach my $field ( keys %fields ) { if ( $self->{'Decripted'} =~ s/(^|\*P1\*)$field=(.*?)(\*P1\*|$)/$1 && $3 ? '*P1*' : ''/e ) { $self->{$fields{$field}} = $2; } } $self->{'CustomInfo'} = trim($self->{'Decripted'}); return 1; } sub query_server { my $self = shift; my $type = $self->{'ToBeEncript'} ne '' ? 'encrypt' : 'decrypt'; my $urlString = $type eq 'encrypt' # ? "$self->{'ScriptEncrypt'}?a=$self->{'ShopLogin'}&b=$self->{'ToBeEncript'}" # : "$self->{'ScriptDecrypt'}?a=$self->{'ShopLogin'}&b=$self->{'EncryptedString'}"; ? "$self->{'ScriptEncrypt'}?a=$self->{'ShopLogin'}&b=$self->{'ToBeEncript'}&c=2.0" # set 0.30 : "$self->{'ScriptDecrypt'}?a=$self->{'ShopLogin'}&b=$self->{'EncryptedString'}&c=2.0"; my $response = $self->cat_server($urlString); return 0 if $response eq ''; if ( $type eq 'encrypt' && $response =~ /#cryptstring#(.*?)#\/cryptstring#/ ) { $self->{'EncryptedString'} = $1 if ( $1 ne '' ); } if ( $type eq 'decrypt' && $response =~ /#decryptstring#(.*?)#\/decryptstring#/ ) { $self->{'Decripted'} = $1 if ( $1 ne '' ); } if ( $response =~ /#error#(.*?)-(.*?)#\/error#/ ) { close(Server); $self->{'ErrorCode'} = $1; $self->{'ErrorDescription'} = $2; return 0; } close(Server); return 1; } sub cat_server { my ($self,$request) = @_; my $response = ''; unless ( socket(Server,PF_INET,SOCK_STREAM,getprotobyname('tcp')) ) { $self->{'ErrorCode'} = '9999'; $self->{'ErrorDescription'} = "Unable to open a socket: $!"; return; } my $ip_addr = inet_aton($self->{'DomainName'}); unless ( defined $ip_addr ) { $self->{'ErrorCode'} = '9999'; $self->{'ErrorDescription'} = "The name of GestPay server is unknown: $!"; return; } unless ( connect(Server,sockaddr_in(80,$ip_addr)) ) { $self->{'ErrorCode'} = '9999'; $self->{'ErrorDescription'} = "Unable to connect to GestPay server: $!"; return; } # enable command buffering select((select(Server),$|=1)[0]); # send the request unless ( print Server "GET $request HTTP/1.0\r\n\r\n" ) { close(Server); $self->{'ErrorCode'} = '9999'; $self->{'ErrorDescription'} = "Unable to send the request to GestPay server: $!"; return; } # get the response my $buffer; while ( read(Server,$buffer,4096) ) { $response .= $buffer; } if ( $response eq '' || $! ) { close(Server); $self->{'ErrorCode'} = '9999'; $self->{'ErrorDescription'} = "Unable to get the response from GestPay server: $!"; return; } # close the connection close(Server); return $response; } # add 0.30 sub trim { my $string = shift; $string =~ s/^ +//; $string =~ s/ +$//; return $string; } # add 0.30 my %escape; for my $char ( 0..255 ) { $escape{chr($char)} = sprintf("%%%02X",$char); } # add 0.30 sub url_encode { my $string = shift; $string =~ s/([^A-Za-z0-9\-_.* ])/$escape{$1}/g; $string =~ tr/ /+/; return $string; } # add 0.300 sub url_decode { my $string = shift; $string =~ tr/+/ /; $string =~ s/%([0-9a-fA-F]{2})/chr(hex($1))/eg; return $string; } sub DESTROY { } # add 0.40 =head1 AUTHOR Marco Gazerro =head1 SEE ALSO Business::GestPayCryptHS Business::BancaSella =head1 COPYRIGHT Copyright (c) 2002-2004 Open2b Software S.r.l. ( www.open2b.com ) =head1 LICENSE This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1;