コード例 #1
0
ファイル: Changelog.cs プロジェクト: thekrugers/duplicati
 public void GET(string key, RequestInfo info)
 {
     var fromUpdate = info.Request.QueryString["from-update"].Value;
     if (!Library.Utility.Utility.ParseBool(fromUpdate, false))
     {
         var path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "changelog.txt");
         info.OutputOK(new GetResponse() {
             Status = "OK",
             Version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(),
             Changelog = System.IO.File.ReadAllText(path)
         });
     }
     else
     {
         var updateInfo = Program.DataConnection.ApplicationSettings.UpdatedVersion;
         if (updateInfo == null)
         {
             info.ReportClientError("No update found");
         }
         else
         {
             info.OutputOK(new GetResponse() {
                 Status = "OK",
                 Version = updateInfo.Version,
                 Changelog = updateInfo.ChangeInfo
             });
         }
     }
 }
コード例 #2
0
ファイル: RemoteOperation.cs プロジェクト: AlexFRAN/duplicati
        private void CreateFolder(string uri, RequestInfo info)
        {
            using(var b = Duplicati.Library.DynamicLoader.BackendLoader.GetBackend(uri, new Dictionary<string, string>()))
                b.CreateFolder();

            info.OutputOK();
        }
コード例 #3
0
        public void GET(string key, RequestInfo info)
        {
            var parts = (key ?? "").Split(new char[] { '/' }, 2);

            if (parts.Length <= 1)
            {
                info.ReportClientError("No url or operation supplied");
                return;
            }

            var url = Library.Utility.Uri.UrlDecode(parts.First());
            var operation = parts.Last().ToLowerInvariant();

            switch (operation)
            {
                case "dbpath":
                    LocateDbUri(url, info);
                    return;
                case "list":
                    ListFolder(url, info);
                    return;
                case "create":
                    CreateFolder(url, info);
                    return;
                case "test":
                    TestConnection(url, info);
                    return;
                default:
                    info.ReportClientError("No such method");
                    return;
            }
        }
