fetcher: create separate Base, SSH, and Git classes. cleaner abstraction.
This commit is contained in:
parent
ec469fa174
commit
beef578e25
|
@ -26,6 +26,6 @@ using System.Reflection;
|
||||||
namespace SparkleLib {
|
namespace SparkleLib {
|
||||||
|
|
||||||
public class Defines {
|
public class Defines {
|
||||||
public const string INSTALL_DIR = "/usr/share/sparkleshare";
|
public const string INSTALL_DIR = "/usr/local/share/sparkleshare";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,7 @@ using SparkleLib;
|
||||||
|
|
||||||
namespace SparkleLib.Git {
|
namespace SparkleLib.Git {
|
||||||
|
|
||||||
// Sets up a fetcher that can get remote folders
|
public class SparkleFetcher : SparkleFetcherSSH {
|
||||||
public class SparkleFetcher : SparkleFetcherBase {
|
|
||||||
|
|
||||||
private SparkleGit git;
|
private SparkleGit git;
|
||||||
private bool use_git_bin;
|
private bool use_git_bin;
|
||||||
|
@ -188,8 +187,6 @@ namespace SparkleLib.Git {
|
||||||
InstallExcludeRules ();
|
InstallExcludeRules ();
|
||||||
InstallAttributeRules ();
|
InstallAttributeRules ();
|
||||||
|
|
||||||
AddWarnings ();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -386,20 +383,5 @@ namespace SparkleLib.Git {
|
||||||
|
|
||||||
writer.Close ();
|
writer.Close ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void AddWarnings ()
|
|
||||||
{
|
|
||||||
if (this.warnings.Count > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SparkleGit git = new SparkleGit (TargetFolder, "config --global core.excludesfile");
|
|
||||||
string output = git.StartAndReadStandardOutput ();
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty (output))
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
this.warnings.Add ("You seem to have a system wide ‘gitignore’ file, this may affect SparkleShare files.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ SOURCES = \
|
||||||
SparkleConfig.cs \
|
SparkleConfig.cs \
|
||||||
SparkleExtensions.cs \
|
SparkleExtensions.cs \
|
||||||
SparkleFetcherBase.cs \
|
SparkleFetcherBase.cs \
|
||||||
|
SparkleFetcherSSH.cs \
|
||||||
SparkleListenerBase.cs \
|
SparkleListenerBase.cs \
|
||||||
SparkleListenerFactory.cs \
|
SparkleListenerFactory.cs \
|
||||||
SparkleListenerTcp.cs \
|
SparkleListenerTcp.cs \
|
||||||
|
|
|
@ -135,41 +135,6 @@ namespace SparkleLib {
|
||||||
if (Directory.Exists (TargetFolder))
|
if (Directory.Exists (TargetFolder))
|
||||||
Directory.Delete (TargetFolder, true);
|
Directory.Delete (TargetFolder, true);
|
||||||
|
|
||||||
string host_key = "";
|
|
||||||
|
|
||||||
if (!RemoteUrl.Scheme.StartsWith ("http")) {
|
|
||||||
host_key = FetchHostKey ();
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty (RemoteUrl.Host) || host_key == null) {
|
|
||||||
SparkleLogger.LogInfo ("Auth", "Could not fetch host key");
|
|
||||||
Failed ();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool warn = true;
|
|
||||||
if (RequiredFingerprint != null) {
|
|
||||||
string host_fingerprint = DeriveFingerprint (host_key);
|
|
||||||
|
|
||||||
if (host_fingerprint == null || !RequiredFingerprint.Equals (host_fingerprint)) {
|
|
||||||
SparkleLogger.LogInfo ("Auth", "Fingerprint doesn't match");
|
|
||||||
|
|
||||||
this.errors.Add ("error: Host fingerprint doesn't match");
|
|
||||||
Failed ();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
warn = false;
|
|
||||||
SparkleLogger.LogInfo ("Auth", "Fingerprint matches");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
SparkleLogger.LogInfo ("Auth", "Skipping fingerprint check");
|
|
||||||
}
|
|
||||||
|
|
||||||
AcceptHostKey (host_key, warn);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.thread = new Thread (() => {
|
this.thread = new Thread (() => {
|
||||||
if (Fetch ()) {
|
if (Fetch ()) {
|
||||||
Thread.Sleep (500);
|
Thread.Sleep (500);
|
||||||
|
@ -222,7 +187,7 @@ namespace SparkleLib {
|
||||||
|
|
||||||
UriBuilder uri_builder = new UriBuilder (RemoteUrl);
|
UriBuilder uri_builder = new UriBuilder (RemoteUrl);
|
||||||
|
|
||||||
if (RemoteUrl.Scheme.StartsWith ("http")) {
|
if (RemoteUrl.Scheme.Contains ("http")) {
|
||||||
uri_builder.UserName = "";
|
uri_builder.UserName = "";
|
||||||
uri_builder.Password = "";
|
uri_builder.Password = "";
|
||||||
}
|
}
|
||||||
|
@ -246,8 +211,7 @@ namespace SparkleLib {
|
||||||
|
|
||||||
public static string CreateIdentifier ()
|
public static string CreateIdentifier ()
|
||||||
{
|
{
|
||||||
string random = Path.GetRandomFileName ();
|
return Path.GetRandomFileName ().SHA1 ();
|
||||||
return random.SHA1 ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -270,91 +234,6 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private string FetchHostKey ()
|
|
||||||
{
|
|
||||||
SparkleLogger.LogInfo ("Auth", "Fetching host key for " + RemoteUrl.Host);
|
|
||||||
|
|
||||||
Process process = new Process ();
|
|
||||||
process.StartInfo.FileName = "ssh-keyscan";
|
|
||||||
process.StartInfo.WorkingDirectory = SparkleConfig.DefaultConfig.TmpPath;
|
|
||||||
process.StartInfo.UseShellExecute = false;
|
|
||||||
process.StartInfo.RedirectStandardOutput = true;
|
|
||||||
process.StartInfo.CreateNoWindow = true;
|
|
||||||
process.EnableRaisingEvents = true;
|
|
||||||
|
|
||||||
string [] key_types = {"rsa", "dsa", "ecdsa"};
|
|
||||||
|
|
||||||
foreach (string key_type in key_types) {
|
|
||||||
if (RemoteUrl.Port < 1)
|
|
||||||
process.StartInfo.Arguments = "-t " + key_type + " -p 22 " + RemoteUrl.Host;
|
|
||||||
else
|
|
||||||
process.StartInfo.Arguments = "-t " + key_type + " -p " + RemoteUrl.Port + " " + RemoteUrl.Host;
|
|
||||||
|
|
||||||
SparkleLogger.LogInfo ("Cmd", process.StartInfo.FileName + " " + process.StartInfo.Arguments);
|
|
||||||
|
|
||||||
process.Start ();
|
|
||||||
string host_key = process.StandardOutput.ReadToEnd ().Trim ();
|
|
||||||
process.WaitForExit ();
|
|
||||||
|
|
||||||
if (process.ExitCode == 0 && !string.IsNullOrWhiteSpace (host_key))
|
|
||||||
return host_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private string DeriveFingerprint (string public_key)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
MD5 md5 = new MD5CryptoServiceProvider ();
|
|
||||||
string key = public_key.Split (" ".ToCharArray ()) [2];
|
|
||||||
byte [] b64_bytes = Convert.FromBase64String (key);
|
|
||||||
byte [] md5_bytes = md5.ComputeHash (b64_bytes);
|
|
||||||
string fingerprint = BitConverter.ToString (md5_bytes);
|
|
||||||
|
|
||||||
return fingerprint.ToLower ().Replace ("-", ":");
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
SparkleLogger.LogInfo ("Fetcher", "Failed creating fingerprint: " + e.Message + " " + e.StackTrace);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void AcceptHostKey (string host_key, bool warn)
|
|
||||||
{
|
|
||||||
string ssh_config_path = Path.Combine (SparkleConfig.DefaultConfig.HomePath, ".ssh");
|
|
||||||
string known_hosts_file_path = Path.Combine (ssh_config_path, "known_hosts");
|
|
||||||
|
|
||||||
if (!File.Exists (known_hosts_file_path)) {
|
|
||||||
if (!Directory.Exists (ssh_config_path))
|
|
||||||
Directory.CreateDirectory (ssh_config_path);
|
|
||||||
|
|
||||||
File.Create (known_hosts_file_path).Close ();
|
|
||||||
}
|
|
||||||
|
|
||||||
string host = RemoteUrl.Host;
|
|
||||||
string known_hosts = File.ReadAllText (known_hosts_file_path);
|
|
||||||
string [] known_hosts_lines = File.ReadAllLines (known_hosts_file_path);
|
|
||||||
|
|
||||||
foreach (string line in known_hosts_lines) {
|
|
||||||
if (line.StartsWith (host + " "))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (known_hosts.EndsWith ("\n"))
|
|
||||||
File.AppendAllText (known_hosts_file_path, host_key + "\n");
|
|
||||||
else
|
|
||||||
File.AppendAllText (known_hosts_file_path, "\n" + host_key + "\n");
|
|
||||||
|
|
||||||
SparkleLogger.LogInfo ("Auth", "Accepted host key for " + host);
|
|
||||||
|
|
||||||
if (warn)
|
|
||||||
this.warnings.Add ("The following host key has been accepted:\n" + DeriveFingerprint (host_key));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static string GetBackend (string address)
|
public static string GetBackend (string address)
|
||||||
{
|
{
|
||||||
if (address.StartsWith ("ssh+")) {
|
if (address.StartsWith ("ssh+")) {
|
||||||
|
|
138
SparkleLib/SparkleFetcherSSH.cs
Normal file
138
SparkleLib/SparkleFetcherSSH.cs
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace SparkleLib {
|
||||||
|
|
||||||
|
public abstract class SparkleFetcherSSH : SparkleFetcherBase {
|
||||||
|
|
||||||
|
public SparkleFetcherSSH (SparkleFetcherInfo info) : base (info)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override bool Fetch ()
|
||||||
|
{
|
||||||
|
if (!RemoteUrl.Scheme.StartsWith ("http")) {
|
||||||
|
string host_key = FetchHostKey ();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty (RemoteUrl.Host) || host_key == null) {
|
||||||
|
SparkleLogger.LogInfo ("Auth", "Could not fetch host key");
|
||||||
|
this.errors.Add ("error: Could not fetch host key");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool warn = true;
|
||||||
|
if (RequiredFingerprint != null) {
|
||||||
|
string host_fingerprint = DeriveFingerprint (host_key);
|
||||||
|
|
||||||
|
if (host_fingerprint == null || !RequiredFingerprint.Equals (host_fingerprint)) {
|
||||||
|
SparkleLogger.LogInfo ("Auth", "Fingerprint doesn't match");
|
||||||
|
this.errors.Add ("error: Host fingerprint doesn't match");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
warn = false;
|
||||||
|
SparkleLogger.LogInfo ("Auth", "Fingerprint matches");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
SparkleLogger.LogInfo ("Auth", "Skipping fingerprint check");
|
||||||
|
}
|
||||||
|
|
||||||
|
AcceptHostKey (host_key, warn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string FetchHostKey ()
|
||||||
|
{
|
||||||
|
SparkleLogger.LogInfo ("Auth", "Fetching host key for " + RemoteUrl.Host);
|
||||||
|
|
||||||
|
Process process = new Process ();
|
||||||
|
process.StartInfo.FileName = "ssh-keyscan";
|
||||||
|
process.StartInfo.WorkingDirectory = SparkleConfig.DefaultConfig.TmpPath;
|
||||||
|
process.StartInfo.UseShellExecute = false;
|
||||||
|
process.StartInfo.RedirectStandardOutput = true;
|
||||||
|
process.StartInfo.CreateNoWindow = true;
|
||||||
|
process.EnableRaisingEvents = true;
|
||||||
|
|
||||||
|
string [] key_types = {"rsa", "dsa", "ecdsa"};
|
||||||
|
|
||||||
|
foreach (string key_type in key_types) {
|
||||||
|
if (RemoteUrl.Port < 1)
|
||||||
|
process.StartInfo.Arguments = "-t " + key_type + " -p 22 " + RemoteUrl.Host;
|
||||||
|
else
|
||||||
|
process.StartInfo.Arguments = "-t " + key_type + " -p " + RemoteUrl.Port + " " + RemoteUrl.Host;
|
||||||
|
|
||||||
|
SparkleLogger.LogInfo ("Cmd", process.StartInfo.FileName + " " + process.StartInfo.Arguments);
|
||||||
|
|
||||||
|
process.Start ();
|
||||||
|
string host_key = process.StandardOutput.ReadToEnd ().Trim ();
|
||||||
|
process.WaitForExit ();
|
||||||
|
|
||||||
|
if (process.ExitCode == 0 && !string.IsNullOrWhiteSpace (host_key))
|
||||||
|
return host_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string DeriveFingerprint (string public_key)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
MD5 md5 = new MD5CryptoServiceProvider ();
|
||||||
|
string key = public_key.Split (" ".ToCharArray ()) [2];
|
||||||
|
byte [] b64_bytes = Convert.FromBase64String (key);
|
||||||
|
byte [] md5_bytes = md5.ComputeHash (b64_bytes);
|
||||||
|
string fingerprint = BitConverter.ToString (md5_bytes);
|
||||||
|
|
||||||
|
return fingerprint.ToLower ().Replace ("-", ":");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
SparkleLogger.LogInfo ("Fetcher", "Failed creating fingerprint: " + e.Message + " " + e.StackTrace);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void AcceptHostKey (string host_key, bool warn)
|
||||||
|
{
|
||||||
|
string ssh_config_path = Path.Combine (SparkleConfig.DefaultConfig.HomePath, ".ssh");
|
||||||
|
string known_hosts_file_path = Path.Combine (ssh_config_path, "known_hosts");
|
||||||
|
|
||||||
|
if (!File.Exists (known_hosts_file_path)) {
|
||||||
|
if (!Directory.Exists (ssh_config_path))
|
||||||
|
Directory.CreateDirectory (ssh_config_path);
|
||||||
|
|
||||||
|
File.Create (known_hosts_file_path).Close ();
|
||||||
|
}
|
||||||
|
|
||||||
|
string host = RemoteUrl.Host;
|
||||||
|
string known_hosts = File.ReadAllText (known_hosts_file_path);
|
||||||
|
string [] known_hosts_lines = File.ReadAllLines (known_hosts_file_path);
|
||||||
|
|
||||||
|
foreach (string line in known_hosts_lines) {
|
||||||
|
if (line.StartsWith (host + " "))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (known_hosts.EndsWith ("\n"))
|
||||||
|
File.AppendAllText (known_hosts_file_path, host_key + "\n");
|
||||||
|
else
|
||||||
|
File.AppendAllText (known_hosts_file_path, "\n" + host_key + "\n");
|
||||||
|
|
||||||
|
SparkleLogger.LogInfo ("Auth", "Accepted host key for " + host);
|
||||||
|
|
||||||
|
if (warn)
|
||||||
|
this.warnings.Add ("The following host key has been accepted:\n" + DeriveFingerprint (host_key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,7 @@
|
||||||
<Compile Include="SparkleUser.cs" />
|
<Compile Include="SparkleUser.cs" />
|
||||||
<Compile Include="SparkleLogger.cs" />
|
<Compile Include="SparkleLogger.cs" />
|
||||||
<Compile Include="Defines.cs" />
|
<Compile Include="Defines.cs" />
|
||||||
|
<Compile Include="SparkleFetcherSSH.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<ProjectExtensions>
|
<ProjectExtensions>
|
||||||
|
|
|
@ -211,13 +211,6 @@ namespace SparkleShare {
|
||||||
else
|
else
|
||||||
name += "'s";
|
name += "'s";
|
||||||
|
|
||||||
string link_code_file_path = Path.Combine (FoldersPath, name + " link code.txt");
|
|
||||||
|
|
||||||
// Create an easily accessible copy of the public
|
|
||||||
// key in the user's SparkleShare folder
|
|
||||||
if (File.Exists (public_key_file_path) && !File.Exists (link_code_file_path))
|
|
||||||
File.Copy (public_key_file_path, link_code_file_path, true);
|
|
||||||
|
|
||||||
CurrentUser.PublicKey = File.ReadAllText (public_key_file_path);
|
CurrentUser.PublicKey = File.ReadAllText (public_key_file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue