Beispiel #1
0
        private static void LoadGPGKeyIdAndPassphrase()
        {
            using (var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary <string, string>()))
                using (var ms = new System.IO.MemoryStream())
                    using (var fs = System.IO.File.OpenRead(gpgkeyfile))
                    {
                        try
                        {
                            enc.Decrypt(fs, ms);
                        }
                        catch (System.Security.Cryptography.CryptographicException e)
                        {
                            throw new ArgumentException("Failed to decrypt gpg secret credentials file: {0}\n", e.Message);
                        }

                        ms.Position = 0;

                        using (var sr = new System.IO.StreamReader(ms))
                        {
                            var lines = sr.ReadToEnd().Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                            gpgkeyid         = lines[0];
                            gpgkeypassphrase = lines[1];
                        }
                    }
        }
Beispiel #2
0
        public static byte[] ExportToJSON(IBackup backup, string passphrase)
        {
            Serializable.ImportExportStructure ipx = Program.DataConnection.PrepareBackupForExport(backup);

            byte[] data;
            using (MemoryStream ms = new System.IO.MemoryStream())
            {
                using (StreamWriter sw = new System.IO.StreamWriter(ms))
                {
                    Serializer.SerializeJson(sw, ipx, true);

                    if (!string.IsNullOrWhiteSpace(passphrase))
                    {
                        ms.Position = 0;
                        using (MemoryStream ms2 = new System.IO.MemoryStream())
                        {
                            using (Library.Encryption.AESEncryption m = new Duplicati.Library.Encryption.AESEncryption(passphrase, new Dictionary <string, string>()))
                            {
                                m.Encrypt(ms, ms2);
                                data = ms2.ToArray();
                            }
                        }
                    }
                    else
                    {
                        data = ms.ToArray();
                    }
                }
            }

            return(data);
        }
Beispiel #3
0
        private static Serializable.ImportExportStructure LoadConfiguration(string filename, bool importMetadata, Func <string> getPassword)
        {
            Serializable.ImportExportStructure ipx;

            var buf = new byte[3];

            using (var fs = System.IO.File.OpenRead(filename))
            {
                Duplicati.Library.Utility.Utility.ForceStreamRead(fs, buf, buf.Length);

                fs.Position = 0;
                if (buf[0] == 'A' && buf[1] == 'E' && buf[2] == 'S')
                {
                    using (var m = new Duplicati.Library.Encryption.AESEncryption(getPassword(), new Dictionary <string, string>()))
                    {
                        using (var m2 = m.Decrypt(fs))
                        {
                            using (var sr = new System.IO.StreamReader(m2))
                            {
                                ipx = Serializer.Deserialize <Serializable.ImportExportStructure>(sr);
                            }
                        }
                    }
                }
                else
                {
                    using (var sr = new System.IO.StreamReader(fs))
                    {
                        ipx = Serializer.Deserialize <Serializable.ImportExportStructure>(sr);
                    }
                }
            }

            if (ipx.Backup == null)
            {
                throw new Exception("No backup found in document");
            }

            if (ipx.Backup.Metadata == null)
            {
                ipx.Backup.Metadata = new Dictionary <string, string>();
            }

            if (!importMetadata)
            {
                ipx.Backup.Metadata.Clear();
            }

            ipx.Backup.ID     = null;
            ipx.Backup.DBPath = null;

            if (ipx.Schedule != null)
            {
                ipx.Schedule.ID = -1;
            }

            return(ipx);
        }
Beispiel #4
0
        private static void LoadKeyFromFile()
        {
            using (var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary <string, string>()))
                using (var ms = new System.IO.MemoryStream())
                    using (var fs = System.IO.File.OpenRead(keyfile))
                    {
                        enc.Decrypt(fs, ms);
                        ms.Position = 0;

                        using (var sr = new System.IO.StreamReader(ms))
                            privkey.FromXmlString(sr.ReadToEnd());
                    }
        }
Beispiel #5
0
        private void Export(IBackup backup, RequestInfo info)
        {
            var cmdline = Library.Utility.Utility.ParseBool(info.Request.QueryString["cmdline"].Value, false);

            if (cmdline)
            {
                info.OutputOK(new { Command = Runner.GetCommandLine(Runner.CreateTask(DuplicatiOperation.Backup, backup)) });
            }
            else
            {
                var passphrase = info.Request.QueryString["passphrase"].Value;
                var ipx        = Program.DataConnection.PrepareBackupForExport(backup);

                byte[] data;
                using (var ms = new System.IO.MemoryStream())
                    using (var sw = new System.IO.StreamWriter(ms))
                    {
                        Serializer.SerializeJson(sw, ipx, true);

                        if (!string.IsNullOrWhiteSpace(passphrase))
                        {
                            ms.Position = 0;
                            using (var ms2 = new System.IO.MemoryStream())
                                using (var m = new Duplicati.Library.Encryption.AESEncryption(passphrase, new Dictionary <string, string>()))
                                {
                                    m.Encrypt(ms, ms2);
                                    data = ms2.ToArray();
                                }
                        }
                        else
                        {
                            data = ms.ToArray();
                        }
                    }

                var filename = Library.Utility.Uri.UrlEncode(backup.Name) + "-duplicati-config.json";
                if (!string.IsNullOrWhiteSpace(passphrase))
                {
                    filename += ".aes";
                }

                info.Response.ContentLength = data.Length;
                info.Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", filename));
                info.Response.ContentType = "application/octet-stream";

                info.BodyWriter.SetOK();
                info.Response.SendHeaders();
                info.Response.SendBody(data);
            }
        }
