Skip to content

Commit

Permalink
Bug fix for DownloadFiles
Browse files Browse the repository at this point in the history
  • Loading branch information
RikuVirtanen committed Sep 21, 2023
1 parent af7eb7f commit e30eec4
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 166 deletions.
3 changes: 2 additions & 1 deletion Frends.FTP.DownloadFiles/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Changelog

## [1.0.5] - 2023-09-12
## [1.1.0] - 2023-09-12
### Added
- Added search for local certificates from machine certification store.
- [Breaking] Added parameters ClientCertificationName and ClientCertificationThumbprint for exclusive search of client certification.

## [1.0.4] - 2023-08-08
### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public void DownloadFTPS_IncorrectFingerprint()
}

[Test]
public void DownloadFTPS_LocalMachineHasNoCertificates()
public void DownloadFTPS_CurrentUserHasNoCertificates()
{
// Setup
FtpHelper.CreateFileOnFTP(FtpDir, "file1.txt");
Expand All @@ -207,30 +207,16 @@ public void DownloadFTPS_LocalMachineHasNoCertificates()
ClientCertificatePath = ""
};

if (Environment.OSVersion.Platform == PlatformID.Unix)
var ex = Assert.Throws<AggregateException>(() =>
{
var ex = Assert.Throws<System.Security.Cryptography.CryptographicException>(() =>
{
var result = FTP.DownloadFiles(source, destination, connection, new Options(), new Info(),
new CancellationToken());

});
var result = FTP.DownloadFiles(source, destination, connection, new Options(), new Info(),
new CancellationToken());

Assert.AreEqual("", ex.Message);
}
else
{
var ex = Assert.Throws<AggregateException>(() =>
{
var result = FTP.DownloadFiles(source, destination, connection, new Options(), new Info(),
new CancellationToken());
});

});
Assert.AreEqual(1, ex.InnerExceptions.Count);
Assert.AreEqual(typeof(AuthenticationException), ex.InnerExceptions[0].GetType());

