RT#29354: Password Security in Email [customer fields, images, js files]
[freeside.git] / FS / FS / svc_acct.pm
index f307033..53b12f1 100644 (file)
@@ -4,6 +4,7 @@ use base qw( FS::svc_Domain_Mixin FS::svc_PBX_Mixin
              FS::svc_Radius_Mixin
              FS::svc_Tower_Mixin
              FS::svc_IP_Mixin
+             FS::Password_Mixin
              FS::svc_Common
            );
 
@@ -43,7 +44,6 @@ use FS::PagedSearch qw( psearch ); # XXX in v4, replace with FS::Cursor
 use FS::part_pkg;
 use FS::part_svc;
 use FS::svc_acct_pop;
-use FS::cust_main_invoice;
 use FS::svc_domain;
 use FS::svc_pbx;
 use FS::raddb;
@@ -684,6 +684,9 @@ sub insert {
     'child_objects' => $self->child_objects,
     %options,
   );
+
+  $error ||= $self->insert_password_history;
+
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
@@ -707,9 +710,37 @@ sub insert {
         || $conf->exists('emailinvoiceauto')
         && ! $cust_main->invoicing_list_emailonly
        ) {
-      my @invoicing_list = $cust_main->invoicing_list;
-      push @invoicing_list, $self->email;
-      $cust_main->invoicing_list(\@invoicing_list);
+
+      # slight false laziness w/ edit/process/cust_main.cgi...
+      # and also slightly arbitrary behavior.
+      # if the "real name" of this account matches the first + last name
+      # of a contact, attach the email address to that person.
+      my @contacts = map { $_->contact } $cust_main->cust_contact;
+      my $myname = $self->get('finger');
+      my ($contact) =
+        grep { $_->get('first') . ' ' . $_->get('last') eq $myname } @contacts;
+      # otherwise just pick the first one
+      $contact ||= $contacts[0];
+      # if there is one
+      $contact ||= FS::contact->new({
+          'custnum'       => $cust_main->get('custnum'),
+          'locationnum'   => $cust_main->get('bill_locationnum'),
+          'last'          => $cust_main->get('last'),
+          'first'         => $cust_main->get('first'),
+      });
+      $contact->set('emailaddress', $self->email);
+      $contact->set('invoice_dest', 'Y');
+
+      if ( $contact->get('contactnum') ) {
+        $error = $contact->replace;
+      } else {
+        $error = $contact->insert;
+      }
+
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return "creating invoice destination contact: $error";
+      }
     }
 
     #welcome email
@@ -796,23 +827,6 @@ sub delete {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
-  foreach my $cust_main_invoice (
-    qsearch( 'cust_main_invoice', { 'dest' => $self->svcnum } )
-  ) {
-    unless ( defined($cust_main_invoice) ) {
-      warn "WARNING: something's wrong with qsearch";
-      next;
-    }
-    my %hash = $cust_main_invoice->hash;
-    $hash{'dest'} = $self->email;
-    my $new = new FS::cust_main_invoice \%hash;
-    my $error = $new->replace($cust_main_invoice);
-    if ( $error ) {
-      $dbh->rollback if $oldAutoCommit;
-      return $error;
-    }
-  }
-
   foreach my $svc_domain (
     qsearch( 'svc_domain', { 'catchall' => $self->svcnum } )
   ) {
@@ -893,6 +907,12 @@ sub replace {
   my $dbh = dbh;
 
   $error = $new->SUPER::replace($old, @_); # usergroup here
+
+  # don't need to record this unless the password was changed
+  if ( $old->_password ne $new->_password ) {
+    $error ||= $new->insert_password_history;
+  }
+
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error if $error;
@@ -2656,6 +2676,25 @@ sub virtual_maildir {
   $self->domain. '/maildirs/'. $self->username. '/';
 }
 
+=item password_svc_check
+
+Override, for L<FS::Password_Mixin>.  Not really intended for other use.
+
+=cut
+
+sub password_svc_check {
+  my ($self, $password) = @_;
+  foreach my $field ( qw(username finger) ) {
+    foreach my $word (split(/\W+/,$self->get($field))) {
+      next unless length($word) > 2;
+      if ($password =~ /$word/i) {
+        return qq(Password contains account information '$word');
+      }
+    }
+  }
+  return '';
+}
+
 =back
 
 =head1 CLASS METHODS