fetcher: create separate Base, SSH, and Git classes. cleaner abstraction.

This commit is contained in:
Hylke Bons 2013-03-24 23:52:05 +01:00
parent 7bfa8537bd
commit 0fba958e49
6 changed files with 145 additions and 127 deletions

View file

@ -26,6 +26,6 @@ using System.Reflection;
namespace SparkleLib {
public class Defines {
public const string INSTALL_DIR = "/usr/share/sparkleshare";
public const string INSTALL_DIR = "/usr/local/share/sparkleshare";
}
}

View file

@ -25,8 +25,7 @@ using SparkleLib;
namespace SparkleLib.Git {
// Sets up a fetcher that can get remote folders
public class SparkleFetcher : SparkleFetcherBase {
public class SparkleFetcher : SparkleFetcherSSH {
private SparkleGit git;
private bool use_git_bin;

View file

@ -9,6 +9,7 @@ SOURCES = \
SparkleConfig.cs \
SparkleExtensions.cs \
SparkleFetcherBase.cs \
SparkleFetcherSSH.cs \
SparkleListenerBase.cs \
SparkleListenerFactory.cs \
SparkleListenerTcp.cs \

View file

@ -133,44 +133,9 @@ namespace SparkleLib {
SparkleLogger.LogInfo ("Fetcher", TargetFolder + " | Fetching folder: " + RemoteUrl);
if (Directory.Exists (TargetFolder))
if (Directory.Exists (TargetFolder))
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 (() => {
if (Fetch ()) {
Thread.Sleep (500);
@ -223,7 +188,7 @@ namespace SparkleLib {
UriBuilder uri_builder = new UriBuilder (RemoteUrl);
if (RemoteUrl.Scheme.StartsWith ("http")) {
if (RemoteUrl.Scheme.Contains ("http")) {
uri_builder.UserName = "";
uri_builder.Password = "";
}
@ -247,8 +212,7 @@ namespace SparkleLib {
public static string CreateIdentifier ()
{
string random = Path.GetRandomFileName ();
return random.SHA1 ();
return Path.GetRandomFileName ().SHA1 ();
}
@ -271,91 +235,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)
{
if (address.StartsWith ("ssh+")) {

View 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));
}
}
}

View file

@ -43,6 +43,7 @@
<Compile Include="SparkleUser.cs" />
<Compile Include="SparkleLogger.cs" />
<Compile Include="Defines.cs" />
<Compile Include="SparkleFetcherSSH.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>