コード例 #4
0
ファイル: Backup.cs プロジェクト: AlexFRAN/duplicati
        private void SearchFiles(IBackup backup, string filterstring, RequestInfo info)
        {
            var filter = Library.Utility.Uri.UrlDecode(filterstring ?? "").Split(new string[] { System.IO.Path.PathSeparator.ToString() }, StringSplitOptions.RemoveEmptyEntries);
            var timestring = info.Request.QueryString["time"].Value;
            var allversion = Duplicati.Library.Utility.Utility.ParseBool(info.Request.QueryString["all-versions"].Value, false);

            if (string.IsNullOrWhiteSpace(timestring) && !allversion)
            {
                info.ReportClientError("Invalid or missing time");
                return;
            }

            var prefixonly = Duplicati.Library.Utility.Utility.ParseBool(info.Request.QueryString["prefix-only"].Value, false);
            var foldercontents = Duplicati.Library.Utility.Utility.ParseBool(info.Request.QueryString["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(backup, filter, prefixonly, allversion, foldercontents, time), false) as Duplicati.Library.Interface.IListResults;

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

            foreach(HttpServer.HttpInputItem n in info.Request.QueryString)
                result[n.Name] = n.Value;

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

            info.OutputOK(result);

        }
コード例 #5
0
ファイル: Backups.cs プロジェクト: neilramsay/duplicati
        public void POST(string key, RequestInfo info)
        {
            if ("import".Equals(key, StringComparison.InvariantCultureIgnoreCase))
            {
                ImportBackup(info);
                return;
            }

            AddOrUpdateBackupData data = null;
            try
            {
                data = Serializer.Deserialize<AddOrUpdateBackupData>(new StringReader(info.Request.Form["data"].Value));
                if (data.Backup == null)
                {
                    info.ReportClientError("Data object had no backup entry");
                    return;
                }

                data.Backup.ID = null;

                if (Duplicati.Library.Utility.Utility.ParseBool(info.Request.Form["temporary"].Value, false))
                {
                    using(var tf = new Duplicati.Library.Utility.TempFile())
                        data.Backup.DBPath = tf;

                    Program.DataConnection.RegisterTemporaryBackup(data.Backup);

                    info.OutputOK(new { status = "OK", ID = data.Backup.ID });
                }
                else
                {
                    if (Library.Utility.Utility.ParseBool(info.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())
                        {
                            info.ReportClientError("There already exists a backup with the name: " + data.Backup.Name);
                            return;
                        }

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

                    info.OutputOK(new { status = "OK", ID = data.Backup.ID });
                }
            }
            catch (Exception ex)
            {
                if (data == null)
                    info.ReportClientError(string.Format("Unable to parse backup or schedule object: {0}", ex.Message));
                else
                    info.ReportClientError(string.Format("Unable to save schedule or backup object: {0}", ex.Message));
            }
        }
コード例 #6
0
        public void POST(string key, RequestInfo info)
        {
            string url;

            using(var sr = new System.IO.StreamReader(info.Request.Body, System.Text.Encoding.UTF8, true))
                url = sr.ReadToEnd();

            switch (key)
            {
                case "dbpath":
                    LocateDbUri(url, info);
                    return;
                case "list":
                    ListFolder(url, info);
                    return;
                case "create":
                    CreateFolder(url, info);
                    return;
                case "test":
                    TestConnection(url, info);
                    return;
                default:
                    info.ReportClientError("No such method");
                    return;
            }
        }
コード例 #7
0
ファイル: Task.cs プロジェクト: chris-cashin/duplicati
        public void POST(string key, RequestInfo info)
        {
            var parts = (key ?? "").Split(new char[] { '/' }, 2);
            long taskid;
            if (parts.Length == 2 && long.TryParse(parts.First(), out taskid))
            {
                var task = Program.WorkThread.CurrentTask;
                var tasks = Program.WorkThread.CurrentTasks;

                if (task != null)
                    tasks.Insert(0, task);

                task = tasks.Where(x => x.TaskID == taskid).FirstOrDefault();
                if (task == null)
                {
                    info.ReportClientError("No such task", System.Net.HttpStatusCode.NotFound);
                    return;
                }

                switch (parts.Last().ToLowerInvariant())
                {
                    case "abort":
                        task.Abort();
                        info.OutputOK();
                        return;

                    case "stop":
                        task.Stop();
                        info.OutputOK();
                        return;
                }
            }

            info.ReportClientError("Invalid or missing task id");
        }
コード例 #8
0
ファイル: BugReport.cs プロジェクト: HITSUN2015/duplicati
        public void GET(string key, RequestInfo info)
        {
            long id;
            long.TryParse(key, out id);

            var tf = Program.DataConnection.GetTempFiles().Where(x => x.ID == id).FirstOrDefault();
            if (tf == null)
            {
                info.ReportClientError("Invalid or missing bugreport id");
                return;
            }

            if (!System.IO.File.Exists(tf.Path))
            {
                info.ReportClientError("File is missing");
                return;
            }

            var filename = "bugreport.zip";
            using(var fs = System.IO.File.OpenRead(tf.Path))
            {
                info.Response.ContentLength = fs.Length;
                info.Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", filename));
                info.Response.ContentType = "application/octet-stream";

                info.BodyWriter.SetOK();
                info.Response.SendHeaders();
                fs.CopyTo(info.Response.Body);
                info.Response.Send();
            }
        }
コード例 #9
0
        public void GET(string key, RequestInfo info)
        {
            var adv_props = from n in Program.DataConnection.GetSettings(Database.Connection.APP_SETTINGS_ID)
                select new KeyValuePair<string, string>(n.Name, n.Value);

            info.OutputOK(adv_props.ToDictionary(x => x.Key, x => x.Value));
        }
コード例 #10
0
        public void PATCH(string key, RequestInfo info)
        {
            string str = info.Request.Form["data"].Value;

            if (string.IsNullOrWhiteSpace(str))
                str = new StreamReader(info.Request.Body, System.Text.Encoding.UTF8).ReadToEnd();

            if (string.IsNullOrWhiteSpace(str))
            {
                info.ReportClientError("Missing data object");
                return;
            }

            Dictionary<string, string> data = null;
            try
            {
                data = Serializer.Deserialize<Dictionary<string, string>>(new StringReader(str));
                if (data == null)
                {
                    info.ReportClientError("Data object had no entry");
                    return;
                }

                Program.DataConnection.ApplicationSettings.UpdateSettings(data, false);

                info.OutputOK();
            }
            catch (Exception ex)
            {
                if (data == null)
                    info.ReportClientError(string.Format("Unable to parse data object: {0}", ex.Message));
                else
                    info.ReportClientError(string.Format("Unable to save settings: {0}", ex.Message));
            }
        }
コード例 #11
0
 public void GET(string key, RequestInfo info)
 {
     var path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "acknowledgements.txt");
     info.OutputOK(new GetResponse() {
         Status = "OK",
         Acknowledgements = System.IO.File.ReadAllText(path)
     });            
 }
コード例 #12
0
ファイル: RemoteOperation.cs プロジェクト: AlexFRAN/duplicati
 private void LocateDbUri(string uri, RequestInfo info)
 {
     var path = Library.Main.DatabaseLocator.GetDatabasePath(uri, null, false, false);
     info.OutputOK(new {
         Exists = !string.IsNullOrWhiteSpace(path),
         Path = path
     });
 }
コード例 #13
0
ファイル: ServerSetting.cs プロジェクト: thekrugers/duplicati
 public void GET(string key, RequestInfo info)
 {
     var prop = typeof(Database.ApplicationSettings).GetProperty(key);
     if (prop == null)
         info.OutputError(null, System.Net.HttpStatusCode.NotFound, "Not found");
     else
         info.OutputOK(prop.GetValue(Program.DataConnection.ApplicationSettings));
 }
コード例 #14
0
ファイル: Filesystem.cs プロジェクト: HITSUN2015/duplicati
 public void GET(string key, RequestInfo info)
 {
     var parts = (key ?? "").Split(new char[] { '/' });
     var path = Duplicati.Library.Utility.Uri.UrlDecode((parts.Length == 2 ? parts.FirstOrDefault() : key ?? ""));
     var command = parts.Length == 2 ? parts.Last() : null;
     if (string.IsNullOrEmpty(path))
         path = info.Request.QueryString["path"].Value;
     
     Process(command, path, info);
 }
コード例 #15
0
ファイル: ServerSetting.cs プロジェクト: thekrugers/duplicati
 public void PUT(string key, RequestInfo info)
 {
     var prop = typeof(Database.ApplicationSettings).GetProperty(key);
     if (prop == null)
         info.OutputError(null, System.Net.HttpStatusCode.NotFound, "Not found");
     else
     {
         var dict = new Dictionary<string, string>();
         dict[key] = info.Request.Form["data"].Value;
         Program.DataConnection.ApplicationSettings.UpdateSettings(dict, false);
         info.OutputOK();
     }
 }
コード例 #16
0
ファイル: Backup.cs プロジェクト: HITSUN2015/duplicati
        private void ListFileSets(IBackup backup, RequestInfo info)
        {
            var input = info.Request.QueryString;
            var extra = new Dictionary<string, string>();
            extra["list-sets-only"] = "true";
            if (input["include-metadata"].Value != null)
                extra["list-sets-only"] = (!Library.Utility.Utility.ParseBool(input["include-metadata"].Value, false)).ToString();
            if (input["from-remote-only"].Value != null)
                extra["no-local-db"] = Library.Utility.Utility.ParseBool(input["from-remote-only"].Value, false).ToString();

            var r = Runner.Run(Runner.CreateTask(DuplicatiOperation.List, backup, extra), false) as Duplicati.Library.Interface.IListResults;

            info.OutputOK(r.Filesets);
        }
コード例 #17
0
ファイル: Backups.cs プロジェクト: neilramsay/duplicati
        public void GET(string key, RequestInfo info)
        {
            var schedules = Program.DataConnection.Schedules;
            var backups = Program.DataConnection.Backups;

            var all = from n in backups
                select new AddOrUpdateBackupData() {
                Backup = (Database.Backup)n,
                Schedule =
                    (from x in schedules
                        where x.Tags != null && x.Tags.Contains("ID=" + n.ID)
                        select (Database.Schedule)x).FirstOrDefault()
                };

            info.BodyWriter.OutputOK(all.ToArray());
        }
コード例 #18
0
ファイル: Backup.cs プロジェクト: AlexFRAN/duplicati
        private void ListFileSets(IBackup backup, RequestInfo info)
        {
            var input = info.Request.QueryString;
            var extra = new Dictionary<string, string>();
            extra["list-sets-only"] = "true";
            if (input["include-metadata"].Value != null)
                extra["list-sets-only"] = (!Library.Utility.Utility.ParseBool(input["include-metadata"].Value, false)).ToString();
            if (input["from-remote-only"].Value != null)
                extra["no-local-db"] = Library.Utility.Utility.ParseBool(input["from-remote-only"].Value, false).ToString();

            var r = Runner.Run(Runner.CreateTask(DuplicatiOperation.List, backup, extra), false) as Duplicati.Library.Interface.IListResults;

            if (r.EncryptedFiles && backup.Settings.Any(x => string.Equals("--no-encryption", x.Name, StringComparison.InvariantCultureIgnoreCase)))
                info.ReportServerError("encrypted-storage");
            else
                info.OutputOK(r.Filesets);
        }
コード例 #19
0
        public void GET(string key, RequestInfo info)
        {
            // Start with a scratch object
            var o = new Newtonsoft.Json.Linq.JObject();

            // Add application wide settings
            o.Add("ApplicationOptions", new Newtonsoft.Json.Linq.JArray(
                from n in Program.DataConnection.Settings
                select Newtonsoft.Json.Linq.JObject.FromObject(n)
            ));

            try
            {
                // Add built-in defaults
                Newtonsoft.Json.Linq.JObject n;
                using(var s = new System.IO.StreamReader(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + ".newbackup.json")))
                    n = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(s.ReadToEnd());

                MergeJsonObjects(o, n);
            }
            catch
            {
            }

            try
            {
                // Add install defaults/overrides, if present
                var path = System.IO.Path.Combine(Duplicati.Library.AutoUpdater.UpdaterManager.InstalledBaseDir, "newbackup.json");
                if (System.IO.File.Exists(path))
                {
                    Newtonsoft.Json.Linq.JObject n;
                    n = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(System.IO.File.ReadAllText(path));

                    MergeJsonObjects(o, n);
                }
            }
            catch
            {
            }

            info.OutputOK(new
            {
                success = true,
                data = o
            });
        }
コード例 #20
0
ファイル: RemoteOperation.cs プロジェクト: AlexFRAN/duplicati
        private void UploadFile(string uri, RequestInfo info)
        {
            var data = info.Request.QueryString["data"].Value;
            var remotename = info.Request.QueryString["filename"].Value;

            using(var ms = new System.IO.MemoryStream())   
            using(var b = Duplicati.Library.DynamicLoader.BackendLoader.GetBackend(uri, new Dictionary<string, string>()))
            {
                using(var tf = new Duplicati.Library.Utility.TempFile())
                {
                    System.IO.File.WriteAllText(tf, data);
                    b.Put(remotename, tf);
                }
            }

            info.OutputOK();
        }
コード例 #21
0
ファイル: ServerState.cs プロジェクト: HITSUN2015/duplicati
        public void GET(string key, RequestInfo info)
        {
            bool isError;
            long id = 0;
            long.TryParse(key, out id);

            if (info.LongPollCheck(Program.StatusEventNotifyer, ref id, out isError))
            {
                //Make sure we do not report a higher number than the eventnotifyer says
                var st = new Serializable.ServerStatus();
                st.LastEventID = id;
                info.OutputOK(st);
            }
            else if (!isError)
            {
                info.OutputOK(new Serializable.ServerStatus());
            }
        }
コード例 #22
0
ファイル: RemoteOperation.cs プロジェクト: AlexFRAN/duplicati
        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();
            }
        }
コード例 #23
0
ファイル: SystemInfo.cs プロジェクト: AlexFRAN/duplicati
        public void POST(string key, RequestInfo info)
        {
            var input = info.Request.Form;
            switch ((key ?? "").ToLowerInvariant())
            {
                case "suppressdonationmessages":
                    Library.Main.Utility.SuppressDonationMessages = true;
                    info.OutputOK();
                    return;

                case "showdonationmessages":
                    Library.Main.Utility.SuppressDonationMessages = false;
                    info.OutputOK();
                    return;

                default:
                    info.ReportClientError("No such action", System.Net.HttpStatusCode.NotFound);
                    return;
            }
        }
コード例 #24
0
ファイル: Task.cs プロジェクト: chris-cashin/duplicati
        public void GET(string key, RequestInfo info)
        {
            var parts = (key ?? "").Split(new char[] { '/' }, 2);
            long taskid;
            if (parts.Length == 2 && long.TryParse(parts.First(), out taskid))
            {
                var task = Program.WorkThread.CurrentTask;
                var tasks = Program.WorkThread.CurrentTasks;

                if (task != null && task.TaskID == taskid)
                {
                    info.OutputOK(new { Status = "Running" });
                    return;
                }

                task = tasks.Where(x => x.TaskID == taskid).FirstOrDefault();
                if (tasks.Where(x => x.TaskID == taskid).FirstOrDefault() == null)
                {
                    KeyValuePair<long, Exception>[] matches;
                    lock(Program.MainLock)
                        matches = Program.TaskResultCache.Where(x => x.Key == taskid).ToArray();

                    if (matches.Length == 0)
                        info.ReportClientError("No such task found", System.Net.HttpStatusCode.NotFound);
                    else
                        info.OutputOK(new {
                            Status = matches[0].Value == null ? "Completed" : "Failed",
                            ErrorMessage = matches[0].Value == null ? null : matches[0].Value.Message,
                            Exception = matches[0].Value == null ? null : matches[0].Value.ToString()
                        });
                }
                else
                {
                    info.OutputOK(new { Status = "Waiting" });
                }
            }
            else
            {
                info.ReportClientError("Invalid request");
            }
        }
コード例 #25
0
ファイル: ServerState.cs プロジェクト: HITSUN2015/duplicati
        public void POST(string key, RequestInfo info)
        {
            var input = info.Request.Form;
            switch ((key ?? "").ToLowerInvariant())
            {
                case "pause":
                    if (input.Contains("duration") && !string.IsNullOrWhiteSpace(input["duration"].Value))
                    {
                        TimeSpan ts;
                        try
                        {
                            ts = Library.Utility.Timeparser.ParseTimeSpan(input["duration"].Value);
                        }
                        catch (Exception ex)
                        {
                            info.ReportClientError(ex.Message);
                            return;
                        }
                        if (ts.TotalMilliseconds > 0)
                            Program.LiveControl.Pause(ts);
                        else
                            Program.LiveControl.Pause();
                    }
                    else
                    {
                        Program.LiveControl.Pause();
                    }

                    info.OutputOK();
                    return;

                case "resume":
                    Program.LiveControl.Resume();
                    info.OutputOK();
                    return;
                    
                default:
                    info.ReportClientError("No such action", System.Net.HttpStatusCode.NotFound);
                    return;
            }
        }
コード例 #26
0
 private void IsDBUsedElseWhere(IBackup backup, RequestInfo info)
 {
     info.OutputOK(new { inuse = Library.Main.DatabaseLocator.IsDatabasePathInUse(backup.DBPath) });
 }
