Added SFTP support.
This commit is contained in:
parent
24b9b51f8a
commit
3049cbdf1c
3 changed files with 165 additions and 49 deletions
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Google.Apis.Drive.v3" Version="1.34.0.1239" />
|
<PackageReference Include="Google.Apis.Drive.v3" Version="1.34.0.1239" />
|
||||||
|
<PackageReference Include="SSH.NET" Version="2016.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
{
|
{
|
||||||
public class Config
|
public class Config
|
||||||
{
|
{
|
||||||
|
public StorageMethod StorageMethod { get; set; } = StorageMethod.GoogleDrive;
|
||||||
|
|
||||||
public string GoogleClientId { get; set; }
|
public string GoogleClientId { get; set; }
|
||||||
public string GoogleClientSecret { get; set; }
|
public string GoogleClientSecret { get; set; }
|
||||||
public string GoogleBackupDirectory { get; set; } = @"Backups";
|
public string GoogleBackupDirectory { get; set; } = @"Backups";
|
||||||
|
@ -13,6 +15,14 @@
|
||||||
public string GoogleRefreshToken { get; set; }
|
public string GoogleRefreshToken { get; set; }
|
||||||
public string GoogleTokenIssued { get; set; }
|
public string GoogleTokenIssued { get; set; }
|
||||||
|
|
||||||
|
public string SftpHost { get; set; }
|
||||||
|
public ushort SftpPort { get; set; }
|
||||||
|
public string SftpUsername { get; set; }
|
||||||
|
public string SftpPassphrase { get; set; }
|
||||||
|
public string SftpPrivateKey { get; set; }
|
||||||
|
public string SftpBackupDirectoryPath { get; set; }
|
||||||
|
public string SftpTrustedHost { get; set; }
|
||||||
|
|
||||||
public string MySqlDumpPathWindows { get; set; } = @"C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqldump.exe";
|
public string MySqlDumpPathWindows { get; set; } = @"C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqldump.exe";
|
||||||
public string MySqlDumpPath { get; set; } = @"mysqldump";
|
public string MySqlDumpPath { get; set; } = @"mysqldump";
|
||||||
public string MySqlHost { get; set; } = @"localhost";
|
public string MySqlHost { get; set; } = @"localhost";
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
using Google.Apis.Auth.OAuth2;
|
using Google.Apis.Auth.OAuth2;
|
||||||
using Google.Apis.Drive.v3;
|
using Google.Apis.Drive.v3;
|
||||||
using Google.Apis.Services;
|
using Google.Apis.Services;
|
||||||
|
using Renci.SshNet;
|
||||||
|
using Renci.SshNet.Common;
|
||||||
|
using Renci.SshNet.Sftp;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -42,7 +45,9 @@ namespace BackupManager
|
||||||
);
|
);
|
||||||
|
|
||||||
private static DriveService DriveService;
|
private static DriveService DriveService;
|
||||||
private static GFile BackupStorage;
|
private static object BackupStorage;
|
||||||
|
|
||||||
|
private static SftpClient SFTP;
|
||||||
|
|
||||||
public static bool Headless;
|
public static bool Headless;
|
||||||
|
|
||||||
|
@ -103,6 +108,9 @@ namespace BackupManager
|
||||||
|
|
||||||
LoadConfig();
|
LoadConfig();
|
||||||
|
|
||||||
|
switch (Config.StorageMethod)
|
||||||
|
{
|
||||||
|
case StorageMethod.GoogleDrive:
|
||||||
UserCredential uc = GoogleAuthenticate(
|
UserCredential uc = GoogleAuthenticate(
|
||||||
new ClientSecrets
|
new ClientSecrets
|
||||||
{
|
{
|
||||||
|
@ -116,6 +124,53 @@ namespace BackupManager
|
||||||
);
|
);
|
||||||
|
|
||||||
CreateDriveService(uc);
|
CreateDriveService(uc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StorageMethod.Sftp:
|
||||||
|
if (string.IsNullOrWhiteSpace(Config.SftpHost) || string.IsNullOrWhiteSpace(Config.SftpUsername))
|
||||||
|
{
|
||||||
|
sw.Stop();
|
||||||
|
Config.SftpHost = Config.SftpHost ?? @"";
|
||||||
|
Config.SftpPort = Config.SftpPort < 1 ? (ushort)22 : Config.SftpPort;
|
||||||
|
Config.SftpUsername = Config.SftpUsername ?? @"";
|
||||||
|
Config.SftpPassphrase = Config.SftpPassphrase ?? @"";
|
||||||
|
Config.SftpPrivateKey = Config.SftpPrivateKey ?? @"";
|
||||||
|
Config.SftpTrustedHost = Config.SftpTrustedHost ?? @"";
|
||||||
|
Config.SftpBackupDirectoryPath = Config.SftpBackupDirectoryPath ?? @"";
|
||||||
|
SaveConfig();
|
||||||
|
Error(@"No Sftp host/auth details found in the configuration.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Config.SftpPrivateKey))
|
||||||
|
SFTP = new SftpClient(Config.SftpHost, Config.SftpPort, Config.SftpUsername, new PrivateKeyFile(Config.SftpPrivateKey, Config.SftpPassphrase ?? string.Empty));
|
||||||
|
else
|
||||||
|
SFTP = new SftpClient(Config.SftpHost, Config.SftpPort, Config.SftpUsername, Config.SftpPassphrase ?? string.Empty);
|
||||||
|
|
||||||
|
using (ManualResetEvent mre = new ManualResetEvent(false))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(Config.SftpTrustedHost))
|
||||||
|
SFTP.HostKeyReceived += (s, e) =>
|
||||||
|
{
|
||||||
|
string checkString = e.HostKeyName + @"#" + Convert.ToBase64String(e.HostKey) + @"#" + Convert.ToBase64String(e.FingerPrint);
|
||||||
|
e.CanTrust = Config.SftpTrustedHost.SequenceEqual(checkString);
|
||||||
|
mre.Set();
|
||||||
|
};
|
||||||
|
else
|
||||||
|
mre.Set();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SFTP.Connect();
|
||||||
|
} catch (SshConnectionException)
|
||||||
|
{
|
||||||
|
Error(@"Error during SFTP connect, it's possible the server key changed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
mre.WaitOne();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
GetBackupStorage();
|
GetBackupStorage();
|
||||||
|
|
||||||
Log(@"Database backup...");
|
Log(@"Database backup...");
|
||||||
|
@ -123,8 +178,18 @@ namespace BackupManager
|
||||||
using (Stream s = CreateMySqlDump())
|
using (Stream s = CreateMySqlDump())
|
||||||
using (Stream g = GZipEncodeStream(s))
|
using (Stream g = GZipEncodeStream(s))
|
||||||
{
|
{
|
||||||
GFile f = Upload(DatabaseDumpName, @"application/sql+gzip", g);
|
object f = Upload(DatabaseDumpName, @"application/sql+gzip", g);
|
||||||
Log($@"MySQL dump uploaded: {f.Name} ({f.Id})");
|
|
||||||
|
switch (f)
|
||||||
|
{
|
||||||
|
case GFile fgf:
|
||||||
|
Log($@"MySQL dump uploaded: {fgf.Name} ({fgf.Id})");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log($@"MySQL dump uploaded.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Directory.Exists(Config.MisuzuPath))
|
if (Directory.Exists(Config.MisuzuPath))
|
||||||
|
@ -144,8 +209,18 @@ namespace BackupManager
|
||||||
|
|
||||||
using (FileStream fs = File.OpenRead(archivePath))
|
using (FileStream fs = File.OpenRead(archivePath))
|
||||||
{
|
{
|
||||||
GFile f = Upload(UserDataName, @"application/zip", fs);
|
object f = Upload(UserDataName, @"application/zip", fs);
|
||||||
Log($@"Misuzu data uploaded: {f.Name} ({f.Id})");
|
|
||||||
|
switch (f)
|
||||||
|
{
|
||||||
|
case GFile fgf:
|
||||||
|
Log($@"Misuzu data uploaded: {fgf.Name} ({fgf.Id})");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log($@"Misuzu data uploaded.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File.Delete(archivePath);
|
File.Delete(archivePath);
|
||||||
|
@ -185,22 +260,37 @@ namespace BackupManager
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
Console.ReadLine();
|
||||||
|
#endif
|
||||||
|
|
||||||
Environment.Exit(exit);
|
Environment.Exit(exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GFile Upload(string name, string type, Stream stream)
|
public static object Upload(string name, string type, Stream stream)
|
||||||
{
|
{
|
||||||
Log($@"Uploading '{name}'...");
|
Log($@"Uploading '{name}'...");
|
||||||
|
|
||||||
|
switch (BackupStorage)
|
||||||
|
{
|
||||||
|
case GFile gfile:
|
||||||
FilesResource.CreateMediaUpload request = DriveService.Files.Create(new GFile
|
FilesResource.CreateMediaUpload request = DriveService.Files.Create(new GFile
|
||||||
{
|
{
|
||||||
Name = name,
|
Name = name,
|
||||||
Parents = new List<string> {
|
Parents = new List<string> {
|
||||||
BackupStorage.Id,
|
gfile.Id,
|
||||||
},
|
},
|
||||||
}, stream, type);
|
}, stream, type);
|
||||||
request.Fields = @"id, name";
|
request.Fields = @"id, name";
|
||||||
request.Upload();
|
request.Upload();
|
||||||
return request.ResponseBody;
|
return request.ResponseBody;
|
||||||
|
|
||||||
|
case string scpName:
|
||||||
|
SFTP.UploadFile(stream, scpName + @"/" + name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetMisuzuConfig()
|
public static string GetMisuzuConfig()
|
||||||
|
@ -278,7 +368,7 @@ namespace BackupManager
|
||||||
sw.WriteLine(@"default-character-set=utf8");
|
sw.WriteLine(@"default-character-set=utf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessStartInfo psi = new ProcessStartInfo
|
Process p = Process.Start(new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = IsWindows ? Config.MySqlDumpPathWindows : Config.MySqlDumpPath,
|
FileName = IsWindows ? Config.MySqlDumpPathWindows : Config.MySqlDumpPath,
|
||||||
RedirectStandardError = false,
|
RedirectStandardError = false,
|
||||||
|
@ -287,8 +377,7 @@ namespace BackupManager
|
||||||
Arguments = $@"--defaults-file={tmpFile} --add-locks -l --order-by-primary -B {Config.MySqlDatabases}",
|
Arguments = $@"--defaults-file={tmpFile} --add-locks -l --order-by-primary -B {Config.MySqlDatabases}",
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
};
|
});
|
||||||
Process p = Process.Start(psi);
|
|
||||||
|
|
||||||
int read;
|
int read;
|
||||||
byte[] buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
|
@ -341,6 +430,9 @@ namespace BackupManager
|
||||||
|
|
||||||
public static void GetBackupStorage(string name = null)
|
public static void GetBackupStorage(string name = null)
|
||||||
{
|
{
|
||||||
|
switch (Config.StorageMethod)
|
||||||
|
{
|
||||||
|
case StorageMethod.GoogleDrive:
|
||||||
name = name ?? Config.GoogleBackupDirectory;
|
name = name ?? Config.GoogleBackupDirectory;
|
||||||
Log(@"Getting backup folder...");
|
Log(@"Getting backup folder...");
|
||||||
FilesResource.ListRequest lr = DriveService.Files.List();
|
FilesResource.ListRequest lr = DriveService.Files.List();
|
||||||
|
@ -362,6 +454,19 @@ namespace BackupManager
|
||||||
}
|
}
|
||||||
|
|
||||||
BackupStorage = backupFolder;
|
BackupStorage = backupFolder;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case StorageMethod.Sftp:
|
||||||
|
string directory = (BackupStorage = name ?? Config.SftpBackupDirectoryPath) as string;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SFTP.ListDirectory(directory);
|
||||||
|
} catch (SftpPathNotFoundException)
|
||||||
|
{
|
||||||
|
SFTP.CreateDirectory(directory);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue