コード例 #1
0
ファイル: GetBackup.cs プロジェクト: admz/duplicati
        private void GetBackup(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");
            else
            {
                var scheduleId = Program.DataConnection.GetScheduleIDsFromTags(new string[] { "ID=" + bk.ID });
                var schedule = scheduleId.Any() ? Program.DataConnection.GetSchedule(scheduleId.First()) : null;
                var sourcenames = GetSourceNames(bk);

                //TODO: Filter out the password in both settings and the target url

                bw.OutputOK(new
                {
                    success = true,
                    data = new {
                        Schedule = schedule,
                        Backup = bk,
                        DisplayNames = sourcenames
                    }
                });
            }
        }
コード例 #2
0
        private void AddBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            var str = request.Form["data"].Value;

            if (string.IsNullOrWhiteSpace(str))
            {
                ReportError(response, bw, "Missing backup object");
                return;
            }

            AddOrUpdateBackupData data = null;
            try
            {
                data = Serializer.Deserialize<AddOrUpdateBackupData>(new StringReader(str));
                if (data.Backup == null)
                {
                    ReportError(response, bw, "Data object had no backup entry");
                    return;
                }

                data.Backup.ID = null;

                if (Duplicati.Library.Utility.Utility.ParseBool(request.Form["temporary"].Value, false))
                {
                    Program.DataConnection.RegisterTemporaryBackup(data.Backup);

                    bw.OutputOK(new { status = "OK", ID = data.Backup.ID });
                }
                else
                {
                    if (Library.Utility.Utility.ParseBool(request.Form["existing_db"].Value, false))
                    {
                        data.Backup.DBPath = Library.Main.DatabaseLocator.GetDatabasePath(data.Backup.TargetURL, null, false, false);
                        if (string.IsNullOrWhiteSpace(data.Backup.DBPath))
                            throw new Exception("Unable to find remote db path?");
                    }

                    lock(Program.DataConnection.m_lock)
                    {
                        if (Program.DataConnection.Backups.Where(x => x.Name.Equals(data.Backup.Name, StringComparison.InvariantCultureIgnoreCase)).Any())
                        {
                            ReportError(response, bw, "There already exists a backup with the name: " + data.Backup.Name);
                            return;
                        }

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

                    bw.OutputOK(new { status = "OK", ID = data.Backup.ID });
                }
            }
            catch (Exception ex)
            {
                if (data == null)
                    ReportError(response, bw, string.Format("Unable to parse backup or schedule object: {0}", ex.Message));
                else
                    ReportError(response, bw, string.Format("Unable to save schedule or backup object: {0}", ex.Message));
            }
        }
コード例 #3
0
ファイル: RESTHandler.cs プロジェクト: Xelio/duplicati
 public static void HandleControlCGI(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw, Type module)
 {
     var method = request.Method;
     if (!string.IsNullOrWhiteSpace(request.Headers["X-HTTP-Method-Override"]))
         method = request.Headers["X-HTTP-Method-Override"];
     
     DoProcess(request, response, session, method, module.Name.ToLowerInvariant(), (request.Method.ToUpper() == "POST" ? request.Form : request.QueryString)["id"].Value);
 }
コード例 #4
0
ファイル: ReadLogData.cs プロジェクト: Torgalide/duplicati
        private void ReadLogData(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
            var backupid = input["id"].Value;

            if (string.IsNullOrWhiteSpace(backupid))
            {
                List<Dictionary<string, object>> res = null;
                Program.DataConnection.ExecuteWithCommand(x =>
                {
                    res = DumpTable(x, "ErrorLog", "Timestamp", input["offset"].Value, input["pagesize"].Value);
                });

                bw.OutputOK(res);
            }
            else
            {
                var backup = Program.DataConnection.GetBackup(backupid);
                if (backup == null)
                {
                    ReportError(response, bw, "Invalid or missing backup id");
                    return;
                }

                using(var con = (System.Data.IDbConnection)Activator.CreateInstance(Duplicati.Library.SQLiteHelper.SQLiteLoader.SQLiteConnectionType))
                {
                    con.ConnectionString = "Data Source=" + backup.DBPath;
                    con.Open();

                    using(var cmd = con.CreateCommand())
                    {
                        if (Duplicati.Library.Utility.Utility.ParseBool(input["remotelog"].Value, false))
                        {
                            var dt = DumpTable(cmd, "RemoteOperation", "ID", input["offset"].Value, input["pagesize"].Value);

                            // Unwrap raw data to a string
                            foreach(var n in dt)
                                try { n["Data"] = System.Text.Encoding.UTF8.GetString((byte[])n["Data"]); }
                            catch { }

                            bw.OutputOK(dt);
                        }
                        else
                        {
                            var dt = DumpTable(cmd, "LogData", "ID", input["offset"].Value, input["pagesize"].Value);
                            bw.OutputOK(dt);
                        }
                    }
                }
            }
        }
コード例 #5
0
ファイル: SearchBackupFiles.cs プロジェクト: admz/duplicati
        private void SearchBackupFiles(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;

            var filter = (input["filter"].Value ?? "").Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries);
            var timestring = input["time"].Value;
            var allversion = Duplicati.Library.Utility.Utility.ParseBool(input["all-versions"].Value, false);

            if (string.IsNullOrWhiteSpace(timestring) && !allversion)
            {
                ReportError(response, bw, "Invalid or missing time");
                return;
            }
            var bk = Program.DataConnection.GetBackup(input["id"].Value);
            if (bk == null)
            {
                ReportError(response, bw, "Invalid or missing backup id");
                return;
            }

            var prefixonly = Duplicati.Library.Utility.Utility.ParseBool(input["prefix-only"].Value, false);
            var foldercontents = Duplicati.Library.Utility.Utility.ParseBool(input["folder-contents"].Value, false);
            var time = new DateTime();
            if (!allversion)
                time = Duplicati.Library.Utility.Timeparser.ParseTimeInterval(timestring, DateTime.Now);

            var r = Runner.Run(Runner.CreateListTask(bk, filter, prefixonly, allversion, foldercontents, time), false) as Duplicati.Library.Interface.IListResults;

            var result = new Dictionary<string, object>();

            foreach(HttpServer.HttpInputItem n in input)
                result[n.Name] = n.Value;

            result["Filesets"] = r.Filesets;
            result["Files"] = r.Files;

            bw.OutputOK(result);
        }
コード例 #6
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void GetFolderContents(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.DoProcess(request, response, session, request.Method, typeof(RESTMethods.Filesystem).Name.ToLowerInvariant(), Library.Utility.Uri.UrlPathEncode(request.QueryString["path"].Value));
 }
コード例 #7
0
        private void SearchBackupFiles(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            var input = request.Method.Equals("POST", StringComparison.InvariantCultureIgnoreCase) ? request.Form : request.QueryString;
            var key = string.Format("{0}/files/{1}", input["id"].Value, input["filter"].Value);

            RESTHandler.DoProcess(request, response, session, request.Method, typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);

        }
コード例 #8
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void UpdateBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     request.Method = HttpServer.Method.Put;
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.Backup));
 }
コード例 #9
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
        private void ReadLogData(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;

            if (string.IsNullOrEmpty(input["id"].Value))
            {
                RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.LogData));
            }
            else
            {
                var key = string.Format("{0}/{1}", input["id"].Value, Duplicati.Library.Utility.Utility.ParseBool(input["remotelog"].Value, false) ? "remotelog" : "log");
                RESTHandler.DoProcess(request, response, session, request.Method, typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
            }
        }
コード例 #10
0
 private void ListApplicationSettings(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.SystemWideSettings));
 }
コード例 #11
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
        private void ListBackupSets(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            var input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
            var key   = string.Format("{0}/filesets", input["id"].Value);

            RESTHandler.DoProcess(request, response, session, request.Method, typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
        }
コード例 #12
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void ListApplicationSettings(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.SystemWideSettings));
 }
コード例 #13
0
 private void ListSystemInfo(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.SystemInfo));
 }
コード例 #14
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
        private void ValidatePath(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            var input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
            var key   = string.Format("{0}/validate", Library.Utility.Uri.UrlPathEncode(input["path"].Value));

            RESTHandler.DoProcess(request, response, session, "GET", typeof(RESTMethods.Filesystem).Name.ToLowerInvariant(), key);
        }
コード例 #15
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void GetCurrentState(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.ServerState));
 }
コード例 #16
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void ListSupportedActions(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     bw.OutputOK(new { Version = 1, Methods = SUPPORTED_METHODS.Keys });
 }
コード例 #17
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void ListSystemInfo(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.SystemInfo));
 }
コード例 #18
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
        private void CreateRemoteFolder(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            var input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
            var key   = string.Format("{0}/create", Library.Utility.Uri.UrlPathEncode(input["url"].Value));

            RESTHandler.DoProcess(request, response, session, request.Method, typeof(RESTMethods.RemoteOperation).Name.ToLowerInvariant(), key);
        }
コード例 #19
0
 private void UpdateBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     request.Method = HttpServer.Method.Put;
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.Backup));
 }
コード例 #20
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void DownloadBugReport(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.BugReport));
 }
コード例 #21
0
 private void ListBackupSets(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     var input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
     var key = string.Format("{0}/filesets", input["id"].Value);
     RESTHandler.DoProcess(request, response, session, request.Method, typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
 }
コード例 #22
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void SetServerOptions(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     request.Method = "PATCH";
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.ServerSettings));
 }
コード例 #23
0
 private void ValidatePath(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     var input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
     var key = string.Format("{0}/validate", Library.Utility.Uri.UrlPathEncode(input["path"].Value));
     RESTHandler.DoProcess(request, response, session, "GET", typeof(RESTMethods.Filesystem).Name.ToLowerInvariant(), key);
 }
コード例 #24
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
        private void ExportBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            var input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
            var key   = string.Format("{0}/export", Library.Utility.Uri.UrlPathEncode(input["id"].Value));

            RESTHandler.DoProcess(request, response, session, request.Method, typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
        }
コード例 #25
0
 private void SetServerOptions(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     request.Method = "PATCH";
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.ServerSettings));
 }
コード例 #26
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void ImportBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backups).Name.ToLowerInvariant(), "import");
 }
コード例 #27
0
        private void SendCommand(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;

            string command = input["command"].Value ?? "";

            switch (command.ToLowerInvariant())
            {
                case "check-update":
                    RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Updates).Name.ToLowerInvariant(), "check");
                    return;

                case "install-update":
                    RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Updates).Name.ToLowerInvariant(), "install");
                    return;

                case "activate-update":
                    RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Updates).Name.ToLowerInvariant(), "activate");
                    return;

                case "pause":
                    RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.ServerState).Name.ToLowerInvariant(), "pause");
                    return;

                case "resume":
                    RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.ServerState).Name.ToLowerInvariant(), "resume");
                    return;

                case "stop":
                case "abort":
                    {
                        var key = string.Format("{0}/{1}", input["taskid"].Value, command);
                        RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Task).Name.ToLowerInvariant(), key);
                    }
                    return;

                case "is-backup-active":
                    {
                        var key = string.Format("{0}/isactive", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                        RESTHandler.DoProcess(request, response, session, "GET", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
                    }
                    return;

                case "run":
                case "run-backup":
                    {
                        var key = string.Format("{0}/start", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                        RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
                    }
                    return;

                case "run-verify":
                    {
                        var key = string.Format("{0}/verify", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                        RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
                    }
                    return;

                case "run-repair-update":
                    {
                        var key = string.Format("{0}/repairupdate", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                        RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
                    }
                    return;

                case "run-repair":
                    {
                        var key = string.Format("{0}/repair", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                        RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
                    }
                    return;
                case "create-report":
                    {
                        var key = string.Format("{0}/createreport", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                        RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
                    }
                    return;

                default:
                    {
                        var key = string.Format("{0}", Library.Utility.Uri.UrlPathEncode(input["command"].Value));
                        RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.WebModule).Name.ToLowerInvariant(), key);
                        return;
                    }
            }
        }
コード例 #28
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void GetNotifications(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.Notifications));
 }
コード例 #29
0
ファイル: DeleteBackup.cs プロジェクト: Berimor66/duplicati
        private void DeleteBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
            var backup = Program.DataConnection.GetBackup(input["id"].Value);
            if (backup == null)
            {
                ReportError(response, bw, "Invalid or missing backup id");
                return;
            }

            if (Program.WorkThread.Active)
            {
                try
                {
                    //TODO: It's not safe to access the values like this,
                    //because the runner thread might interfere
                    var nt = Program.WorkThread.CurrentTask;
                    if (backup.Equals(nt == null ? null : nt.Backup))
                    {
                        bool force;
                        if (!bool.TryParse(input["force"].Value, out force))
                            force = false;

                        if (!force)
                        {
                            bw.WriteJsonObject(new { status = "failed", reason = "backup-in-progress" });
                            return;
                        }

                        bool hasPaused = Program.LiveControl.State == LiveControls.LiveControlState.Paused;
                        Program.LiveControl.Pause();

                        try
                        {
                            for (int i = 0; i < 10; i++)
                                if (Program.WorkThread.Active)
                                {
                                    var t = Program.WorkThread.CurrentTask;
                                    if (backup.Equals(t == null ? null : t.Backup))
                                        System.Threading.Thread.Sleep(1000);
                                    else
                                        break;
                                }
                                else
                                    break;
                        }
                        finally
                        {
                        }

                        if (Program.WorkThread.Active)
                        {
                            var t = Program.WorkThread.CurrentTask;
                            if (backup.Equals(t == null ? null : t.Backup))
                            {
                                if (hasPaused)
                                    Program.LiveControl.Resume();
                                bw.WriteJsonObject(new { status = "failed", reason = "backup-unstoppable" });
                                return;
                            }
                        }

                        if (hasPaused)
                            Program.LiveControl.Resume();
                    }
                }
                catch (Exception ex)
                {
                    bw.WriteJsonObject(new { status = "error", message = ex.Message });
                    return;
                }
            }

            Program.DataConnection.DeleteBackup(backup);

            //We have fiddled with the schedules
            Program.Scheduler.Reschedule();

            bw.OutputOK();
        }
