Added SFTP support.

This commit is contained in:
flash 2019-01-15 15:55:35 +01:00
parent 24b9b51f8a
commit 3049cbdf1c
3 changed files with 165 additions and 49 deletions

View file

@ -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>

View file

@ -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";

View file

@ -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,19 +108,69 @@ namespace BackupManager
LoadConfig(); LoadConfig();
UserCredential uc = GoogleAuthenticate( switch (Config.StorageMethod)
new ClientSecrets {
{ case StorageMethod.GoogleDrive:
ClientId = Config.GoogleClientId, UserCredential uc = GoogleAuthenticate(
ClientSecret = Config.GoogleClientSecret, new ClientSecrets
}, {
new[] { ClientId = Config.GoogleClientId,
DriveService.Scope.Drive, ClientSecret = Config.GoogleClientSecret,
DriveService.Scope.DriveFile, },
} new[] {
); DriveService.Scope.Drive,
DriveService.Scope.DriveFile,
}
);
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;
}
CreateDriveService(uc);
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}'...");
FilesResource.CreateMediaUpload request = DriveService.Files.Create(new GFile
switch (BackupStorage)
{ {
Name = name, case GFile gfile:
Parents = new List<string> { FilesResource.CreateMediaUpload request = DriveService.Files.Create(new GFile
BackupStorage.Id, {
}, Name = name,
}, stream, type); Parents = new List<string> {
request.Fields = @"id, name"; gfile.Id,
request.Upload(); },
return request.ResponseBody; }, stream, type);
request.Fields = @"id, name";
request.Upload();
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,27 +430,43 @@ namespace BackupManager
public static void GetBackupStorage(string name = null) public static void GetBackupStorage(string name = null)
{ {
name = name ?? Config.GoogleBackupDirectory; switch (Config.StorageMethod)
Log(@"Getting backup folder...");
FilesResource.ListRequest lr = DriveService.Files.List();
lr.Q = $@"name = '{name}' and mimeType = '{FOLDER_MIME}'";
lr.PageSize = 1;
lr.Fields = @"files(id)";
GFile backupFolder = lr.Execute().Files.FirstOrDefault();
if (backupFolder == null)
{ {
Log(@"Backup folder doesn't exist yet, creating it..."); case StorageMethod.GoogleDrive:
FilesResource.CreateRequest dcr = DriveService.Files.Create(new GFile name = name ?? Config.GoogleBackupDirectory;
{ Log(@"Getting backup folder...");
Name = name, FilesResource.ListRequest lr = DriveService.Files.List();
MimeType = FOLDER_MIME, lr.Q = $@"name = '{name}' and mimeType = '{FOLDER_MIME}'";
}); lr.PageSize = 1;
dcr.Fields = @"id"; lr.Fields = @"files(id)";
backupFolder = dcr.Execute(); GFile backupFolder = lr.Execute().Files.FirstOrDefault();
}
BackupStorage = backupFolder; if (backupFolder == null)
{
Log(@"Backup folder doesn't exist yet, creating it...");
FilesResource.CreateRequest dcr = DriveService.Files.Create(new GFile
{
Name = name,
MimeType = FOLDER_MIME,
});
dcr.Fields = @"id";
backupFolder = dcr.Execute();
}
BackupStorage = backupFolder;
break;
case StorageMethod.Sftp:
string directory = (BackupStorage = name ?? Config.SftpBackupDirectoryPath) as string;
try
{
SFTP.ListDirectory(directory);
} catch (SftpPathNotFoundException)
{
SFTP.CreateDirectory(directory);
}
break;
}
} }
} }
} }