Beispiel #6
0
        public static int Main(string[] _args)
        {
            var args = new List <string>(_args);
            var opts = Duplicati.Library.Utility.CommandLineParser.ExtractOptions(args);

            string inputfolder;
            string outputfolder;
            string keyfile;
            string manifestfile;
            string keyfilepassword;

            opts.TryGetValue("input", out inputfolder);
            opts.TryGetValue("output", out outputfolder);
            opts.TryGetValue("keyfile", out keyfile);
            opts.TryGetValue("manifest", out manifestfile);
            opts.TryGetValue("keyfile-password", out keyfilepassword);

            var usedoptions = new string[] { "input", "output", "keyfile", "manifest", "keyfile-password" };

            if (string.IsNullOrWhiteSpace(inputfolder))
            {
                Console.WriteLine("Missing input folder");
                return(4);
            }

            if (string.IsNullOrWhiteSpace(outputfolder))
            {
                Console.WriteLine("Missing output folder");
                return(4);
            }

            if (string.IsNullOrWhiteSpace(keyfile))
            {
                Console.WriteLine("Missing keyfile");
                return(4);
            }

            if (!System.IO.Directory.Exists(inputfolder))
            {
                Console.WriteLine("Input folder not found");
                return(4);
            }

            if (string.IsNullOrWhiteSpace(keyfilepassword))
            {
                Console.WriteLine("Enter keyfile passphrase: ");
                keyfilepassword = Console.ReadLine().Trim();
            }

            if (!System.IO.File.Exists(keyfile))
            {
                Console.WriteLine("Keyfile not found, creating new");
                var newkey = System.Security.Cryptography.RSACryptoServiceProvider.Create().ToXmlString(true);
                using (var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary <string, string>()))
                    using (var fs = System.IO.File.OpenWrite(keyfile))
                        using (var ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(newkey)))
                            enc.Encrypt(ms, fs);
            }

            if (!System.IO.Directory.Exists(outputfolder))
            {
                System.IO.Directory.CreateDirectory(outputfolder);
            }

            var privkey = (System.Security.Cryptography.RSACryptoServiceProvider)System.Security.Cryptography.RSACryptoServiceProvider.Create();

            using (var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary <string, string>()))
                using (var ms = new System.IO.MemoryStream())
                    using (var fs = System.IO.File.OpenRead(keyfile))
                    {
                        enc.Decrypt(fs, ms);
                        ms.Position = 0;

                        using (var sr = new System.IO.StreamReader(ms))
                            privkey.FromXmlString(sr.ReadToEnd());
                    }

            if (Duplicati.Library.AutoUpdater.AutoUpdateSettings.SignKey == null || privkey.ToXmlString(false) != Duplicati.Library.AutoUpdater.AutoUpdateSettings.SignKey.ToXmlString(false))
            {
                Console.WriteLine("The public key in the project is not the same as the public key from the file");
                Console.WriteLine("Try setting the key to: ");
                Console.WriteLine(privkey.ToXmlString(false));
                return(5);
            }

            Duplicati.Library.AutoUpdater.UpdateInfo updateInfo;

            using (var fs = System.IO.File.OpenRead(manifestfile))
                using (var sr = new System.IO.StreamReader(fs))
                    using (var jr = new Newtonsoft.Json.JsonTextReader(sr))
                        updateInfo = new Newtonsoft.Json.JsonSerializer().Deserialize <Duplicati.Library.AutoUpdater.UpdateInfo>(jr);


            var isopts = new Dictionary <string, string>(opts, StringComparer.InvariantCultureIgnoreCase);

            foreach (var usedopt in usedoptions)
            {
                isopts.Remove(usedopt);
            }

            foreach (var k in updateInfo.GetType().GetFields())
            {
                if (isopts.ContainsKey(k.Name))
                {
                    try
                    {
                        //Console.WriteLine("Setting {0} to {1}", k.Name, isopts[k.Name]);
                        if (k.FieldType == typeof(string[]))
                        {
                            k.SetValue(updateInfo, isopts[k.Name].Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
                        }
                        else if (k.FieldType == typeof(Version))
                        {
                            k.SetValue(updateInfo, new Version(isopts[k.Name]));
                        }
                        else if (k.FieldType == typeof(int))
                        {
                            k.SetValue(updateInfo, int.Parse(isopts[k.Name]));
                        }
                        else if (k.FieldType == typeof(long))
                        {
                            k.SetValue(updateInfo, long.Parse(isopts[k.Name]));
                        }
                        else
                        {
                            k.SetValue(updateInfo, isopts[k.Name]);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Failed setting {0} to {1}: {2}", k.Name, isopts[k.Name], ex.Message);
                    }

                    isopts.Remove(k.Name);
                }
            }

            foreach (var opt in isopts)
            {
                Console.WriteLine("Warning! unused option: {0} = {1}", opt.Key, opt.Value);
            }

            using (var tf = new Duplicati.Library.Utility.TempFile())
            {
                using (var fs = System.IO.File.OpenWrite(tf))
                    using (var tw = new System.IO.StreamWriter(fs))
                        new Newtonsoft.Json.JsonSerializer().Serialize(tw, updateInfo);

                Duplicati.Library.AutoUpdater.UpdaterManager.CreateUpdatePackage(privkey, inputfolder, outputfolder, tf);
            }

            return(0);
        }
Beispiel #7
0
        public static int Main(string[] _args)
        {
            var args = new List<string>(_args);
            var opts = Duplicati.Library.Utility.CommandLineParser.ExtractOptions(args);

            string inputfolder;
            string outputfolder;
            string keyfile;
            string manifestfile;
            string keyfilepassword;
			string gpgkeyfile;
			string gpgpath;

            opts.TryGetValue("input", out inputfolder);
            opts.TryGetValue("output", out outputfolder);
            opts.TryGetValue("keyfile", out keyfile);
            opts.TryGetValue("manifest", out manifestfile);
            opts.TryGetValue("keyfile-password", out keyfilepassword);
			opts.TryGetValue("gpgkeyfile", out gpgkeyfile);
			opts.TryGetValue("gpgpath", out gpgpath);

			var usedoptions = new string[] { "input", "output", "keyfile", "manifest", "keyfile-password", "gpgkeyfile", "gpgpath" };

            if (string.IsNullOrWhiteSpace(inputfolder))
            {
                Console.WriteLine("Missing input folder");
                return 4;
            }

            if (string.IsNullOrWhiteSpace(outputfolder))
            {
                Console.WriteLine("Missing output folder");
                return 4;
            }

            if (string.IsNullOrWhiteSpace(keyfile))
            {
                Console.WriteLine("Missing keyfile");
                return 4;
            }

            if (!System.IO.Directory.Exists(inputfolder))
            {
                Console.WriteLine("Input folder not found");
                return 4;
            }

            if (string.IsNullOrWhiteSpace(keyfilepassword))
            {
                Console.WriteLine("Enter keyfile passphrase: ");
                keyfilepassword = Console.ReadLine().Trim();
            }

            if (!System.IO.File.Exists(keyfile))
            {
                Console.WriteLine("Keyfile not found, creating new");
                var newkey = System.Security.Cryptography.RSACryptoServiceProvider.Create().ToXmlString(true);
                using (var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary<string, string>()))
                using (var fs = System.IO.File.OpenWrite(keyfile))
                using (var ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(newkey)))
                    enc.Encrypt(ms, fs);
            }

            if (!System.IO.Directory.Exists(outputfolder))
                System.IO.Directory.CreateDirectory(outputfolder);

            var privkey = (System.Security.Cryptography.RSACryptoServiceProvider)System.Security.Cryptography.RSACryptoServiceProvider.Create();

            using(var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary<string, string>()))
            using(var ms = new System.IO.MemoryStream())
            using(var fs = System.IO.File.OpenRead(keyfile))
            {
                enc.Decrypt(fs, ms);
                ms.Position = 0;

                using(var sr = new System.IO.StreamReader(ms))
                    privkey.FromXmlString(sr.ReadToEnd());
            }

            if (Duplicati.Library.AutoUpdater.AutoUpdateSettings.SignKey == null || privkey.ToXmlString(false) != Duplicati.Library.AutoUpdater.AutoUpdateSettings.SignKey.ToXmlString(false))
            {
                Console.WriteLine("The public key in the project is not the same as the public key from the file");
                Console.WriteLine("Try setting the key to: ");
                Console.WriteLine(privkey.ToXmlString(false));
                return 5;
            }


			string gpgkeyid = null;
			string gpgkeypassphrase = null;

			if (string.IsNullOrWhiteSpace(gpgkeyfile))
			{
				Console.WriteLine("No gpgfile, skipping GPG signature files");
			}
			else if (!System.IO.File.Exists(gpgkeyfile))
			{
				Console.WriteLine("Missing gpgfile");
				return 6;
			}
			else
			{
				using(var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary<string, string>()))
				using(var ms = new System.IO.MemoryStream())
				using(var fs = System.IO.File.OpenRead(gpgkeyfile))
				{
					enc.Decrypt(fs, ms);
					ms.Position = 0;

					// No real format, just two lines
					using (var sr = new System.IO.StreamReader(ms))
					{
						var lines = sr.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
						gpgkeyid = lines[0];
						gpgkeypassphrase = lines[1];
					}
				}
			}

                
            Duplicati.Library.AutoUpdater.UpdateInfo updateInfo;

            using (var fs = System.IO.File.OpenRead(manifestfile))
            using (var sr = new System.IO.StreamReader(fs))
            using (var jr = new Newtonsoft.Json.JsonTextReader(sr))
                updateInfo = new Newtonsoft.Json.JsonSerializer().Deserialize<Duplicati.Library.AutoUpdater.UpdateInfo>(jr);


            var isopts = new Dictionary<string, string>(opts, StringComparer.InvariantCultureIgnoreCase);
            foreach (var usedopt in usedoptions)
                isopts.Remove(usedopt);

            foreach (var k in updateInfo.GetType().GetFields())
                if (isopts.ContainsKey(k.Name))
                {
                    try
                    {
                        //Console.WriteLine("Setting {0} to {1}", k.Name, isopts[k.Name]);
                        if (k.FieldType == typeof(string[]))
                            k.SetValue(updateInfo, isopts[k.Name].Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
                        else if (k.FieldType == typeof(Version))
                            k.SetValue(updateInfo, new Version(isopts[k.Name]));
                        else if (k.FieldType == typeof(int))
                            k.SetValue(updateInfo, int.Parse(isopts[k.Name]));
                        else if (k.FieldType == typeof(long))
                            k.SetValue(updateInfo, long.Parse(isopts[k.Name]));
                        else
                            k.SetValue(updateInfo, isopts[k.Name]);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Failed setting {0} to {1}: {2}", k.Name, isopts[k.Name], ex.Message);
                    }

                    isopts.Remove(k.Name);
                }

                foreach(var opt in isopts)
                    Console.WriteLine("Warning! unused option: {0} = {1}", opt.Key, opt.Value);

            using (var tf = new Duplicati.Library.Utility.TempFile())
            {
                using (var fs = System.IO.File.OpenWrite(tf))
                using (var tw = new System.IO.StreamWriter(fs))
                    new Newtonsoft.Json.JsonSerializer().Serialize(tw, updateInfo);

                Duplicati.Library.AutoUpdater.UpdaterManager.CreateUpdatePackage(privkey, inputfolder, outputfolder, tf);
            }

			if (gpgkeyid != null)
			{
				gpgpath = gpgpath ?? "gpg";
				var srcfile = System.IO.Path.Combine(outputfolder, "package.zip");

				var proc = System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo() {
					FileName = gpgpath,
					Arguments = string.Format("--passphrase-fd 0 --batch --yes --default-key={1} --output \"{0}.sig\" --detach-sig \"{0}\"", srcfile, gpgkeyid),
					RedirectStandardInput = true,
					UseShellExecute = false
				});

				proc.StandardInput.WriteLine(gpgkeypassphrase);
				proc.WaitForExit();

				proc = System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo() {
					FileName = gpgpath,
					Arguments = string.Format("--passphrase-fd 0 --batch --yes --default-key={1} --armor --output \"{0}.sig.asc\" --detach-sig \"{0}\"", srcfile, gpgkeyid),
					RedirectStandardInput = true,
					UseShellExecute = false
				});

				proc.StandardInput.WriteLine(gpgkeypassphrase);
				proc.WaitForExit();

			}


            return 0;
        }
