diff --git a/Duplicati Console.sln b/Duplicati Console.sln index 238311cf4..49b2af1a3 100644 --- a/Duplicati Console.sln +++ b/Duplicati Console.sln @@ -5,11 +5,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Main", "Duplicati EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.CommandLine", "Duplicati\CommandLine\Duplicati.CommandLine.csproj", "{81765A64-3661-4E3E-B850-2F6F87A51F74}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackendInterface", "Duplicati\Backend\BackendInterface\BackendInterface.csproj", "{994F3D0A-E91E-4EEE-80EE-064485E09909}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Backend.BackendInterface", "Duplicati\Backend\BackendInterface\Duplicati.Backend.BackendInterface.csproj", "{994F3D0A-E91E-4EEE-80EE-064485E09909}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackendLoader", "Duplicati\Backend\BackendLoader\BackendLoader.csproj", "{0CA86ECF-5BEC-4909-B4F6-110A03B30B92}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Backend.BackendLoader", "Duplicati\Backend\BackendLoader\Duplicati.Backend.BackendLoader.csproj", "{0CA86ECF-5BEC-4909-B4F6-110A03B30B92}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "File", "Duplicati\Backend\File\File.csproj", "{FC9B7611-836F-4127-8B44-A7C31F506807}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Backend.File", "Duplicati\Backend\File\Duplicati.Backend.File.csproj", "{FC9B7611-836F-4127-8B44-A7C31F506807}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Core", "Duplicati\Core\Duplicati.Core.csproj", "{DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65}" EndProject @@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.SharpRSync", "Dup EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Logging", "Duplicati\Logging\Duplicati.Logging.csproj", "{D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Duplicati.Encryption", "Duplicati\Encryption\Duplicati.Encryption.csproj", "{94484FDB-2EFA-4CF0-9BE6-A561157B4F87}" +EndProject Global GlobalSection(SubversionScc) = preSolution Svn-Managed = True @@ -65,6 +67,10 @@ Global {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Debug|Any CPU.Build.0 = Debug|Any CPU {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|Any CPU.ActiveCfg = Release|Any CPU {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798}.Release|Any CPU.Build.0 = Release|Any CPU + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Duplicati/Backend/BackendInterface/BackendInterface.csproj b/Duplicati/Backend/BackendInterface/Duplicati.Backend.BackendInterface.csproj similarity index 100% rename from Duplicati/Backend/BackendInterface/BackendInterface.csproj rename to Duplicati/Backend/BackendInterface/Duplicati.Backend.BackendInterface.csproj diff --git a/Duplicati/Backend/BackendLoader/BackendLoader.cs b/Duplicati/Backend/BackendLoader/BackendLoader.cs index fdcac69b2..7a923a1cb 100644 --- a/Duplicati/Backend/BackendLoader/BackendLoader.cs +++ b/Duplicati/Backend/BackendLoader/BackendLoader.cs @@ -100,6 +100,9 @@ namespace Duplicati.Backend string scheme = new Uri(url).Scheme.ToLower(); + if (m_backends == null) + LoadBackends(); + if (m_backends.ContainsKey(scheme)) return (IBackendInterface)Activator.CreateInstance(m_backends[scheme], url, options); else diff --git a/Duplicati/Backend/BackendLoader/BackendLoader.csproj b/Duplicati/Backend/BackendLoader/Duplicati.Backend.BackendLoader.csproj similarity index 91% rename from Duplicati/Backend/BackendLoader/BackendLoader.csproj rename to Duplicati/Backend/BackendLoader/Duplicati.Backend.BackendLoader.csproj index 9a746916a..16eeb5555 100644 --- a/Duplicati/Backend/BackendLoader/BackendLoader.csproj +++ b/Duplicati/Backend/BackendLoader/Duplicati.Backend.BackendLoader.csproj @@ -37,9 +37,9 @@ - + {994F3D0A-E91E-4EEE-80EE-064485E09909} - BackendInterface + Duplicati.Backend.BackendInterface diff --git a/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.csproj b/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.csproj deleted file mode 100644 index 207c909f9..000000000 --- a/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.csproj +++ /dev/null @@ -1,69 +0,0 @@ - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {A0819A66-A2EF-48B1-BA69-14140C6C230E} - Exe - Properties - Duplicati.Backend - DuplicatiBackend - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - {994F3D0A-E91E-4EEE-80EE-064485E09909} - BackendInterface - - - {0CA86ECF-5BEC-4909-B4F6-110A03B30B92} - BackendLoader - - - {FC9B7611-836F-4127-8B44-A7C31F506807} - File - - - {F61679A9-E5DE-468A-B5A4-05F92D0143D2} - FTP - - - {6BA21DCB-1701-4936-B177-3B6D4DE3474E} - SSH - - - - - \ No newline at end of file diff --git a/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.sln b/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.sln deleted file mode 100644 index 0e7f05153..000000000 --- a/Duplicati/Backend/DuplicatiBackend/DuplicatiBackend.sln +++ /dev/null @@ -1,50 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DuplicatiBackend", "DuplicatiBackend.csproj", "{A0819A66-A2EF-48B1-BA69-14140C6C230E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackendInterface", "..\BackendInterface\BackendInterface.csproj", "{994F3D0A-E91E-4EEE-80EE-064485E09909}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FTP", "..\FTP\FTP.csproj", "{F61679A9-E5DE-468A-B5A4-05F92D0143D2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackendLoader", "..\BackendLoader\BackendLoader.csproj", "{0CA86ECF-5BEC-4909-B4F6-110A03B30B92}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SSH", "..\SSH\SSH.csproj", "{6BA21DCB-1701-4936-B177-3B6D4DE3474E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "File", "..\File\File.csproj", "{FC9B7611-836F-4127-8B44-A7C31F506807}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A0819A66-A2EF-48B1-BA69-14140C6C230E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A0819A66-A2EF-48B1-BA69-14140C6C230E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A0819A66-A2EF-48B1-BA69-14140C6C230E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A0819A66-A2EF-48B1-BA69-14140C6C230E}.Release|Any CPU.Build.0 = Release|Any CPU - {994F3D0A-E91E-4EEE-80EE-064485E09909}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {994F3D0A-E91E-4EEE-80EE-064485E09909}.Debug|Any CPU.Build.0 = Debug|Any CPU - {994F3D0A-E91E-4EEE-80EE-064485E09909}.Release|Any CPU.ActiveCfg = Release|Any CPU - {994F3D0A-E91E-4EEE-80EE-064485E09909}.Release|Any CPU.Build.0 = Release|Any CPU - {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F61679A9-E5DE-468A-B5A4-05F92D0143D2}.Release|Any CPU.Build.0 = Release|Any CPU - {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0CA86ECF-5BEC-4909-B4F6-110A03B30B92}.Release|Any CPU.Build.0 = Release|Any CPU - {6BA21DCB-1701-4936-B177-3B6D4DE3474E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6BA21DCB-1701-4936-B177-3B6D4DE3474E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6BA21DCB-1701-4936-B177-3B6D4DE3474E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6BA21DCB-1701-4936-B177-3B6D4DE3474E}.Release|Any CPU.Build.0 = Release|Any CPU - {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FC9B7611-836F-4127-8B44-A7C31F506807}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FC9B7611-836F-4127-8B44-A7C31F506807}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Duplicati/Backend/DuplicatiBackend/Program.cs b/Duplicati/Backend/DuplicatiBackend/Program.cs deleted file mode 100644 index 41d43e105..000000000 --- a/Duplicati/Backend/DuplicatiBackend/Program.cs +++ /dev/null @@ -1,186 +0,0 @@ -#region Disclaimer / License -// Copyright (C) 2008, Kenneth Skovhede -// http://www.hexad.dk, opensource@hexad.dk -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// -#endregion -using System; -using System.Collections.Generic; -using System.Text; - -namespace Duplicati.Backend -{ - - class Program - { - const string HELPMESSAGE = - "Invalid number of arguments.\r\n\r\n" + - "Usage: DuplicatiBackend [options]\r\n\r\n" + - "Operations:\r\n" + - "\tHELP \t: Return this message\r\n" + - "\tBACKENDS \t: List the avalible backends\r\n" + - "\tLIST \t: Return a list of files at the given url\r\n" + - "\tGET \t: Write the file at the given url to stdout\r\n" + - "\tPUT \t: Write the contents of stdin to the given url\r\n" + - "\tDELETE \t: Delete the file at the given url\r\n" + - "\r\n\r\n" + - "Options:\r\n" + - "\t--file= \t: For GET, use filename rather than stdin\r\n" + - " \t: For PUT, use filename rather than stdout\r\n" + - " \t: For LIST, use filename rather than stdout\r\n"; - - static int Main(string[] args) - { - List largs = new List(args); - - Dictionary options = ExtractOptions(largs); - - if (largs.Count < 1) - { - Console.WriteLine(HELPMESSAGE); - return -1; - } - - string operation = args[0].ToUpper(); - if (operation == "HELP") - { - Console.WriteLine(HELPMESSAGE); - return 0; - } - else if (operation == "BACKENDS") - { - Console.WriteLine("Registered backends:\r\n"); - foreach (string b in BackendLoader.Backends) - Console.WriteLine(b + "\t: " + BackendLoader.GetBackend(b).DisplayName); - - return 0; - } - - if (largs.Count != 2) - { - Console.WriteLine(HELPMESSAGE); - return -1; - } - - - string url = largs[1]; - IBackendInterface backend = null; - try - { - backend = new BackendLoader(url); - } - catch (Exception ex) - { - Console.WriteLine(string.Format("Failed to load backend: {0}", ex.Message)); - return -1; - } - - string file = options.ContainsKey("file") ? options["file"] : null; - - System.IO.Stream s = null; - - try - { - switch (operation.Trim().ToUpper()) - { - case "LIST": - if (file == null) - s = Console.OpenStandardOutput(); - else - s = new System.IO.FileStream(file, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None); - - using (System.IO.StreamWriter sw = new System.IO.StreamWriter(s)) - foreach (FileEntry fe in backend.List(url, options)) - sw.WriteLine(fe.Name); - - break; - case "PUT": - if (file == null) - s = Console.OpenStandardInput(); - else - s = new System.IO.FileStream(file, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); - - backend.Put(url, options, s); - break; - case "GET": - if (file == null) - s = Console.OpenStandardOutput(); - else - s = new System.IO.FileStream(file, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None); - Utility.CopyStream(backend.Get(url, options), s, true); - break; - case "DELETE": - backend.Delete(url, options); - break; - - default: - Console.WriteLine(HELPMESSAGE); - return -1; - } - } - catch (Exception ex) - { - Console.WriteLine(string.Format("Failed: {0}", ex.Message)); - return -1; - } - finally - { - if (file != null && s != null) - { - try { s.Close(); } - catch { } - - try { s.Dispose(); } - catch { } - } - - } - return 0; - } - - private static Dictionary ExtractOptions(List args) - { - Dictionary options = new Dictionary(); - - for (int i = 0; i < args.Count; i++) - { - if (args[i].StartsWith("--")) - { - string key = null; - string value = null; - if (args[i].IndexOf("=") > 0) - { - key = args[i].Substring(0, args[i].IndexOf("=")); - value = args[i].Substring(args[i].IndexOf("=") + 1); - } - else - key = args[i]; - - //Skip the leading -- - key = key.Substring(2); - if (!string.IsNullOrEmpty(value) && value.Length > 1 && value.StartsWith("\"") && value.EndsWith("\"")) - value = value.Substring(1, value.Length - 2); - options[key] = value; - - i--; - } - } - - return options; - - } - } -} diff --git a/Duplicati/Backend/DuplicatiBackend/Properties/AssemblyInfo.cs b/Duplicati/Backend/DuplicatiBackend/Properties/AssemblyInfo.cs deleted file mode 100644 index a42134a46..000000000 --- a/Duplicati/Backend/DuplicatiBackend/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,52 +0,0 @@ -#region Disclaimer / License -// Copyright (C) 2008, Kenneth Skovhede -// http://www.hexad.dk, opensource@hexad.dk -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -// -#endregion -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DuplicatiBackend")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("HexaD")] -[assembly: AssemblyProduct("DuplicatiBackend")] -[assembly: AssemblyCopyright("Copyright © HexaD 2008")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("3c3285d4-1f1c-4673-80fa-7b76bab4b909")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Duplicati/Backend/FTP/FTP.csproj b/Duplicati/Backend/FTP/Duplicati.Backend.FTP.csproj similarity index 100% rename from Duplicati/Backend/FTP/FTP.csproj rename to Duplicati/Backend/FTP/Duplicati.Backend.FTP.csproj diff --git a/Duplicati/Backend/File/File.csproj b/Duplicati/Backend/File/Duplicati.Backend.File.csproj similarity index 91% rename from Duplicati/Backend/File/File.csproj rename to Duplicati/Backend/File/Duplicati.Backend.File.csproj index f8f00b0e5..5cacbb04c 100644 --- a/Duplicati/Backend/File/File.csproj +++ b/Duplicati/Backend/File/Duplicati.Backend.File.csproj @@ -41,9 +41,9 @@ {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65} Duplicati.Core - + {994F3D0A-E91E-4EEE-80EE-064485E09909} - BackendInterface + Duplicati.Backend.BackendInterface diff --git a/Duplicati/Backend/SSH/SSH.csproj b/Duplicati/Backend/SSH/Dplicati.Backend.SSH.csproj similarity index 100% rename from Duplicati/Backend/SSH/SSH.csproj rename to Duplicati/Backend/SSH/Dplicati.Backend.SSH.csproj diff --git a/Duplicati/CommandLine/CommandLineParser.cs b/Duplicati/CommandLine/CommandLineParser.cs index cd95de832..4f30a16b7 100644 --- a/Duplicati/CommandLine/CommandLineParser.cs +++ b/Duplicati/CommandLine/CommandLineParser.cs @@ -48,8 +48,8 @@ namespace Duplicati.CommandLine if (!string.IsNullOrEmpty(value) && value.Length > 1 && value.StartsWith("\"") && value.EndsWith("\"")) value = value.Substring(1, value.Length - 2); - //This is a bit ugly, but we want to preserve the order of "include" and "exclude" - options.Add(key, value); + //Last argument overwrites the current + options[key] = value; args.RemoveAt(i); i--; diff --git a/Duplicati/CommandLine/Duplicati.CommandLine.csproj b/Duplicati/CommandLine/Duplicati.CommandLine.csproj index 0279420ae..d58210e88 100644 --- a/Duplicati/CommandLine/Duplicati.CommandLine.csproj +++ b/Duplicati/CommandLine/Duplicati.CommandLine.csproj @@ -39,9 +39,9 @@ - + {FC9B7611-836F-4127-8B44-A7C31F506807} - File + Duplicati.Backend.File {19ECCE09-B5EB-406C-8C57-BAC66997D469} diff --git a/Duplicati/CommandLine/Program.cs b/Duplicati/CommandLine/Program.cs index e7bc05303..1583dc794 100644 --- a/Duplicati/CommandLine/Program.cs +++ b/Duplicati/CommandLine/Program.cs @@ -39,15 +39,113 @@ namespace Duplicati.CommandLine cargs.Add(Core.FilenameFilter.EncodeAsFilter(Core.FilenameFilter.ParseCommandLine(cargs, true))); Dictionary options = CommandLineParser.ExtractOptions(cargs); + //TODO: Print usage window + if (cargs.Count < 2) + throw new Exception("Not enough parameters"); + string source = cargs[0]; string target = cargs[1]; + if (source.Trim().ToLower() == "restore" && cargs.Count == 3) + { + source = target; + target = cargs[2]; + options["restore"] = null; + } + + if (!options.ContainsKey("passphrase")) + if (!string.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("PASSPHRASE"))) + options["passphrase"] = System.Environment.GetEnvironmentVariable("PASSPHRASE"); + if (source.Trim().ToLower() == "list") Console.WriteLine(string.Join("\r\n", Duplicati.Main.Interface.List(target, options))); - else if (source.IndexOf("://") > 0) + else if (source.IndexOf("://") > 0 || options.ContainsKey("restore")) + { + if (!options.ContainsKey("passphrase") && !options.ContainsKey("no-encryption")) + { + string pwd = ReadPassphraseFromConsole(false); + if (pwd == null) + return; + else + options["passphrase"] = pwd; + } + Duplicati.Main.Interface.Restore(source, target, options); + } else + { + if (!options.ContainsKey("passphrase") && !options.ContainsKey("no-encryption")) + { + string pwd = ReadPassphraseFromConsole(true); + if (pwd == null) + return; + else + options["passphrase"] = pwd; + } + Duplicati.Main.Interface.Backup(source, target, options); + } + } + + private static string ReadPassphraseFromConsole(bool confirm) + { + Console.Write("\nEnter passphrase: "); + StringBuilder password = new StringBuilder(); + + while (true) + { + ConsoleKeyInfo k = Console.ReadKey(true); + if (k.Key == ConsoleKey.Enter) + break; + + if (k.Key == ConsoleKey.Escape) + return null; + + password.Append(k.KeyChar); + + //Unix/Linux user know that there is no feedback, Win user gets scared :) + if (System.Environment.OSVersion.Platform != PlatformID.Unix) + Console.Write("*"); + } + + Console.WriteLine(); + + if (confirm) + { + Console.Write("\nConfirm passphrase: "); + StringBuilder password2 = new StringBuilder(); + + while (true) + { + ConsoleKeyInfo k = Console.ReadKey(true); + if (k.Key == ConsoleKey.Enter) + break; + + if (k.Key == ConsoleKey.Escape) + return null; + + password2.Append(k.KeyChar); + + //Unix/Linux user know that there is no feedback, Win user gets scared :) + if (System.Environment.OSVersion.Platform != PlatformID.Unix) + Console.Write("*"); + } + Console.WriteLine(); + + if (password.ToString() != password2.ToString()) + { + Console.WriteLine("The passwords do not match"); + return null; + } + } + + if (password.ToString().Length == 0) + { + Console.WriteLine("Empty passwords are not allowed"); + return null; + } + + return password.ToString(); } } } diff --git a/Duplicati/CommandLine/UnitTest.cs b/Duplicati/CommandLine/UnitTest.cs index a86f1d573..bb0a0199f 100644 --- a/Duplicati/CommandLine/UnitTest.cs +++ b/Duplicati/CommandLine/UnitTest.cs @@ -17,6 +17,9 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // #endregion + +#if DEBUG + using System; using System.Collections.Generic; using System.Text; @@ -43,6 +46,8 @@ namespace Duplicati.CommandLine { Dictionary options = new Dictionary(); options["time-separator"] = "'"; + options["passphrase"] = "secret password!"; + Console.WriteLine("Backing up the full copy: " + folders[0]); using (new Logging.Timer("Full backup of " + folders[0])) Duplicati.Main.Interface.Backup(folders[0], "file://" + tf, options); @@ -166,3 +171,5 @@ namespace Duplicati.CommandLine } } } + +#endif \ No newline at end of file diff --git a/Duplicati/Core/FilenameFilter.cs b/Duplicati/Core/FilenameFilter.cs index 9a65f12bd..7e1a519da 100644 --- a/Duplicati/Core/FilenameFilter.cs +++ b/Duplicati/Core/FilenameFilter.cs @@ -41,15 +41,18 @@ namespace Duplicati.Core /// A parsed ordered set of filters public static List> ParseCommandLine(List commandline, bool remove) { + //TODO: Support the options --include-filelist, --include-globbin-filelist, --include-regexp-filelist + //and the exclude variants (all work on the lines in a file) + List> lst = new List>(); - Regex includeOrExclude = new Regex(@"(?(\-\-include\=)|(\-\-exclude\=)|(\-\-regexp\-include\=)|(\-\-regexp\-exclude\=))(?.+)", RegexOptions.IgnoreCase); + Regex includeOrExclude = new Regex(@"(?(\-\-include\=)|(\-\-exclude\=)|(\-\-include\-regexp\=)|(\-\-exclude\-regexp\=))(?.+)", RegexOptions.IgnoreCase); for (int i = 0; i < commandline.Count; i++ ) { string s = commandline[i]; Match m = includeOrExclude.Match(s.ToLower()); if (m.Success) { - bool include = m.Groups["prefix"].Value.ToLower() == "--include=" || m.Groups["prefix"].Value.ToLower() == "--regexp-include="; + bool include = m.Groups["prefix"].Value.ToLower() == "--include=" || m.Groups["prefix"].Value.ToLower() == "--include-regexp="; string cmd = m.Groups["content"].Value; if (!m.Groups["prefix"].Value.ToLower().StartsWith("--regexp")) cmd = ConvertGlobbingToRegExp(cmd); diff --git a/Duplicati/Core/Sizeparser.cs b/Duplicati/Core/Sizeparser.cs index b232898f0..296dba57b 100644 --- a/Duplicati/Core/Sizeparser.cs +++ b/Duplicati/Core/Sizeparser.cs @@ -1,3 +1,22 @@ +#region Disclaimer / License +// Copyright (C) 2008, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion using System; using System.Collections.Generic; using System.Text; diff --git a/Duplicati/Core/TempFile.cs b/Duplicati/Core/TempFile.cs index a96ece0a7..cdbb82b12 100644 --- a/Duplicati/Core/TempFile.cs +++ b/Duplicati/Core/TempFile.cs @@ -31,7 +31,7 @@ namespace Duplicati.Core private string m_path; public TempFile() - : this(System.IO.Path.GetTempFileName()) + : this(System.IO.Path.Combine(TempFolder.SystemTempPath, System.IO.Path.GetRandomFileName())) { } @@ -39,7 +39,8 @@ namespace Duplicati.Core { m_path = path; if (!System.IO.File.Exists(m_path)) - System.IO.File.Create(m_path); + using (System.IO.File.Create(m_path)) + { /*Dispose it immediately*/ } } public static implicit operator string(TempFile path) diff --git a/Duplicati/Core/TempFolder.cs b/Duplicati/Core/TempFolder.cs index ca877f6d2..968520909 100644 --- a/Duplicati/Core/TempFolder.cs +++ b/Duplicati/Core/TempFolder.cs @@ -31,7 +31,7 @@ namespace Duplicati.Core private string m_folder; public TempFolder() - : this(System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName())) + : this(System.IO.Path.Combine(SystemTempPath, System.IO.Path.GetRandomFileName())) { } @@ -67,5 +67,22 @@ namespace Duplicati.Core } #endregion + + private static string m_system_temp_dir = null; + + /// + /// Gets or sets the global temporary path used to store temporary files. + /// Set to null to use the system default. + /// + public static string SystemTempPath + { + get { return m_system_temp_dir == null ? System.IO.Path.GetTempPath() : m_system_temp_dir; } + set + { + if (!System.IO.Directory.Exists(value)) + throw new Exception("Temporary folder does not exist: " + value); + m_system_temp_dir = value; + } + } } } diff --git a/Duplicati/Encryption/AESEncryption.cs b/Duplicati/Encryption/AESEncryption.cs index 0e993e057..74b95ef6a 100644 --- a/Duplicati/Encryption/AESEncryption.cs +++ b/Duplicati/Encryption/AESEncryption.cs @@ -1,3 +1,22 @@ +#region Disclaimer / License +// Copyright (C) 2008, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion using System; using System.Collections.Generic; using System.Text; @@ -62,8 +81,11 @@ namespace Duplicati.Encryption throw new Exception("Useless encryption detected"); System.Security.Cryptography.ICryptoTransform ct = m_instance.CreateEncryptor(); - using (System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(input, ct, System.Security.Cryptography.CryptoStreamMode.Write)) - Core.Utility.CopyStream(cs, output); + using (System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(output, ct, System.Security.Cryptography.CryptoStreamMode.Write)) + { + Core.Utility.CopyStream(input, cs); + cs.FlushFinalBlock(); + } } public override void Decrypt(System.IO.Stream input, System.IO.Stream output) diff --git a/Duplicati/Encryption/Duplicati.Encryption.csproj b/Duplicati/Encryption/Duplicati.Encryption.csproj index 3fee9ef5d..8e6b1d132 100644 --- a/Duplicati/Encryption/Duplicati.Encryption.csproj +++ b/Duplicati/Encryption/Duplicati.Encryption.csproj @@ -34,12 +34,21 @@ + + + {994F3D0A-E91E-4EEE-80EE-064485E09909} + Duplicati.Backend.BackendInterface + + + {0CA86ECF-5BEC-4909-B4F6-110A03B30B92} + Duplicati.Backend.BackendLoader + {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65} Duplicati.Core diff --git a/Duplicati/Encryption/EncryptedBackendWrapper.cs b/Duplicati/Encryption/EncryptedBackendWrapper.cs new file mode 100644 index 000000000..d8b8f6097 --- /dev/null +++ b/Duplicati/Encryption/EncryptedBackendWrapper.cs @@ -0,0 +1,105 @@ +#region Disclaimer / License +// Copyright (C) 2008, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System; +using System.Collections.Generic; +using System.Text; + +namespace Duplicati.Encryption +{ + /// + /// Class that wraps a backend and transparently encrypts and decrypts data to and from the backend + /// + public class EncryptedBackendWrapper : Backend.IBackendInterface + { + private Backend.IBackendInterface m_realbackend; + private IEncryption m_encryptionEngine; + + public EncryptedBackendWrapper(string target, Dictionary options) + : this(Backend.BackendLoader.GetBackend(target, options), options) + { + } + + public EncryptedBackendWrapper(Backend.IBackendInterface backend, Dictionary options) + { + if (!options.ContainsKey("passphrase") || string.IsNullOrEmpty(options["passphrase"])) + throw new Exception("No passphrase set"); + + string passphrase = options["passphrase"]; + + m_realbackend = backend; + if (options.ContainsKey("gpg-encryption")) + m_encryptionEngine = new GPGEncryption(passphrase, options.ContainsKey("sign-key") ? options["sign-key"] : null); + else + m_encryptionEngine = new AESEncryption(passphrase); + } + + #region IBackendInterface Members + + public string DisplayName + { + get { return m_realbackend.DisplayName; } + } + + public string ProtocolKey + { + get { return m_realbackend.ProtocolKey; } + } + + public List List() + { + return m_realbackend.List(); + } + + public void Put(string remotename, string filename) + { + remotename += (m_encryptionEngine is AESEncryption ? ".aes" : ".gpg"); + using (Core.TempFile tf = new Duplicati.Core.TempFile()) + { + m_encryptionEngine.Encrypt(filename, tf); + m_realbackend.Put(remotename, tf); + } + } + + public void Get(string remotename, string filename) + { + using (Core.TempFile tf = new Duplicati.Core.TempFile()) + { + m_realbackend.Get(remotename, tf); + m_encryptionEngine.Decrypt(tf, filename); + } + } + + public void Delete(string remotename) + { + m_realbackend.Delete(remotename); + } + + #endregion + + public static Backend.IBackendInterface WrapWithEncryption(Backend.IBackendInterface backend, Dictionary options) + { + if (options.ContainsKey("no-encryption")) + return backend; + else + return new EncryptedBackendWrapper(backend, options); + } + + } +} diff --git a/Duplicati/Encryption/EncryptionBase.cs b/Duplicati/Encryption/EncryptionBase.cs index 70a11275a..71944a9a7 100644 --- a/Duplicati/Encryption/EncryptionBase.cs +++ b/Duplicati/Encryption/EncryptionBase.cs @@ -1,3 +1,22 @@ +#region Disclaimer / License +// Copyright (C) 2008, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion using System; using System.Collections.Generic; using System.Text; diff --git a/Duplicati/Encryption/GPGEncryption.cs b/Duplicati/Encryption/GPGEncryption.cs index 5fac85aed..a10aa8256 100644 --- a/Duplicati/Encryption/GPGEncryption.cs +++ b/Duplicati/Encryption/GPGEncryption.cs @@ -1,3 +1,22 @@ +#region Disclaimer / License +// Copyright (C) 2008, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion using System; using System.Collections.Generic; using System.Text; diff --git a/Duplicati/Encryption/IEncryption.cs b/Duplicati/Encryption/IEncryption.cs index 0ca5893a3..c438827e5 100644 --- a/Duplicati/Encryption/IEncryption.cs +++ b/Duplicati/Encryption/IEncryption.cs @@ -1,3 +1,22 @@ +#region Disclaimer / License +// Copyright (C) 2008, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion using System; using System.Collections.Generic; using System.Text; diff --git a/Duplicati/Encryption/Properties/AssemblyInfo.cs b/Duplicati/Encryption/Properties/AssemblyInfo.cs index d99f1bb9f..0b8710da8 100644 --- a/Duplicati/Encryption/Properties/AssemblyInfo.cs +++ b/Duplicati/Encryption/Properties/AssemblyInfo.cs @@ -1,4 +1,23 @@ -using System.Reflection; +#region Disclaimer / License +// Copyright (C) 2008, Kenneth Skovhede +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// +#endregion +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/Duplicati/Main/Duplicati.Main.csproj b/Duplicati/Main/Duplicati.Main.csproj index 6d11324e9..c40417384 100644 --- a/Duplicati/Main/Duplicati.Main.csproj +++ b/Duplicati/Main/Duplicati.Main.csproj @@ -41,13 +41,13 @@ - + {994F3D0A-E91E-4EEE-80EE-064485E09909} - BackendInterface + Duplicati.Backend.BackendInterface - + {0CA86ECF-5BEC-4909-B4F6-110A03B30B92} - BackendLoader + Duplicati.Backend.BackendLoader {19ECCE09-B5EB-406C-8C57-BAC66997D469} @@ -57,6 +57,10 @@ {DE3E5D4C-51AB-4E5E-BEE8-E636CEBFBA65} Duplicati.Core + + {94484FDB-2EFA-4CF0-9BE6-A561157B4F87} + Duplicati.Encryption + {D10A5FC0-11B4-4E70-86AA-8AEA52BD9798} Duplicati.Logging diff --git a/Duplicati/Main/FilenameStrategy.cs b/Duplicati/Main/FilenameStrategy.cs index d359943a5..612cb45d5 100644 --- a/Duplicati/Main/FilenameStrategy.cs +++ b/Duplicati/Main/FilenameStrategy.cs @@ -33,6 +33,8 @@ namespace Duplicati.Main private bool m_useShortFilenames; private string m_timeSeperator; + private const long TICKS_PR_SECOND = 10000000; + public FilenameStrategy(Dictionary options) { //--short-filenames @@ -68,34 +70,38 @@ namespace Duplicati.Main } else { - //TODO: Finish this - byte[] tmp = new byte[4 + 2 + 2 + 2 + 2 + 2]; - return prefix + "-" + t + (full ? "F" : "I") + ""; + return prefix + "-" + t + (full ? "F" : "I") + (time.Ticks / TICKS_PR_SECOND).ToString("X"); } } public BackupEntry DecodeFilename(string prefix, Duplicati.Backend.FileEntry fe) { - //TODO: Implement short filenames + string shortregexp = @"(?%filename%)\-(?(C|S|M)(?(F|I))(?