コード例 #30
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void DismissNotification(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     request.Method = "DELETE";
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.Notification));
 }
コード例 #31
0
        public override bool Process(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;

            var auth_token = FindAuthCookie(request);
            var xsrf_token = FindXSRFToken(request);

            if (!HasXSRFCookie(request))
            {
                var cookieAdded = AddXSRFTokenToRespone(response);

                if (!cookieAdded)
                {
                    response.Status = System.Net.HttpStatusCode.ServiceUnavailable;
                    response.Reason = "Too Many Concurrent Request, try again later";
                    return(true);
                }
            }

            if (LOGOUT_SCRIPT_URI.Equals(request.Uri.AbsolutePath, StringComparison.InvariantCultureIgnoreCase))
            {
                if (!string.IsNullOrWhiteSpace(auth_token))
                {
                    if (m_activeTokens.ContainsKey(auth_token))
                    {
                        m_activeTokens.Remove(auth_token);
                    }
                }

                response.Status = System.Net.HttpStatusCode.NoContent;
                response.Reason = "OK";

                return(true);
            }
            else if (LOGIN_SCRIPT_URI.Equals(request.Uri.AbsolutePath, StringComparison.InvariantCultureIgnoreCase))
            {
                foreach (var k in (from n in m_activeNonces where DateTime.UtcNow > n.Value.Item1 select n.Key).ToList())
                {
                    m_activeNonces.Remove(k);
                }

                if (input["get-nonce"] != null && !string.IsNullOrWhiteSpace(input["get-nonce"].Value))
                {
                    if (m_activeNonces.Count > 50)
                    {
                        response.Status = System.Net.HttpStatusCode.ServiceUnavailable;
                        response.Reason = "Too many active login attempts";
                        return(true);
                    }

                    var buf     = new byte[32];
                    var expires = DateTime.UtcNow.AddMinutes(AUTH_TIMEOUT_MINUTES);
                    m_prng.GetBytes(buf);
                    var nonce = Convert.ToBase64String(buf);

                    var sha256 = System.Security.Cryptography.SHA256.Create();
                    sha256.TransformBlock(buf, 0, buf.Length, buf, 0);
                    buf = Convert.FromBase64String(Program.DataConnection.ApplicationSettings.WebserverPassword);
                    sha256.TransformFinalBlock(buf, 0, buf.Length);
                    var pwd = Convert.ToBase64String(sha256.Hash);

                    m_activeNonces.Add(nonce, new Tuple <DateTime, string>(expires, pwd));

                    response.Cookies.Add(new HttpServer.ResponseCookie(NONCE_COOKIE_NAME, nonce, expires));
                    using (var bw = new BodyWriter(response, request))
                    {
                        bw.OutputOK(new {
                            Status = "OK",
                            Nonce  = nonce,
                            Salt   = Program.DataConnection.ApplicationSettings.WebserverPasswordSalt
                        });
                    }
                    return(true);
                }
                else
                {
                    if (input["password"] != null && !string.IsNullOrWhiteSpace(input["password"].Value))
                    {
                        var nonce_el   = request.Cookies[NONCE_COOKIE_NAME] ?? request.Cookies[Library.Utility.Uri.UrlEncode(NONCE_COOKIE_NAME)];
                        var nonce      = nonce_el == null || string.IsNullOrWhiteSpace(nonce_el.Value) ? "" : nonce_el.Value;
                        var urldecoded = nonce == null ? "" : Duplicati.Library.Utility.Uri.UrlDecode(nonce);
                        if (m_activeNonces.ContainsKey(urldecoded))
                        {
                            nonce = urldecoded;
                        }

                        if (!m_activeNonces.ContainsKey(nonce))
                        {
                            response.Status      = System.Net.HttpStatusCode.Unauthorized;
                            response.Reason      = "Unauthorized";
                            response.ContentType = "application/json";
                            return(true);
                        }

                        var pwd = m_activeNonces[nonce].Item2;
                        m_activeNonces.Remove(nonce);

                        if (pwd != input["password"].Value)
                        {
                            response.Status      = System.Net.HttpStatusCode.Unauthorized;
                            response.Reason      = "Unauthorized";
                            response.ContentType = "application/json";
                            return(true);
                        }

                        var buf     = new byte[32];
                        var expires = DateTime.UtcNow.AddHours(1);
                        m_prng.GetBytes(buf);
                        var token = Duplicati.Library.Utility.Utility.Base64UrlEncode(buf);
                        while (token.Length > 0 && token.EndsWith("="))
                        {
                            token = token.Substring(0, token.Length - 1);
                        }

                        m_activeTokens.Add(token, expires);
                        response.Cookies.Add(new  HttpServer.ResponseCookie(AUTH_COOKIE_NAME, token, expires));

                        using (var bw = new BodyWriter(response, request))
                            bw.OutputOK();

                        return(true);
                    }
                }
            }

            var limitedAccess =
                ControlHandler.CONTROL_HANDLER_URI.Equals(request.Uri.AbsolutePath, StringComparison.InvariantCultureIgnoreCase)
                ||
                request.Uri.AbsolutePath.StartsWith(RESTHandler.API_URI_PATH, StringComparison.InvariantCultureIgnoreCase)
            ;

            if (limitedAccess)
            {
                if (xsrf_token != null && m_activexsrf.ContainsKey(xsrf_token))
                {
                    var expires = DateTime.UtcNow.AddMinutes(XSRF_TIMEOUT_MINUTES);
                    m_activexsrf[xsrf_token] = expires;
                    response.Cookies.Add(new ResponseCookie(XSRF_COOKIE_NAME, xsrf_token, expires));
                }
                else
                {
                    response.Status = System.Net.HttpStatusCode.BadRequest;
                    response.Reason = "Missing XSRF Token";

                    return(true);
                }
            }

            if (string.IsNullOrWhiteSpace(Program.DataConnection.ApplicationSettings.WebserverPassword))
            {
                return(false);
            }

            foreach (var k in (from n in m_activeTokens where DateTime.UtcNow > n.Value select n.Key).ToList())
            {
                m_activeTokens.Remove(k);
            }


            // If we have a valid token, proceeed
            if (!string.IsNullOrWhiteSpace(auth_token))
            {
                DateTime expires;
                var      found = m_activeTokens.TryGetValue(auth_token, out expires);
                if (!found)
                {
                    auth_token = Duplicati.Library.Utility.Uri.UrlDecode(auth_token);
                    found      = m_activeTokens.TryGetValue(auth_token, out expires);
                }

                if (found && DateTime.UtcNow < expires)
                {
                    expires = DateTime.UtcNow.AddHours(1);
                    m_activeTokens[auth_token] = expires;
                    response.Cookies.Add(new ResponseCookie(AUTH_COOKIE_NAME, auth_token, expires));
                    return(false);
                }
            }

            if ("/".Equals(request.Uri.AbsolutePath, StringComparison.InvariantCultureIgnoreCase) || "/index.html".Equals(request.Uri.AbsolutePath, StringComparison.InvariantCultureIgnoreCase))
            {
                response.Redirect("/login.html");
                return(true);
            }

            if (ControlHandler.CONTROL_HANDLER_URI.Equals(request.Uri.AbsolutePath, StringComparison.InvariantCultureIgnoreCase))
            {
                response.Status = System.Net.HttpStatusCode.Unauthorized;
                response.Reason = "Not logged in";
                response.AddHeader("Location", "login.html");

                return(true);
            }

            return(false);
        }
コード例 #32
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void GetUISettingSchemes(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.UISettings));
 }
コード例 #33
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
        private void SearchBackupFiles(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            var input = request.Method.Equals("POST", StringComparison.InvariantCultureIgnoreCase) ? request.Form : request.QueryString;
            var key   = string.Format("{0}/files/{1}", input["id"].Value, input["filter"].Value);

            RESTHandler.DoProcess(request, response, session, request.Method, typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
        }
コード例 #34
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void GetBackupDefaults(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.BackupDefaults));
 }
コード例 #35
0
 private void GetFolderContents(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.DoProcess(request, response, session, request.Method, typeof(RESTMethods.Filesystem).Name.ToLowerInvariant(), Library.Utility.Uri.UrlPathEncode(request.QueryString["path"].Value));
 }      
コード例 #36
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void PollLogMessages(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.DoProcess(request, response, session, "GET", typeof(RESTMethods.LogData).Name.ToLowerInvariant(), "poll");
 }
コード例 #37
0
 private void GetAcknowledgements(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.Acknowledgements));
 }
コード例 #38
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
        private void SendCommand(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;

            string command = input["command"].Value ?? "";

            switch (command.ToLowerInvariant())
            {
            case "check-update":
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Updates).Name.ToLowerInvariant(), "check");
                return;

            case "install-update":
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Updates).Name.ToLowerInvariant(), "install");
                return;

            case "activate-update":
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Updates).Name.ToLowerInvariant(), "activate");
                return;

            case "pause":
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.ServerState).Name.ToLowerInvariant(), "pause");
                return;

            case "resume":
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.ServerState).Name.ToLowerInvariant(), "resume");
                return;

            case "stop":
            case "abort":
            {
                var key = string.Format("{0}/{1}", input["taskid"].Value, command);
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Task).Name.ToLowerInvariant(), key);
            }
                return;

            case "is-backup-active":
            {
                var key = string.Format("{0}/isactive", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                RESTHandler.DoProcess(request, response, session, "GET", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
            }
                return;

            case "run":
            case "run-backup":
            {
                var key = string.Format("{0}/start", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
            }
                return;

            case "run-verify":
            {
                var key = string.Format("{0}/verify", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
            }
                return;

            case "run-repair-update":
            {
                var key = string.Format("{0}/repairupdate", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
            }
                return;

            case "run-repair":
            {
                var key = string.Format("{0}/repair", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
            }
                return;

            case "create-report":
            {
                var key = string.Format("{0}/createreport", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
            }
                return;

            default:
            {
                var key = string.Format("{0}", Library.Utility.Uri.UrlPathEncode(input["command"].Value));
                RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.WebModule).Name.ToLowerInvariant(), key);
                return;
            }
            }
        }
コード例 #39
0
 private void CreateRemoteFolder(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     var input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
     var key = string.Format("{0}/create", Library.Utility.Uri.UrlPathEncode(input["url"].Value));
     RESTHandler.DoProcess(request, response, session, request.Method, typeof(RESTMethods.RemoteOperation).Name.ToLowerInvariant(), key);
 }
コード例 #40
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
        public override bool Process(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session)
        {
            //We use the fake entry point /control.cgi to listen for requests
            //This ensures that the rest of the webserver can just serve plain files
            if (!request.Uri.AbsolutePath.Equals(CONTROL_HANDLER_URI, StringComparison.InvariantCultureIgnoreCase))
            {
                return(false);
            }

            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;

            string action = input["action"].Value ?? "";

            //Lookup the actual handler method
            ProcessSub method;

            SUPPORTED_METHODS.TryGetValue(action, out method);

            if (method == null)
            {
                response.Status = System.Net.HttpStatusCode.NotImplemented;
                response.Reason = "Unsupported action: " + (action == null ? "<null>" : "");
                response.Send();
            }
            else
            {
                //Default setup
                response.Status = System.Net.HttpStatusCode.OK;
                response.Reason = "OK";
                #if DEBUG
                response.ContentType = "text/plain";
                #else
                response.ContentType = "text/json";
                #endif
                using (BodyWriter bw = new BodyWriter(response, request))
                {
                    try
                    {
                        method(request, response, session, bw);
                    }
                    catch (Exception ex)
                    {
                        Program.DataConnection.LogError("", string.Format("Request for {0} gave error", action), ex);
                        Console.WriteLine(ex.ToString());

                        try
                        {
                            if (!response.HeadersSent)
                            {
                                response.Status      = System.Net.HttpStatusCode.InternalServerError;
                                response.Reason      = "Error";
                                response.ContentType = "text/plain";

                                bw.WriteJsonObject(new
                                {
                                    Message = ex.Message,
                                    Type    = ex.GetType().Name,
                                    #if DEBUG
                                    Stacktrace = ex.ToString()
                                    #endif
                                });
                                bw.Flush();
                            }
                        }
                        catch (Exception flex)
                        {
                            Program.DataConnection.LogError("", "Reporting error gave error", flex);
                        }
                    }
                }
            }

            return(true);
        }
コード例 #41
0
 private void ListSupportedActions(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     bw.OutputOK(new { Version = 1, Methods = SUPPORTED_METHODS.Keys });
 }
コード例 #42
0
 private void ImportBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.DoProcess(request, response, session, "POST", typeof(RESTMethods.Backups).Name.ToLowerInvariant(), "import");
 }
コード例 #43
0
 private void GetCurrentState (HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.ServerState));
 }
コード例 #44
0
 private void DismissNotification(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     request.Method = "DELETE";
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.Notification));
 }
コード例 #45
0
 private void DownloadBugReport(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.BugReport));
 }
コード例 #46
0
 private void GetBackupDefaults(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {   
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.BackupDefaults));
 }
コード例 #47
0
 private void ExportBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     var input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
     var key = string.Format("{0}/export", Library.Utility.Uri.UrlPathEncode(input["id"].Value));
     RESTHandler.DoProcess(request, response, session, request.Method, typeof(RESTMethods.Backup).Name.ToLowerInvariant(), key);
 }
コード例 #48
0
ファイル: ControlHandler.cs プロジェクト: sjoerdapp/duplicati
 private void GetAcknowledgements(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.Acknowledgements));
 }
コード例 #49
0
 private void GetNotifications(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.Notifications));
 }
コード例 #50
0
ファイル: RESTHandler.cs プロジェクト: xuchrist/duplicati
        public static void HandleControlCGI(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw, Type module)
        {
            var method = request.Method;

            if (!string.IsNullOrWhiteSpace(request.Headers["X-HTTP-Method-Override"]))
            {
                method = request.Headers["X-HTTP-Method-Override"];
            }

            DoProcess(request, response, session, method, module.Name.ToLowerInvariant(), (request.Method.ToUpper() == "POST" ? request.Form : request.QueryString)["id"].Value);
        }