Beispiel #8
0
        private void ImportBackup(RequestInfo info)
        {
            var output_template = "<html><body><script type=\"text/javascript\">var rp = null; try { rp = parent['CBM']; } catch (e) {}; rp = rp || alert; rp('MSG');</script></body></html>";
            //output_template = "<html><body><script type=\"text/javascript\">alert('MSG');</script></body></html>";
            try
            {
                var input = info.Request.Form;
                var cmdline = Library.Utility.Utility.ParseBool(input["cmdline"].Value, false);
                output_template = output_template.Replace("CBM", input["callback"].Value);
                if (cmdline)
                {
                    info.Response.ContentType = "text/html";
                    info.BodyWriter.Write(output_template.Replace("MSG", "Import from commandline not yet implemented"));
                }
                else
                {
                    Serializable.ImportExportStructure ipx;

                    var file = info.Request.Form.GetFile("config");
                    if (file == null)
                        throw new Exception("No file uploaded");

                    var buf = new byte[3];
                    using(var fs = System.IO.File.OpenRead(file.Filename))
                    {
                        fs.Read(buf, 0, buf.Length);

                        fs.Position = 0;
                        if (buf[0] == 'A' && buf[1] == 'E' && buf[2] == 'S')
                        {
                            var passphrase = input["passphrase"].Value;
                            using(var m = new Duplicati.Library.Encryption.AESEncryption(passphrase, new Dictionary<string, string>()))
                            using(var m2 = m.Decrypt(fs))
                            using(var sr = new System.IO.StreamReader(m2))
                                ipx = Serializer.Deserialize<Serializable.ImportExportStructure>(sr);
                        }
                        else
                        {
                            using(var sr = new System.IO.StreamReader(fs))
                                ipx = Serializer.Deserialize<Serializable.ImportExportStructure>(sr);
                        }
                    }

                    ipx.Backup.ID = null;
                    ((Database.Backup)ipx.Backup).DBPath = null;

                    if (ipx.Schedule != null)
                        ipx.Schedule.ID = -1;

                    lock(Program.DataConnection.m_lock)
                    {
                        var basename = ipx.Backup.Name;
                        var c = 0;
                        while (c++ < 100 && Program.DataConnection.Backups.Where(x => x.Name.Equals(ipx.Backup.Name, StringComparison.InvariantCultureIgnoreCase)).Any())
                            ipx.Backup.Name = basename + " (" + c.ToString() + ")";

                        if (Program.DataConnection.Backups.Where(x => x.Name.Equals(ipx.Backup.Name, StringComparison.InvariantCultureIgnoreCase)).Any())
                        {
                            info.BodyWriter.SetOK();
                            info.Response.ContentType = "text/html";
                            info.BodyWriter.Write(output_template.Replace("MSG", "There already exists a backup with the name: " + basename.Replace("\'", "\\'")));
                        }

                        Program.DataConnection.AddOrUpdateBackupAndSchedule(ipx.Backup, ipx.Schedule);
                    }

                    info.Response.ContentType = "text/html";
                    info.BodyWriter.Write(output_template.Replace("MSG", "OK"));

                    //bw.OutputOK(new { status = "OK", ID = ipx.Backup.ID });
                }
            }
            catch (Exception ex)
            {
                Program.DataConnection.LogError("", "Failed to import backup", ex);
                info.Response.ContentType = "text/html";
                info.BodyWriter.Write(output_template.Replace("MSG", ex.Message.Replace("\'", "\\'").Replace("\r", "\\r").Replace("\n", "\\n")));
            }
        }
        public static int Main(string[] _args)
        {
            var args = new List <string>(_args);
            var opts = Duplicati.Library.Utility.CommandLineParser.ExtractOptions(args);

            string inputfolder;
            string outputfolder;
            string keyfile;
            string manifestfile;
            string keyfilepassword;
            string gpgkeyfile;
            string gpgpath;

            opts.TryGetValue("input", out inputfolder);
            opts.TryGetValue("output", out outputfolder);
            opts.TryGetValue("keyfile", out keyfile);
            opts.TryGetValue("manifest", out manifestfile);
            opts.TryGetValue("keyfile-password", out keyfilepassword);
            opts.TryGetValue("gpgkeyfile", out gpgkeyfile);
            opts.TryGetValue("gpgpath", out gpgpath);

            var usedoptions = new string[] { "input", "output", "keyfile", "manifest", "keyfile-password", "gpgkeyfile", "gpgpath" };

            if (string.IsNullOrWhiteSpace(inputfolder))
            {
                Console.WriteLine("Missing input folder");
                return(4);
            }

            if (string.IsNullOrWhiteSpace(outputfolder))
            {
                Console.WriteLine("Missing output folder");
                return(4);
            }

            if (string.IsNullOrWhiteSpace(keyfile))
            {
                Console.WriteLine("Missing keyfile");
                return(4);
            }

            if (!System.IO.Directory.Exists(inputfolder))
            {
                Console.WriteLine("Input folder not found");
                return(4);
            }

            if (string.IsNullOrWhiteSpace(keyfilepassword))
            {
                Console.WriteLine("Enter keyfile passphrase: ");
                keyfilepassword = Console.ReadLine().Trim();
            }

            if (!System.IO.File.Exists(keyfile))
            {
                Console.WriteLine("Keyfile not found, creating new");
                var newkey = System.Security.Cryptography.RSACryptoServiceProvider.Create().ToXmlString(true);
                using (var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary <string, string>()))
                    using (var fs = System.IO.File.OpenWrite(keyfile))
                        using (var ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(newkey)))
                            enc.Encrypt(ms, fs);
            }

            if (!System.IO.Directory.Exists(outputfolder))
            {
                System.IO.Directory.CreateDirectory(outputfolder);
            }

            var privkey = (System.Security.Cryptography.RSACryptoServiceProvider)System.Security.Cryptography.RSACryptoServiceProvider.Create();

            using (var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary <string, string>()))
                using (var ms = new System.IO.MemoryStream())
                    using (var fs = System.IO.File.OpenRead(keyfile))
                    {
                        enc.Decrypt(fs, ms);
                        ms.Position = 0;

                        using (var sr = new System.IO.StreamReader(ms))
                            privkey.FromXmlString(sr.ReadToEnd());
                    }

            if (Duplicati.Library.AutoUpdater.AutoUpdateSettings.SignKey == null || privkey.ToXmlString(false) != Duplicati.Library.AutoUpdater.AutoUpdateSettings.SignKey.ToXmlString(false))
            {
                Console.WriteLine("The public key in the project is not the same as the public key from the file");
                Console.WriteLine("Try setting the key to: ");
                Console.WriteLine(privkey.ToXmlString(false));
                return(5);
            }


            string gpgkeyid         = null;
            string gpgkeypassphrase = null;

            if (string.IsNullOrWhiteSpace(gpgkeyfile))
            {
                Console.WriteLine("No gpgfile, skipping GPG signature files");
            }
            else if (!System.IO.File.Exists(gpgkeyfile))
            {
                Console.WriteLine("Missing gpgfile");
                return(6);
            }
            else
            {
                using (var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary <string, string>()))
                    using (var ms = new System.IO.MemoryStream())
                        using (var fs = System.IO.File.OpenRead(gpgkeyfile))
                        {
                            enc.Decrypt(fs, ms);
                            ms.Position = 0;

                            // No real format, just two lines
                            using (var sr = new System.IO.StreamReader(ms))
                            {
                                var lines = sr.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
                                gpgkeyid         = lines[0];
                                gpgkeypassphrase = lines[1];
                            }
                        }
            }


            Duplicati.Library.AutoUpdater.UpdateInfo updateInfo;

            using (var fs = System.IO.File.OpenRead(manifestfile))
                using (var sr = new System.IO.StreamReader(fs))
                    using (var jr = new Newtonsoft.Json.JsonTextReader(sr))
                        updateInfo = new Newtonsoft.Json.JsonSerializer().Deserialize <Duplicati.Library.AutoUpdater.UpdateInfo>(jr);


            var isopts = new Dictionary <string, string>(opts, StringComparer.InvariantCultureIgnoreCase);

            foreach (var usedopt in usedoptions)
            {
                isopts.Remove(usedopt);
            }

            foreach (var k in updateInfo.GetType().GetFields())
            {
                if (isopts.ContainsKey(k.Name))
                {
                    try
                    {
                        //Console.WriteLine("Setting {0} to {1}", k.Name, isopts[k.Name]);
                        if (k.FieldType == typeof(string[]))
                        {
                            k.SetValue(updateInfo, isopts[k.Name].Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
                        }
                        else if (k.FieldType == typeof(Version))
                        {
                            k.SetValue(updateInfo, new Version(isopts[k.Name]));
                        }
                        else if (k.FieldType == typeof(int))
                        {
                            k.SetValue(updateInfo, int.Parse(isopts[k.Name]));
                        }
                        else if (k.FieldType == typeof(long))
                        {
                            k.SetValue(updateInfo, long.Parse(isopts[k.Name]));
                        }
                        else
                        {
                            k.SetValue(updateInfo, isopts[k.Name]);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Failed setting {0} to {1}: {2}", k.Name, isopts[k.Name], ex.Message);
                    }

                    isopts.Remove(k.Name);
                }
            }

            foreach (var opt in isopts)
            {
                Console.WriteLine("Warning! unused option: {0} = {1}", opt.Key, opt.Value);
            }

            using (var tf = new Duplicati.Library.Utility.TempFile())
            {
                using (var fs = System.IO.File.OpenWrite(tf))
                    using (var tw = new System.IO.StreamWriter(fs))
                        new Newtonsoft.Json.JsonSerializer().Serialize(tw, updateInfo);

                Duplicati.Library.AutoUpdater.UpdaterManager.CreateUpdatePackage(privkey, inputfolder, outputfolder, tf);
            }

            if (gpgkeyid != null)
            {
                gpgpath = gpgpath ?? "gpg";
                var srcfile = System.IO.Path.Combine(outputfolder, "package.zip");

                var proc = System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo()
                {
                    FileName              = gpgpath,
                    Arguments             = string.Format("--passphrase-fd 0 --batch --yes --default-key={1} --output \"{0}.sig\" --detach-sig \"{0}\"", srcfile, gpgkeyid),
                    RedirectStandardInput = true,
                    UseShellExecute       = false
                });

                proc.StandardInput.WriteLine(gpgkeypassphrase);
                proc.WaitForExit();

                proc = System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo()
                {
                    FileName              = gpgpath,
                    Arguments             = string.Format("--passphrase-fd 0 --batch --yes --default-key={1} --armor --output \"{0}.sig.asc\" --detach-sig \"{0}\"", srcfile, gpgkeyid),
                    RedirectStandardInput = true,
                    UseShellExecute       = false
                });

                proc.StandardInput.WriteLine(gpgkeypassphrase);
                proc.WaitForExit();
            }


            return(0);
        }
