Browse Source

Switch to using SFTP instead of FTP for downloading vouchers.

Andrew Klopper 8 years ago
parent
commit
80c2d4b3fd

+ 1 - 1
BulkPrintingAPI/BulkPrintingAPI.csproj

9
     <Folder Include="wwwroot\" />
9
     <Folder Include="wwwroot\" />
10
   </ItemGroup>
10
   </ItemGroup>
11
   <ItemGroup>
11
   <ItemGroup>
12
-    <PackageReference Include="CoreFtp" Version="1.3.5" />
13
     <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
12
     <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
14
     <PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
13
     <PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
15
     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="1.1.2" />
14
     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="1.1.2" />
23
     <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" />
22
     <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" />
24
     <PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.2" />
23
     <PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.2" />
25
     <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="1.1.1" />
24
     <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="1.1.1" />
25
+    <PackageReference Include="SSH.NET" Version="2016.0.0" />
26
   </ItemGroup>
26
   </ItemGroup>
27
   <ItemGroup>
27
   <ItemGroup>
28
     <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.1" />
28
     <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="1.0.1" />

+ 6 - 2
BulkPrintingAPI/Configuration/FTPOptions.cs

2
 
2
 
3
 namespace BulkPrintingAPI.Configuration
3
 namespace BulkPrintingAPI.Configuration
4
 {
4
 {
5
-    public class FTPOptions
5
+    public class SFTPOptions
6
     {
6
     {
7
-        public FTPOptions(IConfiguration configuration)
7
+        public SFTPOptions(IConfiguration configuration)
8
         {
8
         {
9
             configuration.Bind(this);
9
             configuration.Bind(this);
10
         }
10
         }
11
 
11
 
12
         public string Host { get; set; }
12
         public string Host { get; set; }
13
 
13
 
14
+        public int Port { get; set; } = 22;
15
+
14
         public string Username { get; set; }
16
         public string Username { get; set; }
15
 
17
 
16
         public string Password { get; set; }
18
         public string Password { get; set; }
19
+
20
+        public int ConnectTimeout { get; set; } = 10;
17
     }
21
     }
18
 }
22
 }

+ 5 - 5
BulkPrintingAPI/Controllers/BatchesController.cs

35
         private readonly ILogger _logger;
35
         private readonly ILogger _logger;
36
         private readonly IMemoryCache _cache;
36
         private readonly IMemoryCache _cache;
37
         private readonly DataEncryptionOptions _dataEncryptionOptions;
37
         private readonly DataEncryptionOptions _dataEncryptionOptions;
38
-        private readonly FTPOptions _ftpOptions;
38
+        private readonly SFTPOptions _sftpOptions;
39
         private readonly MAX.ClientFactory _clientFactory;
39
         private readonly MAX.ClientFactory _clientFactory;
40
         private readonly MAXContext _context;
40
         private readonly MAXContext _context;
41
 
41
 
42
         public BatchesController(ILoggerFactory loggerFactory, IMemoryCache cache,
42
         public BatchesController(ILoggerFactory loggerFactory, IMemoryCache cache,
43
-            DataEncryptionOptions dataEncryptionOptions, FTPOptions ftpOptions,
43
+            DataEncryptionOptions dataEncryptionOptions, SFTPOptions sftpOptions,
44
             MAX.ClientFactory clientFactory, MAXContext context)
44
             MAX.ClientFactory clientFactory, MAXContext context)
45
         {
45
         {
46
             _logger = loggerFactory.CreateLogger(GetType().FullName);
46
             _logger = loggerFactory.CreateLogger(GetType().FullName);
47
             _cache = cache;
47
             _cache = cache;
48
             _dataEncryptionOptions = dataEncryptionOptions;
48
             _dataEncryptionOptions = dataEncryptionOptions;
49
-            _ftpOptions = ftpOptions;
49
+            _sftpOptions = sftpOptions;
50
             _clientFactory = clientFactory;
50
             _clientFactory = clientFactory;
51
             _context = context;
51
             _context = context;
52
         }
52
         }
86
 
86
 
87
             if (!batch.ReadyForDownload)
87
             if (!batch.ReadyForDownload)
88
             {
88
             {
89
-                await Utils.DownloadVouchersAsync(_ftpOptions, _context, _logger, batch);
89
+                await Utils.DownloadVouchersAsync(_sftpOptions, _context, _logger, batch);
90
             }
90
             }
91
 
91
 
92
             return Ok(batch);
92
             return Ok(batch);
130
 
130
 
131
             try
131
             try
132
             {
132
             {
133
-                await Utils.DownloadVouchersAsync(_ftpOptions, _context, _logger, orderResponse.Batch);
133
+                await Utils.DownloadVouchersAsync(_sftpOptions, _context, _logger, orderResponse.Batch);
134
             }
134
             }
135
             catch (Exception e)
135
             catch (Exception e)
136
             {
136
             {

+ 48 - 40
BulkPrintingAPI/Controllers/Utils.cs

1
 using BulkPrintingAPI.Configuration;
1
 using BulkPrintingAPI.Configuration;
2
-using CoreFtp;
3
 using MAX.Models;
2
 using MAX.Models;
4
 using Microsoft.AspNetCore.Http;
3
 using Microsoft.AspNetCore.Http;
5
 using Microsoft.EntityFrameworkCore;
4
 using Microsoft.EntityFrameworkCore;
310
             }
309
             }
311
         }
310
         }
312
 
311
 
313
-        public static async Task DownloadVouchersAsync(FTPOptions ftpOptions, MAXContext context,
312
+        public static async Task DownloadVouchersAsync(SFTPOptions sftpOptions, MAXContext context,
314
             ILogger logger, Batch batch)
313
             ILogger logger, Batch batch)