コード例 #27
0
ファイル: Backup.cs プロジェクト: Marentis/duplicati
        public void DELETE(string key, RequestInfo info)
        {
            var backup = Program.DataConnection.GetBackup(key);

            if (backup == null)
            {
                info.ReportClientError("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(info.Request.QueryString["force"].Value, out force))
                        {
                            force = false;
                        }

                        if (!force)
                        {
                            info.OutputError(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();
                                }
                                info.OutputError(new { status = "failed", reason = "backup-unstoppable" });
                                return;
                            }
                        }

                        if (hasPaused)
                        {
                            Program.LiveControl.Resume();
                        }
                    }
                }
                catch (Exception ex)
                {
                    info.OutputError(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();

            info.OutputOK();
        }
コード例 #28
0
ファイル: SystemInfo.cs プロジェクト: kevinv12/test
 public void GET(string key, RequestInfo info)
 {
     info.BodyWriter.OutputOK(SystemData(info));
 }
コード例 #29
0
ファイル: SystemInfo.cs プロジェクト: kevinv12/test
        private static object SystemData(RequestInfo info)
        {
            var browserlanguage = RESTHandler.ParseDefaultRequestCulture(info) ?? System.Globalization.CultureInfo.InvariantCulture;

            return(new
            {
                APIVersion = 1,
                PasswordPlaceholder = Duplicati.Server.WebServer.Server.PASSWORD_PLACEHOLDER,
                ServerVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(),
                ServerVersionName = Duplicati.License.VersionNumbers.Version,
                ServerVersionType = Duplicati.Library.AutoUpdater.UpdaterManager.SelfVersion.ReleaseType,
                StartedBy = Duplicati.Server.Program.Origin,
                BaseVersionName = Duplicati.Library.AutoUpdater.UpdaterManager.BaseVersion.Displayname,
                DefaultUpdateChannel = Duplicati.Library.AutoUpdater.AutoUpdateSettings.DefaultUpdateChannel,
                DefaultUsageReportLevel = Duplicati.Library.UsageReporter.Reporter.DefaultReportLevel,
                ServerTime = DateTime.Now,
                OSType = Platform.IsClientPosix ? (Platform.IsClientOSX ? "OSX" : "Linux") : "Windows",
                DirectorySeparator = System.IO.Path.DirectorySeparatorChar,
                PathSeparator = System.IO.Path.PathSeparator,
                CaseSensitiveFilesystem = Duplicati.Library.Utility.Utility.IsFSCaseSensitive,
                MonoVersion = Duplicati.Library.Utility.Utility.IsMono ? Duplicati.Library.Utility.Utility.MonoVersion.ToString() : null,
                MachineName = System.Environment.MachineName,
                UserName = System.Environment.UserName,
                NewLine = System.Environment.NewLine,
                CLRVersion = System.Environment.Version.ToString(),
                CLROSInfo = new
                {
                    Platform = System.Environment.OSVersion.Platform.ToString(),
                    ServicePack = System.Environment.OSVersion.ServicePack,
                    Version = System.Environment.OSVersion.Version.ToString(),
                    VersionString = System.Environment.OSVersion.VersionString
                },
                Options = Serializable.ServerSettings.Options,
                CompressionModules = Serializable.ServerSettings.CompressionModules,
                EncryptionModules = Serializable.ServerSettings.EncryptionModules,
                BackendModules = Serializable.ServerSettings.BackendModules,
                GenericModules = Serializable.ServerSettings.GenericModules,
                WebModules = Serializable.ServerSettings.WebModules,
                ConnectionModules = Serializable.ServerSettings.ConnectionModules,
                ServerModules = Serializable.ServerSettings.ServerModules,
                UsingAlternateUpdateURLs = Duplicati.Library.AutoUpdater.AutoUpdateSettings.UsesAlternateURLs,
                LogLevels = Enum.GetNames(typeof(Duplicati.Library.Logging.LogMessageType)),
                SuppressDonationMessages = Duplicati.Library.Main.Utility.SuppressDonationMessages,
                SpecialFolders = from n in SpecialFolders.Nodes select new { ID = n.id, Path = n.resolvedpath },
                BrowserLocale = new
                {
                    Code = browserlanguage.Name,
                    EnglishName = browserlanguage.EnglishName,
                    DisplayName = browserlanguage.NativeName
                },
                SupportedLocales =
                    Library.Localization.LocalizationService.SupportedCultures
                    .Select(x => new {
                    Code = x,
                    EnglishName = new System.Globalization.CultureInfo(x).EnglishName,
                    DisplayName = new System.Globalization.CultureInfo(x).NativeName
                }
                            ),
                BrowserLocaleSupported = Library.Localization.LocalizationService.isCultureSupported(browserlanguage)
            });
        }
コード例 #30
0
        public void GET(string key, RequestInfo info)
        {
            var parts = (key ?? "").Split(new char[] { '/' }, 2);
            var bk    = Program.DataConnection.GetBackup(parts.First());

            if (bk == null)
            {
                info.ReportClientError("Invalid or missing backup id", System.Net.HttpStatusCode.NotFound);
            }
            else
            {
                if (parts.Length > 1)
                {
                    var operation = parts.Last().Split(new char[] { '/' }).First().ToLowerInvariant();

                    switch (operation)
                    {
                    case "files":
                        var filter = parts.Last().Split(new char[] { '/' }, 2).Skip(1).FirstOrDefault();
                        if (!string.IsNullOrWhiteSpace(info.Request.QueryString["filter"].Value))
                        {
                            filter = info.Request.QueryString["filter"].Value;
                        }
                        SearchFiles(bk, filter, info);
                        return;

                    case "log":
                        FetchLogData(bk, info);
                        return;

                    case "remotelog":
                        FetchRemoteLogData(bk, info);
                        return;

                    case "filesets":
                        ListFileSets(bk, info);
                        return;

                    case "export":
                        Export(bk, info);
                        return;

                    case "isdbusedelsewhere":
                        IsDBUsedElseWhere(bk, info);
                        return;

                    case "isactive":
                        IsActive(bk, info);
                        return;

                    default:
                        info.ReportClientError(string.Format("Invalid component: {0}", operation));
                        return;
                    }
                }

                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

                info.OutputOK(new GetResponse()
                {
                    success = true,
                    data    = new GetResponse.GetResponseData()
                    {
                        Schedule     = schedule,
                        Backup       = bk,
                        DisplayNames = sourcenames
                    }
                });
            }
        }
コード例 #31
0
ファイル: RemoteOperation.cs プロジェクト: zora/duplicati
 private void ListFolder(string uri, RequestInfo info)
 {
     using (var b = Duplicati.Library.DynamicLoader.BackendLoader.GetBackend(uri, new Dictionary <string, string>()))
         info.OutputOK(b.List());
 }
コード例 #32
0
ファイル: RemoteOperation.cs プロジェクト: zora/duplicati
        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);
                }
            }
            catch (Duplicati.Library.Utility.HostKeyException hex)
            {
                if (string.IsNullOrWhiteSpace(hex.ReportedHostKey))
                {
                    info.ReportServerError(hex.Message);
                }
                else
                {
                    info.ReportServerError(string.Format(
                                               @"incorrect-host-key:""{0}"", accepted-host-key:""{1}""",
                                               hex.ReportedHostKey,
                                               hex.AcceptedHostKey
                                               ));
                }
            }
            finally
            {
                foreach (var n in modules)
                {
                    if (n is IDisposable)
                    {
                        ((IDisposable)n).Dispose();
                    }
                }
            }
        }