Beispiel #10
0
        private void Export(IBackup backup, RequestInfo info)
        {
            var cmdline = Library.Utility.Utility.ParseBool(info.Request.QueryString["cmdline"].Value, false);
            if (cmdline)
            {
                info.OutputOK(new { Command = Runner.GetCommandLine(Runner.CreateTask(DuplicatiOperation.Backup, backup)) });
            }
            else
            {
                var passphrase = info.Request.QueryString["passphrase"].Value;
                var ipx = Program.DataConnection.PrepareBackupForExport(backup);

                byte[] data;
                using(var ms = new System.IO.MemoryStream())
                using(var sw = new System.IO.StreamWriter(ms))
                {
                    Serializer.SerializeJson(sw, ipx, true);

                    if (!string.IsNullOrWhiteSpace(passphrase))
                    {
                        ms.Position = 0;
                        using(var ms2 = new System.IO.MemoryStream())
                        using(var m = new Duplicati.Library.Encryption.AESEncryption(passphrase, new Dictionary<string, string>()))
                        {
                            m.Encrypt(ms, ms2);
                            data = ms2.ToArray();
                        }
                    }
                    else
                        data = ms.ToArray();
                }

                var filename = Library.Utility.Uri.UrlEncode(backup.Name) + "-duplicati-config.json";
                if (!string.IsNullOrWhiteSpace(passphrase))
                    filename += ".aes";

                info.Response.ContentLength = data.Length;
                info.Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", filename));
                info.Response.ContentType = "application/octet-stream";

                info.BodyWriter.SetOK();
                info.Response.SendHeaders();
                info.Response.SendBody(data);
            }
        }
