public static string OAUTH_LOGIN_URL(string modulename) { var u = new Library.Utility.Uri(OAuthContextSettings.ServerURL); var addr = u.SetPath("").SetQuery((u.Query ?? "") + (string.IsNullOrWhiteSpace(u.Query) ? "" : "&") + "type={0}"); return(string.Format(addr.ToString(), modulename)); }
public void TestWithoutSizeInfo() { var u = new Library.Utility.Uri(TestUtils.GetDefaultTarget()); SizeOmittingBackend.WrappedBackend = u.Scheme; var target = u.SetScheme(new SizeOmittingBackend().ProtocolKey).ToString(); SVNCheckoutTest.RunTest(TestFolders.Take(5).ToArray(), TestOptions, target); }
private void TestConnection(string url, RequestInfo info) { var modules = (from n in Library.DynamicLoader.GenericLoader.Modules where n is Library.Interface.IConnectionModule select n).ToArray(); try { var uri = new Library.Utility.Uri(url); var qp = uri.QueryParameters; var opts = new Dictionary <string, string>(); foreach (var k in qp.Keys.Cast <string>()) { opts[k] = qp[k]; } foreach (var n in modules) { n.Configure(opts); } using (var b = Duplicati.Library.DynamicLoader.BackendLoader.GetBackend(url, new Dictionary <string, string>())) b.Test(); info.OutputOK(); } catch (Duplicati.Library.Interface.FolderMissingException) { info.ReportServerError("missing-folder"); } catch (Duplicati.Library.Utility.SslCertificateValidator.InvalidCertificateException icex) { if (string.IsNullOrWhiteSpace(icex.Certificate)) { info.ReportServerError(icex.Message); } else { info.ReportServerError("incorrect-cert:" + icex.Certificate); } } finally { foreach (var n in modules) { if (n is IDisposable) { ((IDisposable)n).Dispose(); } } } }
private void TestConnection(string url, RequestInfo info) { var modules = (from n in Library.DynamicLoader.GenericLoader.Modules where n is Library.Interface.IConnectionModule select n).ToArray(); try { var uri = new Library.Utility.Uri(url); var qp = uri.QueryParameters; var opts = new Dictionary<string, string>(); foreach(var k in qp.Keys.Cast<string>()) opts[k] = qp[k]; foreach(var n in modules) n.Configure(opts); using(var b = Duplicati.Library.DynamicLoader.BackendLoader.GetBackend(url, new Dictionary<string, string>())) b.Test(); info.OutputOK(); } catch (Duplicati.Library.Interface.FolderMissingException) { info.ReportServerError("missing-folder"); } catch (Duplicati.Library.Utility.SslCertificateValidator.InvalidCertificateException icex) { if (string.IsNullOrWhiteSpace(icex.Certificate)) info.ReportServerError(icex.Message); else info.ReportServerError("incorrect-cert:" + icex.Certificate); } finally { foreach(var n in modules) if (n is IDisposable) ((IDisposable)n).Dispose(); } }
public BackendHandler(Options options, string backendUrl, DatabaseCommon database, StatsCollector stats, ITaskReader taskreader) : base() { m_backendurl = backendUrl; m_database = database; m_options = options; m_backendurl = backendUrl; m_stats = stats; m_taskreader = taskreader; m_backend = DynamicLoader.BackendLoader.GetBackend(backendUrl, options.RawOptions); var shortname = m_backendurl; // Try not to leak hostnames or other information in the error messages try { shortname = new Library.Utility.Uri(shortname).Scheme; } catch { } if (m_backend == null) { throw new Duplicati.Library.Interface.UserInformationException(string.Format("Backend not supported: {0}", shortname), "BackendNotSupported"); } }
/// <summary> /// This function will examine all options passed on the commandline, and test for unsupported or deprecated values. /// Any errors will be logged into the statistics module. /// </summary> /// <param name="log">The log instance</param> private void ValidateOptions(ILogWriter log) { if (m_options.KeepTime.Ticks > 0 && m_options.KeepVersions > 0) { throw new Interface.UserInformationException(string.Format("Setting both --{0} and --{1} is not permitted", "keep-versions", "keep-time")); } if (!string.IsNullOrWhiteSpace(m_options.Prefix) && m_options.Prefix.Contains("-")) { throw new Interface.UserInformationException("The prefix cannot contain hyphens (-)"); } //No point in going through with this if we can't report if (log == null) { return; } //Keep a list of all supplied options Dictionary <string, string> ropts = new Dictionary <string, string>(m_options.RawOptions); //Keep a list of all supported options Dictionary <string, Library.Interface.ICommandLineArgument> supportedOptions = new Dictionary <string, Library.Interface.ICommandLineArgument>(); //There are a few internal options that are not accessible from outside, and thus not listed foreach (string s in Options.InternalOptions) { supportedOptions[s] = null; } //Figure out what module options are supported in the current setup List <Library.Interface.ICommandLineArgument> moduleOptions = new List <Duplicati.Library.Interface.ICommandLineArgument>(); Dictionary <string, string> disabledModuleOptions = new Dictionary <string, string>(); foreach (KeyValuePair <bool, Library.Interface.IGenericModule> m in m_options.LoadedModules) { if (m.Value.SupportedCommands != null) { if (m.Key) { moduleOptions.AddRange(m.Value.SupportedCommands); } else { foreach (Library.Interface.ICommandLineArgument c in m.Value.SupportedCommands) { disabledModuleOptions[c.Name] = m.Value.DisplayName + " (" + m.Value.Key + ")"; if (c.Aliases != null) { foreach (string s in c.Aliases) { disabledModuleOptions[s] = disabledModuleOptions[c.Name]; } } } } } } // Throw url-encoded options into the mix //TODO: This can hide values if both commandline and url-parameters supply the same key var ext = new Library.Utility.Uri(m_backend).QueryParameters; foreach (var k in ext.AllKeys) { ropts[k] = ext[k]; } //Now run through all supported options, and look for deprecated options foreach (IList <Library.Interface.ICommandLineArgument> l in new IList <Library.Interface.ICommandLineArgument>[] { m_options.SupportedCommands, DynamicLoader.BackendLoader.GetSupportedCommands(m_backend), m_options.NoEncryption ? null : DynamicLoader.EncryptionLoader.GetSupportedCommands(m_options.EncryptionModule), moduleOptions, DynamicLoader.CompressionLoader.GetSupportedCommands(m_options.CompressionModule) }) { if (l != null) { foreach (Library.Interface.ICommandLineArgument a in l) { if (supportedOptions.ContainsKey(a.Name) && Array.IndexOf(Options.KnownDuplicates, a.Name.ToLower()) < 0) { log.AddWarning(Strings.Controller.DuplicateOptionNameWarning(a.Name), null); } supportedOptions[a.Name] = a; if (a.Aliases != null) { foreach (string s in a.Aliases) { if (supportedOptions.ContainsKey(s) && Array.IndexOf(Options.KnownDuplicates, s.ToLower()) < 0) { log.AddWarning(Strings.Controller.DuplicateOptionNameWarning(s), null); } supportedOptions[s] = a; } } if (a.Deprecated) { List <string> aliases = new List <string>(); aliases.Add(a.Name); if (a.Aliases != null) { aliases.AddRange(a.Aliases); } foreach (string s in aliases) { if (ropts.ContainsKey(s)) { string optname = a.Name; if (a.Name != s) { optname += " (" + s + ")"; } log.AddWarning(Strings.Controller.DeprecatedOptionUsedWarning(optname, a.DeprecationMessage), null); } } } } } } //Now look for options that were supplied but not supported foreach (string s in ropts.Keys) { if (!supportedOptions.ContainsKey(s)) { if (disabledModuleOptions.ContainsKey(s)) { log.AddWarning(Strings.Controller.UnsupportedOptionDisabledModuleWarning(s, disabledModuleOptions[s]), null); } else { log.AddWarning(Strings.Controller.UnsupportedOptionWarning(s), null); } } } //Look at the value supplied for each argument and see if is valid according to its type foreach (string s in ropts.Keys) { Library.Interface.ICommandLineArgument arg; if (supportedOptions.TryGetValue(s, out arg) && arg != null) { string validationMessage = ValidateOptionValue(arg, s, ropts[s]); if (validationMessage != null) { log.AddWarning(validationMessage, null); } } } //TODO: Based on the action, see if all options are relevant }
private void SendMessages(string message) { Exception ex = null; var waitEvent = new System.Threading.ManualResetEvent(false); var uri = new Library.Utility.Uri(m_username.Contains("://") ? m_username : "******" + m_username); var con = new agsXMPP.XmppClientConnection(uri.Host, uri.Port == -1 ? (uri.Scheme == "https" ? 5223 :5222) : uri.Port); if (uri.Scheme == "https") con.UseSSL = true; var resource = uri.Path ?? ""; if (resource.StartsWith("/")) resource = resource.Substring(1); if (string.IsNullOrWhiteSpace(resource)) resource = "Duplicati"; agsXMPP.ObjectHandler loginDelegate = (sender) => { try { foreach(var recipient in m_to.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)) con.Send(new agsXMPP.protocol.client.Message(recipient, agsXMPP.protocol.client.MessageType.chat, message)); } catch (Exception e) { ex = e; } finally { waitEvent.Set(); } }; agsXMPP.ErrorHandler errorHandler = (sender, e) => { ex = e; waitEvent.Set(); }; agsXMPP.XmppElementHandler loginErroHandler = (sender, e) => { ex = new Exception(string.Format("Failed to log in: {0}", e.ToString())); waitEvent.Set(); }; con.OnLogin += loginDelegate; con.OnError += errorHandler; con.OnAuthError += loginErroHandler; //con.OnBinded += (sender) => {Console.WriteLine("Binded: {0}", sender);}; //con.OnIq += (sender, iq) => {Console.WriteLine("Iq: {0}", iq);}; //con.OnReadXml += (sender, xml) => {Console.WriteLine("ReadXml: {0}", xml);}; //con.OnWriteXml += (sender, xml) => {Console.WriteLine("writeXml: {0}", xml);};; con.Open(uri.Username, string.IsNullOrWhiteSpace(m_password) ? uri.Password : m_password, resource); var timeout = !waitEvent.WaitOne(TimeSpan.FromSeconds(30), true); con.OnLogin -= loginDelegate; con.OnError -= errorHandler; con.OnAuthError -= loginErroHandler; try { con.Close(); } catch { } if (ex != null) throw ex; if (timeout) throw new TimeoutException(Strings.SendJabberMessage.LoginTimeoutError); }
private void SetupCommonOptions(ISetCommonOptions result, ref string[] paths, ref IFilter filter) { m_options.MainAction = result.MainOperation; result.MessageSink = m_messageSink; switch (m_options.MainAction) { case OperationMode.Backup: break; default: //It only makes sense to enable auto-creation if we are writing files. if (!m_options.RawOptions.ContainsKey("disable-autocreate-folder")) { m_options.RawOptions["disable-autocreate-folder"] = "true"; } break; } //Load all generic modules m_options.LoadedModules.Clear(); foreach (Library.Interface.IGenericModule m in DynamicLoader.GenericLoader.Modules) { m_options.LoadedModules.Add(new KeyValuePair <bool, Library.Interface.IGenericModule>(Array.IndexOf <string>(m_options.DisableModules, m.Key.ToLower()) < 0 && (m.LoadAsDefault || Array.IndexOf <string>(m_options.EnableModules, m.Key.ToLower()) >= 0), m)); } // Make the filter read-n-write able in the generic modules var pristinefilter = string.Join(System.IO.Path.PathSeparator.ToString(), FilterExpression.Serialize(filter)); m_options.RawOptions["filter"] = pristinefilter; // Store the URL connection options separately, as these should only be visible to modules implementing IConnectionModule var conopts = new Dictionary <string, string>(m_options.RawOptions); var qp = new Library.Utility.Uri(m_backend).QueryParameters; foreach (var k in qp.Keys) { conopts[(string)k] = qp[(string)k]; } foreach (var mx in m_options.LoadedModules) { if (mx.Key) { if (mx.Value is Library.Interface.IConnectionModule) { mx.Value.Configure(conopts); } else { mx.Value.Configure(m_options.RawOptions); } if (mx.Value is Library.Interface.IGenericSourceModule) { var sourcemodule = (Library.Interface.IGenericSourceModule)mx.Value; if (sourcemodule.ContainFilesForBackup(paths)) { var sourceoptions = sourcemodule.ParseSourcePaths(ref paths, ref pristinefilter, m_options.RawOptions); foreach (var sourceoption in sourceoptions) { m_options.RawOptions[sourceoption.Key] = sourceoption.Value; } } } if (mx.Value is Library.Interface.IGenericCallbackModule) { ((Library.Interface.IGenericCallbackModule)mx.Value).OnStart(result.MainOperation.ToString(), ref m_backend, ref paths); } } } // If the filters were changed by a module, read them back in if (pristinefilter != m_options.RawOptions["filter"]) { filter = FilterExpression.Deserialize(m_options.RawOptions["filter"].Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries)); } m_options.RawOptions.Remove("filter"); // "--filter" is not a supported command line option OperationRunning(true); if (m_options.HasLoglevel) { Library.Logging.Log.LogLevel = m_options.Loglevel; } if (!string.IsNullOrEmpty(m_options.Logfile)) { var path = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(m_options.Logfile)); if (!System.IO.Directory.Exists(path)) { System.IO.Directory.CreateDirectory(path); } m_logfilescope = Logging.Log.StartScope(m_logfile = new Library.Logging.StreamLog(m_options.Logfile)); } result.VerboseErrors = m_options.DebugOutput; result.VerboseOutput = m_options.Verbose; if (m_options.HasTempDir) { Library.Utility.TempFolder.SystemTempPath = m_options.TempDir; if (Library.Utility.Utility.IsClientLinux) { m_resetKeys["TMPDIR"] = Environment.GetEnvironmentVariable("TMPDIR"); Environment.SetEnvironmentVariable("TMPDIR", m_options.TempDir); } else { m_resetKeys["TMP"] = Environment.GetEnvironmentVariable("TMP"); m_resetKeys["TEMP"] = Environment.GetEnvironmentVariable("TEMP"); Environment.SetEnvironmentVariable("TMP", m_options.TempDir); Environment.SetEnvironmentVariable("TEMP", m_options.TempDir); } } if (m_options.HasForcedLocale) { try { var locale = m_options.ForcedLocale; DoGetLocale(out m_resetLocale, out m_resetLocaleUI); m_doResetLocale = true; // Wrap the call to avoid loading issues for the setLocale method DoSetLocale(locale, locale); } catch (Exception ex) // or only: MissingMethodException { Library.Logging.Log.WriteMessage(Strings.Controller.FailedForceLocaleError(ex.Message), Logging.LogMessageType.Warning); m_doResetLocale = false; m_resetLocale = m_resetLocaleUI = null; } } if (!string.IsNullOrEmpty(m_options.ThreadPriority)) { m_resetPriority = System.Threading.Thread.CurrentThread.Priority; System.Threading.Thread.CurrentThread.Priority = Library.Utility.Utility.ParsePriority(m_options.ThreadPriority); } if (string.IsNullOrEmpty(m_options.Dbpath)) { m_options.Dbpath = DatabaseLocator.GetDatabasePath(m_backend, m_options); } ValidateOptions(result); }
public static string GetDatabasePath(string backend, Options options, bool autoCreate = true, bool anyUsername = false) { if (options == null) options = new Options(new Dictionary<string, string>()); if (!string.IsNullOrEmpty(options.Dbpath)) return options.Dbpath; var folder = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Duplicati"); if (!System.IO.Directory.Exists(folder)) System.IO.Directory.CreateDirectory(folder); var file = System.IO.Path.Combine(folder, "dbconfig.json"); List<BackendEntry> configs; if (!System.IO.File.Exists(file)) configs = new List<BackendEntry>(); else configs = Newtonsoft.Json.JsonConvert.DeserializeObject<List<BackendEntry>>(System.IO.File.ReadAllText(file, System.Text.Encoding.UTF8)); var uri = new Library.Utility.Uri(backend); string server = uri.Host; string path = uri.Path; string type = uri.Scheme; int port = uri.Port; string username = uri.Username; string password = uri.Password; string prefix = options.Prefix; if (username == null || password == null) { var sopts = DynamicLoader.BackendLoader.GetSupportedCommands(backend); var ropts = new Dictionary<string, string>(options.RawOptions); foreach(var k in uri.QueryParameters.AllKeys) ropts[k] = uri.QueryParameters[k]; if (sopts != null) { foreach(var o in sopts) { if (username == null && o.Aliases != null && o.Aliases.Contains("auth-username", StringComparer.InvariantCultureIgnoreCase) && ropts.ContainsKey(o.Name)) username = ropts[o.Name]; if (password == null && o.Aliases != null && o.Aliases.Contains("auth-password", StringComparer.InvariantCultureIgnoreCase) && ropts.ContainsKey(o.Name)) password = ropts[o.Name]; } foreach(var o in sopts) { if (username == null && o.Name.Equals("auth-username", StringComparison.InvariantCultureIgnoreCase) && ropts.ContainsKey("auth-username")) username = ropts["auth-username"]; if (password == null && o.Name.Equals("auth-password", StringComparison.InvariantCultureIgnoreCase) && ropts.ContainsKey("auth-password")) password = ropts["auth-password"]; } } } if (password != null) password = Library.Utility.Utility.ByteArrayAsHexString(System.Security.Cryptography.SHA256.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(password + "!" + uri.Scheme + "!" + uri.HostAndPath))); //Now find the one that matches :) var matches = (from n in configs where n.Type == type && //n.Passwordhash == password && n.Username == username && n.Port == port && n.Server == server && n.Path == path && n.Prefix == prefix select n).ToList(); if (matches.Count > 1) throw new Exception(string.Format("Multiple sources found for: {0}", backend)); // Re-select if (matches.Count == 0 && anyUsername && string.IsNullOrEmpty(username)) { matches = (from n in configs where n.Type == type && n.Port == port && n.Server == server && n.Path == path && n.Prefix == prefix select n).ToList(); if (matches.Count > 1) throw new Exception(String.Format("Multiple sources found for \"{0}\", try supplying --{1}", backend, "auth-username")); } if (matches.Count == 0 && !autoCreate) return null; if (matches.Count == 0) { var backupname = options.BackupName; if (string.IsNullOrEmpty(backupname) || backupname == Options.DefaultBackupName) backupname = GenerateRandomName(); else { foreach(var c in System.IO.Path.GetInvalidFileNameChars()) backupname = backupname.Replace(c.ToString(), ""); } var newpath = System.IO.Path.Combine(folder, backupname + ".sqlite"); int max_tries = 100; while (System.IO.File.Exists(newpath) && max_tries-- > 0) newpath = System.IO.Path.Combine(folder, GenerateRandomName()); if (System.IO.File.Exists(newpath)) throw new Exception("Unable to find a unique name for the database, please use --dbpath"); //Create a new one, add it to the list, and save it configs.Add(new BackendEntry() { Type = type, Server = server, Path = path, Prefix = prefix, Username = username, //Passwordhash = password, Port = port, Databasepath = newpath, ParameterFile = null }); var settings = new Newtonsoft.Json.JsonSerializerSettings(); settings.Formatting = Newtonsoft.Json.Formatting.Indented; System.IO.File.WriteAllText(file, Newtonsoft.Json.JsonConvert.SerializeObject(configs, settings), System.Text.Encoding.UTF8); return newpath; } else { return matches[0].Databasepath; } }
{
private void TestBackend(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw) { HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString; if (input["url"] == null || input["url"].Value == null) { ReportError(response, bw, "The url parameter was not set"); return; } var modules = (from n in Library.DynamicLoader.GenericLoader.Modules where n is Library.Interface.IConnectionModule select n).ToArray(); try { var url = input["url"].Value; var uri = new Library.Utility.Uri(url); var qp = uri.QueryParameters; var opts = new Dictionary<string, string>(); foreach(var k in qp.Keys.Cast<string>()) opts[k] = qp[k]; foreach(var n in modules) n.Configure(opts); using(var b = Duplicati.Library.DynamicLoader.BackendLoader.GetBackend(url, new Dictionary<string, string>())) b.Test(); bw.OutputOK(); } catch (Duplicati.Library.Interface.FolderMissingException) { ReportError(response, bw, "missing-folder"); } catch (Duplicati.Library.Utility.SslCertificateValidator.InvalidCertificateException icex) { if (string.IsNullOrWhiteSpace(icex.Certificate)) ReportError(response, bw, icex.Message); else ReportError(response, bw, "incorrect-cert:" + icex.Certificate); } catch (Exception ex) { ReportError(response, bw, ex.Message); } finally { foreach(var n in modules) if (n is IDisposable) ((IDisposable)n).Dispose(); } }
private void SetupCommonOptions(ISetCommonOptions result, ref string[] paths) { m_options.MainAction = result.MainOperation; result.MessageSink = m_messageSink; switch (m_options.MainAction) { case OperationMode.Backup: break; default: //It only makes sense to enable auto-creation if we are writing files. if (!m_options.RawOptions.ContainsKey("disable-autocreate-folder")) { m_options.RawOptions["disable-autocreate-folder"] = "true"; } break; } //Load all generic modules m_options.LoadedModules.Clear(); foreach (Library.Interface.IGenericModule m in DynamicLoader.GenericLoader.Modules) { m_options.LoadedModules.Add(new KeyValuePair <bool, Library.Interface.IGenericModule>(Array.IndexOf <string>(m_options.DisableModules, m.Key.ToLower()) < 0 && (m.LoadAsDefault || Array.IndexOf <string>(m_options.EnableModules, m.Key.ToLower()) >= 0), m)); } var conopts = new Dictionary <string, string>(m_options.RawOptions); var qp = new Library.Utility.Uri(m_backend).QueryParameters; foreach (var k in qp.Keys) { conopts[(string)k] = qp[(string)k]; } foreach (KeyValuePair <bool, Library.Interface.IGenericModule> mx in m_options.LoadedModules) { if (mx.Key) { if (mx.Value is Library.Interface.IConnectionModule) { mx.Value.Configure(conopts); } else { mx.Value.Configure(m_options.RawOptions); } if (mx.Value is Library.Interface.IGenericCallbackModule) { ((Library.Interface.IGenericCallbackModule)mx.Value).OnStart(result.MainOperation.ToString(), ref m_backend, ref paths); } } } OperationRunning(true); if (m_options.HasLoglevel) { Library.Logging.Log.LogLevel = m_options.Loglevel; } if (!string.IsNullOrEmpty(m_options.Logfile)) { m_hasSetLogging = true; var path = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(m_options.Logfile)); if (!System.IO.Directory.Exists(path)) { System.IO.Directory.CreateDirectory(path); } Library.Logging.Log.CurrentLog = new Library.Logging.StreamLog(m_options.Logfile); } result.VerboseErrors = m_options.DebugOutput; result.VerboseOutput = m_options.Verbose; if (m_options.HasTempDir) { Library.Utility.TempFolder.SystemTempPath = m_options.TempDir; } if (!string.IsNullOrEmpty(m_options.ThreadPriority)) { System.Threading.Thread.CurrentThread.Priority = Library.Utility.Utility.ParsePriority(m_options.ThreadPriority); } if (string.IsNullOrEmpty(m_options.Dbpath)) { m_options.Dbpath = DatabaseLocator.GetDatabasePath(m_backend, m_options); } ValidateOptions(result); Library.Logging.Log.WriteMessage(Strings.Controller.StartingOperationMessage(m_options.MainAction), Logging.LogMessageType.Information); }
public RandomErrorBackend(string url, Dictionary <string, string> options) { var u = new Library.Utility.Uri(url).SetScheme(WrappedBackend).ToString(); m_backend = (IStreamingBackend)Library.DynamicLoader.BackendLoader.GetBackend(u, options); }
private void SetupCommonOptions(ISetCommonOptions result, ref string[] paths, ref IFilter filter) { m_options.MainAction = result.MainOperation; result.MessageSink = m_messageSink; switch (m_options.MainAction) { case OperationMode.Backup: break; default: //It only makes sense to enable auto-creation if we are writing files. if (!m_options.RawOptions.ContainsKey("disable-autocreate-folder")) { m_options.RawOptions["disable-autocreate-folder"] = "true"; } break; } //Load all generic modules m_options.LoadedModules.Clear(); foreach (Library.Interface.IGenericModule m in DynamicLoader.GenericLoader.Modules) { m_options.LoadedModules.Add(new KeyValuePair <bool, Library.Interface.IGenericModule>(Array.IndexOf <string>(m_options.DisableModules, m.Key.ToLower()) < 0 && (m.LoadAsDefault || Array.IndexOf <string>(m_options.EnableModules, m.Key.ToLower()) >= 0), m)); } var conopts = new Dictionary <string, string>(m_options.RawOptions); var qp = new Library.Utility.Uri(m_backend).QueryParameters; foreach (var k in qp.Keys) { conopts[(string)k] = qp[(string)k]; } // Make the filter read-n-write able in the generic modules var pristinefilter = conopts["filter"] = string.Join(System.IO.Path.PathSeparator.ToString(), FilterExpression.Serialize(filter)); foreach (KeyValuePair <bool, Library.Interface.IGenericModule> mx in m_options.LoadedModules) { if (mx.Key) { if (mx.Value is Library.Interface.IConnectionModule) { mx.Value.Configure(conopts); } else { mx.Value.Configure(m_options.RawOptions); } if (mx.Value is Library.Interface.IGenericCallbackModule) { ((Library.Interface.IGenericCallbackModule)mx.Value).OnStart(result.MainOperation.ToString(), ref m_backend, ref paths); } } } // If the filters were changed, read them back in if (pristinefilter != conopts["filter"]) { filter = FilterExpression.Deserialize(conopts["filter"].Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries)); } OperationRunning(true); if (m_options.HasLoglevel) { Library.Logging.Log.LogLevel = m_options.Loglevel; } if (!string.IsNullOrEmpty(m_options.Logfile)) { m_hasSetLogging = true; var path = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(m_options.Logfile)); if (!System.IO.Directory.Exists(path)) { System.IO.Directory.CreateDirectory(path); } Library.Logging.Log.CurrentLog = new Library.Logging.StreamLog(m_options.Logfile); } result.VerboseErrors = m_options.DebugOutput; result.VerboseOutput = m_options.Verbose; if (m_options.HasTempDir) { Library.Utility.TempFolder.SystemTempPath = m_options.TempDir; if (Library.Utility.Utility.IsClientLinux) { m_resetKeys["TMPDIR"] = Environment.GetEnvironmentVariable("TMPDIR"); Environment.SetEnvironmentVariable("TMPDIR", m_options.TempDir); } else { m_resetKeys["TMP"] = Environment.GetEnvironmentVariable("TMP"); m_resetKeys["TEMP"] = Environment.GetEnvironmentVariable("TEMP"); Environment.SetEnvironmentVariable("TMP", m_options.TempDir); Environment.SetEnvironmentVariable("TEMP", m_options.TempDir); } } if (m_options.HasForcedLocale) { var locale = m_options.ForcedLocale; m_resetLocale = System.Globalization.CultureInfo.DefaultThreadCurrentCulture; m_resetLocaleUI = System.Globalization.CultureInfo.DefaultThreadCurrentUICulture; m_doResetLocale = true; System.Globalization.CultureInfo.DefaultThreadCurrentCulture = locale; System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = locale; } if (!string.IsNullOrEmpty(m_options.ThreadPriority)) { m_resetPriority = System.Threading.Thread.CurrentThread.Priority; System.Threading.Thread.CurrentThread.Priority = Library.Utility.Utility.ParsePriority(m_options.ThreadPriority); } if (string.IsNullOrEmpty(m_options.Dbpath)) { m_options.Dbpath = DatabaseLocator.GetDatabasePath(m_backend, m_options); } ValidateOptions(result); Library.Logging.Log.WriteMessage(Strings.Controller.StartingOperationMessage(m_options.MainAction), Logging.LogMessageType.Information); }
public static bool DownloadAndUnpackUpdate(UpdateInfo version, Action <double> progress = null) { if (INSTALLDIR == null) { return(false); } var updates = version.RemoteURLS.ToList(); // If alternate update URLs are specified, // we look for packages there as well if (AutoUpdateSettings.UsesAlternateURLs) { var packagepath = new Library.Utility.Uri(updates[0]).Path; var packagename = packagepath.Split('/').Last(); foreach (var alt_url in AutoUpdateSettings.URLs.Reverse()) { var alt_uri = new Library.Utility.Uri(alt_url); var path_components = alt_uri.Path.Split('/'); var path = string.Join("/", path_components.Take(path_components.Count() - 1).Union(new string[] { packagename })); var new_path = alt_uri.SetPath(path); updates.Insert(0, new_path.ToString()); } } using (var tempfile = new Library.Utility.TempFile()) { foreach (var url in updates) { try { Action <long> cb = null; if (progress != null) { cb = (s) => { progress(Math.Min(1.0, Math.Max(0.0, (double)s / version.CompressedSize))); } } ; var wreq = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url); wreq.UserAgent = string.Format("{0} v{1}", APPNAME, SelfVersion.Version); wreq.Headers.Add("X-Install-ID", InstallID); var areq = new Duplicati.Library.Utility.AsyncHttpRequest(wreq); using (var resp = areq.GetResponse()) using (var rss = areq.GetResponseStream()) using (var pgs = new Duplicati.Library.Utility.ProgressReportingStream(rss, version.CompressedSize, cb)) using (var fs = System.IO.File.Open(tempfile, System.IO.FileMode.Create)) Duplicati.Library.Utility.Utility.CopyStream(pgs, fs); var sha256 = System.Security.Cryptography.SHA256.Create(); var md5 = System.Security.Cryptography.MD5.Create(); using (var s = System.IO.File.OpenRead(tempfile)) { if (s.Length != version.CompressedSize) { throw new Exception(string.Format("Invalid file size {0}, expected {1} for {2}", s.Length, version.CompressedSize, url)); } var sha256hash = Convert.ToBase64String(sha256.ComputeHash(s)); if (sha256hash != version.SHA256) { throw new Exception(string.Format("Damaged or corrupted file, sha256 mismatch for {0}", url)); } } using (var s = System.IO.File.OpenRead(tempfile)) { var md5hash = Convert.ToBase64String(md5.ComputeHash(s)); if (md5hash != version.MD5) { throw new Exception(string.Format("Damaged or corrupted file, md5 mismatch for {0}", url)); } } using (var tempfolder = new Duplicati.Library.Utility.TempFolder()) using (var zip = new Duplicati.Library.Compression.FileArchiveZip(tempfile, new Dictionary <string, string>())) { foreach (var file in zip.ListFilesWithSize("")) { if (System.IO.Path.IsPathRooted(file.Key) || file.Key.Trim().StartsWith("..", StringComparison.InvariantCultureIgnoreCase)) { throw new Exception(string.Format("Out-of-place file path detected: {0}", file.Key)); } var targetpath = System.IO.Path.Combine(tempfolder, file.Key); var targetfolder = System.IO.Path.GetDirectoryName(targetpath); if (!System.IO.Directory.Exists(targetfolder)) { System.IO.Directory.CreateDirectory(targetfolder); } using (var zs = zip.OpenRead(file.Key)) using (var fs = System.IO.File.Create(targetpath)) zs.CopyTo(fs); } if (VerifyUnpackedFolder(tempfolder, version)) { var versionstring = TryParseVersion(version.Version).ToString(); var targetfolder = System.IO.Path.Combine(INSTALLDIR, versionstring); if (System.IO.Directory.Exists(targetfolder)) { System.IO.Directory.Delete(targetfolder, true); } System.IO.Directory.CreateDirectory(targetfolder); var tempfolderpath = Duplicati.Library.Utility.Utility.AppendDirSeparator(tempfolder); var tempfolderlength = tempfolderpath.Length; // Would be nice, but does not work :( //System.IO.Directory.Move(tempfolder, targetfolder); foreach (var e in Duplicati.Library.Utility.Utility.EnumerateFileSystemEntries(tempfolder)) { var relpath = e.Substring(tempfolderlength); if (string.IsNullOrWhiteSpace(relpath)) { continue; } var fullpath = System.IO.Path.Combine(targetfolder, relpath); if (relpath.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString())) { System.IO.Directory.CreateDirectory(fullpath); } else { System.IO.File.Copy(e, fullpath); } } // Verification will kick in when we list the installed updates //VerifyUnpackedFolder(targetfolder, version); System.IO.File.WriteAllText(System.IO.Path.Combine(INSTALLDIR, CURRENT_FILE), versionstring); m_hasUpdateInstalled = null; var obsolete = (from n in FindInstalledVersions() where n.Value.Version != version.Version && n.Value.Version != SelfVersion.Version let x = TryParseVersion(n.Value.Version) orderby x descending select n).Skip(1).ToArray(); foreach (var f in obsolete) { try { System.IO.Directory.Delete(f.Key, true); } catch { } } return(true); } else { throw new Exception(string.Format("Unable to verify unpacked folder for url: {0}", url)); } } } catch (Exception ex) { if (OnError != null) { OnError(ex); } } } } return(false); }
public SizeOmittingBackend(string url, Dictionary<string, string> options) { var u = new Library.Utility.Uri(url).SetScheme(WrappedBackend).ToString(); m_backend = (IStreamingBackend)Library.DynamicLoader.BackendLoader.GetBackend(u, options); }
public static bool DownloadAndUnpackUpdate(UpdateInfo version, Action<double> progress = null) { if (INSTALLDIR == null) return false; var updates = version.RemoteURLS.ToList(); // If alternate update URLs are specified, // we look for packages there as well if (AutoUpdateSettings.UsesAlternateURLs) { var packagepath = new Library.Utility.Uri(updates[0]).Path; var packagename = packagepath.Split('/').Last(); foreach(var alt_url in AutoUpdateSettings.URLs.Reverse()) { var alt_uri = new Library.Utility.Uri(alt_url); var path_components = alt_uri.Path.Split('/'); var path = string.Join("/", path_components.Take(path_components.Count() - 1).Union(new string[] { packagename})); var new_path = alt_uri.SetPath(path); updates.Insert(0, new_path.ToString()); } } using(var tempfile = new Library.Utility.TempFile()) { foreach(var url in updates) { try { Action<long> cb = null; if (progress != null) cb = (s) => { progress(Math.Min(1.0, Math.Max(0.0, (double)s / version.CompressedSize))); }; var wreq = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url); wreq.UserAgent = string.Format("{0} v{1}", APPNAME, SelfVersion.Version); wreq.Headers.Add("X-Install-ID", InstallID); using(var resp = wreq.GetResponse()) using(var rss = resp.GetResponseStream()) using(var pgs = new Duplicati.Library.Utility.ProgressReportingStream(rss, version.CompressedSize, cb)) using(var fs = System.IO.File.Open(tempfile, System.IO.FileMode.Create)) Duplicati.Library.Utility.Utility.CopyStream(pgs, fs); var sha256 = System.Security.Cryptography.SHA256.Create(); var md5 = System.Security.Cryptography.MD5.Create(); using(var s = System.IO.File.OpenRead(tempfile)) { if (s.Length != version.CompressedSize) throw new Exception(string.Format("Invalid file size {0}, expected {1} for {2}", s.Length, version.CompressedSize, url)); var sha256hash = Convert.ToBase64String(sha256.ComputeHash(s)); if (sha256hash != version.SHA256) throw new Exception(string.Format("Damaged or corrupted file, sha256 mismatch for {0}", url)); } using(var s = System.IO.File.OpenRead(tempfile)) { var md5hash = Convert.ToBase64String(md5.ComputeHash(s)); if (md5hash != version.MD5) throw new Exception(string.Format("Damaged or corrupted file, md5 mismatch for {0}", url)); } using(var tempfolder = new Duplicati.Library.Utility.TempFolder()) using(var zip = new Duplicati.Library.Compression.FileArchiveZip(tempfile, new Dictionary<string, string>())) { foreach(var file in zip.ListFilesWithSize("")) { if (System.IO.Path.IsPathRooted(file.Key) || file.Key.Trim().StartsWith("..", StringComparison.InvariantCultureIgnoreCase)) throw new Exception(string.Format("Out-of-place file path detected: {0}", file.Key)); var targetpath = System.IO.Path.Combine(tempfolder, file.Key); var targetfolder = System.IO.Path.GetDirectoryName(targetpath); if (!System.IO.Directory.Exists(targetfolder)) System.IO.Directory.CreateDirectory(targetfolder); using(var zs = zip.OpenRead(file.Key)) using(var fs = System.IO.File.Create(targetpath)) zs.CopyTo(fs); } if (VerifyUnpackedFolder(tempfolder, version)) { var versionstring = TryParseVersion(version.Version).ToString(); var targetfolder = System.IO.Path.Combine(INSTALLDIR, versionstring); if (System.IO.Directory.Exists(targetfolder)) System.IO.Directory.Delete(targetfolder, true); System.IO.Directory.CreateDirectory(targetfolder); var tempfolderpath = Duplicati.Library.Utility.Utility.AppendDirSeparator(tempfolder); var tempfolderlength = tempfolderpath.Length; // Would be nice, but does not work :( //System.IO.Directory.Move(tempfolder, targetfolder); foreach(var e in Duplicati.Library.Utility.Utility.EnumerateFileSystemEntries(tempfolder)) { var relpath = e.Substring(tempfolderlength); if (string.IsNullOrWhiteSpace(relpath)) continue; var fullpath = System.IO.Path.Combine(targetfolder, relpath); if (relpath.EndsWith(System.IO.Path.DirectorySeparatorChar.ToString())) System.IO.Directory.CreateDirectory(fullpath); else System.IO.File.Copy(e, fullpath); } // Verification will kick in when we list the installed updates //VerifyUnpackedFolder(targetfolder, version); System.IO.File.WriteAllText(System.IO.Path.Combine(INSTALLDIR, CURRENT_FILE), versionstring); m_hasUpdateInstalled = null; var obsolete = (from n in FindInstalledVersions() where n.Value.Version != version.Version && n.Value.Version != SelfVersion.Version let x = TryParseVersion(n.Value.Version) orderby x descending select n).Skip(1).ToArray(); foreach(var f in obsolete) try { System.IO.Directory.Delete(f.Key, true); } catch { } return true; } else { throw new Exception(string.Format("Unable to verify unpacked folder for url: {0}", url)); } } } catch(Exception ex) { if (OnError != null) OnError(ex); } } } return false; }
private void SendMessages(string message) { Exception ex = null; var waitEvent = new System.Threading.ManualResetEvent(false); var uri = new Library.Utility.Uri(m_username.Contains("://") ? m_username : "******" + m_username); var con = new agsXMPP.XmppClientConnection(uri.Host, uri.Port == -1 ? (uri.Scheme == "https" ? 5223 :5222) : uri.Port); if (uri.Scheme == "https") { con.UseSSL = true; } var resource = uri.Path ?? ""; if (resource.StartsWith("/", StringComparison.Ordinal)) { resource = resource.Substring(1); } if (string.IsNullOrWhiteSpace(resource)) { resource = "Duplicati"; } agsXMPP.ObjectHandler loginDelegate = (sender) => { try { foreach (var recipient in m_to.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)) { con.Send(new agsXMPP.protocol.client.Message(recipient, agsXMPP.protocol.client.MessageType.chat, message)); } } catch (Exception e) { ex = e; } finally { waitEvent.Set(); } }; agsXMPP.ErrorHandler errorHandler = (sender, e) => { ex = e; waitEvent.Set(); }; agsXMPP.XmppElementHandler loginErroHandler = (sender, e) => { ex = new Exception(string.Format("Failed to log in: {0}", e)); waitEvent.Set(); }; con.OnLogin += loginDelegate; con.OnError += errorHandler; con.OnAuthError += loginErroHandler; //con.OnBinded += (sender) => {Console.WriteLine("Binded: {0}", sender);}; //con.OnIq += (sender, iq) => {Console.WriteLine("Iq: {0}", iq);}; //con.OnReadXml += (sender, xml) => {Console.WriteLine("ReadXml: {0}", xml);}; //con.OnWriteXml += (sender, xml) => {Console.WriteLine("writeXml: {0}", xml);};; con.Open(uri.Username, string.IsNullOrWhiteSpace(m_password) ? uri.Password : m_password, resource); var timeout = !waitEvent.WaitOne(TimeSpan.FromSeconds(30), true); con.OnLogin -= loginDelegate; con.OnError -= errorHandler; con.OnAuthError -= loginErroHandler; try { con.Close(); } catch { } if (ex != null) { throw ex; } if (timeout) { throw new TimeoutException(Strings.SendJabberMessage.LoginTimeoutError); } }
public static string GetDatabasePath(string backend, Options options, bool autoCreate = true, bool anyUsername = false) { if (options == null) { options = new Options(new Dictionary <string, string>()); } if (!string.IsNullOrEmpty(options.Dbpath)) { return(options.Dbpath); } //Normal mode uses the systems "(Local) Application Data" folder // %LOCALAPPDATA% on Windows, ~/.config on Linux // Special handling for Windows: // - Older versions use %APPDATA% // - but new versions use %LOCALAPPDATA% // // If we find a new version, lets use that // otherwise use the older location // var folder = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Duplicati"); if (Duplicati.Library.Utility.Utility.IsClientWindows) { var newlocation = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Duplicati"); var prevfile = System.IO.Path.Combine(folder, "dbconfig.json"); var curfile = System.IO.Path.Combine(newlocation, "dbconfig.json"); // If the new file exists, we use that // If the new file does not exist, and the old file exists we use the old // Otherwise we use the new location if (System.IO.File.Exists(curfile) || !System.IO.File.Exists(prevfile)) { folder = newlocation; } } if (!System.IO.Directory.Exists(folder)) { System.IO.Directory.CreateDirectory(folder); } var file = System.IO.Path.Combine(folder, "dbconfig.json"); List <BackendEntry> configs; if (!System.IO.File.Exists(file)) { configs = new List <BackendEntry>(); } else { configs = Newtonsoft.Json.JsonConvert.DeserializeObject <List <BackendEntry> >(System.IO.File.ReadAllText(file, System.Text.Encoding.UTF8)); } var uri = new Library.Utility.Uri(backend); string server = uri.Host; string path = uri.Path; string type = uri.Scheme; int port = uri.Port; string username = uri.Username; string prefix = options.Prefix; if (username == null || uri.Password == null) { var sopts = DynamicLoader.BackendLoader.GetSupportedCommands(backend); var ropts = new Dictionary <string, string>(options.RawOptions); foreach (var k in uri.QueryParameters.AllKeys) { ropts[k] = uri.QueryParameters[k]; } if (sopts != null) { foreach (var o in sopts) { if (username == null && o.Aliases != null && o.Aliases.Contains("auth-username", StringComparer.OrdinalIgnoreCase) && ropts.ContainsKey(o.Name)) { username = ropts[o.Name]; } } foreach (var o in sopts) { if (username == null && o.Name.Equals("auth-username", StringComparison.OrdinalIgnoreCase) && ropts.ContainsKey("auth-username")) { username = ropts["auth-username"]; } } } } //Now find the one that matches :) var matches = (from n in configs where n.Type == type && //n.Passwordhash == password && n.Username == username && n.Port == port && n.Server == server && n.Path == path && n.Prefix == prefix select n).ToList(); if (matches.Count > 1) { throw new Duplicati.Library.Interface.UserInformationException(string.Format("Multiple sources found for: {0}", backend), "MultipleLocalDatabaseSourcesFound"); } // Re-select if (matches.Count == 0 && anyUsername && string.IsNullOrEmpty(username)) { matches = (from n in configs where n.Type == type && n.Port == port && n.Server == server && n.Path == path && n.Prefix == prefix select n).ToList(); if (matches.Count > 1) { throw new Duplicati.Library.Interface.UserInformationException(String.Format("Multiple sources found for \"{0}\", try supplying --{1}", backend, "auth-username"), "MultipleLocalDatabaseSourcesFound"); } } if (matches.Count == 0 && !autoCreate) { return(null); } if (matches.Count == 0) { var backupname = options.BackupName; if (string.IsNullOrEmpty(backupname) || backupname == Options.DefaultBackupName) { backupname = GenerateRandomName(); } else { foreach (var c in System.IO.Path.GetInvalidFileNameChars()) { backupname = backupname.Replace(c.ToString(), ""); } } var newpath = System.IO.Path.Combine(folder, backupname + ".sqlite"); int max_tries = 100; while (System.IO.File.Exists(newpath) && max_tries-- > 0) { newpath = System.IO.Path.Combine(folder, GenerateRandomName()); } if (System.IO.File.Exists(newpath)) { throw new Duplicati.Library.Interface.UserInformationException("Unable to find a unique name for the database, please use --dbpath", "CannotCreateRandomName"); } //Create a new one, add it to the list, and save it configs.Add(new BackendEntry() { Type = type, Server = server, Path = path, Prefix = prefix, Username = username, //Passwordhash = password, Port = port, Databasepath = newpath, ParameterFile = null }); var settings = new Newtonsoft.Json.JsonSerializerSettings(); settings.Formatting = Newtonsoft.Json.Formatting.Indented; System.IO.File.WriteAllText(file, Newtonsoft.Json.JsonConvert.SerializeObject(configs, settings), System.Text.Encoding.UTF8); return(newpath); } else { return(matches[0].Databasepath); } }
public BackendManager(string backendurl, Options options, IBackendWriter statwriter, LocalDatabase database) { m_options = options; m_backendurl = backendurl; m_statwriter = statwriter; m_taskControl = statwriter as BasicResults; m_db = new DatabaseCollector(database, statwriter); m_backend = DynamicLoader.BackendLoader.GetBackend(m_backendurl, m_options.RawOptions); if (m_backend == null) { string shortname = m_backendurl; // Try not to leak hostnames or other information in the error messages try { shortname = new Library.Utility.Uri(shortname).Scheme; } catch { } throw new Exception(string.Format("Backend not supported: {0}", shortname)); } if (!m_options.NoEncryption) { m_encryption = DynamicLoader.EncryptionLoader.GetModule(m_options.EncryptionModule, m_options.Passphrase, m_options.RawOptions); if (m_encryption == null) throw new Exception(string.Format("Encryption method not supported: {0}", m_options.EncryptionModule)); } if (m_taskControl != null) m_taskControl.StateChangedEvent += (state) => { if (state == TaskControlState.Abort) m_thread.Abort(); }; m_queue = new BlockingQueue<FileEntryItem>(options.SynchronousUpload ? 1 : (options.AsynchronousUploadLimit == 0 ? int.MaxValue : options.AsynchronousUploadLimit)); m_thread = new System.Threading.Thread(this.ThreadRun); m_thread.Name = "Backend Async Worker"; m_thread.IsBackground = true; m_thread.Start(); }