using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using Tor.Config; using Tor.Helpers; namespace Tor { /// /// A class containing the configurations needed when launching a tor application executable. /// [DebuggerStepThrough] [Serializable] public sealed class ClientCreateParams { private string defaultConfigurationFile; private string configurationFile; private string controlPassword; private int controlPort; private Dictionary overrides; private string path; /// /// Initializes a new instance of the class. /// public ClientCreateParams() : this(null, 9051, "", null) { } /// /// Initializes a new instance of the class. /// /// The path to the application executable file. public ClientCreateParams(string path) : this(path, 9051, "", null) { } /// /// Initializes a new instance of the class. /// /// The path to the application executable file. /// The path to the configuration file. public ClientCreateParams(string path, string configurationFile) : this(path, 9051, "", configurationFile) { } /// /// Initializes a new instance of the class. /// /// The path to the application executable file. /// The port number which the application will listening on for control connections. public ClientCreateParams(string path, int controlPort) : this(path, controlPort, "", null) { } /// /// Initializes a new instance of the class. /// /// The path to the application executable file. /// The port number which the application will listening on for control connections. /// The password used when authenticating with the control connection. public ClientCreateParams(string path, int controlPort, string controlPassword) : this(path, controlPort, controlPassword, null) { } /// /// Initializes a new instance of the class. /// /// The path to the application executable file. /// The port number which the application will listening on for control connections. /// The password used when authenticating with the control connection. /// The path to the configuration file. public ClientCreateParams(string path, int controlPort, string controlPassword, string configurationFile) { this.configurationFile = configurationFile; this.controlPassword = controlPassword; this.controlPort = controlPort; this.defaultConfigurationFile = null; this.overrides = new Dictionary(); this.path = path; } #region Properties /// /// Gets or sets the path to the configuration file containing the default values. A value of null /// indicates that no default configuration file will be loaded. /// public string DefaultConfigurationFile { get { return defaultConfigurationFile; } set { defaultConfigurationFile = value; } } /// /// Gets or sets the path to the configuration file. A value of null indicates that no /// configuration file will be loaded. /// public string ConfigurationFile { get { return configurationFile; } set { configurationFile = value; } } /// /// Gets or sets the password used when authenticating with the tor application on the control connection. A value of /// null or blank indicates that no password has been configured. /// public string ControlPassword { get { return controlPassword; } set { controlPassword = value; } } /// /// Gets or sets the port number which the application will be listening on for control connections. /// public int ControlPort { get { return controlPort; } set { controlPort = value; } } /// /// Gets or sets the path to the application executable file. /// public string Path { get { return path; } set { path = value; } } #endregion #region System.Object /// /// Determines whether the specified , is equal to this instance. /// /// The to compare with this instance. /// /// true if the specified is equal to this instance; otherwise, false. /// public override bool Equals(object obj) { ClientCreateParams compare = obj as ClientCreateParams; if (compare == null) return false; return compare.configurationFile == configurationFile && compare.controlPassword == controlPassword && compare.controlPort == controlPort && compare.defaultConfigurationFile == defaultConfigurationFile && compare.path == path; } /// /// Returns a hash code for this instance. /// /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { unchecked { int hash = 17; hash = hash * 23 + (defaultConfigurationFile != null ? defaultConfigurationFile.GetHashCode() : 0); hash = hash * 23 + (configurationFile != null ? configurationFile.GetHashCode() : 0); hash = hash * 23 + (controlPassword != null ? controlPassword.GetHashCode() : 0); hash = hash * 23 + (controlPort); hash = hash * 23 + (path != null ? path.GetHashCode() : 0); return hash; } } /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// public override string ToString() { StringBuilder builder; builder = new StringBuilder(); builder.Append("--ignore-missing-torrc "); builder.Append("--allow-missing-torrc "); builder.AppendFormat("--ControlPort {0}", controlPort); /** TEMPORARY: DELETE LATER **/ builder.AppendFormat(" --SocksPort 9050"); if (!string.IsNullOrWhiteSpace(configurationFile)) builder.AppendFormat(" -f \"{0}\"", configurationFile); if (!string.IsNullOrWhiteSpace(defaultConfigurationFile)) builder.AppendFormat(" --defaults-torrc \"{0}\"", defaultConfigurationFile); foreach (KeyValuePair over in overrides) { string value = ""; ConfigurationAssocAttribute attribute = ReflectionHelper.GetAttribute(over.Key); if (attribute == null) continue; if (over.Value != null) value = ReflectionHelper.Convert(over.Value, typeof(string)) as string; if (value == null) value = ""; if (value.Contains(" ")) value = "\"" + value + "\""; builder.AppendFormat(" --{0} {1}", attribute.Name, value); } return builder.ToString(); } #endregion /// /// Sets the value of a configuration supplied with the process arguments. Setting a configuration value within the create /// parameters overrides any values stored in the configuration file. The control port can also be set using this method. /// /// The configuration which should be overridden. /// The value of the configuration. This should align with the type specified in the class. public void SetConfig(ConfigurationNames configuration, object value) { ConfigurationAssocAttribute attribute = ReflectionHelper.GetAttribute(configuration); if (attribute == null) return; if (value != null && !value.GetType().Equals(attribute.Type)) throw new ArgumentException("The value of this configuration should be of type " + attribute.Type, "value"); ConfigurationValidation validation = attribute.Validation; if (validation != ConfigurationValidation.None) { if (validation.HasFlag(ConfigurationValidation.NonNull) && value == null) throw new ArgumentNullException("value"); if (validation.HasFlag(ConfigurationValidation.NonZero) || validation.HasFlag(ConfigurationValidation.NonNegative) || validation.HasFlag(ConfigurationValidation.PortRange)) { int converted = Convert.ToInt32(value); if (validation.HasFlag(ConfigurationValidation.NonZero) && converted == 0) throw new ArgumentOutOfRangeException("value", "The value of this configuration cannot be zero"); if (validation.HasFlag(ConfigurationValidation.NonNegative) && converted < 0) throw new ArgumentOutOfRangeException("value", "The value of this configuration cannot be below zero"); if (validation.HasFlag(ConfigurationValidation.PortRange) && (converted <= 0 || short.MaxValue < converted)) throw new ArgumentOutOfRangeException("value", "The value of this configuration must be within a valid port range"); } if (validation.HasFlag(ConfigurationValidation.SizeDivision)) { double converted = Convert.ToDouble(value); if (converted % 1024 != 0) throw new ArgumentException("The value of this configuration must be divisible by 1024"); } } if (configuration == ConfigurationNames.ControlPort) controlPort = Convert.ToInt32(value); else overrides[configuration] = value; } /// /// Validates the parameters assigned to the object, and throws relevant exceptions where necessary. /// internal void ValidateParameters() { if (string.IsNullOrWhiteSpace(path)) throw new TorException("The path cannot be null or white-space"); if (controlPort <= 0 || short.MaxValue < controlPort) throw new TorException("The control port number must be within a valid port range"); } } }