Beispiel #11
0
        private void ImportBackup(RequestInfo info)
        {
            var output_template = "<html><body><script type=\"text/javascript\">var rp = null; try { rp = parent['CBM']; } catch (e) {}; rp = rp || alert; rp('MSG');</script></body></html>";

            //output_template = "<html><body><script type=\"text/javascript\">alert('MSG');</script></body></html>";
            try
            {
                var input   = info.Request.Form;
                var cmdline = Library.Utility.Utility.ParseBool(input["cmdline"].Value, false);
                output_template = output_template.Replace("CBM", input["callback"].Value);
                if (cmdline)
                {
                    info.Response.ContentType = "text/html";
                    info.BodyWriter.Write(output_template.Replace("MSG", "Import from commandline not yet implemented"));
                }
                else
                {
                    Serializable.ImportExportStructure ipx;

                    var file = info.Request.Form.GetFile("config");
                    if (file == null)
                    {
                        throw new Exception("No file uploaded");
                    }

                    var buf = new byte[3];
                    using (var fs = System.IO.File.OpenRead(file.Filename))
                    {
                        fs.Read(buf, 0, buf.Length);

                        fs.Position = 0;
                        if (buf[0] == 'A' && buf[1] == 'E' && buf[2] == 'S')
                        {
                            var passphrase = input["passphrase"].Value;
                            using (var m = new Duplicati.Library.Encryption.AESEncryption(passphrase, new Dictionary <string, string>()))
                                using (var m2 = m.Decrypt(fs))
                                    using (var sr = new System.IO.StreamReader(m2))
                                        ipx = Serializer.Deserialize <Serializable.ImportExportStructure>(sr);
                        }
                        else
                        {
                            using (var sr = new System.IO.StreamReader(fs))
                                ipx = Serializer.Deserialize <Serializable.ImportExportStructure>(sr);
                        }
                    }

                    ipx.Backup.ID = null;
                    ((Database.Backup)ipx.Backup).DBPath = null;

                    if (ipx.Schedule != null)
                    {
                        ipx.Schedule.ID = -1;
                    }

                    lock (Program.DataConnection.m_lock)
                    {
                        var basename = ipx.Backup.Name;
                        var c        = 0;
                        while (c++ < 100 && Program.DataConnection.Backups.Where(x => x.Name.Equals(ipx.Backup.Name, StringComparison.InvariantCultureIgnoreCase)).Any())
                        {
                            ipx.Backup.Name = basename + " (" + c.ToString() + ")";
                        }

                        if (Program.DataConnection.Backups.Where(x => x.Name.Equals(ipx.Backup.Name, StringComparison.InvariantCultureIgnoreCase)).Any())
                        {
                            info.BodyWriter.SetOK();
                            info.Response.ContentType = "text/html";
                            info.BodyWriter.Write(output_template.Replace("MSG", "There already exists a backup with the name: " + basename.Replace("\'", "\\'")));
                        }

                        Program.DataConnection.AddOrUpdateBackupAndSchedule(ipx.Backup, ipx.Schedule);
                    }

                    info.Response.ContentType = "text/html";
                    info.BodyWriter.Write(output_template.Replace("MSG", "OK"));

                    //bw.OutputOK(new { status = "OK", ID = ipx.Backup.ID });
                }
            }
            catch (Exception ex)
            {
                Program.DataConnection.LogError("", "Failed to import backup", ex);
                info.Response.ContentType = "text/html";
                info.BodyWriter.Write(output_template.Replace("MSG", ex.Message.Replace("\'", "\\'").Replace("\r", "\\r").Replace("\n", "\\n")));
            }
        }