コード例 #33
0
        public void GET(string key, RequestInfo info)
        {
            var sb = new StringBuilder();

            if (string.IsNullOrWhiteSpace(key))
            {
                foreach (var m in RESTHandler.Modules.Keys.OrderBy(x => x))
                {
                    var mod = RESTHandler.Modules[m];
                    if (mod == this)
                    {
                        continue;
                    }

                    var desc = mod.GetType().Name;
                    if (mod is IRESTMethodDocumented)
                    {
                        desc = ((IRESTMethodDocumented)mod).Description;
                    }
                    sb.AppendFormat(ITEM_TEMPLATE, RESTHandler.API_URI_PATH, m, mod.GetType().Name, desc);
                }


                var data = Encoding.UTF8.GetBytes(string.Format(TEMPLATE, "API Information", "", sb));

                info.Response.ContentType   = "text/html";
                info.Response.ContentLength = data.Length;
                info.Response.Body.Write(data, 0, data.Length);
                info.Response.Send();
            }
            else
            {
                IRESTMethod m;
                RESTHandler.Modules.TryGetValue(key, out m);
                if (m == null)
                {
                    info.Response.Status = System.Net.HttpStatusCode.NotFound;
                    info.Response.Reason = "Module not found";
                }
                else
                {
                    var desc = "";
                    if (m is IRESTMethodDocumented)
                    {
                        var doc = m as IRESTMethodDocumented;
                        desc = doc.Description;
                        foreach (var t in doc.Types)
                        {
                            sb.AppendFormat(METHOD_TEMPLATE, t.Key, JsonConvert.SerializeObject(t.Value)); //TODO: Format the type
                        }
                    }

                    var data = Encoding.UTF8.GetBytes(string.Format(TEMPLATE, m.GetType().Name, desc, sb));

                    info.Response.ContentType   = "text/html";
                    info.Response.ContentLength = data.Length;
                    info.Response.Body.Write(data, 0, data.Length);
                    info.Response.Send();
                }
            }
        }
コード例 #34
0
ファイル: Filesystem.cs プロジェクト: mjtworks/duplicati
 public void POST(string key, RequestInfo info)
 {
     Process(key, info.Request.Form["path"].Value, info);
 }
コード例 #35
0
 private void Repair(IBackup backup, RequestInfo info)
 {
     DoRepair(backup, info, false);
 }
コード例 #36
0
        private void Export(IBackup backup, RequestInfo info)
        {
            var cmdline  = Library.Utility.Utility.ParseBool(info.Request.QueryString["cmdline"].Value, false);
            var argsonly = Library.Utility.Utility.ParseBool(info.Request.QueryString["argsonly"].Value, false);

            if (cmdline)
            {
                info.OutputOK(new { Command = Runner.GetCommandLine(Runner.CreateTask(DuplicatiOperation.Backup, backup)) });
            }
            else if (argsonly)
            {
                var parts = Runner.GetCommandLineParts(Runner.CreateTask(DuplicatiOperation.Backup, backup));

                info.OutputOK(new {
                    Backend   = parts.First(),
                    Arguments = parts.Skip(1).Where(x => !x.StartsWith("--", StringComparison.Ordinal)),
                    Options   = parts.Skip(1).Where(x => x.StartsWith("--", StringComparison.Ordinal))
                });
            }
            else
            {
                var passphrase = info.Request.QueryString["passphrase"].Value;
                var ipx        = Program.DataConnection.PrepareBackupForExport(backup);

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

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

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

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

                info.BodyWriter.SetOK();
                info.Response.SendHeaders();
                info.Response.SendBody(data);
            }
        }
コード例 #37
0
ファイル: ServerSettings.cs プロジェクト: rivy/duplicati
        public void PATCH(string key, RequestInfo info)
        {
            string str = info.Request.Form["data"].Value;

            if (string.IsNullOrWhiteSpace(str))
            {
                str = new StreamReader(info.Request.Body, System.Text.Encoding.UTF8).ReadToEnd();
            }

            if (string.IsNullOrWhiteSpace(str))
            {
                info.ReportClientError("Missing data object");
                return;
            }

            Dictionary <string, string> data = null;

            try
            {
                data = Serializer.Deserialize <Dictionary <string, string> >(new StringReader(str));
                if (data == null)
                {
                    info.ReportClientError("Data object had no entry");
                    return;
                }

                // Split into server settings and global settings

                var serversettings = data.Where(x => !string.IsNullOrWhiteSpace(x.Key)).ToDictionary(x => x.Key, x => x.Key.StartsWith("--", StringComparison.Ordinal) ? null : x.Value);
                var globalsettings = data.Where(x => !string.IsNullOrWhiteSpace(x.Key) && x.Key.StartsWith("--", StringComparison.Ordinal));

                serversettings.Remove("server-ssl-certificate");
                serversettings.Remove("ServerSSLCertificate");

                Program.DataConnection.ApplicationSettings.UpdateSettings(serversettings, false);

                // Update based on inputs
                var existing = Program.DataConnection.Settings.ToDictionary(x => x.Name, x => x);
                foreach (var g in globalsettings)
                {
                    if (g.Value == null)
                    {
                        existing.Remove(g.Key);
                    }
                    else
                    {
                        if (existing.ContainsKey(g.Key))
                        {
                            existing[g.Key].Value = g.Value;
                        }
                        else
                        {
                            existing[g.Key] = new Setting()
                            {
                                Name = g.Key, Value = g.Value
                            }
                        };
                    }
                }

                Program.DataConnection.Settings = existing.Select(x => x.Value).ToArray();

                info.OutputOK();
            }
            catch (Exception ex)
            {
                if (data == null)
                {
                    info.ReportClientError(string.Format("Unable to parse data object: {0}", ex.Message));
                }
                else
                {
                    info.ReportClientError(string.Format("Unable to save settings: {0}", ex.Message));
                }
            }
        }
コード例 #38
0
        public void DELETE(string key, RequestInfo info)
        {
            var backup = Program.DataConnection.GetBackup(key);

            if (backup == null)
            {
                info.ReportClientError("Invalid or missing backup id", System.Net.HttpStatusCode.NotFound);
                return;
            }

            var delete_remote_files = Library.Utility.Utility.ParseBool(info.Request.Param["delete-remote-files"].Value, false);

            if (delete_remote_files)
            {
                var captcha_token  = info.Request.Param["captcha-token"].Value;
                var captcha_answer = info.Request.Param["captcha-answer"].Value;
                if (string.IsNullOrWhiteSpace(captcha_token) || string.IsNullOrWhiteSpace(captcha_answer))
                {
                    info.ReportClientError("Missing captcha");
                    return;
                }

                if (!Captcha.SolvedCaptcha(captcha_token, "DELETE /backup/" + backup.ID, captcha_answer))
                {
                    info.ReportClientError("Invalid captcha", System.Net.HttpStatusCode.Forbidden);
                    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(info.Request.QueryString["force"].Value, out force))
                        {
                            force = false;
                        }

                        if (!force)
                        {
                            info.OutputError(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();
                                }
                                info.OutputError(new { status = "failed", reason = "backup-unstoppable" });
                                return;
                            }
                        }

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

            var extra = new Dictionary <string, string>();

            if (!string.IsNullOrWhiteSpace(info.Request.Param["delete-local-db"].Value))
            {
                extra["delete-local-db"] = info.Request.Param["delete-local-db"].Value;
            }
            if (delete_remote_files)
            {
                extra["delete-remote-files"] = "true";
            }

            var task = Runner.CreateTask(DuplicatiOperation.Delete, backup, extra);

            Program.WorkThread.AddTask(task);
            Program.StatusEventNotifyer.SignalNewEvent();

            info.OutputOK(new { Status = "OK", ID = task.TaskID });
        }