コード例 #51
0
 private void GetUISettingSchemes(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.HandleControlCGI(request, response, session, bw, typeof(RESTMethods.UISettings));
 }
コード例 #52
0
        public override bool Process(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;

            var auth_token = FindAuthCookie(request);
            var xsrf_token = FindXSRFToken(request);

            if (!HasXSRFCookie(request))
            {
                var cookieAdded = AddXSRFTokenToRespone(response);

                if (!cookieAdded)
                {
                    response.Status = System.Net.HttpStatusCode.ServiceUnavailable;
                    response.Reason = "Too Many Concurrent Request, try again later";
                    return(true);
                }
            }
            Tuple <DateTime, string> tmpTuple;
            DateTime tmpDateTime;

            if (LOGOUT_SCRIPT_URI.Equals(request.Uri.AbsolutePath, StringComparison.OrdinalIgnoreCase))
            {
                if (!string.IsNullOrWhiteSpace(auth_token))
                {
                    // Remove the active auth token
                    m_activeTokens.TryRemove(auth_token, out tmpDateTime);
                }

                response.Status = System.Net.HttpStatusCode.NoContent;
                response.Reason = "OK";

                return(true);
            }
            else if (LOGIN_SCRIPT_URI.Equals(request.Uri.AbsolutePath, StringComparison.OrdinalIgnoreCase))
            {
                // Remove expired nonces
                foreach (var k in (from n in m_activeNonces where DateTime.UtcNow > n.Value.Item1 select n.Key))
                {
                    m_activeNonces.TryRemove(k, out tmpTuple);
                }

                if (input["get-nonce"] != null && !string.IsNullOrWhiteSpace(input["get-nonce"].Value))
                {
                    if (m_activeNonces.Count > 50)
                    {
                        response.Status = System.Net.HttpStatusCode.ServiceUnavailable;
                        response.Reason = "Too many active login attempts";
                        return(true);
                    }

                    var password = Program.DataConnection.ApplicationSettings.WebserverPassword;

                    if (request.Headers[TRAYICONPASSWORDSOURCE_HEADER] == "database")
                    {
                        password = Program.DataConnection.ApplicationSettings.WebserverPasswordTrayIconHash;
                    }

                    var buf     = new byte[32];
                    var expires = DateTime.UtcNow.AddMinutes(AUTH_TIMEOUT_MINUTES);
                    m_prng.GetBytes(buf);
                    var nonce = Convert.ToBase64String(buf);

                    var sha256 = System.Security.Cryptography.SHA256.Create();
                    sha256.TransformBlock(buf, 0, buf.Length, buf, 0);
                    buf = Convert.FromBase64String(password);
                    sha256.TransformFinalBlock(buf, 0, buf.Length);
                    var pwd = Convert.ToBase64String(sha256.Hash);

                    m_activeNonces.AddOrUpdate(nonce, key => new Tuple <DateTime, string>(expires, pwd), (key, existingValue) =>
                    {
                        // Simulate the original behavior => if the nonce, against all odds, is already used
                        // we throw an ArgumentException
                        throw new ArgumentException("An element with the same key already exists in the dictionary.");
                    });

                    response.Cookies.Add(new HttpServer.ResponseCookie(NONCE_COOKIE_NAME, nonce, expires));
                    using (var bw = new BodyWriter(response, request))
                    {
                        bw.OutputOK(new {
                            Status = "OK",
                            Nonce  = nonce,
                            Salt   = Program.DataConnection.ApplicationSettings.WebserverPasswordSalt
                        });
                    }
                    return(true);
                }
                else
                {
                    if (input["password"] != null && !string.IsNullOrWhiteSpace(input["password"].Value))
                    {
                        var nonce_el   = request.Cookies[NONCE_COOKIE_NAME] ?? request.Cookies[Library.Utility.Uri.UrlEncode(NONCE_COOKIE_NAME)];
                        var nonce      = nonce_el == null || string.IsNullOrWhiteSpace(nonce_el.Value) ? "" : nonce_el.Value;
                        var urldecoded = nonce == null ? "" : Duplicati.Library.Utility.Uri.UrlDecode(nonce);
                        if (m_activeNonces.ContainsKey(urldecoded))
                        {
                            nonce = urldecoded;
                        }

                        if (!m_activeNonces.ContainsKey(nonce))
                        {
                            response.Status      = System.Net.HttpStatusCode.Unauthorized;
                            response.Reason      = "Unauthorized";
                            response.ContentType = "application/json";
                            return(true);
                        }

                        var pwd = m_activeNonces[nonce].Item2;

                        // Remove the nonce
                        m_activeNonces.TryRemove(nonce, out tmpTuple);

                        if (pwd != input["password"].Value)
                        {
                            response.Status      = System.Net.HttpStatusCode.Unauthorized;
                            response.Reason      = "Unauthorized";
                            response.ContentType = "application/json";
                            return(true);
                        }

                        var buf     = new byte[32];
                        var expires = DateTime.UtcNow.AddHours(1);
                        m_prng.GetBytes(buf);
                        var token = Duplicati.Library.Utility.Utility.Base64UrlEncode(buf);
                        while (token.Length > 0 && token.EndsWith("="))
                        {
                            token = token.Substring(0, token.Length - 1);
                        }

                        m_activeTokens.AddOrUpdate(token, key => expires, (key, existingValue) =>
                        {
                            // Simulate the original behavior => if the token, against all odds, is already used
                            // we throw an ArgumentException
                            throw new ArgumentException("An element with the same key already exists in the dictionary.");
                        });

                        response.Cookies.Add(new  HttpServer.ResponseCookie(AUTH_COOKIE_NAME, token, expires));

                        using (var bw = new BodyWriter(response, request))
                            bw.OutputOK();

                        return(true);
                    }
                }
            }

            var limitedAccess =
                request.Uri.AbsolutePath.StartsWith(RESTHandler.API_URI_PATH, StringComparison.OrdinalIgnoreCase)
            ;

            // Override to allow the CAPTCHA call to go through
            if (request.Uri.AbsolutePath.StartsWith(CAPTCHA_IMAGE_URI, StringComparison.OrdinalIgnoreCase) && request.Method == "GET")
            {
                limitedAccess = false;
            }

            if (limitedAccess)
            {
                if (xsrf_token != null && m_activexsrf.ContainsKey(xsrf_token))
                {
                    var expires = DateTime.UtcNow.AddMinutes(XSRF_TIMEOUT_MINUTES);
                    m_activexsrf[xsrf_token] = expires;
                    response.Cookies.Add(new ResponseCookie(XSRF_COOKIE_NAME, xsrf_token, expires));
                }
                else
                {
                    response.Status = System.Net.HttpStatusCode.BadRequest;
                    response.Reason = "Missing XSRF Token";

                    return(true);
                }
            }

            if (string.IsNullOrWhiteSpace(Program.DataConnection.ApplicationSettings.WebserverPassword))
            {
                return(false);
            }

            foreach (var k in (from n in m_activeTokens where DateTime.UtcNow > n.Value select n.Key))
            {
                m_activeTokens.TryRemove(k, out tmpDateTime);
            }


            // If we have a valid token, proceed
            if (!string.IsNullOrWhiteSpace(auth_token))
            {
                DateTime expires;
                var      found = m_activeTokens.TryGetValue(auth_token, out expires);
                if (!found)
                {
                    auth_token = Duplicati.Library.Utility.Uri.UrlDecode(auth_token);
                    found      = m_activeTokens.TryGetValue(auth_token, out expires);
                }

                if (found && DateTime.UtcNow < expires)
                {
                    expires = DateTime.UtcNow.AddHours(1);

                    m_activeTokens[auth_token] = expires;
                    response.Cookies.Add(new ResponseCookie(AUTH_COOKIE_NAME, auth_token, expires));
                    return(false);
                }
            }

            if ("/".Equals(request.Uri.AbsolutePath, StringComparison.OrdinalIgnoreCase) || "/index.html".Equals(request.Uri.AbsolutePath, StringComparison.OrdinalIgnoreCase))
            {
                response.Redirect("/login.html");
                return(true);
            }

            if (limitedAccess)
            {
                response.Status = System.Net.HttpStatusCode.Unauthorized;
                response.Reason = "Not logged in";
                response.AddHeader("Location", "login.html");

                return(true);
            }

            return(false);
        }
