SFTP transport and encryption
[Business-BatchPayment-TD_EFT.git] / TD_EFT / Transport.pm
diff --git a/TD_EFT/Transport.pm b/TD_EFT/Transport.pm
new file mode 100644 (file)
index 0000000..7292e9f
--- /dev/null
@@ -0,0 +1,116 @@
+package Business::BatchPayment::TD_EFT::Transport;
+
+use File::Temp qw(tempdir);
+use File::Slurp qw( read_file write_file );
+use File::Copy;
+use IPC::Run qw(run);
+use Moose;
+extends 'Business::BatchPayment::Transport::SFTP';
+
+=head1 ATTRIBUTES
+
+=over 4
+
+=item encrypt_cmd
+
+Path to the encrypt command, including any options.  The name of the 
+file to encrypt will be passed on standard input, and the name of the 
+destination file will be inserted after the first (whitespace-separated)
+word of the command.  This is in deference to compx/Comm-Press/TDClient
+conventions.
+
+=item decrypt_cmd
+
+Path to the decrypt command, as above.
+
+=item encrypt_key
+
+Path to the encryption key.  This will be copied to the temp directory
+before running encrypt/decrypt commands.
+
+=cut
+
+has [ qw( encrypt_cmd encrypt_key decrypt_cmd ) ] => (
+  is  => 'rw',
+  isa => 'Maybe[Str]',
+  required => 0,
+);
+
+sub upload {
+  my $self = shift;
+  my $path = $self->put_path;
+
+  my $content = shift;
+
+  # get the batch ID of the content
+  # (questionable--on the one hand, upload isn't supposed to concern 
+  # itself with the contents of the batch, but on the other hand it 
+  # needs to know what to name the file.)
+  my $id = substr($content, 20, 4);
+
+  my $tmpdir = tempdir( CLEANUP => 1 );
+  chdir($tmpdir);
+  my $filename = 'update' . $id;
+  warn "Writing temp file to $tmpdir/$filename\n" if $self->debug;
+  write_file("$tmpdir/$filename", $content);
+  if ( $self->encrypt_cmd ) {
+    warn "Encrypting temp file.\n" if $self->debug;
+    if ( $self->encrypt_key ) {
+      copy($self->encrypt_key, "$tmpdir/encrypt.key")
+        or die "Failed to read encryption key: $!\n";
+    }
+    my @cmd = split(/\s+/, $self->encrypt_cmd);
+    # insert output file name into command line
+    splice(@cmd, 1, 0, "$filename.cmp");
+    # run(COMMMAND, STDIN, STDOUT)
+    run(\@cmd, \$filename) or die "Failed to encrypt temp file: $!\n";
+    $filename = "$filename.cmp";
+  }
+  warn "Uploading file to $path/$filename\n" if $self->debug;
+  $self->sftp->setcwd($path);
+  $self->sftp->put("$tmpdir/$filename", $filename);
+  chdir('/');
+}
+
+sub download {
+  my $self = shift;
+  my $path = $self->get_path;
+
+  my @batches;
+  my $tmpdir = tempdir( CLEANUP => 1 );
+  chdir($tmpdir);
+  warn "Fetching list of return files from $path\n" if $self->debug;
+  $self->sftp->setcwd($path);
+  my $files = $self->sftp->ls('.', wanted => qr/^APXQA807/, names_only => 1);
+  if ( !@$files ) {
+    warn "No files found.\n" if $self->debug;
+  }
+  if ( $self->encrypt_key ) {
+    copy($self->encrypt_key, "$tmpdir/encrypt.key")
+      or die "Failed to read encryption key: $!\n";
+  }
+  FILE: foreach my $filename (@$files) {
+    warn "Retrieving file $filename\n" if $self->debug;
+    $self->sftp->get($filename, "$tmpdir/$filename");
+    if ( $self->sftp->error ) {
+      warn "failed to download $filename: ".$self->sftp->error;
+      next FILE;
+    }
+    $filename = "$tmpdir/$filename";
+    if ( $self->decrypt_cmd ) {
+      my @cmd = split(/\s+/, $self->decrypt_cmd);
+      splice(@cmd, 1, 0, "$filename.txt");
+      if ( !run(\@cmd, \$filename) ) {
+        warn "Failed to decrypt file: $!\n";
+        next FILE;
+      }
+    }
+    push @batches, read_file($filename);
+  }
+  chdir('/');
+  @batches;
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;