File: Microsoft.NetCore.Analyzers\Security\Helpers\SecurityHelpers.cs
Web Access
Project: src\sdk\src\Microsoft.CodeAnalysis.NetAnalyzers\src\Microsoft.CodeAnalysis.NetAnalyzers\Microsoft.CodeAnalysis.NetAnalyzers.csproj (Microsoft.CodeAnalysis.NetAnalyzers)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;

#pragma warning disable CA1054 // Uri parameters should not be strings

namespace Microsoft.NetCore.Analyzers.Security.Helpers
{
    using static MicrosoftNetCoreAnalyzersResources;

    internal static class SecurityHelpers
    {
        /// <summary>
        /// Creates a DiagnosticDescriptor with <see cref="LocalizableResourceString"/>s from the specified resource source type.
        /// </summary>
        /// <param name="id">Diagnostic identifier.</param>
        /// <param name="titleResourceStringName">Name of the resource string for the diagnostic's title.</param>
        /// <param name="messageResourceStringName">Name of the resource string for the diagnostic's message.</param>
        /// <param name="ruleLevel">Indicates the <see cref="RuleLevel"/> for this rule.</param>
        /// <param name="descriptionResourceStringName">Name of the resource string for the diagnostic's description.</param>
        /// <param name="isPortedFxCopRule">Flag indicating if this is a rule ported from legacy FxCop.</param>
        /// <param name="isDataflowRule">Flag indicating if this is a dataflow analysis based rule.</param>
        /// <returns>new DiagnosticDescriptor</returns>
        public static DiagnosticDescriptor CreateDiagnosticDescriptor(
            string id,
            string titleResourceStringName,
            string messageResourceStringName,
            RuleLevel ruleLevel,
            bool isPortedFxCopRule,
            bool isDataflowRule,
            bool isReportedAtCompilationEnd,
            string? descriptionResourceStringName = null)
        {
            return DiagnosticDescriptorHelper.Create(
                id,
                CreateLocalizableResourceString(titleResourceStringName),
                CreateLocalizableResourceString(messageResourceStringName),
                DiagnosticCategory.Security,
                ruleLevel,
                descriptionResourceStringName != null ? CreateLocalizableResourceString(descriptionResourceStringName) : null,
                isPortedFxCopRule,
                isDataflowRule,
                isReportedAtCompilationEnd: isReportedAtCompilationEnd);
        }

