﻿// Decompiled with JetBrains decompiler
// Type: System.Security.Policy.NetCodeGroup
// Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: 255ABCDF-D9D6-4E3D-BAD4-F74D4CE3D7A8
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll

using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security;
using System.Text;

namespace System.Security.Policy
{
  /// <summary>
  /// Grants Web permission to the site from which the assembly was downloaded. This class cannot be inherited.
  /// </summary>
  [ComVisible(true)]
  [Serializable]
  public sealed class NetCodeGroup : CodeGroup, IUnionSemanticCodeGroup
  {
    private static readonly char[] c_SomeRegexChars = new char[12]
    {
      '.',
      '-',
      '+',
      '[',
      ']',
      '{',
      '$',
      '^',
      '#',
      ')',
      '(',
      ' '
    };
    /// <summary>
    /// Contains a value used to specify any other unspecified origin scheme.
    /// </summary>
    public static readonly string AnyOtherOriginScheme = CodeConnectAccess.AnyScheme;
    /// <summary>
    /// Contains a value used to specify connection access for code with an unknown or unrecognized origin scheme.
    /// </summary>
    public static readonly string AbsentOriginScheme = string.Empty;
    [OptionalField(VersionAdded = 2)]
    private ArrayList m_schemesList;
    [OptionalField(VersionAdded = 2)]
    private ArrayList m_accessList;
    private const string c_IgnoreUserInfo = "";
    private const string c_AnyScheme = "([0-9a-z+\\-\\.]+)://";

    /// <summary>
    /// Gets the logic to use for merging groups.
    /// </summary>
    /// 
    /// <returns>
    /// The string "Union".
    /// </returns>
    public override string MergeLogic
    {
      get
      {
        return Environment.GetResourceString("MergeLogic_Union");
      }
    }

    /// <summary>
    /// Gets the name of the <see cref="T:System.Security.NamedPermissionSet"/> for the code group.
    /// </summary>
    /// 
    /// <returns>
    /// Always the string "Same site Web."
    /// </returns>
    public override string PermissionSetName
    {
      get
      {
        return Environment.GetResourceString("NetCodeGroup_PermissionSet");
      }
    }

    /// <summary>
    /// Gets a string representation of the attributes of the policy statement for the code group.
    /// </summary>
    /// 
    /// <returns>
    /// Always null.
    /// </returns>
    public override string AttributeString
    {
      get
      {
        return (string) null;
      }
    }