Beispiel #12
0

        
Beispiel #13
0
        private void ExportBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
            var bk = Program.DataConnection.GetBackup(input["id"].Value);
            if (bk == null)
            {
                ReportError(response, bw, "Invalid or missing backup id");
                return;
            }

            var cmdline = Library.Utility.Utility.ParseBool(input["cmdline"].Value, false);
            if (cmdline)
            {
                bw.OutputOK(new { Command = Runner.GetCommandLine(Runner.CreateTask(DuplicatiOperation.Backup, bk)) });
            }
            else
            {
                var passphrase = input["passphrase"].Value;
                var scheduleId = Program.DataConnection.GetScheduleIDsFromTags(new string[] { "ID=" + bk.ID });

                var ipx = new ImportExportStructure() {
                    CreatedByVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(),
                    Backup = (Database.Backup)bk,
                    Schedule = (Database.Schedule)(scheduleId.Any() ? Program.DataConnection.GetSchedule(scheduleId.First()) : null),
                    DisplayNames = GetSourceNames(bk)
                };

                byte[] data;
                using(var ms = new System.IO.MemoryStream())
                using(var sw = new System.IO.StreamWriter(ms))
                {
                    Serializer.SerializeJson(sw, ipx, true);

                    if (!string.IsNullOrWhiteSpace(passphrase))
                    {
                        ms.Position = 0;
                        using(var ms2 = new System.IO.MemoryStream())
                        using(var m = new Duplicati.Library.Encryption.AESEncryption(passphrase, new Dictionary<string, string>()))
                        {
                            m.Encrypt(ms, ms2);
                            data = ms2.ToArray();
                        }
                    }
                    else
                        data = ms.ToArray();
                }

                var filename = Library.Utility.Uri.UrlEncode(bk.Name) + "-duplicati-config.json";
                if (!string.IsNullOrWhiteSpace(passphrase))
                    filename += ".aes";

                response.ContentLength = data.Length;
                response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", filename));
                response.ContentType = "application/octet-stream";

                bw.SetOK();
                response.SendHeaders();
                response.SendBody(data);
            }
        }
Beispiel #14
0
        private void ExportBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
            var bk = Program.DataConnection.GetBackup(input["id"].Value);
            if (bk == null)
            {
                ReportError(response, bw, "Invalid or missing backup id");
                return;
            }

            var cmdline = Library.Utility.Utility.ParseBool(input["cmdline"].Value, false);
            if (cmdline)
            {
                bw.OutputOK(new { Command = Runner.GetCommandLine(Runner.CreateTask(DuplicatiOperation.Backup, bk)) });
            }
            else
            {
                var passphrase = input["passphrase"].Value;
                var ipx = Program.DataConnection.PrepareBackupForExport(bk);

                byte[] data;
                using(var ms = new System.IO.MemoryStream())
                using(var sw = new System.IO.StreamWriter(ms))
                {
                    Serializer.SerializeJson(sw, ipx, true);

                    if (!string.IsNullOrWhiteSpace(passphrase))
                    {
                        ms.Position = 0;
                        using(var ms2 = new System.IO.MemoryStream())
                        using(var m = new Duplicati.Library.Encryption.AESEncryption(passphrase, new Dictionary<string, string>()))
                        {
                            m.Encrypt(ms, ms2);
                            data = ms2.ToArray();
                        }
                    }
                    else
                        data = ms.ToArray();
                }

                var filename = Library.Utility.Uri.UrlEncode(bk.Name) + "-duplicati-config.json";
                if (!string.IsNullOrWhiteSpace(passphrase))
                    filename += ".aes";

                response.ContentLength = data.Length;
                response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", filename));
                response.ContentType = "application/octet-stream";

                bw.SetOK();
                response.SendHeaders();
                response.SendBody(data);
            }
        }
