source: branches/eraser6/pluginsRewrite/Eraser.Manager/Settings.cs @ 2366

Revision 2366, 20.0 KB checked in by lowjoel, 2 years ago (diff)

Since the types have been moved to the Eraser.Plugins.ExtensionPoints? namespace, reference that.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2010 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25using System.Reflection;
26using System.Runtime.InteropServices;
27using System.Globalization;
28
29using Eraser.Util;
30using Eraser.Plugins;
31using Eraser.Plugins.ExtensionPoints;
32
33namespace Eraser.Manager
34{
35    public abstract class SettingsManager
36    {
37        /// <summary>
38        /// Saves all the settings to persistent storage.
39        /// </summary>
40        public abstract void Save();
41
42        /// <summary>
43        /// Gets the dictionary holding settings for the calling assembly.
44        /// </summary>
45        public Settings ModuleSettings
46        {
47            get
48            {
49                return GetSettings(new Guid(((GuidAttribute)Assembly.GetCallingAssembly().
50                    GetCustomAttributes(typeof(GuidAttribute), false)[0]).Value));
51            }
52        }
53
54        /// <summary>
55        /// Gets the settings from the data source.
56        /// </summary>
57        /// <param name="value">The GUID of the calling plugin</param>
58        /// <returns>The Settings object which will act as the data store.</returns>
59        protected abstract Settings GetSettings(Guid value);
60    }
61
62    /// <summary>
63    /// Settings class. Represents settings to a given client.
64    /// </summary>
65    public abstract class Settings
66    {
67        /// <summary>
68        /// Gets the setting for the given name, coercing the object stored in the backend
69        /// to the given type <typeparamref name="T"/>.
70        /// </summary>
71        /// <typeparam name="T">The type of the setting that is currently stored in the
72        /// backend.</typeparam>
73        /// <param name="name">The name of the setting that is used to uniquely refer
74        /// to the value.</param>
75        /// <param name="defaultValue">The default to return if the no data is assocated
76        /// with the given setting.</param>
77        /// <returns>The value stored in the backend, or null if none exists.</returns>
78        public abstract T GetValue<T>(string name, T defaultValue);
79
80        /// <summary>
81        /// Overload for <see cref="GetValue"/> which returns a default for the given type.
82        /// </summary>
83        /// <typeparam name="T">The type of the setting that is currently stored in the
84        /// backend.</typeparam>
85        /// <param name="name">The name of the setting that is used to uniquely refer
86        /// to the value.</param>
87        /// <param name="defaultValue">The default to return if the no data is assocated
88        /// with the given setting.</param>
89        /// <returns>The value stored in the backend, or null if none exists.</returns>
90        public T GetValue<T>(string name)
91        {
92            return GetValue<T>(name, default(T));
93        }
94
95        /// <summary>
96        /// Sets the setting with the given name.
97        /// </summary>
98        /// <param name="name">The name of the setting.</param>
99        /// <param name="value">The value to store in the backend. This may be serialised.</param>
100        public abstract void SetValue(string name, object value);
101
102        /// <summary>
103        /// Gets or sets the given setting, without type hinting. This will not attempt to coerce
104        /// a type from an old version of the assembly to its current type.
105        /// </summary>
106        /// <param name="setting">The name of the setting.</param>
107        /// <returns>The object stored in the settings database, or null if undefined.</returns>
108        [Obsolete("Use the GetValue<T> and SetValue functions instead")]
109        public object this[string setting]
110        {
111            get
112            {
113                return GetValue<object>(setting);
114            }
115            set
116            {
117                SetValue(setting, value);
118            }
119        }
120    }
121
122    #region Default attributes
123    /// <summary>
124    /// Indicates that the marked class should be used as a default when no
125    /// settings have been set by the user.
126    /// </summary>
127    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
128    public abstract class DefaultAttribute : Attribute
129    {
130        /// <summary>
131        /// Constructor.
132        /// </summary>
133        /// <param name="priority">The priority of the current element in terms of
134        /// it being the default.</param>
135        protected DefaultAttribute(int priority)
136        {
137            Priority = priority;
138        }
139
140        /// <summary>
141        /// The priority of the default.
142        /// </summary>
143        public int Priority
144        {
145            get
146            {
147                return priority;
148            }
149            private set
150            {
151                priority = value;
152            }
153        }
154
155        private int priority;
156    }
157
158    /// <summary>
159    /// Indicates that the marked class should be used as the default file erasure
160    /// method.
161    /// </summary>
162    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
163    public sealed class DefaultFileErasureAttribute : DefaultAttribute
164    {
165        /// <summary>
166        /// Constructor.
167        /// </summary>
168        /// <param name="priority">The priority of the current element in terms of
169        /// it being the default.</param>
170        public DefaultFileErasureAttribute(int priority)
171            : base(priority)
172        {
173        }
174    }
175
176    /// <summary>
177    /// Indicates that the marked class should be used as the default unused space
178    /// erasure method.
179    /// </summary>
180    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
181    public sealed class DefaultUnusedSpaceErasureAttribute : DefaultAttribute
182    {
183        /// <summary>
184        /// Constructor.
185        /// </summary>
186        /// <param name="priority">The priority of the current element in terms of
187        /// it being the default.</param>
188        public DefaultUnusedSpaceErasureAttribute(int priority)
189            : base(priority)
190        {
191        }
192    }
193
194    /// <summary>
195    /// Indicates that the marked class should be used as the default PRNG.
196    /// </summary>
197    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
198    public sealed class DefaultPrngAttribute : DefaultAttribute
199    {
200        /// <summary>
201        /// Constructor.
202        /// </summary>
203        /// <param name="priority">The priority of the current element in terms of
204        /// it being the default.</param>
205        public DefaultPrngAttribute(int priority)
206            : base(priority)
207        {
208        }
209    }
210    #endregion
211
212    /// <summary>
213    /// Presents an opaque type for the management of the Manager settings.
214    /// </summary>
215    public class ManagerSettings
216    {
217        /// <summary>
218        /// Constructor.
219        /// </summary>
220        /// <param name="settings">The Settings object which is the data store for
221        /// this object.</param>
222        public ManagerSettings()
223        {
224            settings = ManagerLibrary.Instance.SettingsManager.ModuleSettings;
225        }
226
227        /// <summary>
228        /// The default file erasure method. This is a GUID since methods are
229        /// implemented through plugins and plugins may not be loaded and missing
230        /// references may follow.
231        /// </summary>
232        public Guid DefaultFileErasureMethod
233        {
234            get
235            {
236                //If the user did not define anything for this field, check all plugins
237                //and use the method which was declared by us to be the highest
238                //priority default
239                Guid result = settings.GetValue<Guid>("DefaultFileErasureMethod");
240                if (result == Guid.Empty)
241                    result = FindHighestPriorityDefault(typeof(ErasureMethod),
242                        typeof(DefaultFileErasureAttribute));
243                if (result == Guid.Empty)
244                    result = new Guid("{1407FC4E-FEFF-4375-B4FB-D7EFBB7E9922}");
245
246                return result;
247            }
248            set
249            {
250                settings.SetValue("DefaultFileErasureMethod", value);
251            }
252        }
253
254        /// <summary>
255        /// The default unused space erasure method. This is a GUID since methods
256        /// are implemented through plugins and plugins may not be loaded and
257        /// missing references may follow.
258        /// </summary>
259        public Guid DefaultUnusedSpaceErasureMethod
260        {
261            get
262            {
263                Guid result = settings.GetValue<Guid>("DefaultUnusedSpaceErasureMethod");
264                if (result == Guid.Empty)
265                    result = FindHighestPriorityDefault(typeof(UnusedSpaceErasureMethod),
266                        typeof(DefaultUnusedSpaceErasureAttribute));
267                if (result == Guid.Empty)
268                    result = new Guid("{BF8BA267-231A-4085-9BF9-204DE65A6641}");
269                return result;
270            }
271            set
272            {
273                settings.SetValue("DefaultUnusedSpaceErasureMethod", value);
274            }
275        }
276
277        /// <summary>
278        /// The PRNG used. This is a GUID since PRNGs are implemented through
279        /// plugins and plugins may not be loaded and missing references may follow.
280        /// </summary>
281        public Guid ActivePrng
282        {
283            get
284            {
285                Guid result = settings.GetValue<Guid>("ActivePRNG");
286                if (result == Guid.Empty)
287                    result = FindHighestPriorityDefault(typeof(Prng), typeof(DefaultPrngAttribute));
288                if (result == Guid.Empty)
289                    result = new Guid("{6BF35B8E-F37F-476e-B6B2-9994A92C3B0C}");
290                return result;
291            }
292            set
293            {
294                settings.SetValue("ActivePRNG", value);
295            }
296        }
297
298        /// <summary>
299        /// Whether files which are locked when being erased should be forcibly
300        /// unlocked for erasure.
301        /// </summary>
302        public bool ForceUnlockLockedFiles
303        {
304            get
305            {
306                return settings.GetValue("ForceUnlockLockedFiles", true);
307            }
308            set
309            {
310                settings.SetValue("ForceUnlockLockedFiles", value);
311            }
312        }
313
314        /// <summary>
315        /// Whether missed tasks should be run when the program next starts.
316        /// </summary>
317        public bool ExecuteMissedTasksImmediately
318        {
319            get
320            {
321                return settings.GetValue("ExecuteMissedTasksImmediately", true);
322            }
323            set
324            {
325                settings.SetValue("ExecuteMissedTasksImmediately", value);
326            }
327        }
328
329        /// <summary>
330        /// Whether erasures should be run with plausible deniability. This is
331        /// achieved by the executor copying files over the file to be removed
332        /// before removing it.
333        /// </summary>
334        /// <seealso cref="PlausibleDeniabilityFiles"/>
335        public bool PlausibleDeniability
336        {
337            get
338            {
339                return settings.GetValue("PlausibleDeniability", false);
340            }
341            set
342            {
343                settings.SetValue("PlausibleDeniability", value);
344            }
345        }
346
347        /// <summary>
348        /// The files which are overwritten with when a file has been erased.
349        /// </summary>
350        public IList<string> PlausibleDeniabilityFiles
351        {
352            get
353            {
354                return new SettingsList<string>(settings, "PlausibleDeniabilityFiles");
355            }
356        }
357
358        #region Default Attributes retrieval
359        /// <summary>
360        /// Finds the type for the given attribute that is the default (i.e. the
361        /// DefaultAttribute value is the highest) and that the type inherits
362        /// from the given <paramref name="superClass"/>.
363        /// </summary>
364        /// <param name="superClass">A class that the default must inherit from.</param>
365        /// <param name="attributeType">The attribute to look for.</param>
366        /// <returns>The GUID of the type that is the default.</returns>
367        private static Guid FindHighestPriorityDefault(Type superClass,
368            Type attributeType)
369        {
370            //Check if we've computed the value before. If so, we return the cached
371            //value.
372            if (DefaultForAttributes.ContainsKey(attributeType) &&
373                DefaultForAttributes[attributeType].ContainsKey(superClass))
374            {
375                return DefaultForAttributes[attributeType][superClass];
376            }
377
378            //We have not computed the value. Compute the default.
379            IList<PluginInfo> plugins = Host.Instance.Plugins;
380            SortedList<int, Guid> priorities = new SortedList<int, Guid>();
381
382            foreach (PluginInfo plugin in plugins)
383            {
384                //Check whether the plugin is signed by us.
385                byte[] pluginKey = plugin.Assembly.GetName().GetPublicKey();
386                byte[] ourKey = Assembly.GetExecutingAssembly().GetName().GetPublicKey();
387
388                if (pluginKey.Length != ourKey.Length ||
389                    !Security.VerifyStrongName(plugin.Assembly.Location))
390                    continue;
391                bool officialPlugin = true;
392                for (int i = 0, j = ourKey.Length; i != j; ++i)
393                    if (pluginKey[i] != ourKey[i])
394                        officialPlugin = false;
395                if (!officialPlugin)
396                    continue;
397
398                Type[] types = FindTypeAttributeInAssembly(plugin.Assembly,
399                    superClass, attributeType);
400
401                //Prioritize the types.
402                if (types != null)
403                    foreach (Type type in types)
404                    {
405                        object[] guids =
406                            type.GetCustomAttributes(typeof(GuidAttribute), false);
407                        DefaultAttribute defaultAttr = (DefaultAttribute)
408                            type.GetCustomAttributes(attributeType, false)[0];
409
410                        if (guids.Length == 1)
411                            priorities.Add(defaultAttr.Priority,
412                                new Guid(((GuidAttribute)guids[0]).Value));
413                    }
414            }
415
416            //If we actually have a result, cache it then return the result.
417            if (priorities.Count > 0)
418            {
419                Guid result = priorities[priorities.Keys[priorities.Count - 1]];
420                if (!DefaultForAttributes.ContainsKey(attributeType))
421                    DefaultForAttributes.Add(attributeType, new Dictionary<Type, Guid>());
422                DefaultForAttributes[attributeType].Add(superClass, result);
423                return result;
424            }
425
426            //If we do not have any results, don't store it.
427            return Guid.Empty;
428        }
429
430        /// <summary>
431        /// Finds a type with the given characteristics in the provided assembly.
432        /// </summary>
433        /// <param name="assembly">The assembly to look into.</param>
434        /// <param name="superClass">A class the type must inherit from.</param>
435        /// <param name="attributeType">The attribute the class must possess.</param>
436        /// <returns>An array of types with the given characteristics.</returns>
437        private static Type[] FindTypeAttributeInAssembly(Assembly assembly, Type superClass,
438            Type attributeType)
439        {
440            //Yes, if we got here the plugin is signed by us. Find the
441            //type which inherits from ErasureMethod.
442            Type[] types = assembly.GetExportedTypes();
443            List<Type> result = new List<Type>();
444            foreach (Type type in types)
445            {
446                if (!type.IsPublic || type.IsAbstract)
447                    //Not interesting.
448                    continue;
449
450                //Try to see if this class inherits from the specified super class.
451                if (!type.IsSubclassOf(superClass))
452                    continue;
453
454                //See if this class has the DefaultFileErasureAttribute
455                object[] attributes = type.GetCustomAttributes(attributeType, false);
456                if (attributes.Length > 0)
457                    result.Add(type);
458            }
459
460            return result.ToArray();
461        }
462
463        /// <summary>
464        /// Caches the defaults as computed by FindHighestPriorityDefault. The first
465        /// key is the attribute type, the second key is the superclass, the
466        /// value is the Guid.
467        /// </summary>
468        private static Dictionary<Type, Dictionary<Type, Guid>> DefaultForAttributes =
469            new Dictionary<Type, Dictionary<Type, Guid>>();
470        #endregion
471
472        /// <summary>
473        /// Holds user decisions on whether the plugin will be loaded at the next
474        /// start up.
475        /// </summary>
476        public IDictionary<Guid, bool> PluginApprovals
477        {
478            get
479            {
480                return new SettingsDictionary<Guid, bool>(settings, "ApprovedPlugins");
481            }
482        }
483
484        /// <summary>
485        /// The Settings object which is the data store of this object.
486        /// </summary>
487        private Settings settings;
488
489        /// <summary>
490        /// Encapsulates an abstract list that is used to store settings.
491        /// </summary>
492        /// <typeparam name="T">The type of the list element.</typeparam>
493        private class SettingsList<T> : IList<T>
494        {
495            public SettingsList(Settings settings, string settingName)
496            {
497                Settings = settings;
498                SettingName = settingName;
499                List = new List<T>();
500
501                T[] values = settings.GetValue<T[]>(settingName);
502                if (values != null)
503                    List.AddRange(values);
504            }
505
506            ~SettingsList()
507            {
508                Save();
509            }
510
511            #region IList<T> Members
512
513            public int IndexOf(T item)
514            {
515                return List.IndexOf(item);
516            }
517
518            public void Insert(int index, T item)
519            {
520                List.Insert(index, item);
521                Save();
522            }
523
524            public void RemoveAt(int index)
525            {
526                List.RemoveAt(index);
527                Save();
528            }
529
530            public T this[int index]
531            {
532                get
533                {
534                    return List[index];
535                }
536                set
537                {
538                    List[index] = value;
539                    Save();
540                }
541            }
542
543            #endregion
544
545            #region ICollection<T> Members
546
547            public void Add(T item)
548            {
549                List.Add(item);
550                Save();
551            }
552
553            public void Clear()
554            {
555                List.Clear();
556                Save();
557            }
558
559            public bool Contains(T item)
560            {
561                return List.Contains(item);
562            }
563
564            public void CopyTo(T[] array, int arrayIndex)
565            {
566                List.CopyTo(array, arrayIndex);
567            }
568
569            public int Count
570            {
571                get { return List.Count; }
572            }
573
574            public bool IsReadOnly
575            {
576                get { return false; }
577            }
578
579            public bool Remove(T item)
580            {
581                bool result = List.Remove(item);
582                Save();
583                return result;
584            }
585
586            #endregion
587
588            #region IEnumerable<T> Members
589
590            public IEnumerator<T> GetEnumerator()
591            {
592                return List.GetEnumerator();
593            }
594
595            #endregion
596
597            #region IEnumerable Members
598
599            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
600            {
601                return List.GetEnumerator();
602            }
603
604            #endregion
605
606            /// <summary>
607            /// Saves changes made to the list to the settings manager.
608            /// </summary>
609            private void Save()
610            {
611                Settings.SetValue(SettingName, List);
612            }
613
614            /// <summary>
615            /// The settings object storing the settings.
616            /// </summary>
617            private Settings Settings;
618
619            /// <summary>
620            /// The name of the setting we are encapsulating.
621            /// </summary>
622            private string SettingName;
623
624            /// <summary>
625            /// The list we are using as scratch.
626            /// </summary>
627            private List<T> List;
628        }
629
630        /// <summary>
631        /// Encapsulates an abstract dictionary that is used to store settings.
632        /// </summary>
633        /// <typeparam name="TKey">The key type of the dictionary.</typeparam>
634        /// <typeparam name="TValue">The value type of the dictionary.</typeparam>
635        private class SettingsDictionary<TKey, TValue> : IDictionary<TKey, TValue>
636        {
637            public SettingsDictionary(Settings settings, string settingName)
638            {
639                Settings = settings;
640                SettingName = settingName;
641                Dictionary = settings.GetValue<Dictionary<TKey, TValue>>(settingName);
642                if (Dictionary == null)
643                    Dictionary = new Dictionary<TKey, TValue>();
644            }
645
646            ~SettingsDictionary()
647            {
648                Save();
649            }
650
651            #region IDictionary<TKey,TValue> Members
652
653            public void Add(TKey key, TValue value)
654            {
655                Dictionary.Add(key, value);
656                Save();
657            }
658
659            public bool ContainsKey(TKey key)
660            {
661                return Dictionary.ContainsKey(key);
662            }
663
664            public ICollection<TKey> Keys
665            {
666                get { return Dictionary.Keys; }
667            }
668
669            public bool Remove(TKey key)
670            {
671                bool result = Dictionary.Remove(key);
672                Save();
673                return result;
674            }
675
676            public bool TryGetValue(TKey key, out TValue value)
677            {
678                return Dictionary.TryGetValue(key, out value);
679            }
680
681            public ICollection<TValue> Values
682            {
683                get { return Dictionary.Values; }
684            }
685
686            public TValue this[TKey key]
687            {
688                get
689                {
690                    return Dictionary[key];
691                }
692                set
693                {
694                    Dictionary[key] = value;
695                    Save();
696                }
697            }
698
699            #endregion
700
701            #region ICollection<KeyValuePair<TKey,TValue>> Members
702
703            public void Add(KeyValuePair<TKey, TValue> item)
704            {
705                Dictionary.Add(item.Key, item.Value);
706                Save();
707            }
708
709            public void Clear()
710            {
711                Dictionary.Clear();
712                Save();
713            }
714
715            public bool Contains(KeyValuePair<TKey, TValue> item)
716            {
717                return Dictionary.ContainsKey(item.Key) && Dictionary[item.Key].Equals(item.Value);
718            }
719
720            public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
721            {
722                throw new NotImplementedException();
723            }
724
725            public int Count
726            {
727                get { return Dictionary.Count; }
728            }
729
730            public bool IsReadOnly
731            {
732                get { return false; }
733            }
734
735            public bool Remove(KeyValuePair<TKey, TValue> item)
736            {
737                if (Dictionary.ContainsKey(item.Key) && Dictionary[item.Key].Equals(item.Value))
738                {
739                    bool result = Dictionary.Remove(item.Key);
740                    Save();
741                    return result;
742                }
743
744                return false;
745            }
746
747            #endregion
748
749            #region IEnumerable<KeyValuePair<TKey,TValue>> Members
750
751            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
752            {
753                return Dictionary.GetEnumerator();
754            }
755
756            #endregion
757
758            #region IEnumerable Members
759
760            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
761            {
762                return Dictionary.GetEnumerator();
763            }
764
765            #endregion
766
767            /// <summary>
768            /// Saves changes made to the list to the settings manager.
769            /// </summary>
770            private void Save()
771            {
772                Settings.SetValue(SettingName, Dictionary);
773            }
774
775            /// <summary>
776            /// The settings object storing the settings.
777            /// </summary>
778            private Settings Settings;
779
780            /// <summary>
781            /// The name of the setting we are encapsulating.
782            /// </summary>
783            private string SettingName;
784
785            /// <summary>
786            /// The list we are using as scratch.
787            /// </summary>
788            private Dictionary<TKey, TValue> Dictionary;
789        }
790
791    }
792}
Note: See TracBrowser for help on using the repository browser.