315
         {
314
         {
316
             var remoteFileName = string.Format("{0}_{1}.dat", batch.Account.Id, batch.Id);
315
             var remoteFileName = string.Format("{0}_{1}.dat", batch.Account.Id, batch.Id);
317
             using (var voucherStream = new MemoryStream())
316
             using (var voucherStream = new MemoryStream())
318
             {
317
             {
319
-                using (var ftp = new FtpClient(new FtpClientConfiguration()
318
+                var connectionInfo = new Renci.SshNet.ConnectionInfo(
319
+                    sftpOptions.Host,
320
+                    sftpOptions.Port,
321
+                    sftpOptions.Username,
322
+                    new Renci.SshNet.PasswordAuthenticationMethod(sftpOptions.Username, sftpOptions.Password)
323
+                );
324
+                connectionInfo.Timeout = TimeSpan.FromSeconds(sftpOptions.ConnectTimeout);
325
+
326
+                await Task.Run(() =>
320
                 {
327
                 {
321
-                    Host = ftpOptions.Host,
322
-                    Username = ftpOptions.Username,
323
-                    Password = ftpOptions.Password
324
-                }))
325
-                {
326
-                    await ftp.LoginAsync().ConfigureAwait(false);
327
-                    using (var downloadStream = await ftp.OpenFileReadStreamAsync(remoteFileName)
328
-                        .ConfigureAwait(false))
328
+                    using (var sshClient = new Renci.SshNet.SftpClient(connectionInfo))
329
                     {
329
                     {
330
-                        await downloadStream.CopyToAsync(voucherStream).ConfigureAwait(false);
330
+                        sshClient.Connect();
331
+                        sshClient.DownloadFile(remoteFileName, voucherStream);
331
                     }
332
                     }
333
+                });
332
 
334
 
333
-                    voucherStream.Position = 0;
334
-                    using (var streamReader = new StreamReader(voucherStream))
335
+                voucherStream.Position = 0;
336
+                using (var streamReader = new StreamReader(voucherStream))
337
+                {
338
+                    while (streamReader.Peek() >= 0)
335
                     {
339
                     {
336
-                        while (streamReader.Peek() >= 0)
340
+                        var line = streamReader.ReadLine();
341
+                        var parts = line.Split('|');
342
+
343
+                        VoucherSanityCheck(batch, decimal.Parse(parts[4]), int.Parse(parts[5]),
344
+                            parts[7]);
345
+
346
+                        context.Add(new Voucher()
337
                         {
347
                         {
338
-                            var line = streamReader.ReadLine();
339
-                            var parts = line.Split('|');
340
-
341
-                            VoucherSanityCheck(batch, decimal.Parse(parts[4]), int.Parse(parts[5]),
342
-                                parts[7]);
343
-
344
-                            context.Add(new Voucher()
345
-                            {
346
-                                Id = int.Parse(parts[0]),
347
-                                ExpiryDate = DateTime.Parse(parts[1]),
348
-                                Serial = parts[2],
349
-                                EncryptedPIN = parts[3],
350
-                                SequenceNumber = int.Parse(parts[6]),
351
-                                Batch = batch
352
-                            });
353
-                        }
348
+                            Id = int.Parse(parts[0]),
349
+                            ExpiryDate = DateTime.Parse(parts[1]),
350
+                            Serial = parts[2],
351
+                            EncryptedPIN = parts[3],
352
+                            SequenceNumber = int.Parse(parts[6]),
353
+                            Batch = batch
354
+                        });
354
                     }
355
                     }
356
+                }
355
 
357
 
356
-                    batch.ReadyForDownload = true;
357
-                    await context.SaveChangesAsync().ConfigureAwait(false);
358
+                batch.ReadyForDownload = true;
359
+                await context.SaveChangesAsync().ConfigureAwait(false);
358
 
360
 
359
-                    try
360
-                    {
361
-                        await ftp.DeleteFileAsync(remoteFileName).ConfigureAwait(false);
362
-                    }
363
-                    catch (Exception e)
361
+                try
362
+                {
363
+                    await Task.Run(() =>
364
                     {
364
                     {
365
-                        logger.LogWarning("Failed to delete file on FTP server: {0}: {1}", remoteFileName, e.Message);
366
-                    }
365
+                        using (var sshClient = new Renci.SshNet.SftpClient(connectionInfo))
366
+                        {
367
+                            sshClient.Connect();
368
+                            sshClient.DeleteFile(remoteFileName);
369
+                        }
370
+                    });
371
+                }
372
+                catch (Exception e)
373
+                {
374
+                    logger.LogWarning("Failed to delete file on FTP server: {0}: {1}", remoteFileName, e.Message);
367
                 }
375
                 }
368
             }
376
             }
369
         }
377
         }

+ 2 - 2
BulkPrintingAPI/Startup.cs

42
                 Configuration.GetSection("DataEncryption")));
42
                 Configuration.GetSection("DataEncryption")));
43
             services.AddSingleton(new MAX.ClientFactory(
43
             services.AddSingleton(new MAX.ClientFactory(
44
                 Configuration.GetSection("MAX")));
44
                 Configuration.GetSection("MAX")));
45
-            services.AddSingleton(new FTPOptions(
46
-                Configuration.GetSection("FTP")));
45
+            services.AddSingleton(new SFTPOptions(
46
+                Configuration.GetSection("SFTP")));
47
             services.AddDbContext<MAX.Models.MAXContext>(
47
             services.AddDbContext<MAX.Models.MAXContext>(
48
                 options => options.UseSqlServer(
48
                 options => options.UseSqlServer(
49
                     Configuration["Database:ConnectionString"],
49
                     Configuration["Database:ConnectionString"],