コード例 #39
0
 public void POST(string key, RequestInfo info)
 {
     PATCH(key, info);
 }
コード例 #40
0
        public void PUT(string key, RequestInfo info)
        {
            string str = info.Request.Form["data"].Value;

            if (string.IsNullOrWhiteSpace(str))
            {
                str = new StreamReader(info.Request.Body, System.Text.Encoding.UTF8).ReadToEnd();
            }

            if (string.IsNullOrWhiteSpace(str))
            {
                info.ReportClientError("Missing backup object");
                return;
            }

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

                if (!string.IsNullOrEmpty(key))
                {
                    data.Backup.ID = key;
                }

                if (string.IsNullOrEmpty(data.Backup.ID))
                {
                    info.ReportClientError("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);
                    info.OutputOK();
                }
                else
                {
                    lock (Program.DataConnection.m_lock)
                    {
                        var backup = Program.DataConnection.GetBackup(data.Backup.ID);
                        if (backup == null)
                        {
                            info.ReportClientError("Invalid or missing backup id");
                            return;
                        }

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

                        var err = Program.DataConnection.ValidateBackup(data.Backup, data.Schedule);
                        if (!string.IsNullOrWhiteSpace(err))
                        {
                            info.ReportClientError(err);
                            return;
                        }

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

                    info.OutputOK();
                }
            }
            catch (Exception ex)
            {
                if (data == null)
                {
                    info.ReportClientError(string.Format("Unable to parse backup or schedule object: {0}", ex.Message));
                }
                else
                {
                    info.ReportClientError(string.Format("Unable to save backup or schedule: {0}", ex.Message));
                }
            }
        }
コード例 #41
0
ファイル: Filesystem.cs プロジェクト: sacrednetwork/duplicati
        private void Process(string command, string path, RequestInfo info)
        {
            if (string.IsNullOrEmpty(path))
            {
                info.ReportClientError("No path parameter was found");
                return;
            }

            bool skipFiles  = Library.Utility.Utility.ParseBool(info.Request.QueryString["onlyfolders"].Value, false);
            bool showHidden = Library.Utility.Utility.ParseBool(info.Request.QueryString["showhidden"].Value, false);

            string specialpath  = null;
            string specialtoken = null;

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

            path = SpecialFolders.ExpandEnvironmentVariables(path);

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

            if (!string.IsNullOrWhiteSpace(command))
            {
                if ("validate".Equals(command, StringComparison.OrdinalIgnoreCase))
                {
                    try
                    {
                        if (System.IO.Path.IsPathRooted(path) && (System.IO.Directory.Exists(path) || System.IO.File.Exists(path)))
                        {
                            info.OutputOK();
                            return;
                        }
                    }
                    catch
                    {
                    }

                    info.ReportServerError("File or folder not found");
                    return;
                }
                else
                {
                    info.ReportClientError(string.Format("No such operation found: {0}", command));
                    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 = DriveInfo.GetDrives()
                          .Where(di =>
                                 (di.DriveType == DriveType.Fixed || di.DriveType == DriveType.Network || di.DriveType == DriveType.Removable) &&
                                 di.IsReady                  // Only try to create TreeNode entries for drives who were ready 'now'
                                 )
                          .Select(TryCreateTreeNodeForDrive) // This will try to create a TreeNode for selected drives
                          .Where(tn => tn != null);          // This filters out such entries that could not be created
                }
                else
                {
                    res = ListFolderAsNodes(path, skipFiles, showHidden);
                }

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

                if (specialtoken != null)
                {
                    res = res.Select(x => {
                        x.resolvedpath = x.id;
                        x.id           = specialtoken + x.id.Substring(specialpath.Length);
                        return(x);
                    });
                }

                // We have to resolve the query before giving it to OutputOK
                // If we do not do this, and the query throws an exception when OutputOK resolves it,
                // the exception would not be handled properly
                res = res.ToList();

                info.OutputOK(res);
            }
            catch (Exception ex)
            {
                info.ReportClientError("Failed to process the path: " + ex.Message);
            }
        }
コード例 #42
0
        public void POST(string key, RequestInfo info)
        {
            var parts = (key ?? "").Split(new char[] { '/' }, 2);
            var bk    = Program.DataConnection.GetBackup(parts.First());

            if (bk == null)
            {
                info.ReportClientError("Invalid or missing backup id");
            }
            else
            {
                if (parts.Length > 1)
                {
                    var operation = parts.Last().Split(new char[] { '/' }).First().ToLowerInvariant();

                    switch (operation)
                    {
                    case "deletedb":
                        System.IO.File.Delete(bk.DBPath);
                        info.OutputOK();
                        return;

                    case "movedb":
                        UpdateDatabasePath(bk, info, true);
                        return;

                    case "updatedb":
                        UpdateDatabasePath(bk, info, false);
                        return;

                    case "restore":
                        RestoreFiles(bk, info);
                        return;

                    case "createreport":
                        CreateReport(bk, info);
                        return;

                    case "repair":
                        Repair(bk, info);
                        return;

                    case "repairupdate":
                        RepairUpdate(bk, info);
                        return;

                    case "verify":
                        Verify(bk, info);
                        return;

                    case "compact":
                        Compact(bk, info);
                        return;

                    case "start":
                    case "run":
                        RunBackup(bk, info);
                        return;

                    case "report-remote-size":
                        ReportRemoteSize(bk, info);
                        return;

                    case "copytotemp":
                        var ipx = Serializer.Deserialize <Database.Backup>(new StringReader(Newtonsoft.Json.JsonConvert.SerializeObject(bk)));

                        using (var tf = new Duplicati.Library.Utility.TempFile())
                            ipx.DBPath = tf;
                        ipx.ID = null;

                        info.OutputOK(new { status = "OK", ID = Program.DataConnection.RegisterTemporaryBackup(ipx) });
                        return;
                    }
                }

                info.ReportClientError("Invalid request");
            }
        }
コード例 #43
0
ファイル: Backups.cs プロジェクト: xuchrist/duplicati
        private void ImportBackup(RequestInfo info)
        {
            var output_template = "<html><body><script type=\"text/javascript\">var rp = null; try { rp = parent['CBM']; } catch (e) {}; rp = rp || alert; rp('MSG');</script></body></html>";

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

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

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

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

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

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

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

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

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

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

                    //bw.OutputOK(new { status = "OK", ID = ipx.Backup.ID });
                }
            }
            catch (Exception ex)
            {
                Program.DataConnection.LogError("", "Failed to import backup", ex);
                info.Response.ContentType = "text/html";
                info.BodyWriter.Write(output_template.Replace("MSG", ex.Message.Replace("\'", "\\'").Replace("\r", "\\r").Replace("\n", "\\n")));
            }
        }
コード例 #44
0
 private void RepairUpdate(IBackup backup, RequestInfo info)
 {
     DoRepair(backup, info, true);
 }
コード例 #45
0
ファイル: RESTHandler.cs プロジェクト: Xelio/duplicati
 public static void DoProcess(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, string method, string module, string key)
 {
     using(var reqinfo = new RequestInfo(request, response, session))
         DoProcess(reqinfo, method, module, key);
 }
コード例 #46
0
        private void ImportBackup(RequestInfo info)
        {
            var output_template = "<html><body><script type=\"text/javascript\">var jso = 'JSO'; var rp = null; try { rp = parent['CBM']; } catch (e) {}; if (rp) { rp('MSG', jso); } else { alert; rp('MSG'); };</script></body></html>";

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

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

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

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

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

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

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

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

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

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

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

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

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

                        info.Response.ContentType = "text/html";
                        info.BodyWriter.Write(output_template.Replace("MSG", "OK"));
                    }
                    else
                    {
                        using (var sw = new StringWriter())
                        {
                            Serializer.SerializeJson(sw, ipx, true);
                            output_template = output_template.Replace("'JSO'", sw.ToString());
                        }
                        info.BodyWriter.Write(output_template.Replace("MSG", "Import completed, but a browser issue prevents loading the contents. Try using the direct import method instead."));
                    }
                }
            }
            catch (Exception ex)
            {
                Program.DataConnection.LogError("", "Failed to import backup", ex);
                info.Response.ContentType = "text/html";
                info.BodyWriter.Write(output_template.Replace("MSG", ex.Message.Replace("\'", "\\'").Replace("\r", "\\r").Replace("\n", "\\n")));
            }
        }
コード例 #47
0
ファイル: UISettings.cs プロジェクト: videocrap/duplicati
 public void GET(string key, RequestInfo info)
 {
     if (string.IsNullOrWhiteSpace(key))
     {
コード例 #48
0
        public void POST(string key, RequestInfo info)
        {
            if (string.IsNullOrWhiteSpace(key))
            {
                var target = info.Request.Param["target"].Value;
                if (string.IsNullOrWhiteSpace(target))
                {
                    info.ReportClientError("Missing target parameter", System.Net.HttpStatusCode.BadRequest);
                    return;
                }

                var answer = CaptchaUtil.CreateRandomAnswer(minlength: 6, maxlength: 6);
                var nonce  = Guid.NewGuid().ToString();

                string token;
                using (var ms = new System.IO.MemoryStream())
                {
                    var bytes = System.Text.Encoding.UTF8.GetBytes(answer + nonce);
                    ms.Write(bytes, 0, bytes.Length);
                    ms.Position = 0;
                    token       = Library.Utility.Utility.Base64PlainToBase64Url(Library.Utility.Utility.CalculateHash(ms));
                }

                lock (m_lock)
                {
                    var expired = m_captchas.Where(x => x.Value.Expires < DateTime.Now).Select(x => x.Key).ToArray();
                    foreach (var x in expired)
                    {
                        m_captchas.Remove(x);
                    }

                    if (m_captchas.Count > 3)
                    {
                        info.ReportClientError("Too many captchas, wait 2 minutes and try again", System.Net.HttpStatusCode.ServiceUnavailable);
                        return;
                    }

                    m_captchas[token] = new CaptchaEntry(answer, target);
                }

                info.OutputOK(new
                {
                    token = token
                });
            }
            else
            {
                var answer = info.Request.Param["answer"].Value;
                var target = info.Request.Param["target"].Value;
                if (string.IsNullOrWhiteSpace(answer))
                {
                    info.ReportClientError("Missing answer parameter", System.Net.HttpStatusCode.BadRequest);
                    return;
                }
                if (string.IsNullOrWhiteSpace(target))
                {
                    info.ReportClientError("Missing target parameter", System.Net.HttpStatusCode.BadRequest);
                    return;
                }

                if (SolvedCaptcha(key, target, answer))
                {
                    info.OutputOK();
                }
                else
                {
                    info.ReportClientError("Incorrect", System.Net.HttpStatusCode.Forbidden);
                }
            }
        }
コード例 #49
0
ファイル: CommandLine.cs プロジェクト: yuhisa/duplicati
        public void POST(string key, RequestInfo info)
        {
            if (string.IsNullOrWhiteSpace(key))
            {
                string[] args;
                using (var sr = new StreamReader(info.Request.Body, System.Text.Encoding.UTF8, true))
                    args = Newtonsoft.Json.JsonConvert.DeserializeObject <string[]>(sr.ReadToEnd());

                var k = new ActiveRun();
                k.Writer = new LogWriter(k);

                m_activeItems[k.ID] = k;
                StartCleanupTask();

                k.Task = Runner.CreateCustomTask((sink) =>
                {
                    try
                    {
                        k.Thread  = System.Threading.Thread.CurrentThread;
                        k.Started = true;

                        var code = Duplicati.CommandLine.Program.RunCommandLine(k.Writer, k.Writer, c => {
                            k.Task.SetController(c);
                            c.AppendSink(sink);
                        }, args);
                        k.Writer.WriteLine(string.Format("Return code: {0}", code));
                    }
                    catch (Exception ex)
                    {
                        var rx = ex;
                        if (rx is System.Reflection.TargetInvocationException)
                        {
                            rx = rx.InnerException;
                        }

                        if (rx is Library.Interface.UserInformationException)
                        {
                            k.Log.Add(rx.Message);
                        }
                        else
                        {
                            k.Log.Add(rx.ToString());
                        }

                        throw rx;
                    }
                    finally
                    {
                        k.Finished = true;
                        k.Thread   = null;
                    }
                });

                Program.WorkThread.AddTask(k.Task);

                info.OutputOK(new
                {
                    ID = k.ID
                });
            }
            else
            {
                if (!key.EndsWith("/abort", StringComparison.OrdinalIgnoreCase))
                {
                    info.ReportClientError("Only abort commands are allowed", System.Net.HttpStatusCode.BadRequest);
                    return;
                }

                key = key.Substring(0, key.Length - "/abort".Length);
                if (string.IsNullOrWhiteSpace(key))
                {
                    info.ReportClientError("No task key found", System.Net.HttpStatusCode.BadRequest);
                    return;
                }

                ActiveRun t;
                if (!m_activeItems.TryGetValue(key, out t))
                {
                    info.OutputError(code: System.Net.HttpStatusCode.NotFound);
                    return;
                }

                var tt = t.Task;
                if (tt != null)
                {
                    tt.Abort();
                }

                var tr = t.Thread;
                if (tr != null)
                {
                    tr.Abort();
                }

                info.OutputOK();
            }
        }
コード例 #50
0
ファイル: Tags.cs プロジェクト: HITSUN2015/duplicati
{
コード例 #51
0
 private void FetchLogData(IBackup backup, RequestInfo info)
 {
     using (var con = Duplicati.Library.SQLiteHelper.SQLiteLoader.LoadConnection(backup.DBPath))
         using (var cmd = con.CreateCommand())
             info.OutputOK(LogData.DumpTable(cmd, "LogData", "ID", info.Request.QueryString["offset"].Value, info.Request.QueryString["pagesize"].Value));
 }
コード例 #52
0
ファイル: RESTHandler.cs プロジェクト: Xelio/duplicati
        public static void DoProcess(RequestInfo info, string method, string module, string key)
        {
            try
            {
                IRESTMethod mod;
                _modules.TryGetValue(module, out mod);

                if (mod == null)
                {
                    info.Response.Status = System.Net.HttpStatusCode.NotFound;
                    info.Response.Reason = "No such module";
                }
                else if (method == HttpServer.Method.Get && mod is IRESTMethodGET)
                {
                    if (info.Request.Form != HttpServer.HttpForm.EmptyForm)
                    {
                        if (info.Request.QueryString == HttpServer.HttpInput.Empty)
                        {
                            var r = info.Request.GetType().GetField("_queryString", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                            r.SetValue(info.Request, new HttpServer.HttpInput("formdata"));
                        }

                        foreach(HttpServer.HttpInputItem v in info.Request.Form)
                            if (!info.Request.QueryString.Contains(v.Name))
                                info.Request.QueryString.Add(v.Name, v.Value);
                    }
                    ((IRESTMethodGET)mod).GET(key, info);
                }
                else if (method == HttpServer.Method.Put && mod is IRESTMethodPUT)
                    ((IRESTMethodPUT)mod).PUT(key, info);
                else if (method == HttpServer.Method.Post && mod is IRESTMethodPOST)
                {
                    if (info.Request.Form == HttpServer.HttpForm.EmptyForm)
                    {
                        var r = info.Request.GetType().GetMethod("AssignForm", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] { typeof(HttpServer.HttpForm) }, null);
                        r.Invoke(info.Request, new object[] { new HttpServer.HttpForm(info.Request.QueryString) });
                    }
                    else
                    {
                        foreach(HttpServer.HttpInputItem v in info.Request.QueryString)
                            if (!info.Request.Form.Contains(v.Name))
                                info.Request.Form.Add(v.Name, v.Value);
                    }
                    ((IRESTMethodPOST)mod).POST(key, info);
                }
                else if (method == HttpServer.Method.Delete && mod is IRESTMethodDELETE)
                    ((IRESTMethodDELETE)mod).DELETE(key, info);
                else if (method == "PATCH" && mod is IRESTMethodPATCH)
                    ((IRESTMethodPATCH)mod).PATCH(key, info);
                else
                {
                    info.Response.Status = System.Net.HttpStatusCode.MethodNotAllowed;
                    info.Response.Reason = "Method is not allowed";
                }
            }
            catch(Exception ex)
            {
                Program.DataConnection.LogError("", string.Format("Request for {0} gave error", info.Request.Uri), ex);
                Console.WriteLine(ex.ToString());

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

                        var wex = ex;
                        while (wex is System.Reflection.TargetInvocationException && wex.InnerException != wex)
                            wex = wex.InnerException;
                            

                        info.BodyWriter.WriteJsonObject(new
                        {
                            Message = ex.Message,
                            Type = ex.GetType().Name,
                            #if DEBUG
                            Stacktrace = ex.ToString()
                            #endif
                        });
                        info.BodyWriter.Flush();
                    }
                }
                catch (Exception flex)
                {
                    Program.DataConnection.LogError("", "Reporting error gave error", flex);
                }
            }
        }
コード例 #53
0
ファイル: Backups.cs プロジェクト: xuchrist/duplicati
        public void POST(string key, RequestInfo info)
        {
            if ("import".Equals(key, StringComparison.InvariantCultureIgnoreCase))
            {
                ImportBackup(info);
                return;
            }

            AddOrUpdateBackupData data = null;

            try
            {
                var str = info.Request.Form["data"].Value;
                if (string.IsNullOrWhiteSpace(str))
                {
                    str = new StreamReader(info.Request.Body, System.Text.Encoding.UTF8).ReadToEnd();
                }

                data = Serializer.Deserialize <AddOrUpdateBackupData>(new StringReader(str));
                if (data.Backup == null)
                {
                    info.ReportClientError("Data object had no backup entry");
                    return;
                }

                data.Backup.ID = null;

                if (Duplicati.Library.Utility.Utility.ParseBool(info.Request.Form["temporary"].Value, false))
                {
                    using (var tf = new Duplicati.Library.Utility.TempFile())
                        data.Backup.DBPath = tf;

                    data.Backup.Filters  = data.Backup.Filters ?? new Duplicati.Server.Serialization.Interface.IFilter[0];
                    data.Backup.Settings = data.Backup.Settings ?? new Duplicati.Server.Serialization.Interface.ISetting[0];

                    Program.DataConnection.RegisterTemporaryBackup(data.Backup);

                    info.OutputOK(new { status = "OK", ID = data.Backup.ID });
                }
                else
                {
                    if (Library.Utility.Utility.ParseBool(info.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())
                        {
                            info.ReportClientError("There already exists a backup with the name: " + data.Backup.Name);
                            return;
                        }

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

                    info.OutputOK(new { status = "OK", ID = data.Backup.ID });
                }
            }
            catch (Exception ex)
            {
                if (data == null)
                {
                    info.ReportClientError(string.Format("Unable to parse backup or schedule object: {0}", ex.Message));
                }
                else
                {
                    info.ReportClientError(string.Format("Unable to save schedule or backup object: {0}", ex.Message));
                }
            }
        }
コード例 #54
0
ファイル: UISettings.cs プロジェクト: videocrap/duplicati
 }
 else
 {
     info.OutputOK(Program.DataConnection.GetUISettings(key));
コード例 #55
0
ファイル: Filesystem.cs プロジェクト: mjtworks/duplicati
        private void Process(string command, string path, RequestInfo info)
        {
            if (string.IsNullOrEmpty(path))
            {
                info.ReportClientError("No path parameter was found");
                return;
            }

            bool skipFiles  = Library.Utility.Utility.ParseBool(info.Request.QueryString["onlyfolders"].Value, false);
            bool showHidden = Library.Utility.Utility.ParseBool(info.Request.QueryString["showhidden"].Value, false);

            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("/"))
            {
                info.ReportClientError("The path parameter must start with a forward-slash");
                return;
            }

            if (!string.IsNullOrWhiteSpace(command))
            {
                if ("validate".Equals(command, StringComparison.InvariantCultureIgnoreCase))
                {
                    try
                    {
                        if (System.IO.Path.IsPathRooted(path) && (System.IO.Directory.Exists(path) || System.IO.File.Exists(path)))
                        {
                            info.OutputOK();
                            return;
                        }
                    }
                    catch
                    {
                    }

                    info.ReportServerError("File or folder not found");
                    return;
                }
                else
                {
                    info.ReportClientError(string.Format("No such operation found: {0}", command));
                    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, showHidden);
                }

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

                if (specialtoken != null)
                {
                    res = res.Select(x => {
                        x.resolvedpath = x.id;
                        x.id           = specialtoken + x.id.Substring(specialpath.Length);
                        return(x);
                    });
                }

                info.OutputOK(res);
            }
            catch (Exception ex)
            {
                info.ReportClientError("Failed to process the path: " + ex.Message);
            }
        }