    internal NetCodeGroup()
    {
      this.SetDefaults();
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="T:System.Security.Policy.NetCodeGroup"/> class.
    /// </summary>
    /// <param name="membershipCondition">A membership condition that tests evidence to determine whether this code group applies code access security policy. </param><exception cref="T:System.ArgumentNullException">The <paramref name="membershipCondition"/> parameter is null. </exception><exception cref="T:System.ArgumentException">The type of the <paramref name="membershipCondition"/> parameter is not valid. </exception>
    public NetCodeGroup(IMembershipCondition membershipCondition)
      : base(membershipCondition, (PolicyStatement) null)
    {
      this.SetDefaults();
    }

    /// <summary>
    /// Removes all connection access information for the current code group.
    /// </summary>
    public void ResetConnectAccess()
    {
      this.m_schemesList = (ArrayList) null;
      this.m_accessList = (ArrayList) null;
    }

    /// <summary>
    /// Adds the specified connection access to the current code group.
    /// </summary>
    /// <param name="originScheme">A <see cref="T:System.String"/> containing the scheme to match against the code's scheme.</param><param name="connectAccess">A <see cref="T:System.Security.Policy.CodeConnectAccess"/> that specifies the scheme and port code can use to connect back to its origin server.</param><exception cref="T:System.ArgumentNullException"><paramref name="originScheme"/> is null.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="originScheme"/> contains characters that are not permitted in schemes.-or-<paramref name="originScheme"/> = <see cref="F:System.Security.Policy.NetCodeGroup.AbsentOriginScheme"/> and <paramref name="connectAccess"/> specifies <see cref="F:System.Security.Policy.CodeConnectAccess.OriginScheme"/> as its scheme.</exception>
    public void AddConnectAccess(string originScheme, CodeConnectAccess connectAccess)
    {
      if (originScheme == null)
        throw new ArgumentNullException("originScheme");
      if (originScheme != NetCodeGroup.AbsentOriginScheme && originScheme != NetCodeGroup.AnyOtherOriginScheme && !CodeConnectAccess.IsValidScheme(originScheme))
        throw new ArgumentOutOfRangeException("originScheme");
      if (originScheme == NetCodeGroup.AbsentOriginScheme && connectAccess.IsOriginScheme)
        throw new ArgumentOutOfRangeException("connectAccess");
      if (this.m_schemesList == null)
      {
        this.m_schemesList = new ArrayList();
        this.m_accessList = new ArrayList();
      }
      originScheme = originScheme.ToLower(CultureInfo.InvariantCulture);
      for (int index1 = 0; index1 < this.m_schemesList.Count; ++index1)
      {
        if ((string) this.m_schemesList[index1] == originScheme)
        {
          if (connectAccess == null)
            return;
          ArrayList arrayList = (ArrayList) this.m_accessList[index1];
          for (int index2 = 0; index2 < arrayList.Count; ++index2)
          {
            if (((CodeConnectAccess) arrayList[index2]).Equals((object) connectAccess))
              return;
          }
          arrayList.Add((object) connectAccess);
          return;
        }
      }
      this.m_schemesList.Add((object) originScheme);
      ArrayList arrayList1 = new ArrayList();
      this.m_accessList.Add((object) arrayList1);
      if (connectAccess == null)
        return;
      arrayList1.Add((object) connectAccess);
    }

    /// <summary>
    /// Gets the connection access information for the current code group.
    /// </summary>
    /// 
    /// <returns>
    /// A <see cref="T:System.Collections.DictionaryEntry"/> array containing connection access information.
    /// </returns>
    public DictionaryEntry[] GetConnectAccessRules()
    {
      if (this.m_schemesList == null)
        return (DictionaryEntry[]) null;
      DictionaryEntry[] dictionaryEntryArray = new DictionaryEntry[this.m_schemesList.Count];
      for (int index = 0; index < dictionaryEntryArray.Length; ++index)
      {
        dictionaryEntryArray[index].Key = this.m_schemesList[index];
        dictionaryEntryArray[index].Value = (object) ((ArrayList) this.m_accessList[index]).ToArray(typeof (CodeConnectAccess));
      }
      return dictionaryEntryArray;
    }

    /// <summary>
    /// Resolves policy for the code group and its descendants for a set of evidence.
    /// </summary>
    /// 
    /// <returns>
    /// A <see cref="T:System.Security.Policy.PolicyStatement"/> that consists of the permissions granted by the code group with optional attributes, or null if the code group does not apply (the membership condition does not match the specified evidence).
    /// </returns>
    /// <param name="evidence">The <see cref="T:System.Security.Policy.Evidence"/> for the assembly. </param><exception cref="T:System.ArgumentNullException">The <paramref name="evidence"/> parameter is null. </exception><exception cref="T:System.Security.Policy.PolicyException">More than one code group (including the parent code group and any child code groups) is marked <see cref="F:System.Security.Policy.PolicyStatementAttribute.Exclusive"/>. </exception><PermissionSet><IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="ControlEvidence"/></PermissionSet>
    [SecuritySafeCritical]
    public override PolicyStatement Resolve(Evidence evidence)
    {
      if (evidence == null)
        throw new ArgumentNullException("evidence");
      object usedEvidence = (object) null;
      if (!PolicyManager.CheckMembershipCondition(this.MembershipCondition, evidence, out usedEvidence))
        return (PolicyStatement) null;
      PolicyStatement policyStatement = this.CalculateAssemblyPolicy(evidence);
      IDelayEvaluatedEvidence dependentEvidence = usedEvidence as IDelayEvaluatedEvidence;
      if (dependentEvidence != null && !dependentEvidence.IsVerified)
        policyStatement.AddDependentEvidence(dependentEvidence);
      bool flag = false;
      IEnumerator enumerator = this.Children.GetEnumerator();
      while (enumerator.MoveNext() && !flag)
      {
        PolicyStatement childPolicy = PolicyManager.ResolveCodeGroup(enumerator.Current as CodeGroup, evidence);
        if (childPolicy != null)
        {
          policyStatement.InplaceUnion(childPolicy);
          if ((childPolicy.Attributes & PolicyStatementAttribute.Exclusive) == PolicyStatementAttribute.Exclusive)
            flag = true;
        }
      }
      return policyStatement;
    }

    PolicyStatement IUnionSemanticCodeGroup.InternalResolve(Evidence evidence)
    {
      if (evidence == null)
        throw new ArgumentNullException("evidence");
      if (this.MembershipCondition.Check(evidence))
        return this.CalculateAssemblyPolicy(evidence);
      return (PolicyStatement) null;
    }

    /// <summary>
    /// Resolves matching code groups.
    /// </summary>
    /// 
    /// <returns>
    /// The complete set of code groups that were matched by the evidence.
    /// </returns>
    /// <param name="evidence">The evidence for the assembly. </param><exception cref="T:System.ArgumentNullException">The <paramref name="evidence"/> parameter is null. </exception>
    public override CodeGroup ResolveMatchingCodeGroups(Evidence evidence)
    {
      if (evidence == null)
        throw new ArgumentNullException("evidence");
      if (!this.MembershipCondition.Check(evidence))
        return (CodeGroup) null;
      CodeGroup codeGroup1 = this.Copy();
      codeGroup1.Children = (IList) new ArrayList();
      foreach (CodeGroup codeGroup2 in (IEnumerable) this.Children)
      {
        CodeGroup group = codeGroup2.ResolveMatchingCodeGroups(evidence);
        if (group != null)
          codeGroup1.AddChild(group);
      }
      return codeGroup1;
    }

    internal SecurityElement CreateWebPermission(string host, string scheme, string port, string assemblyOverride)
    {
      if (scheme == null)
        scheme = string.Empty;
      if (host == null || host.Length == 0)
        return (SecurityElement) null;
      host = host.ToLower(CultureInfo.InvariantCulture);
      scheme = scheme.ToLower(CultureInfo.InvariantCulture);
      int intPort = -1;
      if (port != null && port.Length != 0)
        intPort = int.Parse(port, (IFormatProvider) CultureInfo.InvariantCulture);
      else
        port = string.Empty;
      CodeConnectAccess[] accessRulesForScheme = this.FindAccessRulesForScheme(scheme);
      if (accessRulesForScheme == null || accessRulesForScheme.Length == 0)
        return (SecurityElement) null;
      SecurityElement securityElement = new SecurityElement("IPermission");
      string str1 = assemblyOverride == null ? "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" : assemblyOverride;
      securityElement.AddAttribute("class", "System.Net.WebPermission, " + str1);
      securityElement.AddAttribute("version", "1");
      SecurityElement child1 = new SecurityElement("ConnectAccess");
      host = this.EscapeStringForRegex(host);
      scheme = this.EscapeStringForRegex(scheme);
      string str2 = this.TryPermissionAsOneString(accessRulesForScheme, scheme, host, intPort);
      if (str2 != null)
      {
        SecurityElement child2 = new SecurityElement("URI");
        child2.AddAttribute("uri", str2);
        child1.AddChild(child2);
      }
      else
      {
        if (port.Length != 0)
          port = ":" + port;
        for (int index = 0; index < accessRulesForScheme.Length; ++index)
        {
          string accessElementString = this.GetPermissionAccessElementString(accessRulesForScheme[index], scheme, host, port);
          SecurityElement child2 = new SecurityElement("URI");
          child2.AddAttribute("uri", accessElementString);
          child1.AddChild(child2);
        }
      }
      securityElement.AddChild(child1);
      return securityElement;
    }

    internal PolicyStatement CalculatePolicy(string host, string scheme, string port)
    {
      SecurityElement webPermission = this.CreateWebPermission(host, scheme, port, (string) null);
      SecurityElement et = new SecurityElement("PolicyStatement");
      SecurityElement child = new SecurityElement("PermissionSet");
      child.AddAttribute("class", "System.Security.PermissionSet");
      child.AddAttribute("version", "1");
      if (webPermission != null)
        child.AddChild(webPermission);
      et.AddChild(child);
      PolicyStatement policyStatement = new PolicyStatement();
      policyStatement.FromXml(et);
      return policyStatement;
    }

    /// <summary>
    /// Makes a deep copy of the current code group.
    /// </summary>
    /// 
    /// <returns>
    /// An equivalent copy of the current code group, including its membership conditions and child code groups.
    /// </returns>
    public override CodeGroup Copy()
    {
      NetCodeGroup netCodeGroup = new NetCodeGroup(this.MembershipCondition);
      netCodeGroup.Name = this.Name;
      netCodeGroup.Description = this.Description;
      if (this.m_schemesList != null)
      {
        netCodeGroup.m_schemesList = (ArrayList) this.m_schemesList.Clone();
        netCodeGroup.m_accessList = new ArrayList(this.m_accessList.Count);
        for (int index = 0; index < this.m_accessList.Count; ++index)
          netCodeGroup.m_accessList.Add(((ArrayList) this.m_accessList[index]).Clone());
      }
      foreach (CodeGroup group in (IEnumerable) this.Children)
        netCodeGroup.AddChild(group);
      return (CodeGroup) netCodeGroup;
    }

    /// <summary>
    /// Determines whether the specified code group is equivalent to the current code group.
    /// </summary>
    /// 
    /// <returns>
    /// true if the specified code group is equivalent to the current code group; otherwise, false.
    /// </returns>
    /// <param name="o">The <see cref="T:System.Security.Policy.NetCodeGroup"/> object to compare with the current code group.</param>
    public override bool Equals(object o)
    {
      if (this == o)
        return true;
      NetCodeGroup netCodeGroup = o as NetCodeGroup;
      if (netCodeGroup == null || !base.Equals((object) netCodeGroup) || this.m_schemesList == null != (netCodeGroup.m_schemesList == null))
        return false;
      if (this.m_schemesList == null)
        return true;
      if (this.m_schemesList.Count != netCodeGroup.m_schemesList.Count)
        return false;
      for (int index1 = 0; index1 < this.m_schemesList.Count; ++index1)
      {
        int index2 = netCodeGroup.m_schemesList.IndexOf(this.m_schemesList[index1]);
        if (index2 == -1)
          return false;
        ArrayList arrayList1 = (ArrayList) this.m_accessList[index1];
        ArrayList arrayList2 = (ArrayList) netCodeGroup.m_accessList[index2];
        if (arrayList1.Count != arrayList2.Count)
          return false;
        for (int index3 = 0; index3 < arrayList1.Count; ++index3)
        {
          if (!arrayList2.Contains(arrayList1[index3]))
            return false;
        }
      }
      return true;
    }

    /// <returns>
    /// The hash code of the current code group.
    /// </returns>
    public override int GetHashCode()
    {
      return base.GetHashCode() + this.GetRulesHashCode();
    }

    protected override void CreateXml(SecurityElement element, PolicyLevel level)
    {
      DictionaryEntry[] connectAccessRules = this.GetConnectAccessRules();
      if (connectAccessRules == null)
        return;
      SecurityElement child1 = new SecurityElement("connectAccessRules");
      foreach (DictionaryEntry dictionaryEntry in connectAccessRules)
      {
        SecurityElement child2 = new SecurityElement("codeOrigin");
        child2.AddAttribute("scheme", (string) dictionaryEntry.Key);
        foreach (CodeConnectAccess codeConnectAccess in (CodeConnectAccess[]) dictionaryEntry.Value)
        {
          SecurityElement child3 = new SecurityElement("connectAccess");
          child3.AddAttribute("scheme", codeConnectAccess.Scheme);
          child3.AddAttribute("port", codeConnectAccess.StrPort);
          child2.AddChild(child3);
        }
        child1.AddChild(child2);
      }
      element.AddChild(child1);
    }

    protected override void ParseXml(SecurityElement e, PolicyLevel level)
    {
      this.ResetConnectAccess();
      SecurityElement securityElement1 = e.SearchForChildByTag("connectAccessRules");
      if (securityElement1 == null || securityElement1.Children == null)
      {
        this.SetDefaults();
      }
      else
      {
        foreach (SecurityElement securityElement2 in securityElement1.Children)
        {
          if (securityElement2.Tag.Equals("codeOrigin"))
          {
            string originScheme = securityElement2.Attribute("scheme");
            bool flag = false;
            if (securityElement2.Children != null)
            {
              foreach (SecurityElement securityElement3 in securityElement2.Children)
              {
                if (securityElement3.Tag.Equals("connectAccess"))
                {
                  string allowScheme = securityElement3.Attribute("scheme");
                  string allowPort = securityElement3.Attribute("port");
                  this.AddConnectAccess(originScheme, new CodeConnectAccess(allowScheme, allowPort));
                  flag = true;
                }
              }
            }
            if (!flag)
              this.AddConnectAccess(originScheme, (CodeConnectAccess) null);
          }
        }
      }
    }

    internal override string GetTypeName()
    {
      return "System.Security.Policy.NetCodeGroup";
    }

    [SecurityCritical]
    [Conditional("_DEBUG")]
    private static void DEBUG_OUT(string str)
    {
    }

    [OnDeserializing]
    private void OnDeserializing(StreamingContext ctx)
    {
      this.m_schemesList = (ArrayList) null;
      this.m_accessList = (ArrayList) null;
    }

    private string EscapeStringForRegex(string str)
    {
      int startIndex = 0;
      StringBuilder stringBuilder = (StringBuilder) null;
      int index;
      for (; startIndex < str.Length && (index = str.IndexOfAny(NetCodeGroup.c_SomeRegexChars, startIndex)) != -1; startIndex = index + 1)
      {
        if (stringBuilder == null)
          stringBuilder = new StringBuilder(str.Length * 2);
        stringBuilder.Append(str, startIndex, index - startIndex).Append('\\').Append(str[index]);
      }
      if (stringBuilder == null)
        return str;
      if (startIndex < str.Length)
        stringBuilder.Append(str, startIndex, str.Length - startIndex);
      return stringBuilder.ToString();
    }

    private CodeConnectAccess[] FindAccessRulesForScheme(string lowerCaseScheme)
    {
      if (this.m_schemesList == null)
        return (CodeConnectAccess[]) null;
      int index = this.m_schemesList.IndexOf((object) lowerCaseScheme);
      if (index == -1 && (lowerCaseScheme == NetCodeGroup.AbsentOriginScheme || (index = this.m_schemesList.IndexOf((object) NetCodeGroup.AnyOtherOriginScheme)) == -1))
        return (CodeConnectAccess[]) null;
      return (CodeConnectAccess[]) ((ArrayList) this.m_accessList[index]).ToArray(typeof (CodeConnectAccess));
    }

    private string TryPermissionAsOneString(CodeConnectAccess[] access, string escapedScheme, string escapedHost, int intPort)
    {
      bool flag1 = true;
      bool flag2 = true;
      bool flag3 = false;
      int num = -2;
      for (int index = 0; index < access.Length; ++index)
      {
        flag1 = ((flag1 ? 1 : 0) & (access[index].IsDefaultPort ? 1 : (!access[index].IsOriginPort ? 0 : (intPort == -1 ? 1 : 0)))) != 0;
        flag2 = ((flag2 ? 1 : 0) & (access[index].IsOriginPort ? 1 : (access[index].Port == intPort ? 1 : 0))) != 0;
        if (access[index].Port >= 0)
        {
          if (num == -2)
            num = access[index].Port;
          else if (access[index].Port != num)
            num = -1;
        }
        else
          num = -1;
        if (access[index].IsAnyScheme)
          flag3 = true;
      }
      if (!flag1 && !flag2 && num == -1)
        return (string) null;
      StringBuilder stringBuilder = new StringBuilder("([0-9a-z+\\-\\.]+)://".Length * access.Length + "".Length * 2 + escapedHost.Length);
      if (flag3)
      {
        stringBuilder.Append("([0-9a-z+\\-\\.]+)://");
      }
      else
      {
        stringBuilder.Append('(');
        for (int index1 = 0; index1 < access.Length; ++index1)
        {
          int index2 = 0;
          while (index2 < index1 && !(access[index1].Scheme == access[index2].Scheme))
            ++index2;
          if (index2 == index1)
          {
            if (index1 != 0)
              stringBuilder.Append('|');
            stringBuilder.Append(access[index1].IsOriginScheme ? escapedScheme : this.EscapeStringForRegex(access[index1].Scheme));
          }
        }
        stringBuilder.Append(")://");
      }
      stringBuilder.Append("").Append(escapedHost);
      if (!flag1)
      {
        if (flag2)
          stringBuilder.Append(':').Append(intPort);
        else
          stringBuilder.Append(':').Append(num);
      }
      stringBuilder.Append("/.*");
      return stringBuilder.ToString();
    }

    private string GetPermissionAccessElementString(CodeConnectAccess access, string escapedScheme, string escapedHost, string strPort)
    {
      StringBuilder stringBuilder = new StringBuilder("([0-9a-z+\\-\\.]+)://".Length * 2 + "".Length + escapedHost.Length);
      if (access.IsAnyScheme)
        stringBuilder.Append("([0-9a-z+\\-\\.]+)://");
      else if (access.IsOriginScheme)
        stringBuilder.Append(escapedScheme).Append("://");
      else
        stringBuilder.Append(this.EscapeStringForRegex(access.Scheme)).Append("://");
      stringBuilder.Append("").Append(escapedHost);
      if (!access.IsDefaultPort)
      {
        if (access.IsOriginPort)
          stringBuilder.Append(strPort);
        else
          stringBuilder.Append(':').Append(access.StrPort);
      }
      stringBuilder.Append("/.*");
      return stringBuilder.ToString();
    }

    private PolicyStatement CalculateAssemblyPolicy(Evidence evidence)
    {
      PolicyStatement policyStatement = (PolicyStatement) null;
      Url hostEvidence1 = evidence.GetHostEvidence<Url>();
      if (hostEvidence1 != null)
        policyStatement = this.CalculatePolicy(hostEvidence1.GetURLString().Host, hostEvidence1.GetURLString().Scheme, hostEvidence1.GetURLString().Port);
      if (policyStatement == null)
      {
        Site hostEvidence2 = evidence.GetHostEvidence<Site>();
        if (hostEvidence2 != null)
          policyStatement = this.CalculatePolicy(hostEvidence2.Name, (string) null, (string) null);
      }
      if (policyStatement == null)
        policyStatement = new PolicyStatement(new PermissionSet(false), PolicyStatementAttribute.Nothing);
      return policyStatement;
    }

    private int GetRulesHashCode()
    {
      if (this.m_schemesList == null)
        return 0;
      int num = 0;
      for (int index = 0; index < this.m_schemesList.Count; ++index)
        num += ((string) this.m_schemesList[index]).GetHashCode();
      foreach (ArrayList arrayList in this.m_accessList)
      {
        for (int index = 0; index < arrayList.Count; ++index)
          num += ((CodeConnectAccess) arrayList[index]).GetHashCode();
      }
      return num;
    }

    private void SetDefaults()
    {
      this.AddConnectAccess("file", (CodeConnectAccess) null);
      this.AddConnectAccess("http", new CodeConnectAccess("http", CodeConnectAccess.OriginPort));
      this.AddConnectAccess("http", new CodeConnectAccess("https", CodeConnectAccess.OriginPort));
      this.AddConnectAccess("https", new CodeConnectAccess("https", CodeConnectAccess.OriginPort));
      this.AddConnectAccess(NetCodeGroup.AbsentOriginScheme, CodeConnectAccess.CreateAnySchemeAccess(CodeConnectAccess.OriginPort));
      this.AddConnectAccess(NetCodeGroup.AnyOtherOriginScheme, CodeConnectAccess.CreateOriginSchemeAccess(CodeConnectAccess.OriginPort));
    }
  }
}