コード例 #53
0
 private void PollLogMessages(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
 {
     RESTHandler.DoProcess(request, response, session, "GET", typeof(RESTMethods.LogData).Name.ToLowerInvariant(), "poll");
 }
コード例 #54
0
        private void DeleteBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
            var backup = Program.DataConnection.GetBackup(input["id"].Value);

            if (backup == null)
            {
                ReportError(response, bw, "Invalid or missing backup id");
                return;
            }

            if (Program.WorkThread.Active)
            {
                try
                {
                    //TODO: It's not safe to access the values like this,
                    //because the runner thread might interfere
                    var nt = Program.WorkThread.CurrentTask;
                    if (backup.Equals(nt == null ? null : nt.Backup))
                    {
                        bool force;
                        if (!bool.TryParse(input["force"].Value, out force))
                        {
                            force = false;
                        }

                        if (!force)
                        {
                            bw.WriteJsonObject(new { status = "failed", reason = "backup-in-progress" });
                            return;
                        }

                        bool hasPaused = Program.LiveControl.State == LiveControls.LiveControlState.Paused;
                        Program.LiveControl.Pause();

                        try
                        {
                            for (int i = 0; i < 10; i++)
                            {
                                if (Program.WorkThread.Active)
                                {
                                    var t = Program.WorkThread.CurrentTask;
                                    if (backup.Equals(t == null ? null : t.Backup))
                                    {
                                        System.Threading.Thread.Sleep(1000);
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                        finally
                        {
                        }

                        if (Program.WorkThread.Active)
                        {
                            var t = Program.WorkThread.CurrentTask;
                            if (backup.Equals(t == null ? null : t.Backup))
                            {
                                if (hasPaused)
                                {
                                    Program.LiveControl.Resume();
                                }
                                bw.WriteJsonObject(new { status = "failed", reason = "backup-unstoppable" });
                                return;
                            }
                        }

                        if (hasPaused)
                        {
                            Program.LiveControl.Resume();
                        }
                    }
                }
                catch (Exception ex)
                {
                    bw.WriteJsonObject(new { status = "error", message = ex.Message });
                    return;
                }
            }

            Program.DataConnection.DeleteBackup(backup);

            //We have fiddled with the schedules
            Program.Scheduler.Reschedule();

            bw.OutputOK();
        }
コード例 #55
0
        public override bool Process (HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session)
        {
            //We use the fake entry point /control.cgi to listen for requests
            //This ensures that the rest of the webserver can just serve plain files
            if (!request.Uri.AbsolutePath.Equals(CONTROL_HANDLER_URI, StringComparison.InvariantCultureIgnoreCase))
                return false;

            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;

            string action = input["action"].Value ?? "";

            //Lookup the actual handler method
            ProcessSub method;
            SUPPORTED_METHODS.TryGetValue(action, out method);

            if (method == null) {
                response.Status = System.Net.HttpStatusCode.NotImplemented;
                response.Reason = "Unsupported action: " + (action == null ? "<null>" : "");
                response.Send();
            } else {
                //Default setup
                response.Status = System.Net.HttpStatusCode.OK;
                response.Reason = "OK";
                #if DEBUG
                response.ContentType = "text/plain";
                #else
                response.ContentType = "text/json";
                #endif
                using (BodyWriter bw = new BodyWriter(response, request))
                {
                    try
                    {
                        method(request, response, session, bw);
                    }
                    catch (Exception ex)
                    {
                        Program.DataConnection.LogError("", string.Format("Request for {0} gave error", action), ex);
                        Console.WriteLine(ex.ToString());

                        try
                        {
                            if (!response.HeadersSent)
                            {
                                response.Status = System.Net.HttpStatusCode.InternalServerError;
                                response.Reason = "Error";
                                response.ContentType = "text/plain";

                                bw.WriteJsonObject(new
                                {
                                    Message = ex.Message,
                                    Type = ex.GetType().Name,
                                    #if DEBUG
                                    Stacktrace = ex.ToString()
                                    #endif
                                });
                                bw.Flush();
                            }
                        }
                        catch (Exception flex)
                        {
                            Program.DataConnection.LogError("", "Reporting error gave error", flex);
                        }
                    }
                }
            }

            return true;
        }
コード例 #56
0
ファイル: GetBackup.cs プロジェクト: rocifier/duplicati
        private void GetBackup(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");
            }
            else
            {
                var scheduleId  = Program.DataConnection.GetScheduleIDsFromTags(new string[] { "ID=" + bk.ID });
                var schedule    = scheduleId.Any() ? Program.DataConnection.GetSchedule(scheduleId.First()) : null;
                var sourcenames = SpecialFolders.GetSourceNames(bk);

                //TODO: Filter out the password in both settings and the target url

                bw.OutputOK(new
                {
                    success = true,
                    data    = new {
                        Schedule     = schedule,
                        Backup       = bk,
                        DisplayNames = sourcenames
                    }
                });
            }
        }
コード例 #57
0
        private void GetFolderContents(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["path"] == null || input["path"].Value == null)
            {
                ReportError(response, bw, "The path parameter was not set");
                return;
            }

            bool skipFiles = Library.Utility.Utility.ParseBool(input["onlyfolders"].Value, false);

            var path = input["path"].Value;
            string specialpath = null;
            string specialtoken = null;

            if (path.StartsWith("%"))
            {
                var ix = path.IndexOf("%", 1);
                if (ix > 0)
                {
                    var tk = path.Substring(0, ix + 1);
                    var node = SpecialFolders.Nodes.Where(x => x.id.Equals(tk, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
                    if (node != null)
                    {
                        specialpath = node.resolvedpath;
                        specialtoken = node.id;
                    }
                }
            }

            path = SpecialFolders.ExpandEnvironmentVariables(path);

            if (Duplicati.Library.Utility.Utility.IsClientLinux && !path.StartsWith("/"))
            {
                ReportError(response, bw, "The path parameter must start with a forward-slash");
                return;
            }

            try
            {
                if (path != "" && path != "/")
                    path = Duplicati.Library.Utility.Utility.AppendDirSeparator(path);

                IEnumerable<Serializable.TreeNode> res;

                if (!Library.Utility.Utility.IsClientLinux && (path.Equals("/") || path.Equals("")))
                {
                    res =
                        from di in System.IO.DriveInfo.GetDrives()
                            where di.DriveType == DriveType.Fixed || di.DriveType == DriveType.Network || di.DriveType == DriveType.Removable
                        select new Serializable.TreeNode()
                    {
                        id = di.RootDirectory.FullName,
                        text = di.RootDirectory.FullName.Replace('\\', ' ') + "(" + di.DriveType + ")",
                        iconCls = "x-tree-icon-drive"
                    };
                }
                else
                {
                    res = ListFolderAsNodes(path, skipFiles);
                }

                if ((path.Equals("/") || path.Equals("")) && specialtoken == null)
                {
                    // Prepend special folders
                    res = SpecialFolders.Nodes.Union(res);
                }

                if (specialtoken != null)
                {
                    res = from n in res
                        select new Serializable.TreeNode() {
                        id = specialtoken + n.id.Substring(specialpath.Length),
                        text = n.text,
                        iconCls = n.iconCls,
                        leaf = n.leaf,
                        resolvedpath = n.id
                    };
                }

                bw.OutputOK(res);
            }
            catch (Exception ex)
            {
                ReportError(response, bw, "Failed to process the path: " + ex.Message);
            }
        }
コード例 #58
0
        private void DeleteBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;
            var backup = Program.DataConnection.GetBackup(input["id"].Value);

            if (backup == null)
            {
                ReportError(response, bw, "Invalid or missing backup id");
                return;
            }

            if (Program.WorkThread.Active)
            {
                try
                {
                    //TODO: It's not safe to access the values like this,
                    //because the runner thread might interfere
                    var nt = Program.WorkThread.CurrentTask;
                    if (backup.Equals(nt == null ? null : nt.Backup))
                    {
                        bool force;
                        if (!bool.TryParse(input["force"].Value, out force))
                        {
                            force = false;
                        }

                        if (!force)
                        {
                            bw.WriteJsonObject(new { status = "failed", reason = "backup-in-progress" });
                            return;
                        }

                        bool hasPaused = Program.LiveControl.State == LiveControls.LiveControlState.Paused;
                        Program.LiveControl.Pause();

                        try
                        {
                            for (int i = 0; i < 10; i++)
                            {
                                if (Program.WorkThread.Active)
                                {
                                    var t = Program.WorkThread.CurrentTask;
                                    if (backup.Equals(t == null ? null : t.Backup))
                                    {
                                        System.Threading.Thread.Sleep(1000);
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                        finally
                        {
                        }

                        if (Program.WorkThread.Active)
                        {
                            var t = Program.WorkThread.CurrentTask;
                            if (backup.Equals(t == null ? null : t.Backup))
                            {
                                if (hasPaused)
                                {
                                    Program.LiveControl.Resume();
                                }
                                bw.WriteJsonObject(new { status = "failed", reason = "backup-unstoppable" });
                                return;
                            }
                        }

                        if (hasPaused)
                        {
                            Program.LiveControl.Resume();
                        }
                    }
                }
                catch (Exception ex)
                {
                    bw.WriteJsonObject(new { status = "error", message = ex.Message });
                    return;
                }
            }


            //var dbpath = backup.DBPath;
            Program.DataConnection.DeleteBackup(backup);

            // TODO: Before we activate this,
            // we need some strategy to figure out
            // if the db is shared with something else
            // like the commandline or another backup

            /*try
             * {
             *  if (System.IO.File.Exists(dbpath))
             *      System.IO.File.Delete(dbpath);
             * }
             * catch (Exception ex)
             * {
             *  Program.DataConnection.LogError(null, string.Format("Failed to delete database: {0}", dbpath), ex);
             * }*/

            //We have fiddled with the schedules
            Program.Scheduler.Reschedule();

            bw.OutputOK();
        }
コード例 #59
0
        public override bool Process(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session)
        {
            HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString;

            var auth_token = FindAuthCookie(request);
            var xsrf_token = FindXSRFToken(request);

            if (!HasXSRFCookie(request))
            {
                var cookieAdded = AddXSRFTokenToRespone(response);

                if (!cookieAdded)
                {
                    response.Status = System.Net.HttpStatusCode.ServiceUnavailable;
                    response.Reason = "Too Many Concurrent Request, try again later";
                    return true;
                }
			}
			Tuple<DateTime, string> tmpTuple;
			DateTime tmpDateTime;

			if (LOGOUT_SCRIPT_URI.Equals(request.Uri.AbsolutePath, StringComparison.InvariantCultureIgnoreCase))
            {
                if (!string.IsNullOrWhiteSpace(auth_token))
                {
					// Remove the active auth token
	                m_activeTokens.TryRemove(auth_token, out tmpDateTime);
                }

                response.Status = System.Net.HttpStatusCode.NoContent;
                response.Reason = "OK";

                return true;
            }
            else if (LOGIN_SCRIPT_URI.Equals(request.Uri.AbsolutePath, StringComparison.InvariantCultureIgnoreCase))
            {
				// Remove expired nonces
                foreach(var k in (from n in m_activeNonces where DateTime.UtcNow > n.Value.Item1 select n.Key))
                    m_activeNonces.TryRemove(k, out tmpTuple);

                if (input["get-nonce"] != null && !string.IsNullOrWhiteSpace(input["get-nonce"].Value))
                {
                    if (m_activeNonces.Count > 50)
                    {
                        response.Status = System.Net.HttpStatusCode.ServiceUnavailable;
                        response.Reason = "Too many active login attempts";
                        return true;
                    }

                    var buf = new byte[32];
                    var expires = DateTime.UtcNow.AddMinutes(AUTH_TIMEOUT_MINUTES);
                    m_prng.GetBytes(buf);
                    var nonce = Convert.ToBase64String(buf);

                    var sha256 = System.Security.Cryptography.SHA256.Create();
                    sha256.TransformBlock(buf, 0, buf.Length, buf, 0);
                    buf = Convert.FromBase64String(Program.DataConnection.ApplicationSettings.WebserverPassword);
                    sha256.TransformFinalBlock(buf, 0, buf.Length);
                    var pwd = Convert.ToBase64String(sha256.Hash);

					m_activeNonces.AddOrUpdate(nonce, key => new Tuple<DateTime, string>(expires, pwd), (key, existingValue) =>
					{
						// Simulate the original behavior => if the nonce, against all odds, is already used
						// we throw an ArgumentException
						throw new ArgumentException("An element with the same key already exists in the dictionary.");
					});

                    response.Cookies.Add(new HttpServer.ResponseCookie(NONCE_COOKIE_NAME, nonce, expires));
                    using(var bw = new BodyWriter(response, request))
                    {
                        bw.OutputOK(new {
                            Status = "OK",
                            Nonce = nonce,
                            Salt = Program.DataConnection.ApplicationSettings.WebserverPasswordSalt
                        });
                    }
                    return true;
                }
                else
                {
                    if (input["password"] != null && !string.IsNullOrWhiteSpace(input["password"].Value))
                    {
                        var nonce_el = request.Cookies[NONCE_COOKIE_NAME] ?? request.Cookies[Library.Utility.Uri.UrlEncode(NONCE_COOKIE_NAME)];
                        var nonce = nonce_el == null || string.IsNullOrWhiteSpace(nonce_el.Value) ? "" : nonce_el.Value;
                        var urldecoded = nonce == null ? "" : Duplicati.Library.Utility.Uri.UrlDecode(nonce);
                        if (m_activeNonces.ContainsKey(urldecoded))
                            nonce = urldecoded;

                        if (!m_activeNonces.ContainsKey(nonce))
                        {
                            response.Status = System.Net.HttpStatusCode.Unauthorized;
                            response.Reason = "Unauthorized";
                            response.ContentType = "application/json";
                            return true;
                        }

						var pwd = m_activeNonces[nonce].Item2;

						// Remove the nonce
                        m_activeNonces.TryRemove(nonce, out tmpTuple);

                        if (pwd != input["password"].Value)
                        {
                            response.Status = System.Net.HttpStatusCode.Unauthorized;
                            response.Reason = "Unauthorized";
                            response.ContentType = "application/json";
                            return true;
                        }

                        var buf = new byte[32];
                        var expires = DateTime.UtcNow.AddHours(1);
                        m_prng.GetBytes(buf);
                        var token = Duplicati.Library.Utility.Utility.Base64UrlEncode(buf);
                        while (token.Length > 0 && token.EndsWith("="))
                            token = token.Substring(0, token.Length - 1);

						m_activeTokens.AddOrUpdate(token, key => expires, (key, existingValue) =>
						{
							// Simulate the original behavior => if the token, against all odds, is already used
							// we throw an ArgumentException
							throw new ArgumentException("An element with the same key already exists in the dictionary.");
						});

						response.Cookies.Add(new  HttpServer.ResponseCookie(AUTH_COOKIE_NAME, token, expires));

                        using(var bw = new BodyWriter(response, request))
                            bw.OutputOK();

                        return true;
                    }
                }
            }

            var limitedAccess =
                ControlHandler.CONTROL_HANDLER_URI.Equals(request.Uri.AbsolutePath, StringComparison.InvariantCultureIgnoreCase)
                ||
                request.Uri.AbsolutePath.StartsWith(RESTHandler.API_URI_PATH, StringComparison.InvariantCultureIgnoreCase)
            ;

            if (limitedAccess)
            {
                if (xsrf_token != null && m_activexsrf.ContainsKey(xsrf_token))
                {
                    var expires = DateTime.UtcNow.AddMinutes(XSRF_TIMEOUT_MINUTES);
                    m_activexsrf[xsrf_token] = expires;
                    response.Cookies.Add(new ResponseCookie(XSRF_COOKIE_NAME, xsrf_token, expires));
                }
                else
                {
                    response.Status = System.Net.HttpStatusCode.BadRequest;
                    response.Reason = "Missing XSRF Token";

                    return true;
                }
            }

            if (string.IsNullOrWhiteSpace(Program.DataConnection.ApplicationSettings.WebserverPassword))
                return false;

            foreach(var k in (from n in m_activeTokens where DateTime.UtcNow > n.Value select n.Key))
                m_activeTokens.TryRemove(k, out tmpDateTime);


            // If we have a valid token, proceed
            if (!string.IsNullOrWhiteSpace(auth_token))
            {
                DateTime expires;
                var found = m_activeTokens.TryGetValue(auth_token, out expires);
                if (!found)
                {
                    auth_token = Duplicati.Library.Utility.Uri.UrlDecode(auth_token);
                    found = m_activeTokens.TryGetValue(auth_token, out expires);
                }

                if (found && DateTime.UtcNow < expires)
                {
                    expires = DateTime.UtcNow.AddHours(1);

					m_activeTokens[auth_token] = expires;
                    response.Cookies.Add(new ResponseCookie(AUTH_COOKIE_NAME, auth_token, expires));
                    return false;
                }
            }

            if ("/".Equals(request.Uri.AbsolutePath, StringComparison.InvariantCultureIgnoreCase) || "/index.html".Equals(request.Uri.AbsolutePath, StringComparison.InvariantCultureIgnoreCase))
            {
                response.Redirect("/login.html");
                return true;
            }
                
            if (limitedAccess)
            {
                response.Status = System.Net.HttpStatusCode.Unauthorized;
                response.Reason = "Not logged in";
                response.AddHeader("Location", "login.html");

                return true;
            }

            return false;
        }
コード例 #60
0
        private void UpdateBackup(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw)
        {
            string str = request.Form["data"].Value;

            if (string.IsNullOrWhiteSpace(str))
            {
                ReportError(response, bw, "Missing backup object");
                return;
            }

            AddOrUpdateBackupData data = null;

            try
            {
                data = Serializer.Deserialize <AddOrUpdateBackupData>(new StringReader(str));
                if (data.Backup == null)
                {
                    ReportError(response, bw, "Data object had no backup entry");
                    return;
                }

                if (data.Backup.ID == null)
                {
                    ReportError(response, bw, "Invalid or missing backup id");
                    return;
                }

                if (data.Backup.IsTemporary)
                {
                    var backup = Program.DataConnection.GetBackup(data.Backup.ID);
                    if (backup.IsTemporary)
                    {
                        throw new InvalidDataException("External is temporary but internal is not?");
                    }

                    Program.DataConnection.UpdateTemporaryBackup(backup);
                    bw.OutputOK();
                }
                else
                {
                    lock (Program.DataConnection.m_lock)
                    {
                        var backup = Program.DataConnection.GetBackup(data.Backup.ID);
                        if (backup == null)
                        {
                            ReportError(response, bw, "Invalid or missing backup id");
                            return;
                        }

                        if (Program.DataConnection.Backups.Where(x => x.Name.Equals(data.Backup.Name, StringComparison.InvariantCultureIgnoreCase) && x.ID != data.Backup.ID).Any())
                        {
                            ReportError(response, bw, "There already exists a backup with the name: " + data.Backup.Name);
                            return;
                        }

                        //TODO: Merge in real passwords where the placeholder is found
                        Program.DataConnection.AddOrUpdateBackupAndSchedule(data.Backup, data.Schedule);
                    }

                    bw.OutputOK();
                }
            }
            catch (Exception ex)
            {
                if (data == null)
                {
                    ReportError(response, bw, string.Format("Unable to parse backup or schedule object: {0}", ex.Message));
                }
                else
                {
                    ReportError(response, bw, string.Format("Unable to save backup or schedule: {0}", ex.Message));
                }
            }
        }