SFTP transport and encryption
[Business-BatchPayment-TD_EFT.git] / TD_EFT / Transport.pm
1 package Business::BatchPayment::TD_EFT::Transport;
2
3 use File::Temp qw(tempdir);
4 use File::Slurp qw( read_file write_file );
5 use File::Copy;
6 use IPC::Run qw(run);
7 use Moose;
8 extends 'Business::BatchPayment::Transport::SFTP';
9
10 =head1 ATTRIBUTES
11
12 =over 4
13
14 =item encrypt_cmd
15
16 Path to the encrypt command, including any options.  The name of the 
17 file to encrypt will be passed on standard input, and the name of the 
18 destination file will be inserted after the first (whitespace-separated)
19 word of the command.  This is in deference to compx/Comm-Press/TDClient
20 conventions.
21
22 =item decrypt_cmd
23
24 Path to the decrypt command, as above.
25
26 =item encrypt_key
27
28 Path to the encryption key.  This will be copied to the temp directory
29 before running encrypt/decrypt commands.
30
31 =cut
32
33 has [ qw( encrypt_cmd encrypt_key decrypt_cmd ) ] => (
34   is  => 'rw',
35   isa => 'Maybe[Str]',
36   required => 0,
37 );
38
39 sub upload {
40   my $self = shift;
41   my $path = $self->put_path;
42
43   my $content = shift;
44
45   # get the batch ID of the content
46   # (questionable--on the one hand, upload isn't supposed to concern 
47   # itself with the contents of the batch, but on the other hand it 
48   # needs to know what to name the file.)
49   my $id = substr($content, 20, 4);
50
51   my $tmpdir = tempdir( CLEANUP => 1 );
52   chdir($tmpdir);
53   my $filename = 'update' . $id;
54   warn "Writing temp file to $tmpdir/$filename\n" if $self->debug;
55   write_file("$tmpdir/$filename", $content);
56   if ( $self->encrypt_cmd ) {
57     warn "Encrypting temp file.\n" if $self->debug;
58     if ( $self->encrypt_key ) {
59       copy($self->encrypt_key, "$tmpdir/encrypt.key")
60         or die "Failed to read encryption key: $!\n";
61     }
62     my @cmd = split(/\s+/, $self->encrypt_cmd);
63     # insert output file name into command line
64     splice(@cmd, 1, 0, "$filename.cmp");
65     # run(COMMMAND, STDIN, STDOUT)
66     run(\@cmd, \$filename) or die "Failed to encrypt temp file: $!\n";
67     $filename = "$filename.cmp";
68   }
69   warn "Uploading file to $path/$filename\n" if $self->debug;
70   $self->sftp->setcwd($path);
71   $self->sftp->put("$tmpdir/$filename", $filename);
72   chdir('/');
73 }
74
75 sub download {
76   my $self = shift;
77   my $path = $self->get_path;
78
79   my @batches;
80   my $tmpdir = tempdir( CLEANUP => 1 );
81   chdir($tmpdir);
82   warn "Fetching list of return files from $path\n" if $self->debug;
83   $self->sftp->setcwd($path);
84   my $files = $self->sftp->ls('.', wanted => qr/^APXQA807/, names_only => 1);
85   if ( !@$files ) {
86     warn "No files found.\n" if $self->debug;
87   }
88   if ( $self->encrypt_key ) {
89     copy($self->encrypt_key, "$tmpdir/encrypt.key")
90       or die "Failed to read encryption key: $!\n";
91   }
92   FILE: foreach my $filename (@$files) {
93     warn "Retrieving file $filename\n" if $self->debug;
94     $self->sftp->get($filename, "$tmpdir/$filename");
95     if ( $self->sftp->error ) {
96       warn "failed to download $filename: ".$self->sftp->error;
97       next FILE;
98     }
99     $filename = "$tmpdir/$filename";
100     if ( $self->decrypt_cmd ) {
101       my @cmd = split(/\s+/, $self->decrypt_cmd);
102       splice(@cmd, 1, 0, "$filename.txt");
103       if ( !run(\@cmd, \$filename) ) {
104         warn "Failed to decrypt file: $!\n";
105         next FILE;
106       }
107     }
108     push @batches, read_file($filename);
109   }
110   chdir('/');
111   @batches;
112 }
113
114 __PACKAGE__->meta->make_immutable;
115
116 1;