Beispiel #15
0
using Duplicati.Server.Serialization.Interface;
Beispiel #16
0
        private void ImportBackup(RequestInfo info)
        {
            var output_template = "<html><body><script type=\"text/javascript\">var jso = 'JSO'; var rp = null; try { rp = parent['CBM']; } catch (e) {}; if (rp) { rp('MSG', jso); } else { alert; rp('MSG'); };</script></body></html>";

            //output_template = "<html><body><script type=\"text/javascript\">alert('MSG');</script></body></html>";
            try
            {
                var input           = info.Request.Form;
                var cmdline         = Library.Utility.Utility.ParseBool(input["cmdline"].Value, false);
                var import_metadata = Library.Utility.Utility.ParseBool(input["import_metadata"].Value, false);
                var direct          = Library.Utility.Utility.ParseBool(input["direct"].Value, false);
                output_template = output_template.Replace("CBM", input["callback"].Value);
                if (cmdline)
                {
                    info.Response.ContentType = "text/html";
                    info.BodyWriter.Write(output_template.Replace("MSG", "Import from commandline not yet implemented"));
                }
                else
                {
                    Serializable.ImportExportStructure ipx;

                    var file = info.Request.Form.GetFile("config");
                    if (file == null)
                    {
                        throw new Exception("No file uploaded");
                    }

                    var buf = new byte[3];
                    using (var fs = System.IO.File.OpenRead(file.Filename))
                    {
                        Duplicati.Library.Utility.Utility.ForceStreamRead(fs, buf, buf.Length);

                        fs.Position = 0;
                        if (buf[0] == 'A' && buf[1] == 'E' && buf[2] == 'S')
                        {
                            var passphrase = input["passphrase"].Value;
                            using (var m = new Duplicati.Library.Encryption.AESEncryption(passphrase, new Dictionary <string, string>()))
                                using (var m2 = m.Decrypt(fs))
                                    using (var sr = new System.IO.StreamReader(m2))
                                        ipx = Serializer.Deserialize <Serializable.ImportExportStructure>(sr);
                        }
                        else
                        {
                            using (var sr = new System.IO.StreamReader(fs))
                                ipx = Serializer.Deserialize <Serializable.ImportExportStructure>(sr);
                        }
                    }

                    if (ipx.Backup == null)
                    {
                        throw new Exception("No backup found in document");
                    }

                    if (ipx.Backup.Metadata == null)
                    {
                        ipx.Backup.Metadata = new Dictionary <string, string>();
                    }

                    if (!import_metadata)
                    {
                        ipx.Backup.Metadata.Clear();
                    }

                    ipx.Backup.ID = null;
                    ((Database.Backup)ipx.Backup).DBPath = null;

                    if (ipx.Schedule != null)
                    {
                        ipx.Schedule.ID = -1;
                    }

                    if (direct)
                    {
                        lock (Program.DataConnection.m_lock)
                        {
                            var basename = ipx.Backup.Name;
                            var c        = 0;
                            while (c++ < 100 && Program.DataConnection.Backups.Where(x => x.Name.Equals(ipx.Backup.Name, StringComparison.OrdinalIgnoreCase)).Any())
                            {
                                ipx.Backup.Name = basename + " (" + c.ToString() + ")";
                            }

                            if (Program.DataConnection.Backups.Where(x => x.Name.Equals(ipx.Backup.Name, StringComparison.OrdinalIgnoreCase)).Any())
                            {
                                info.BodyWriter.SetOK();
                                info.Response.ContentType = "text/html";
                                info.BodyWriter.Write(output_template.Replace("MSG", "There already exists a backup with the name: " + basename.Replace("\'", "\\'")));
                            }

                            var err = Program.DataConnection.ValidateBackup(ipx.Backup, ipx.Schedule);
                            if (!string.IsNullOrWhiteSpace(err))
                            {
                                info.ReportClientError(err, System.Net.HttpStatusCode.BadRequest);
                                return;
                            }

                            Program.DataConnection.AddOrUpdateBackupAndSchedule(ipx.Backup, ipx.Schedule);
                        }

                        info.Response.ContentType = "text/html";
                        info.BodyWriter.Write(output_template.Replace("MSG", "OK"));
                    }
                    else
                    {
                        using (var sw = new StringWriter())
                        {
                            Serializer.SerializeJson(sw, ipx, true);
                            output_template = output_template.Replace("'JSO'", sw.ToString());
                        }
                        info.BodyWriter.Write(output_template.Replace("MSG", "Import completed, but a browser issue prevents loading the contents. Try using the direct import method instead."));
                    }
                }
            }
            catch (Exception ex)
            {
                Program.DataConnection.LogError("", "Failed to import backup", ex);
                info.Response.ContentType = "text/html";
                info.BodyWriter.Write(output_template.Replace("MSG", ex.Message.Replace("\'", "\\'").Replace("\r", "\\r").Replace("\n", "\\n")));
            }
        }