Assert.AreEqual(1, ex.InnerExceptions.Count);
Assert.AreEqual(typeof(AuthenticationException), ex.InnerExceptions[0].GetType());
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,25 +147,25 @@ private static FtpClient CreateFtpClient(Connection connect)
if (connect.EnableClientAuth)
{
if (!string.IsNullOrEmpty(connect.ClientCertificatePath))
{
client.ClientCertificates.Add(new X509Certificate2(connect.ClientCertificatePath));
}
else
{
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadOnly);
foreach (var cert in store.Certificates)
try
{
var test = cert.FriendlyName;
test = "";
store.Open(OpenFlags.ReadOnly);
if (!string.IsNullOrEmpty(connect.ClientCertificateName))
client.ClientCertificates.Add(store.Certificates.Find(X509FindType.FindBySubjectName, connect.ClientCertificateName, false)[0]);
else if (!string.IsNullOrEmpty(connect.ClientCertificateThumbprint))
client.ClientCertificates.Add(store.Certificates.Find(X509FindType.FindByThumbprint, connect.ClientCertificateThumbprint, false)[0]);
else
client.ClientCertificates.AddRange(store.Certificates);
}
finally
{
store.Close();
}
client.ClientCertificates.AddRange(store.Certificates);
}
finally
{
store.Close();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<IncludeSource>true</IncludeSource>
<PackageTags>Frends</PackageTags>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Version>1.0.5</Version>
<Version>1.1.0</Version>
<Description>Task for downloading files from FTP(S) servers.</Description>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,139 +1,155 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Frends.FTP.DownloadFiles.Enums;

namespace Frends.FTP.DownloadFiles.TaskConfiguration;

/// <summary>Parameters class usually contains parameters that are required.</summary>
public class Connection
{
/// <summary>
/// FTP(S) host address
/// </summary>
/// <example>my.ftp.server.com</example>
[DisplayFormat(DataFormatString = "Text")]
public string Address { get; set; }

/// <summary>
/// Port number to use in the connection to the server.
/// </summary>
/// <example>21</example>
[DefaultValue(21)]
public int Port { get; set; } = 21;

/// <summary>
/// Username to use for authentication to the server. Note that the file endpoint only supports
/// username for remote shares and the username must be in the format DOMAIN\Username.
/// </summary>
/// <example>myUsername</example>
[DisplayFormat(DataFormatString = "Text")]
public string UserName { get; set; }

/// <summary>
/// Password to use in the authentication to the server.
/// </summary>
/// <example>myPassword</example>
[PasswordPropertyText]
public string Password { get; set; }

/// <summary>
/// Type of transfer: 'Ascii' sends files as text and must only be used for sending ASCII text files. 'Binary' (default) sends files as raw data and should be used for sending e.g. UTF-encoded text files
/// </summary>
/// <example>FtpTransportType.Binary</example>
[DefaultValue(FtpTransportType.Binary)]
public FtpTransportType TransportType { get; set; }

/// <summary>
/// Connection mode to use to connect to the FTP server
/// </summary>
/// <example>FtpMode.Passive</example>
[DefaultValue(FtpMode.Passive)]
public FtpMode Mode { get; set; }

/// <summary>
/// Sends NOOP command to keep connection alive at specified time-interval in seconds. If set to 0 the connection is not kept alive. Default value is 0
/// </summary>
/// <example>60</example>
[DefaultValue(0)]
public int KeepConnectionAliveInterval { get; set; }

/// <summary>
/// The length of time, in seconds, until the connection times out. You can use value 0 to indicate that the connection does not time out. Default value is 60 seconds
/// </summary>
/// <example>60</example>
[DefaultValue(60)]
public int ConnectionTimeout { get; set; } = 60;

/// <summary>
/// If set, this encoding will be used to encode and decode command parameters and server responses, such as file names. Example values: utf-8, utf-16, windows-1252
/// </summary>
/// <example>utf-8</example>
public string Encoding { get; set; }

/// <summary>
/// Integer value of used buffer size as bytes.
/// Default value is 4 KB.
/// </summary>
/// <example>4096</example>
[DefaultValue(4096)]
public int BufferSize { get; set; }

#region FTPS settings

/// <summary>
/// Whether to use FTPS or not.
/// </summary>
/// <example>false</example>
[DefaultValue("false")]
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Frends.FTP.DownloadFiles.Enums;

namespace Frends.FTP.DownloadFiles.TaskConfiguration;

/// <summary>Parameters class usually contains parameters that are required.</summary>
public class Connection
{
/// <summary>
/// FTP(S) host address
/// </summary>
/// <example>my.ftp.server.com</example>
[DisplayFormat(DataFormatString = "Text")]
public string Address { get; set; }

/// <summary>
/// Port number to use in the connection to the server.
/// </summary>
/// <example>21</example>
[DefaultValue(21)]
public int Port { get; set; } = 21;

/// <summary>
/// Username to use for authentication to the server. Note that the file endpoint only supports
/// username for remote shares and the username must be in the format DOMAIN\Username.
/// </summary>
/// <example>myUsername</example>
[DisplayFormat(DataFormatString = "Text")]
public string UserName { get; set; }

/// <summary>
/// Password to use in the authentication to the server.
/// </summary>
/// <example>myPassword</example>
[PasswordPropertyText]
public string Password { get; set; }

/// <summary>
/// Type of transfer: 'Ascii' sends files as text and must only be used for sending ASCII text files. 'Binary' (default) sends files as raw data and should be used for sending e.g. UTF-encoded text files
/// </summary>
/// <example>FtpTransportType.Binary</example>
[DefaultValue(FtpTransportType.Binary)]
public FtpTransportType TransportType { get; set; }

/// <summary>
/// Connection mode to use to connect to the FTP server
/// </summary>
/// <example>FtpMode.Passive</example>
[DefaultValue(FtpMode.Passive)]
public FtpMode Mode { get; set; }

/// <summary>
/// Sends NOOP command to keep connection alive at specified time-interval in seconds. If set to 0 the connection is not kept alive. Default value is 0
/// </summary>
/// <example>60</example>
[DefaultValue(0)]
public int KeepConnectionAliveInterval { get; set; }

/// <summary>
/// The length of time, in seconds, until the connection times out. You can use value 0 to indicate that the connection does not time out. Default value is 60 seconds
/// </summary>
/// <example>60</example>
[DefaultValue(60)]
public int ConnectionTimeout { get; set; } = 60;

/// <summary>
/// If set, this encoding will be used to encode and decode command parameters and server responses, such as file names. Example values: utf-8, utf-16, windows-1252
/// </summary>
/// <example>utf-8</example>
public string Encoding { get; set; }

/// <summary>
/// Integer value of used buffer size as bytes.
/// Default value is 4 KB.
/// </summary>
/// <example>4096</example>
[DefaultValue(4096)]
public int BufferSize { get; set; }

#region FTPS settings

/// <summary>
/// Whether to use FTPS or not.
/// </summary>
/// <example>false</example>
[DefaultValue("false")]
public bool UseFTPS { get; set; } = false;

/// <summary>
/// Whether the data channel is secured or not.
/// </summary>
/// <example>false</example>
[DefaultValue("true")]
[UIHint(nameof(UseFTPS), "", true)]
public bool SecureDataChannel { get; set; }

/// <summary>
/// Specifies whether to use Explicit or Implicit SSL
/// </summary>
/// <example>FtpsSslMode.None</example>
[DefaultValue(FtpsSslMode.None)]
[UIHint(nameof(UseFTPS), "", true)]
public FtpsSslMode SslMode { get; set; }

/// <summary>
/// If enabled the client certificate is searched from user's certificate store
/// </summary>
/// <example>false</example>
[DefaultValue("false")]
[UIHint(nameof(UseFTPS), "", true)]
/// <summary>
/// Whether the data channel is secured or not.
/// </summary>
/// <example>false</example>
[DefaultValue("true")]
[UIHint(nameof(UseFTPS), "", true)]
public bool SecureDataChannel { get; set; }

/// <summary>
/// Specifies whether to use Explicit or Implicit SSL
/// </summary>
/// <example>FtpsSslMode.None</example>
[DefaultValue(FtpsSslMode.None)]
[UIHint(nameof(UseFTPS), "", true)]
public FtpsSslMode SslMode { get; set; }

/// <summary>
/// If enabled the client certificate is searched from user's certificate store
/// </summary>
/// <example>false</example>
[DefaultValue("false")]
[UIHint(nameof(UseFTPS), "", true)]
public bool EnableClientAuth { get; set; }

/// <summary>
/// If enabled the any certificate will be considered valid.
/// </summary>
/// <example>false</example>
[DefaultValue("false")]
[UIHint(nameof(UseFTPS), "", true)]
/// <summary>
/// Optional. Enables certification search by name from the certification store of current user.
/// </summary>
/// <example>mycert.crt</example>
[DefaultValue("")]
[UIHint(nameof(EnableClientAuth), "", true)]
public string ClientCertificateName { get; set; }

/// <summary>
/// Optional. Enables certification search by thumbprint from the certification store of current user.
/// </summary>
/// <example>a909502dd82ae41433e6f83886b00d4277a32a7b</example>
[DefaultValue("")]
[UIHint(nameof(EnableClientAuth), "", true)]
public string ClientCertificateThumbprint { get; set; }

/// <summary>
/// If enabled the any certificate will be considered valid.
/// </summary>
/// <example>false</example>
[DefaultValue("false")]
[UIHint(nameof(UseFTPS), "", true)]
public bool ValidateAnyCertificate { get; set; }

/// <summary>
/// Path to client certificate (X509).
/// </summary>
/// <example>c:\example.cer</example>
[UIHint(nameof(UseFTPS), "", true)]
[DisplayFormat(DataFormatString = "Text")]
/// <summary>
/// Path to client certificate (X509).
/// </summary>
/// <example>c:\example.cer</example>
[UIHint(nameof(UseFTPS), "", true)]
[DisplayFormat(DataFormatString = "Text")]
public string ClientCertificatePath { get; set; }

/// <summary>
/// Certificate SHA1 hash string to validate against.
/// </summary>
/// <example>BA7816BF8F01CFEA414140DE5DAE2223B00361A3</example>
[DefaultValue("")]
[UIHint(nameof(UseFTPS), "", true)]
public string CertificateHashStringSHA1 { get; set; }

#endregion
/// <summary>
/// Certificate SHA1 hash string to validate against.
/// </summary>
/// <example>BA7816BF8F01CFEA414140DE5DAE2223B00361A3</example>
[DefaultValue("")]
[UIHint(nameof(UseFTPS), "", true)]
public string CertificateHashStringSHA1 { get; set; }

#endregion
}

0 comments on commit e30eec4

Please sign in to comment.