        /// <summary>
        /// Deserialization methods for <see cref="T:System.Runtime.Serialization.Formatters.Binary.BinaryFormatter"/>.
        /// </summary>
        [SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The comment references a type that is not referenced by this compilation.")]
        public static readonly ImmutableHashSet<string> BinaryFormatterDeserializationMethods =
            ImmutableHashSet.Create(
                StringComparer.Ordinal,
                "Deserialize",
                "DeserializeMethodResponse",
                "UnsafeDeserialize",
                "UnsafeDeserializeMethodResponse");

        /// <summary>
        /// Deserialization methods for <see cref="T:System.Runtime.Serialization.NetDataContractSerializer"/>.
        /// </summary>
        [SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The comment references a type that is not referenced by this compilation.")]
        public static readonly ImmutableHashSet<string> NetDataContractSerializerDeserializationMethods =
            ImmutableHashSet.Create(
                StringComparer.Ordinal,
                "Deserialize",
                "ReadObject");

        /// <summary>
        /// Deserialization methods for <see cref="T:System.Web.Script.Serialization.JavaScriptSerializer"/>.
        /// </summary>
        [SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The comment references a type that is not referenced by this compilation.")]
        public static readonly ImmutableHashSet<string> JavaScriptSerializerDeserializationMethods =
            ImmutableHashSet.Create(
                StringComparer.Ordinal,
                "Deserialize",
                "DeserializeObject");

        /// <summary>
        /// Deserialization methods for <see cref="T:System.Web.UI.ObjectStateFormatter"/>.
        /// </summary>
        [SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The comment references a type that is not referenced by this compilation.")]
        public static readonly ImmutableHashSet<string> ObjectStateFormatterDeserializationMethods =
            ImmutableHashSet.Create(
                StringComparer.Ordinal,
                "Deserialize");

        /// <summary>
        /// Deserialization methods for <see cref="T:System.Runtime.Serialization.Formatters.Soap.SoapFormatter"/>.
        /// </summary>
        [SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The comment references a type that is not referenced by this compilation.")]
        public static readonly ImmutableHashSet<string> SoapFormatterDeserializationMethods =
            ImmutableHashSet.Create(
                StringComparer.Ordinal,
                "Deserialize");

        /// <summary>
        /// Methods using a <see cref="T:Newtonsoft.Json.JsonSerializerSettings"/> parameter for <see cref="T:Newtonsoft.Json.JsonSerializer"/>.
        /// </summary>
        [SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The comment references a type that is not referenced by this compilation.")]
        public static readonly ImmutableHashSet<string> JsonSerializerInstantiateWithSettingsMethods =
            ImmutableHashSet.Create(
                StringComparer.Ordinal,
                "Create",
                "CreateDefault");

        /// <summary>
        /// Methods using a <see cref="T:Newtonsoft.Json.JsonSerializerSettings"/> parameter for <see cref="T:Newtonsoft.Json.JsonConvert"/>.
        /// </summary>
        [SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The comment references a type that is not referenced by this compilation.")]
        public static readonly ImmutableHashSet<string> JsonConvertWithSettingsMethods =
            ImmutableHashSet.Create(
                StringComparer.Ordinal,
                "DeserializeObject",
                "DeserializeAnonymousType",
                "PopulateObject");

        /// <summary>
        /// Deserialization methods for <see cref="T:Newtonsoft.Json.JsonSerializer"/>.
        /// </summary>
        [SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The comment references a type that is not referenced by this compilation.")]
        public static readonly ImmutableHashSet<string> JsonSerializerDeserializationMethods =
            ImmutableHashSet.Create(
                StringComparer.Ordinal,
                "Deserialize",
                "Populate");

        /// <summary>
        /// Deserialization methods for <see cref="T:System.Data.DataTable"/>.
        /// </summary>
        [SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The comment references a type that is not referenced by this compilation.")]
        public static readonly ImmutableHashSet<string> DataTableDeserializationMethods =
            ImmutableHashSet.Create(
                StringComparer.Ordinal,
                "ReadXml");

        /// <summary>
        /// Deserialization methods for <see cref="T:System.Data.DataSet"/>.
        /// </summary>
        [SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The comment references a type that is not referenced by this compilation.")]
        public static readonly ImmutableHashSet<string> DataSetDeserializationMethods =
            ImmutableHashSet.Create(
                StringComparer.Ordinal,
                "ReadXml");

        /// <summary>
        /// Determines if an operation is inside autogenerated code that's probably for a GUI app.
        /// </summary>
        /// <param name="operationAnalysisContext">Context for the operation in question.</param>
        /// <param name="wellKnownTypeProvider"><see cref="WellKnownTypeProvider"/> for the operation's compilation.</param>
        /// <returns>True if so, false otherwise.</returns>
        /// <remarks>
        /// This is useful for analyzers categorizing cases into different rules to represent different risks.
        /// </remarks>
        public static bool IsOperationInsideAutogeneratedCodeForGuiApp(
            OperationAnalysisContext operationAnalysisContext,
            WellKnownTypeProvider wellKnownTypeProvider)
        {
            INamedTypeSymbol? xmlReaderTypeSymbol =
                wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemXmlXmlReader);
            INamedTypeSymbol? designerCategoryAttributeTypeSymbol =
                wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemComponentModelDesignerCategoryAttribute);
            INamedTypeSymbol? debuggerNonUserCodeAttributeTypeSymbol =
                wellKnownTypeProvider.GetOrCreateTypeByMetadataName(
                    WellKnownTypeNames.SystemDiagnosticsDebuggerNonUserCode);

            return
                operationAnalysisContext.ContainingSymbol is IMethodSymbol methodSymbol
                && methodSymbol.MetadataName == "ReadXmlSerializable"
                && methodSymbol.DeclaredAccessibility == Accessibility.Protected
                && methodSymbol.IsOverride
                && methodSymbol.ReturnsVoid
                && methodSymbol.Parameters.Length == 1
                && methodSymbol.Parameters[0].Type.Equals(xmlReaderTypeSymbol)
                && methodSymbol.ContainingType?.HasAnyAttribute(designerCategoryAttributeTypeSymbol) == true
                && methodSymbol.HasAnyAttribute(debuggerNonUserCodeAttributeTypeSymbol);
        }
    }
}