RT#29354: Password Security in Email [xmlhttp validation for selfservice]
[freeside.git] / fs_selfservice / FS-SelfService / cgi / signup.cgi
index 12452e6..072ce96 100755 (executable)
@@ -17,9 +17,11 @@ use subs qw( print_form print_okay print_decline
            );
 use CGI;
 #use CGI::Carp qw(fatalsToBrowser);
+use Tie::IxHash;
 use Text::Template;
 use Business::CreditCard;
 use HTTP::BrowserDetect;
+use HTML::Widgets::SelectLayers;
 use FS::SelfService qw( signup_info new_customer );
 
 #acceptable payment methods
@@ -139,7 +141,7 @@ if ( -e $decline_html ) {
 
 $cgi = new CGI;
 
-$init_data = signup_info( 'agentnum'   => $agentnum,
+$init_data = signup_info( 'agentnum'   => $agentnum || scalar($cgi->param('agentnum')),
                           'promo_code' => scalar($cgi->param('promo_code')),
                           'reg_code'   => uc(scalar($cgi->param('reg_code'))),
                         );
@@ -158,31 +160,31 @@ if ( $magic eq 'process' || $action eq 'process_signup' ) {
     my $payby = $cgi->param('payby');
     if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) {
       #$payinfo = join('@', map { $cgi->param( $payby. "_payinfo$_" ) } (1,2) );
-      $cgi->param('payinfo' => $cgi->param($payby. '_payinfo1'). '@'. 
-                               $cgi->param($payby. '_payinfo2')
+      $cgi->param('payinfo' => scalar($cgi->param($payby. '_payinfo1')). '@'. 
+                               scalar($cgi->param($payby. '_payinfo2'))
                  );
     } else {
-      $cgi->param('payinfo' => $cgi->param( $payby. '_payinfo' ) );
+      $cgi->param('payinfo' => scalar($cgi->param( $payby. '_payinfo' ) ) );
     }
-    $cgi->param('paydate' => $cgi->param( $payby. '_month' ). '-'.
-                             $cgi->param( $payby. '_year' )
+    $cgi->param('paydate' => scalar($cgi->param( $payby. '_month' )). '-'.
+                             scalar($cgi->param( $payby. '_year' ))
                );
-    $cgi->param('payname' => $cgi->param( $payby. '_payname' ) );
+    $cgi->param('payname' => scalar($cgi->param( $payby. '_payname' ) ) );
     $cgi->param('paycvv' => defined $cgi->param( $payby. '_paycvv' )
-                              ? $cgi->param( $payby. '_paycvv' )
+                              ? scalar($cgi->param( $payby. '_paycvv' ))
                               : ''
                );
     $cgi->param('paytype' => defined $cgi->param( $payby. '_paytype' )
-                              ? $cgi->param( $payby. '_paytype' )
+                              ? scalar($cgi->param( $payby. '_paytype' ))
                               : ''
                );
     $cgi->param('paystate' => defined $cgi->param( $payby. '_paystate' )
-                              ? $cgi->param( $payby. '_paystate' )
+                              ? scalar($cgi->param( $payby. '_paystate' ))
                               : ''
                );
 
     if ( $cgi->param('invoicing_list') ) {
-      $cgi->param('invoicing_list' => $cgi->param('invoicing_list'). ', POST')
+      $cgi->param('invoicing_list' => scalar($cgi->param('invoicing_list')). ', POST')
         if $cgi->param('invoicing_list_POST');
     } else {
       $cgi->param('invoicing_list' => 'POST' );
@@ -199,13 +201,18 @@ if ( $magic eq 'process' || $action eq 'process_signup' ) {
       my $payinfo = $cgi->param('payinfo');
       $payinfo =~ s/\D//g;
 
-      $payinfo =~ /^(\d{13,16})$/
+      $payinfo =~ /^(\d{13,16}|\d{8,9})$/
         or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
       $payinfo = $1;
       validate($payinfo)
         or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
       cardtype($payinfo) eq $cgi->param('CARD_type')
         or $error ||= $init_data->{msgcat}{not_a}. $cgi->param('CARD_type');
+
+      $error ||= 'CVV2 is required'
+        if ! $cgi->param('paycvv')
+        && $init_data->{require_cvv};
+
     }
 
     if ($init_data->{emailinvoiceonly} && (length $cgi->param('invoicing_list') < 1)) {
@@ -227,11 +234,13 @@ if ( $magic eq 'process' || $action eq 'process_signup' ) {
 
                 payby payinfo paycvv paydate payname paystate paytype
                 invoicing_list referral_custnum promo_code reg_code
+                override_ban_warn
                 pkgpart refnum agentnum
-                username sec_phrase _password popnum
-                countrycode phonenum sip_password pin
+                username sec_phrase _password popnum domsvc
+                mac_addr
+                countrycode phonenum sip_password pin prepaid_shortform
               ),
-            grep { /^snarf_/ } $cgi->param
+            grep { /^(snarf_|tax_)/ } $cgi->param
         ),
         'payip' => $cgi->remote_host(),
       } );
@@ -243,13 +252,21 @@ if ( $magic eq 'process' || $action eq 'process_signup' ) {
       print_decline();
     } elsif ( $error eq '_collect' ) {
       map { $cgi->param($_, $rv->{$_}) }
-        qw( popup_url reference collectitems amount );
-      print_collect();
+        qw( popup_url reference amount );
+      print_collect($rv);
     } elsif ( $error ) {
-      #fudge the snarf info
+      #fudge the snarf and tax info
       no strict 'refs';
-      ${$_} = $cgi->param($_) foreach grep { /^snarf_/ } $cgi->param;
+      ${$_} = $cgi->param($_) foreach grep { /^(snarf_|tax_)/ } $cgi->param;
+
+      if ( $error =~ /^_duplicate_(card|ach)/ ) {
+        my $what = ($1 eq 'card') ? 'Credit card' : 'Electronic check';
+        $error = "Warning: $what already used to sign up recently";
+        $init_data->{'override_ban_warn'} = 1;
+      }
+
       print_form();
+
     } else {
       print_okay(
         'pkgpart' => scalar($cgi->param('pkgpart')),
@@ -274,7 +291,7 @@ if ( $magic eq 'process' || $action eq 'process_signup' ) {
 
 sub print_form {
 
-  $error = "Error: $error" if $error;
+  $error = "Error: $error" if $error && $error !~ /^Warning:/i;
 
   my $r = {
     $cgi->Vars,
@@ -289,6 +306,8 @@ sub print_form {
   #$cgi->delete('init_popstate');
   $r->{self_url} = $cgi->self_url;
 
+  $r->{prepaid_shortform} = $cgi->param('prepaid_shortform');
+
   print $cgi->header( '-expires' => 'now' ),
         $signup_template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi',
                                    HASH    => $r
@@ -299,9 +318,11 @@ sub print_collect {
 
   $error = "Error: $error" if $error;
 
+  my $rv = shift || {};
   my $r = {
     $cgi->Vars,
     %{$init_data},
+    %$rv,
     'error' => $error,
   };
 
@@ -311,14 +332,21 @@ sub print_collect {
   $r->{self_url} = $cgi->self_url;
 
   print $cgi->header( '-expires' => 'now' ),
+
         $collect_template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi',
                                     HASH    => $r
                                   );
 }
 
 sub print_decline {
+  my $r = {
+    %{$init_data},
+  };
+
   print $cgi->header( '-expires' => 'now' ),
-        $decline_template->fill_in();
+        $decline_template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi',
+                                    HASH    => $r
+                                  );
 }
 
 sub print_okay {
@@ -386,6 +414,8 @@ sub print_okay {
     print $cgi->header( '-expires' => 'now' ),
           $success_template->fill_in( HASH => {
 
+            %{$init_data},
+
             email_name     => $email_name,
             pkg            => $pkg,
             part_pkg       => \$part_pkg,
@@ -431,23 +461,25 @@ sub collect_default { #html to use if there is a collect phase
   <<'END';
 <HTML><HEAD><TITLE>Pay now</TITLE></HEAD>
 <BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>Pay now</FONT><BR><BR>
-<SCRIPT TYPE="text/javascript">
-  function popcollect() {
-    overlib( OLiframeContent('<%= $popup_url %>', 336, 550, 'Secure Payment Area', 0, 'auto' ), CAPTION, 'Pay now', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK, BGCOLOR, '#333399', CGCOLOR, '#333399', CLOSETEXT, 'Close' );
-    return false;
-  }
-</SCRIPT>
-<SCRIPT TYPE="text/javascript" SRC="overlibmws.js"></SCRIPT>
-<SCRIPT TYPE="text/javascript" SRC="overlibmws_iframe.js"></SCRIPT>
-<SCRIPT TYPE="text/javascript" SRC="overlibmws_draggable.js"></SCRIPT>
-<SCRIPT TYPE="text/javascript" SRC="overlibmws_crossframe.js"></SCRIPT>
-<SCRIPT TYPE="text/javascript" SRC="iframecontentmws.js"></SCRIPT>
+<%=
+#<SCRIPT TYPE="text/javascript">
+#  function popcollect() {
+#    overlib( OLiframeContent('<%= $popup_url %>', 336, 550, 'Secure Payment Area', 0, 'auto' ), CAPTION, 'Pay now', STICKY, AUTOSTATUSCAP, MIDX, 0, MIDY, 0, DRAGGABLE, CLOSECLICK, BGCOLOR, '#333399', CGCOLOR, '#333399', CLOSETEXT, 'Close' );
+#    return false;
+#  }
+#</SCRIPT>
+#<SCRIPT TYPE="text/javascript" SRC="overlibmws.js"></SCRIPT>
+#<SCRIPT TYPE="text/javascript" SRC="overlibmws_iframe.js"></SCRIPT>
+#<SCRIPT TYPE="text/javascript" SRC="overlibmws_draggable.js"></SCRIPT>
+#<SCRIPT TYPE="text/javascript" SRC="overlibmws_crossframe.js"></SCRIPT>
+#<SCRIPT TYPE="text/javascript" SRC="iframecontentmws.js"></SCRIPT>
+%>
 You are about to contact our payment processor to pay <%= $amount %> for
 <%= $pkg %>.<BR><BR>
 Your transaction reference number is <%= $reference %><BR><BR>
-<FORM NAME="collect_popper" method="post" action="javascript:void(0)" onSubmit="popcollect()">
+<FORM NAME="collect_popper" method="post" action="<%= $popup_url %>">
 <%=
-  my %itemhash = @collectitems;
+  my %itemhash = @collectitems ;
   foreach my $input (keys %itemhash) {
     $OUT .= qq!<INPUT NAME="$input" TYPE="hidden" VALUE="$itemhash{$input}">!;
   }
@@ -472,5 +504,35 @@ END
 
 package FS::SelfService::_signupcgi;
 use HTML::Entities;
-use FS::SelfService qw(regionselector expselect popselector didselector);
+use FS::SelfService qw( regionselector expselect popselector domainselector
+                        didselector
+                      );
+
+sub add_password_validation {
+  my $fieldid = shift;
+  my $out = '';
+  if ((-e './send_xmlhttp.html') && (-e './add_password_validation.html')) {
+    my $template = new Text::Template( TYPE   => 'FILE',
+                                       SOURCE => "./send_xmlhttp.html",
+                                       DELIMITERS => [ '<%=', '%>' ],
+                                       UNTAINT => 1,                   
+                                     )
+      or die $Text::Template::ERROR;
+    $out .= $template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi' );
+    $template = new Text::Template( TYPE   => 'FILE',
+                                       SOURCE => "./add_password_validation.html",
+                                       DELIMITERS => [ '<%=', '%>' ],
+                                       UNTAINT => 1,                   
+                                     )
+      or die $Text::Template::ERROR;
+    $out .= $template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi' );
+    $out .= <<ENDOUT;
+<SCRIPT>
+add_password_validation('$fieldid');
+</SCRIPT>
+ENDOUT
+  }
+  return $out;
+}
+