3.5.2 commit

This commit is contained in:
Doug Macintosh
2026-03-08 16:20:06 -04:00
parent a59a047cd1
commit bfe37f6426
26 changed files with 1998 additions and 102714 deletions

576
SFTP.cs
View File

@@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Threading;
using Renci.SshNet;
using System.Linq;
using Renci.SshNet.Common;
using System.Threading.Tasks;
namespace bdf
{
@@ -34,7 +36,7 @@ namespace bdf
{
if (cd.ppkFile.Contains("Embedded"))
{
Logger.Log(1, " Processing internal PPK");
Logger.Log(2, " Processing internal PPK");
// Get the assembly where the resource is stored
Assembly asm = Assembly.GetExecutingAssembly();
Stream stream = Stream.Null;
@@ -92,7 +94,7 @@ namespace bdf
if (pkFile != null)
{
auth.Add(new Renci.SshNet.PrivateKeyAuthenticationMethod(cd.username, pkFile)); //preferred
Logger.Log(0, " Added PPK method.");
Logger.Log(1, " -added PPK auth method.");
}
}
@@ -108,7 +110,7 @@ namespace bdf
auth.Add(kb);
auth.Add(new Renci.SshNet.PasswordAuthenticationMethod(cd.username, cd.password));
Logger.Log(0, " Added user/pass method.");
Logger.Log(1, " -added user/pass auth method.");
}
return new Renci.SshNet.ConnectionInfo(cd.host, cd.port, cd.username, auth.ToArray())
@@ -127,7 +129,6 @@ namespace bdf
{
Renci.SshNet.SftpClient client = null;
try
{
var task = System.Threading.Tasks.Task.Run(() =>
@@ -140,7 +141,6 @@ namespace bdf
client.KeepAliveInterval =
System.TimeSpan.FromSeconds(15);
client.Connect();
});
@@ -154,7 +154,9 @@ namespace bdf
{
client?.Dispose();
}
catch { }
catch
{
}
//return null;
}
@@ -179,7 +181,6 @@ namespace bdf
return null;
}
public static bool serverExists(string host)
{
try
@@ -232,30 +233,34 @@ namespace bdf
return;
}
string cpath = EnsureSftpDirectoryExists(sftpClient, filename);
// file upload
try
{
ms.Position = 0;
sftpClient.UploadFile(
ms,
filename,
uploaded =>
{
Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file.");
Logger.Log(2, $"Uploaded {Math.Round((double)uploaded / ms.Length * 100)}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message);
}
Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, cd.host, cd.port, (ms.Length / 1024)+1);
Logger.Log(0, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, cd.host, cd.port, (ms.Length / 1024)+1);
//Console.WriteLine("starting dir pull");
var files = sftpClient.ListDirectory(".").Where(f => f.IsRegularFile &&
(f.Name.EndsWith(".ttf", System.StringComparison.OrdinalIgnoreCase) || //pdf
f.Name.EndsWith(".xlsx", System.StringComparison.OrdinalIgnoreCase)));
//Console.WriteLine("starting dir pull {0}", cpath);
var files = sftpClient.ListDirectory(cpath).Where(f => f.IsRegularFile &&
(f.Name.EndsWith(".pdf", System.StringComparison.OrdinalIgnoreCase) || //pdf
f.Name.EndsWith(".zip", System.StringComparison.OrdinalIgnoreCase) || //pdf
f.Name.EndsWith(".xlsx", System.StringComparison.OrdinalIgnoreCase)));
foreach (var s in files)
{
Logger.Log(0, " => {0} {1}", s.FullName, s.Attributes);
Logger.Log(1, " => {0} {1}", s.FullName, s.Attributes);
}
sftpClient.Disconnect();
@@ -276,526 +281,55 @@ namespace bdf
}
// Legacy modules
/*
public static void Upload_Stream_old(MemoryStream ms, string outfile, ConnectionDetails cd)
public static string EnsureSftpDirectoryExists(SftpClient client, string path)
{
//Logger.Log(0, "usp: file={0} host={1}:{2} user={3} pass={4}", outfile, cd.host, cd.port, cd.username, cd.password);
int attempts = 0;
while (true)
// The path needs to be absolute for reliable operation across different SFTP servers.
// Ensure the path starts with a '/' if it's meant to be absolute from the root.
if (!path.StartsWith(Path.DirectorySeparatorChar.ToString() ))
{
path = Path.DirectorySeparatorChar + path;
}
// Split the path into components, handling potential leading slash
var parts = path.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);
string currentPath = Path.DirectorySeparatorChar.ToString();
Logger.Log(3, "Checking path: {0}", path);
foreach (var part in parts)
{
Logger.Log(4, " checking path part {0}", part);
if (string.IsNullOrEmpty(part)) continue;
if (parts[parts.Length-1].ToString() == part) break; // last part is the filename so skip pit. arrays are 0-based
currentPath = currentPath == Path.DirectorySeparatorChar.ToString() ? Path.DirectorySeparatorChar.ToString() + part : currentPath + Path.DirectorySeparatorChar.ToString() + part;
try
{
var valid_methods = new List<AuthenticationMethod>();
PrivateKeyFile keyFile;
if (cd.username != "" && cd.ppkFile != "")
// Attempt to get attributes of the current path component
var attrs = client.GetAttributes(currentPath);
if (!attrs.IsDirectory)
{
if (cd.ppkFile.StartsWith("BDF"))
{
Logger.Log(3, "Processing PPK");
// Add in loading the private.key from an embedded resource file
// Get the assembly where the resource is stored
Assembly asm = Assembly.GetExecutingAssembly();
// Fully-qualified resource name (namespace + filename)
Stream stream = asm.GetManifestResourceStream(cd.ppkFile);
if (stream == null || !stream.CanRead)
throw new Exception("Private key file not found. ");
else
stream.Position = 0; // reset stream position
try
{
keyFile =
string.IsNullOrEmpty(cd.passPhrase)
? new PrivateKeyFile(stream)
: new PrivateKeyFile(stream, cd.passPhrase);
}
catch (Renci.SshNet.Common.SshException e)
{
throw new Exception("Problems with your internal private key and/or passphrase. " + e.Message);
}
stream.Close();
}
else
{
try
{
keyFile =
string.IsNullOrEmpty(cd.passPhrase)
? new PrivateKeyFile(cd.ppkFile)
: new PrivateKeyFile(cd.ppkFile, cd.passPhrase);Console.WriteLine("b");
}
catch (Renci.SshNet.Common.SshException e)
{
throw new Exception("Problems with your private key and/or passphrase. " + e.Message);
}
}
valid_methods.Add(new PrivateKeyAuthenticationMethod(cd.username, keyFile)); //preferred
}
if (cd.username != "" && cd.password != "")
{
valid_methods.Add(new PasswordAuthenticationMethod(cd.username, cd.password)); //fallback to user/pass
}
if (valid_methods.Count == 0)
throw new Exception("No valid login credentials found.");
Logger.Log(0, " Found {0} valid methods. Using method={1}", valid_methods.Count, valid_methods[0].Name);
AuthenticationMethod[] methods = valid_methods.ToArray();
ConnectionInfo connectionInfo =
new ConnectionInfo(
cd.host,
cd.port,
cd.username,
methods ) //fallback to user/pass
{
Timeout = System.TimeSpan.FromSeconds(cd.timeOutSecs)
};
//Console.WriteLine("Connection info done:");
using (var sftpClient = new SftpClient(connectionInfo))
{
//sftpClient.ConnectionInfo.Timeout = System.TimeSpan.FromSeconds(15); //set above in connectionInfo
sftpClient.OperationTimeout = System.TimeSpan.FromSeconds(cd.OperationTimeout);
sftpClient.KeepAliveInterval = System.TimeSpan.FromSeconds(cd.KeepAliveInterval);
attempts++;
try
{
Logger.Log(5, "trying connect {0}", sftpClient.ConnectionInfo.Username);
sftpClient.Connect();
}
catch (Renci.SshNet.Common.SshAuthenticationException e)
{
Logger.Log(1, " authentication exception ({0}) : {1}", attempts, e.Message);
}
catch (Renci.SshNet.Common.SshConnectionException e)
{
Logger.Log(1, " connection exception ({0}) : {1}", attempts, e.Message);
}
catch (Exception e)
{
Logger.Log(1, " connection exception ({0}) : {1}", attempts, e.Message);
}
//------------
if (!sftpClient.IsConnected)
{
Logger.Log(1, " connection failure {0}", attempts);
if (attempts < 10) { Thread.Sleep(TimeSpan.FromSeconds(5)); continue; } else { break; };
}
try
{
sftpClient.UploadFile(
ms,
outfile,
uploaded =>
{
Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message);
}
Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", outfile, cd.host, cd.port, ((ms.Length / 1024) + 1));
//Console.WriteLine("starting dir pull");
var files = sftpClient.ListDirectory(".").Where(f => f.IsRegularFile &&
( f.Name.EndsWith(".ttf", System.StringComparison.OrdinalIgnoreCase) || //pdf
f.Name.EndsWith(".xlsx", System.StringComparison.OrdinalIgnoreCase) ) );
foreach (var s in files)
{
Logger.Log(0, " => {0} {1}", s.FullName, s.Attributes);
}
//if (client.Exists(path))
//{
// client.DeleteFile(path);
//}
sftpClient.Disconnect();
Logger.Log(" SSH Disconnected");
return; // success
// Handle the case where a file exists with the same name as a directory component
//throw new Exception($"A file exists with the same name as the directory component: {currentPath}");
Logger.Log(4, " found existing filename {0}", part);
break;
}
}
catch (Exception e)
catch (SftpPathNotFoundException)
{
Logger.Log(0, "SFTP exception {0}:{1}", e.Message, e.InnerException.Message);
// If the path is not found, create the directory
client.CreateDirectory(currentPath);
Logger.Log(0, "Creating SFTP directory: {0}", currentPath);
System.Threading.Thread.Sleep(2000);
}
attempts++;
if (attempts >= cd.maxAttempts)
catch (Exception ex)
{
Logger.Log(0, ("Failed to Connect after 10 attempts."));
return;
// Handle other potential exceptions (permissions, etc.)
Logger.Log(0, "Error checking/creating directory {0}: {1}",currentPath,ex.Message);
throw; // Re-throw to propagate the error
}
Logger.Log(1, " ...retrying ({0})", attempts);
Thread.Sleep(TimeSpan.FromSeconds(5));
} // end of while true/do forever
}
public static void Upload_stream_dev(MemoryStream ms, string filename)
{
int attempts = 0;
int maxAttempts = 5;
int timeOut = 30; //seconds
string ppkFile = "BDF.Embedded.private_passphr.ppk";
//passPhrase = "";
string passPhrase = "Rogers1!";
string username = "DEV_APP_BDF";
string host = "dev.mft.rogers.com";
int port = 22;
Logger.Log(5, "usp: file={0} host={1}:{2} user={3} pass={4}", filename, host, port, username, passPhrase);
while (true)
{
try
{
// Add in loading the private.key from an embedded resource file
// Get the assembly where the resource is stored
Assembly asm = Assembly.GetExecutingAssembly();
// Fully-qualified resource name (namespace + filename)
Stream stream = asm.GetManifestResourceStream(ppkFile);
//Stream stream = asm.GetManifestResourceStream("BDF.Embedded.private_nopassphr.ppk");
if (stream == null || !stream.CanRead)
throw new Exception("Private keys not found. ");
PrivateKeyFile keyFile =
string.IsNullOrEmpty(passPhrase)
? new PrivateKeyFile(stream)
: new PrivateKeyFile(stream, passPhrase);
stream.Close();
ConnectionInfo connectionInfo =
new ConnectionInfo(
host,
port,
username,
new PrivateKeyAuthenticationMethod(username, keyFile))
{
Timeout = System.TimeSpan.FromSeconds(timeOut)
};
//Console.WriteLine("Connection info done:");
using (var sftpClient = new SftpClient(connectionInfo))
{
sftpClient.ConnectionInfo.Timeout = System.TimeSpan.FromSeconds(15);
sftpClient.OperationTimeout = System.TimeSpan.FromSeconds(30);
sftpClient.KeepAliveInterval = System.TimeSpan.FromSeconds(10);
attempts++;
try
{
Logger.Log(5, "trying connect {0}", sftpClient.ConnectionInfo.Username);
sftpClient.Connect();
}
catch (Renci.SshNet.Common.SshConnectionException e)
{
Logger.Log(1, " connection exception ({0}) : {1}", attempts, e.Message);
}
//------------
if (!sftpClient.IsConnected)
{
Logger.Log(1, " connection failure {0}", attempts);
if (attempts < 10) { Thread.Sleep(TimeSpan.FromSeconds(5)); continue; } else { break; };
}
try
{
sftpClient.UploadFile(
ms,
filename,
uploaded =>
{
Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message);
}
Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, host, port, ((ms.Length / 1024)+1));
//Console.WriteLine("starting dir pull");
var files = sftpClient.ListDirectory(".").Where(f => f.IsRegularFile &&
f.Name.EndsWith(".ttf", System.StringComparison.OrdinalIgnoreCase));
foreach (var s in files)
{
Logger.Log(0, " => {0} {1}", s.FullName, s.Attributes);
}
//if (client.Exists(path))
//{
// client.DeleteFile(path);
//}
sftpClient.Disconnect();
Logger.Log(" SSH Disconnected");
return; // success
}
}
catch (Exception e)
{
Logger.Log(0, "SFTP exception {0}:{1}", e.Message, e.InnerException.Message);
}
attempts++;
if (attempts >= maxAttempts)
{
Logger.Log(0, ("Failed to Connect after 10 attempts."));
return;
}
Logger.Log(1, " ...retrying ({0})", attempts);
Thread.Sleep(TimeSpan.FromSeconds(5));
} // end of while true/do forever
}
public static void Upload_stream_ppk(MemoryStream ms, string filename, string host, int port, string username)
{
int attempts = 0;
int maxAttempts = 5;
int timeOut = 30; //seconds
string passPhrase = "Rogers1!";
//passPhrase = "";
//string username = "DEV_APP_BDF";
//string host = "dev.mft.rogers.com";
//int port = 22;
Logger.Log(5,"usp: file={0} host={1}:{2} user={3} pass={4}", filename, host, port, username, passPhrase);
while (true)
{
try
{
// Add in loading the private.key from an embedded resource file
// Get the assembly where the resource is stored
Assembly asm = Assembly.GetExecutingAssembly();
// Fully-qualified resource name (namespace + filename)
Stream stream = asm.GetManifestResourceStream("BDF.Embedded.private_passphr.ppk");
//Stream stream = asm.GetManifestResourceStream("BDF.Embedded.private_nopassphr.ppk");
if (stream == null || !stream.CanRead)
throw new Exception("Private keys not found. ");
PrivateKeyFile keyFile =
string.IsNullOrEmpty(passPhrase)
? new PrivateKeyFile(stream)
: new PrivateKeyFile(stream, passPhrase);
stream.Close();
ConnectionInfo connectionInfo =
new ConnectionInfo(
host,
port,
username,
new PrivateKeyAuthenticationMethod(username, keyFile))
{
Timeout = System.TimeSpan.FromSeconds(timeOut)
};
//Console.WriteLine("Connection info done:");
using (var sftpClient = new SftpClient(connectionInfo))
{
sftpClient.ConnectionInfo.Timeout = System.TimeSpan.FromSeconds(15);
sftpClient.OperationTimeout = System.TimeSpan.FromSeconds(30);
sftpClient.KeepAliveInterval = System.TimeSpan.FromSeconds(10);
attempts++;
try
{
Logger.Log(5,"trying connect {0}", sftpClient.ConnectionInfo.Username);
sftpClient.Connect();
}
catch (Renci.SshNet.Common.SshConnectionException e)
{
Logger.Log(1, " connection exception ({0}) : {1}", attempts, e.Message);
}
//------------
if (!sftpClient.IsConnected)
{
Logger.Log(1, " connection failure {0}", attempts);
if (attempts < 10) { Thread.Sleep(TimeSpan.FromSeconds(5)); continue; } else { break; };
}
try
{
Console.WriteLine("trying to upload");
sftpClient.UploadFile(
ms,
filename,
uploaded =>
{
Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message);
}
Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, host, port, (ms.Length / 1024));
Console.WriteLine("starting dir pull");
var files = sftpClient.ListDirectory(".");
foreach(var s in files)
{
Console.WriteLine("* {0}", s.FullName);
}
Console.WriteLine("disconnecting");
sftpClient.Disconnect();
Logger.Log(" SSH Disconnected");
return; // success
}
}
catch (Exception e)
{
Logger.Log(0, "SFTP exception {0}:{1}", e.Message, e.InnerException.Message);
}
attempts++;
if (attempts >= maxAttempts)
{
Logger.Log(0, ("Failed to Connect after 10 attempts."));
return;
}
Logger.Log(1, " ...retrying ({0})", attempts);
Thread.Sleep(TimeSpan.FromSeconds(5));
} // end of while true/do forever
}
public static void Upload_stream_old( MemoryStream ms, string filename, string host, int port, string username, string password)
{
try
{
using (var sftpClient = new SftpClient(host, port, username, password))
//using (var fs = new FileStream(fileToUpload, FileMode.Open))
{
sftpClient.OperationTimeout = TimeSpan.FromSeconds(30);
sftpClient.ConnectionInfo.Timeout = TimeSpan.FromSeconds(30);
int attempts = 0;
do
{
attempts++;
try
{
sftpClient.Connect();
}
catch (Renci.SshNet.Common.SshConnectionException e)
{
Logger.Log(1," retrying ({0}) : {1}",attempts, e.Message);
Thread.Sleep(TimeSpan.FromSeconds(5));
}
}
while (attempts < 10 && !sftpClient.IsConnected);
if (attempts >= 10)
{
throw new Exception("Failed to Connect after 10 attempts.");
}
else
{
Logger.Log(" SSH Connected");
try
{
sftpClient.UploadFile(
ms,
filename,
uploaded =>
{
Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message);
}
Logger.Log(" SSH Disconnected");
sftpClient.Disconnect();
}
}
Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, host, port, ( ms.Length/1024) );
}
catch (Exception e)
{
Logger.Log(e.Message);
}
return currentPath;
}
public static void Upload_file(string fileToUpload, string host, int port, string username, string password)
{
try
{
using (var sftpClient = new SftpClient(host, port, username, password))
using (var fs = new FileStream(fileToUpload, FileMode.Open))
{
sftpClient.OperationTimeout = TimeSpan.FromSeconds(30);
int attempts = 0;
do
{
try
{
attempts += 1;
sftpClient.Connect();
}
catch (Renci.SshNet.Common.SshConnectionException e)
{
Logger.Log(1, " retrying in 5s ({0}) : {1}", attempts, e.Message);
Thread.Sleep(TimeSpan.FromSeconds(5));
}
} while (attempts < 10 && !sftpClient.IsConnected);
Logger.Log(" SSH Connected");
try
{
sftpClient.UploadFile(
fs,
"/Doug/" + Path.GetFileName(fileToUpload),
uploaded =>
{
Logger.Log(5,$"Uploaded {(double)uploaded / fs.Length * 100}% of the file.");
});
}
catch (Renci.SshNet.Common.SshException e)
{
Logger.Log(0, " SSH Exception {0}:{1}", e.Message, e.InnerException.Message);
}
sftpClient.Disconnect();
}
Logger.Log(1," uploaded: {0}", fileToUpload);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
*/
}
}