Beispiel #17
0
        public static int Main(string[] _args)
        {
            var args = new List <string>(_args);
            var opts = Duplicati.Library.Utility.CommandLineParser.ExtractOptions(args);

            opts.TryGetValue("input", out string inputfolder);
            opts.TryGetValue("output", out string outputfolder);
            opts.TryGetValue("allow-new-key", out string allowNewKey);
            opts.TryGetValue("keyfile", out keyfile);
            opts.TryGetValue("manifest", out string manifestfile);
            opts.TryGetValue("keyfile-password", out keyfilepassword);

            var usedoptions = new [] { "allow-new-key", "input", "output", "keyfile", "manifest", "keyfile-password" };

            if (string.IsNullOrWhiteSpace(inputfolder))
            {
                Console.WriteLine("Missing input folder");
                return(4);
            }

            if (string.IsNullOrWhiteSpace(outputfolder))
            {
                Console.WriteLine("Missing output folder");
                return(4);
            }

            if (string.IsNullOrWhiteSpace(keyfile))
            {
                Console.WriteLine("Missing keyfile");
                return(4);
            }

            if (!System.IO.Directory.Exists(inputfolder))
            {
                Console.WriteLine("Input folder not found");
                return(4);
            }

            if (string.IsNullOrWhiteSpace(keyfilepassword))
            {
                Console.WriteLine("Enter keyfile passphrase: ");
                keyfilepassword = Console.ReadLine().Trim();
            }

            if (!System.IO.File.Exists(keyfile))
            {
                Console.WriteLine("Keyfile not found, creating new");
                var newkey = RSA.Create().ToXmlString(true);
                using (var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary <string, string>()))
                    using (var fs = System.IO.File.OpenWrite(keyfile))
                        using (var ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(newkey)))
                            enc.Encrypt(ms, fs);
            }

            if (!System.IO.Directory.Exists(outputfolder))
            {
                System.IO.Directory.CreateDirectory(outputfolder);
            }

            privkey = (RSACryptoServiceProvider)RSA.Create();

            LoadKeyFromFile();

            if (!Boolean.TryParse(allowNewKey, out Boolean newKeyAllowed) || !newKeyAllowed)
            {
                CompareToManifestPublicKey();
            }

            Duplicati.Library.AutoUpdater.UpdateInfo updateInfo;

            using (var fs = System.IO.File.OpenRead(manifestfile))
                using (var sr = new System.IO.StreamReader(fs))
                    using (var jr = new Newtonsoft.Json.JsonTextReader(sr))
                        updateInfo = new Newtonsoft.Json.JsonSerializer().Deserialize <Duplicati.Library.AutoUpdater.UpdateInfo>(jr);

            var isopts = new Dictionary <string, string>(opts, StringComparer.InvariantCultureIgnoreCase);

            foreach (var usedopt in usedoptions)
            {
                isopts.Remove(usedopt);
            }

            foreach (var k in updateInfo.GetType().GetFields())
            {
                if (!isopts.ContainsKey(k.Name))
                {
                    continue;
                }
                try
                {
                    //Console.WriteLine("Setting {0} to {1}", k.Name, isopts[k.Name]);
                    if (k.FieldType == typeof(string[]))
                    {
                        k.SetValue(updateInfo, isopts[k.Name].Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
                    }
                    else if (k.FieldType == typeof(Version))
                    {
                        k.SetValue(updateInfo, new Version(isopts[k.Name]));
                    }
                    else if (k.FieldType == typeof(int))
                    {
                        k.SetValue(updateInfo, int.Parse(isopts[k.Name]));
                    }
                    else if (k.FieldType == typeof(long))
                    {
                        k.SetValue(updateInfo, long.Parse(isopts[k.Name]));
                    }
                    else
                    {
                        k.SetValue(updateInfo, isopts[k.Name]);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Failed setting {0} to {1}: {2}", k.Name, isopts[k.Name], ex.Message);
                }

                isopts.Remove(k.Name);
            }

            foreach (var opt in isopts)
            {
                Console.WriteLine("Warning! unused option: {0} = {1}", opt.Key, opt.Value);
            }

            using (var tf = new Duplicati.Library.Utility.TempFile())
            {
                using (var fs = System.IO.File.OpenWrite(tf))
                    using (var tw = new System.IO.StreamWriter(fs))
                        new Newtonsoft.Json.JsonSerializer().Serialize(tw, updateInfo);

                Duplicati.Library.AutoUpdater.UpdaterManager.CreateUpdatePackage(privkey, inputfolder, outputfolder, tf);
            }

            return(0);
        }
Beispiel #18
0
        public static int Main(string[] _args)
        {
            var args = new List<string>(_args);
            var opts = Duplicati.Library.Utility.CommandLineParser.ExtractOptions(args);

            string inputfolder;
            string outputfolder;
            string keyfile;
            string manifestfile;
            string keyfilepassword;

            opts.TryGetValue("input", out inputfolder);
            opts.TryGetValue("output", out outputfolder);
            opts.TryGetValue("keyfile", out keyfile);
            opts.TryGetValue("manifest", out manifestfile);
            opts.TryGetValue("keyfile-password", out keyfilepassword);

            var usedoptions = new string[] { "input", "output", "keyfile", "manifest", "keyfile-password" };

            if (string.IsNullOrWhiteSpace(inputfolder))
            {
                Console.WriteLine("Missing input folder");
                return 4;
            }

            if (string.IsNullOrWhiteSpace(outputfolder))
            {
                Console.WriteLine("Missing output folder");
                return 4;
            }

            if (string.IsNullOrWhiteSpace(keyfile))
            {
                Console.WriteLine("Missing keyfile");
                return 4;
            }

            if (!System.IO.Directory.Exists(inputfolder))
            {
                Console.WriteLine("Input folder not found");
                return 4;
            }

            if (string.IsNullOrWhiteSpace(keyfilepassword))
            {
                Console.WriteLine("Enter keyfile passphrase: ");
                keyfilepassword = Console.ReadLine().Trim();
            }

            if (!System.IO.File.Exists(keyfile))
            {
                Console.WriteLine("Keyfile not found, creating new");
                var newkey = System.Security.Cryptography.RSACryptoServiceProvider.Create().ToXmlString(true);
                using (var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary<string, string>()))
                using (var fs = System.IO.File.OpenWrite(keyfile))
                using (var ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(newkey)))
                    enc.Encrypt(ms, fs);
            }

            if (!System.IO.Directory.Exists(outputfolder))
                System.IO.Directory.CreateDirectory(outputfolder);

            var privkey = (System.Security.Cryptography.RSACryptoServiceProvider)System.Security.Cryptography.RSACryptoServiceProvider.Create();

            using(var enc = new Duplicati.Library.Encryption.AESEncryption(keyfilepassword, new Dictionary<string, string>()))
            using(var ms = new System.IO.MemoryStream())
            using(var fs = System.IO.File.OpenRead(keyfile))
            {
                enc.Decrypt(fs, ms);
                ms.Position = 0;

                using(var sr = new System.IO.StreamReader(ms))
                    privkey.FromXmlString(sr.ReadToEnd());
            }

            if (Duplicati.Library.AutoUpdater.AutoUpdateSettings.SignKey == null || privkey.ToXmlString(false) != Duplicati.Library.AutoUpdater.AutoUpdateSettings.SignKey.ToXmlString(false))
            {
                Console.WriteLine("The public key in the project is not the same as the public key from the file");
                Console.WriteLine("Try setting the key to: ");
                Console.WriteLine(privkey.ToXmlString(false));
                return 5;
            }
                
            Duplicati.Library.AutoUpdater.UpdateInfo updateInfo;

            using (var fs = System.IO.File.OpenRead(manifestfile))
            using (var sr = new System.IO.StreamReader(fs))
            using (var jr = new Newtonsoft.Json.JsonTextReader(sr))
                updateInfo = new Newtonsoft.Json.JsonSerializer().Deserialize<Duplicati.Library.AutoUpdater.UpdateInfo>(jr);


            var isopts = new Dictionary<string, string>(opts, StringComparer.InvariantCultureIgnoreCase);
            foreach (var usedopt in usedoptions)
                isopts.Remove(usedopt);

            foreach (var k in updateInfo.GetType().GetFields())
                if (isopts.ContainsKey(k.Name))
                {
                    try
                    {
                        //Console.WriteLine("Setting {0} to {1}", k.Name, isopts[k.Name]);
                        if (k.FieldType == typeof(string[]))
                            k.SetValue(updateInfo, isopts[k.Name].Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
                        else if (k.FieldType == typeof(Version))
                            k.SetValue(updateInfo, new Version(isopts[k.Name]));
                        else if (k.FieldType == typeof(int))
                            k.SetValue(updateInfo, int.Parse(isopts[k.Name]));
                        else if (k.FieldType == typeof(long))
                            k.SetValue(updateInfo, long.Parse(isopts[k.Name]));
                        else
                            k.SetValue(updateInfo, isopts[k.Name]);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Failed setting {0} to {1}: {2}", k.Name, isopts[k.Name], ex.Message);
                    }

                    isopts.Remove(k.Name);
                }

                foreach(var opt in isopts)
                    Console.WriteLine("Warning! unused option: {0} = {1}", opt.Key, opt.Value);

            using (var tf = new Duplicati.Library.Utility.TempFile())
            {
                using (var fs = System.IO.File.OpenWrite(tf))
                using (var tw = new System.IO.StreamWriter(fs))
                    new Newtonsoft.Json.JsonSerializer().Serialize(tw, updateInfo);

                Duplicati.Library.AutoUpdater.UpdaterManager.CreateUpdatePackage(privkey, inputfolder, outputfolder, tf);
            }

            return 0;
        }