From e60e00e7b5a62e6e6d2d7b97a9ea79a35eecce8f Mon Sep 17 00:00:00 2001 From: Si Carter Date: Sun, 1 Sep 2024 09:24:25 +0200 Subject: [PATCH] Include code analyzers as part of build --- .../Providers/CronJobProvider.cs | 2 +- .../Tables/Products/ProductDataTriggers.cs | 2 +- .../Products/ProductGroupDataTriggers.cs | 2 +- Demo/DemoApiPlugin/GlobalSuppressions.cs | 1 + .../GlobalSuppressions.cs | 9 + ...spNetCore.PluginManager.DemoWebsite.csproj | 7 + .../GlobalSuppressions.cs | 2 + Directory.Build.props | 17 +- Docs/XmlFiles/BadEgg.Plugin.xml | 358 ++++++++++++++++-- .../Minify/Operations/MinifyOperation.cs | 2 +- .../Minify/Operations/RemoveBlankLines.cs | 2 +- .../Minify/Operations/RemoveDoubleSpaces.cs | 2 +- .../Minify/Operations/RemoveWhiteSpace.cs | 2 +- .../Classes/Minify/Operations/TrimLine.cs | 2 +- NetCorePluginManager/NetCorePluginManager.cs | 6 +- .../src/Comparers/FileVersionComparison.cs | 8 +- PluginManager/src/GlobalSuppressions.cs | 8 + .../GlobalSuppressions.cs | 8 + .../WebDefender/ValidateConnections.cs | 2 + .../Classes/ErrorThreadManager.cs | 1 + .../ImageManager.Plugin/GlobalSuppressions.cs | 3 +- Plugins/Login.Plugin/GlobalSuppressions.cs | 9 + .../PluginMiddleware/GlobalSuppressions.cs | 1 + Plugins/Products.Plugin/GlobalSuppressions.cs | 9 + .../Resources.Plugin/GlobalSuppressions.cs | 3 + .../Classes/Search/DefaultSearchProvider.cs | 2 +- Plugins/Search.Plugin/GlobalSuppressions.cs | 8 + .../Controllers/CartController.Paypoint.cs | 3 +- .../ShoppingCart.Plugin/GlobalSuppressions.cs | 9 + .../SystemAdmin.Plugin/GlobalSuppressions.cs | 3 + .../AbstractClasses/DynamicContentTemplate.cs | 2 +- .../Attributes/ApiAuthorizationAttribute.cs | 3 + .../BaseClasses/BaseController.cs | 6 +- SharedPluginFeatures/GlobalSuppressions.cs | 7 + .../ProductAdminControllerTests.cs | 4 +- 35 files changed, 459 insertions(+), 56 deletions(-) create mode 100644 Demo/DemoRazorWebsitePlugin/GlobalSuppressions.cs create mode 100644 PluginManager/src/GlobalSuppressions.cs create mode 100644 Plugins/ApiAuthorization.Plugin/GlobalSuppressions.cs create mode 100644 Plugins/Login.Plugin/GlobalSuppressions.cs create mode 100644 Plugins/Products.Plugin/GlobalSuppressions.cs create mode 100644 Plugins/Search.Plugin/GlobalSuppressions.cs create mode 100644 Plugins/ShoppingCart.Plugin/GlobalSuppressions.cs diff --git a/DAL/PluginManager.DAL.TextFiles/Providers/CronJobProvider.cs b/DAL/PluginManager.DAL.TextFiles/Providers/CronJobProvider.cs index c3e914bb2..ac2d74856 100644 --- a/DAL/PluginManager.DAL.TextFiles/Providers/CronJobProvider.cs +++ b/DAL/PluginManager.DAL.TextFiles/Providers/CronJobProvider.cs @@ -58,7 +58,7 @@ public void SetLastRun(ICronJob cronJob, DateTime lastRun) private CronJobDataRow GetOrCreateCronJobDataRow(ICronJob cronJob) { - CronJobDataRow cronJobDataRow = _cronJobSettings.Select(cj => cj.JobId.Equals(cronJob.JobId) && cj.Name.Equals(cronJob.Name)).FirstOrDefault(); + CronJobDataRow cronJobDataRow = _cronJobSettings.Select().FirstOrDefault(cj => cj.JobId.Equals(cronJob.JobId) && cj.Name.Equals(cronJob.Name)); if (cronJobDataRow == null) { diff --git a/DAL/PluginManager.DAL.TextFiles/Tables/Products/ProductDataTriggers.cs b/DAL/PluginManager.DAL.TextFiles/Tables/Products/ProductDataTriggers.cs index de7f380f9..816484368 100644 --- a/DAL/PluginManager.DAL.TextFiles/Tables/Products/ProductDataTriggers.cs +++ b/DAL/PluginManager.DAL.TextFiles/Tables/Products/ProductDataTriggers.cs @@ -95,7 +95,7 @@ public void BeforeUpdate(ProductDataRow newRecord, ProductDataRow oldRecord) // from interface but unused in this context } - private void ValidateData(ProductDataRow row) + private static void ValidateData(ProductDataRow row) { if (String.IsNullOrEmpty(row.Name)) throw new InvalidDataRowException(nameof(ProductDataRow), nameof(row.Name), "Can not be null or empty"); diff --git a/DAL/PluginManager.DAL.TextFiles/Tables/Products/ProductGroupDataTriggers.cs b/DAL/PluginManager.DAL.TextFiles/Tables/Products/ProductGroupDataTriggers.cs index 76e2b3a49..59d663b86 100644 --- a/DAL/PluginManager.DAL.TextFiles/Tables/Products/ProductGroupDataTriggers.cs +++ b/DAL/PluginManager.DAL.TextFiles/Tables/Products/ProductGroupDataTriggers.cs @@ -71,7 +71,7 @@ public void BeforeUpdate(ProductGroupDataRow newRecord, ProductGroupDataRow oldR // from interface but unused in this context } - private void ValidateData(ProductGroupDataRow row) + private static void ValidateData(ProductGroupDataRow row) { if (String.IsNullOrEmpty(row.Description)) throw new InvalidDataRowException(nameof(ProductGroupDataRow), nameof(row.Description), "Can not be null or empty"); diff --git a/Demo/DemoApiPlugin/GlobalSuppressions.cs b/Demo/DemoApiPlugin/GlobalSuppressions.cs index f7831b110..1a2acfaf3 100644 --- a/Demo/DemoApiPlugin/GlobalSuppressions.cs +++ b/Demo/DemoApiPlugin/GlobalSuppressions.cs @@ -7,3 +7,4 @@ [assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "", Scope = "member", Target = "~M:DemoApiPlugin.Controllers.DemoApiController.TestApi(System.String,System.String,System.String)~Microsoft.AspNetCore.Mvc.IActionResult")] [assembly: SuppressMessage("Major Code Smell", "S6962:You should pool HTTP connections with HttpClientFactory", Justification = "Used as part of a demo app in this context", Scope = "member", Target = "~M:DemoApiPlugin.Controllers.DemoApiController.TestApi(System.String,System.String,System.String)~Microsoft.AspNetCore.Mvc.IActionResult")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:DemoApiPlugin.Startup.Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder)")] diff --git a/Demo/DemoRazorWebsitePlugin/GlobalSuppressions.cs b/Demo/DemoRazorWebsitePlugin/GlobalSuppressions.cs new file mode 100644 index 000000000..cd8c5b81d --- /dev/null +++ b/Demo/DemoRazorWebsitePlugin/GlobalSuppressions.cs @@ -0,0 +1,9 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:DemoWebsitePlugin.Startup.ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection)")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:DemoWebsitePlugin.Startup.Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder)")] diff --git a/Demo/NetCorePluginDemoWebsite/AspNetCore.PluginManager.DemoWebsite.csproj b/Demo/NetCorePluginDemoWebsite/AspNetCore.PluginManager.DemoWebsite.csproj index 0d74194fc..2fb013614 100644 --- a/Demo/NetCorePluginDemoWebsite/AspNetCore.PluginManager.DemoWebsite.csproj +++ b/Demo/NetCorePluginDemoWebsite/AspNetCore.PluginManager.DemoWebsite.csproj @@ -151,4 +151,11 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/Demo/NetCorePluginDemoWebsite/GlobalSuppressions.cs b/Demo/NetCorePluginDemoWebsite/GlobalSuppressions.cs index 2062ec744..4683b269f 100644 --- a/Demo/NetCorePluginDemoWebsite/GlobalSuppressions.cs +++ b/Demo/NetCorePluginDemoWebsite/GlobalSuppressions.cs @@ -17,3 +17,5 @@ [assembly: SuppressMessage("Major Code Smell", "S4144:Methods should not have identical implementations", Justification = "Required for demo only", Scope = "member", Target = "~M:AspNetCore.PluginManager.DemoWebsite.Classes.MockProductProvider.ProductDelete(System.Int32@,System.String@)~System.Boolean")] [assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Startup class, good as is", Scope = "member", Target = "~M:AspNetCore.PluginManager.DemoWebsite.Startup.ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection)")] [assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Startup class, good as is", Scope = "member", Target = "~M:AspNetCore.PluginManager.DemoWebsite.Startup.Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder)")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:AspNetCore.PluginManager.DemoWebsite.Startup.Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder)")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:AspNetCore.PluginManager.DemoWebsite.Startup.ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection)")] diff --git a/Directory.Build.props b/Directory.Build.props index 2ac74a5b0..3a4107858 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -49,6 +49,18 @@ Copyright (c) 2018 - 2024. Simon Carter. All rights reserved. Plugin Manager + + + + $(NoWarn);CA1510;CA1512;CA1513 + + + + + all + runtime; build; native; contentfiles; analyzers + + true @@ -111,10 +123,5 @@ $(DebugType) %(DebugSymbols) - - - - $(NoWarn);CA1510;CA1512;CA1513 - \ No newline at end of file diff --git a/Docs/XmlFiles/BadEgg.Plugin.xml b/Docs/XmlFiles/BadEgg.Plugin.xml index 79edeb44d..7933d5171 100644 --- a/Docs/XmlFiles/BadEgg.Plugin.xml +++ b/Docs/XmlFiles/BadEgg.Plugin.xml @@ -1,75 +1,379 @@ - Cron.Plugin + BadEgg.Plugin - + - Cron middleware extender + BadEgg Middleware - + - Adds Cron functionality to the application + BadEgg middleware extender + + + + + Adds BadEgg to the request pipeline IApplicationBuilder instance - Thread manager services IApplicationBuilder - app.UseCron(threadManagerServices); + app.UseBadEgg(); - + - Settings which affect how Cron is configured and used. + Settings which affect how BadEgg is configured and used. - + Name of settings - + + + Number of minutes until a connection is timed out and removed from the list of monitored connections. + + Default value: 5 + Minimum value: 1 + Maximum value: 300 + + uint + + + + Maximum average connection per second, if this value is exceeded then http response from TooManyRequestResponseCode will be returned + + Default value: 100 + Minimum value: 1 + Maximum value: uint.MaxValue + + uint + + + + Http response code provided should the connection be banned. + + Default: 400 + + Must be a valid http client error response (in the range of 400) + + int + + + + Http response provided should the connection make too many requests. + + Default Value: 429 + + Must be a valid http client error response (in the range of 400) + + int + + + + The code which is used to ignore validation within BadEgg middleware, this is + sent within the header of the request, if it matches this code, no validation takes place + + string + + - Primary thread which manages and processes cron jobs + Returns a list of current connections and their BadEgg status and can + be viewed within SystemAdmin.Plugin. + + This class descends from SystemAdminSubMenu. - + - Implements IPlugin which allows the Cron.Plugin module to be + Returns delimited data on all connections being monitored by BadEgg.Plugin. + + string + + + + Returns a list of current Timings and can be viewed within SystemAdmin.Plugin. + + This class descends from SystemAdminSubMenu. + + + + + Returns Timings data in milliseconds for time spent processing by BadEgg.Plugin. + + string + + + + Implements IPlugin which allows the BadEgg.Plugin module to be loaded as a plugin module - + + + Constructor + + Address of client + + + + Constructor + + Address of client + Date/time the connection was created. + + + + IP Address for client + + + + + DateTime this record was created + + + + + DateTime last entry was made + + + + + Number of requests made + + + + + Results for the connection + + + + + Unique text being scanned + + + + + Host Information + + + + + Increments the number of requests + + + + + Determines how many hits per second + + + + + + Determines how many hits per second + + + + + + Total time the connection has been active from when logged to last entry + + TimeSpan + + - Cron data storage, used as json + keywords used to determine sql injection - + - Default constructor + Phrases to find / Replace within a string - + + + Hacking keywords + + + + + Hacking phrases to find/replace + + + + + Words/Chars to replace with a space in Random Word checker + + + + + Address list lock object for unique access + + + + + Period of inactivity in which a connection times out + + + Constructor - - - + + + Probability of web attack/hacking + + + + + Almost certain web attack/hacking + + + + + Propability of bot Number of hit's per second + + + + + Propability of bot Number of hit's per second + + + + + Validates a string + + String request being validated + number of occurances of *possible* attacks detected in the string + IP Address for connection + Results of probability that the attack is an attempt hack + + + + Validates a web request + + Request being validated + Validates form post values if available + number of occurances of *possible* attacks detected in the Uri + Weight of probability that the attack is an attempt hack + + + + Adds an IP address to a black list + + Ip address to add to black list + + + + Adds an IP address to a black list + + Ip address to add to black list + + + + Gets connection information object for the IP Address + + IP Address + ConnectionInfo object associated with the IP Address + + + + Raise connection removed event + + connection info being removed + + + + Raise connection removed event + + connection info being removed + + + + Raises an event for banning an IP Address + + + + + + True if the IP Address should be black listed and added to banned list, otherwise false + + + + Event raised when an IP Address needs to be banned + + + + + Event raised when connection info object add + + + + + Event raised when connection info object removed + + + + + Reports a connection that has Result attributes + + + + + Certain form values can be ignored and will not be evaluated + + + true if value should be ignored, otherwise false + + + + Updates result flags on connection info object + + Result of this validation + connection info object + + + + Verify's an address to see if it's black/white listed + + Ip address to verify + ValidateRequestResult enum with results + + + + Determines the probability that user is bot/spider + + Ip connection information + validation Results + + - Cron job unique guid + Determines the probability of a hacking attempt + data to be checked + Number of attempts found + Result of the check - + - Name of cron job + Determines if the url contains sql which could be a SQL Injection + current request data + number of attempts found + Result of the check - + - Date/Time job last run + Determines if a word is made up of random characters + + Assumption is if has 2 or more upper/lower case chars and at least 1 number then it's random + Word which is being tested + true if contains 2 or more upper/lower case chars and at least 1 number, otherwise false diff --git a/NetCorePluginManager/Classes/Minify/Operations/MinifyOperation.cs b/NetCorePluginManager/Classes/Minify/Operations/MinifyOperation.cs index 875f5df56..94f5e42c5 100644 --- a/NetCorePluginManager/Classes/Minify/Operations/MinifyOperation.cs +++ b/NetCorePluginManager/Classes/Minify/Operations/MinifyOperation.cs @@ -38,7 +38,7 @@ internal abstract class MinifyOperation [System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "Intended for dev not public use.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Protected and used in other places")] - protected bool IsInPreBlock(in int currentPosition, in List preserveBlocks, out MinificationPreserveBlock blockType) + protected static bool IsInPreBlock(in int currentPosition, in List preserveBlocks, out MinificationPreserveBlock blockType) { blockType = MinificationPreserveBlock.Undefined; diff --git a/NetCorePluginManager/Classes/Minify/Operations/RemoveBlankLines.cs b/NetCorePluginManager/Classes/Minify/Operations/RemoveBlankLines.cs index d37520de1..c76373977 100644 --- a/NetCorePluginManager/Classes/Minify/Operations/RemoveBlankLines.cs +++ b/NetCorePluginManager/Classes/Minify/Operations/RemoveBlankLines.cs @@ -56,7 +56,7 @@ public override IMinifyResult Process(in MinificationFileType fileType, ref stri return Result; } - private string RemoveEmptyLines(string data, in List preserveBlocks) + private static string RemoveEmptyLines(string data, in List preserveBlocks) { StringBuilder Result = new(data.Length); diff --git a/NetCorePluginManager/Classes/Minify/Operations/RemoveDoubleSpaces.cs b/NetCorePluginManager/Classes/Minify/Operations/RemoveDoubleSpaces.cs index db055117a..b070a569d 100644 --- a/NetCorePluginManager/Classes/Minify/Operations/RemoveDoubleSpaces.cs +++ b/NetCorePluginManager/Classes/Minify/Operations/RemoveDoubleSpaces.cs @@ -56,7 +56,7 @@ public override IMinifyResult Process(in MinificationFileType fileType, ref stri return Result; } - private string RemoveCarriageReturns(string data, in List preserveBlocks) + private static string RemoveCarriageReturns(string data, in List preserveBlocks) { StringBuilder Result = new(data.Length); diff --git a/NetCorePluginManager/Classes/Minify/Operations/RemoveWhiteSpace.cs b/NetCorePluginManager/Classes/Minify/Operations/RemoveWhiteSpace.cs index 8baaeba01..f98141bb3 100644 --- a/NetCorePluginManager/Classes/Minify/Operations/RemoveWhiteSpace.cs +++ b/NetCorePluginManager/Classes/Minify/Operations/RemoveWhiteSpace.cs @@ -56,7 +56,7 @@ public override IMinifyResult Process(in MinificationFileType fileType, ref stri return Result; } - private string RemoveCarriageReturns(string data, in List preserveBlocks) + private static string RemoveCarriageReturns(string data, in List preserveBlocks) { StringBuilder Result = new(data.Length); diff --git a/NetCorePluginManager/Classes/Minify/Operations/TrimLine.cs b/NetCorePluginManager/Classes/Minify/Operations/TrimLine.cs index 6b2532642..1240f6a49 100644 --- a/NetCorePluginManager/Classes/Minify/Operations/TrimLine.cs +++ b/NetCorePluginManager/Classes/Minify/Operations/TrimLine.cs @@ -56,7 +56,7 @@ public override IMinifyResult Process(in MinificationFileType fileType, ref stri return Result; } - private string TrimAllLines(string data, in List preserveBlocks) + private static string TrimAllLines(string data, in List preserveBlocks) { StringBuilder Result = new(data.Length); diff --git a/NetCorePluginManager/NetCorePluginManager.cs b/NetCorePluginManager/NetCorePluginManager.cs index 0f2bb33cc..625555461 100644 --- a/NetCorePluginManager/NetCorePluginManager.cs +++ b/NetCorePluginManager/NetCorePluginManager.cs @@ -95,17 +95,17 @@ protected override void ModifyPluginResourceName(ref string resourceName) protected override void PluginConfigured(in IPluginModule pluginModule) { - + // required by interface, not used in this context } protected override void PluginInitialised(in IPluginModule pluginModule) { - + // required by interface, not used in this context } protected override void PluginLoaded(in Assembly pluginFile) { - + // required by interface, not used in this context } protected override void PluginLoading(in Assembly pluginFile) diff --git a/PluginManager/src/Comparers/FileVersionComparison.cs b/PluginManager/src/Comparers/FileVersionComparison.cs index 9f746acd7..95246d93f 100644 --- a/PluginManager/src/Comparers/FileVersionComparison.cs +++ b/PluginManager/src/Comparers/FileVersionComparison.cs @@ -36,13 +36,13 @@ namespace PluginManager { public sealed class FileVersionComparison : Comparer { - public override int Compare(FileInfo objectCompare1, FileInfo objectCompare2) + public override int Compare(FileInfo x, FileInfo y) { - if (objectCompare1 == null || objectCompare2 == null) + if (x == null || y == null) return 0; - FileVersionInfo versionX = FileVersionInfo.GetVersionInfo(objectCompare1.FullName); - FileVersionInfo versionY = FileVersionInfo.GetVersionInfo(objectCompare2.FullName); + FileVersionInfo versionX = FileVersionInfo.GetVersionInfo(x.FullName); + FileVersionInfo versionY = FileVersionInfo.GetVersionInfo(y.FullName); return versionX.FileVersion.CompareTo(versionY.FileVersion); } diff --git a/PluginManager/src/GlobalSuppressions.cs b/PluginManager/src/GlobalSuppressions.cs new file mode 100644 index 000000000..0d69f57a2 --- /dev/null +++ b/PluginManager/src/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Minor Bug", "S2674:The length returned from a stream read should be checked", Justification = "Reads entire length in one go", Scope = "member", Target = "~M:PluginManager.BasePluginManager.ExtractResources(System.Reflection.Assembly@,PluginManager.PluginSetting@)")] diff --git a/Plugins/ApiAuthorization.Plugin/GlobalSuppressions.cs b/Plugins/ApiAuthorization.Plugin/GlobalSuppressions.cs new file mode 100644 index 000000000..ecf980dad --- /dev/null +++ b/Plugins/ApiAuthorization.Plugin/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Minor Bug", "S2674:The length returned from a stream read should be checked", Justification = "Reads entire length of stream", Scope = "member", Target = "~M:ApiAuthorization.Plugin.Classes.HmacApiAuthorizationService.ValidateApiRequest(Microsoft.AspNetCore.Http.HttpRequest,System.String,System.Int32@)~System.Boolean")] diff --git a/Plugins/BadEgg.Plugin/WebDefender/ValidateConnections.cs b/Plugins/BadEgg.Plugin/WebDefender/ValidateConnections.cs index 9d274c7e3..46c524ca5 100644 --- a/Plugins/BadEgg.Plugin/WebDefender/ValidateConnections.cs +++ b/Plugins/BadEgg.Plugin/WebDefender/ValidateConnections.cs @@ -355,6 +355,7 @@ public ValidateRequestResult ValidateRequest(in HttpRequest request, in bool val /// /// Ip address to add to black list [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Public and used in other places")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "As above")] public void AddToBlackList(in string ipAddress) { if (String.IsNullOrEmpty(ipAddress)) @@ -371,6 +372,7 @@ public void AddToBlackList(in string ipAddress) /// /// Ip address to add to black list [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Public and used in other places")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "As above")] public void AddToWhiteList(in string ipAddress) { if (String.IsNullOrEmpty(ipAddress)) diff --git a/Plugins/ErrorManager.Plugin/Classes/ErrorThreadManager.cs b/Plugins/ErrorManager.Plugin/Classes/ErrorThreadManager.cs index 4c1b6e977..c94b1edd8 100644 --- a/Plugins/ErrorManager.Plugin/Classes/ErrorThreadManager.cs +++ b/Plugins/ErrorManager.Plugin/Classes/ErrorThreadManager.cs @@ -104,6 +104,7 @@ protected override bool Run(object parameters) #region Internal Methods [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Internal and used in other places")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "As above")] internal void AddError(ErrorInformation errorInformation) { using (TimedLock lck = TimedLock.Lock(_lockObject)) diff --git a/Plugins/ImageManager.Plugin/GlobalSuppressions.cs b/Plugins/ImageManager.Plugin/GlobalSuppressions.cs index 208a13ac3..ead9d3bb4 100644 --- a/Plugins/ImageManager.Plugin/GlobalSuppressions.cs +++ b/Plugins/ImageManager.Plugin/GlobalSuppressions.cs @@ -7,4 +7,5 @@ [assembly: SuppressMessage("Critical Code Smell", "S2696:Instance members should not write to \"static\" fields", Justification = "Required for unique id in app lifetime", Scope = "member", Target = "~M:ImageManager.Plugin.Controllers.ImageManagerController.GetCacheId~System.String")] [assembly: SuppressMessage("Performance", "CA1859:Use concrete types when possible for improved performance", Justification = "The right model is returned here", Scope = "member", Target = "~M:ImageManager.Plugin.Controllers.ImageManagerController.CreateImagesViewModel(System.String,System.String,System.String)~ImageManager.Plugin.Models.ImagesViewModel")] - +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:ImageManager.Plugin.Startup.ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection)")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:ImageManager.Plugin.Startup.Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder)")] diff --git a/Plugins/Login.Plugin/GlobalSuppressions.cs b/Plugins/Login.Plugin/GlobalSuppressions.cs new file mode 100644 index 000000000..53abaf919 --- /dev/null +++ b/Plugins/Login.Plugin/GlobalSuppressions.cs @@ -0,0 +1,9 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:LoginPlugin.Startup.Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder)")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:LoginPlugin.Startup.ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection)")] diff --git a/Plugins/PluginMiddleware/GlobalSuppressions.cs b/Plugins/PluginMiddleware/GlobalSuppressions.cs index 8b99d0b30..4d8bec9e5 100644 --- a/Plugins/PluginMiddleware/GlobalSuppressions.cs +++ b/Plugins/PluginMiddleware/GlobalSuppressions.cs @@ -7,3 +7,4 @@ [assembly: SuppressMessage("Major Code Smell", "S6561:Avoid using \"DateTime.Now\" for benchmarking or timing operations", Justification = "Required for this context", Scope = "member", Target = "~M:Middleware.Search.DefaultSearchThread.KeywordSearch(Middleware.ISearchKeywordProvider@,Middleware.Search.KeywordSearchOptions@)~System.Collections.Generic.List{Middleware.Search.SearchResponseItem}")] [assembly: SuppressMessage("Major Code Smell", "S6561:Avoid using \"DateTime.Now\" for benchmarking or timing operations", Justification = "Required for this context", Scope = "member", Target = "~M:Middleware.Search.DefaultSearchThread.KeywordSearch(System.Collections.Generic.List{Middleware.ISearchKeywordProvider}@,Middleware.Search.KeywordSearchOptions@)~System.Collections.Generic.List{Middleware.Search.SearchResponseItem}")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of the design", Scope = "member", Target = "~M:Middleware.ShoppingCart.ShoppingCartItem.UpdateDiscountCode(System.String,SharedPluginFeatures.DiscountType,System.Decimal,System.Int32)")] diff --git a/Plugins/Products.Plugin/GlobalSuppressions.cs b/Plugins/Products.Plugin/GlobalSuppressions.cs new file mode 100644 index 000000000..65061cd15 --- /dev/null +++ b/Plugins/Products.Plugin/GlobalSuppressions.cs @@ -0,0 +1,9 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:ProductPlugin.Startup.ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection)")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:ProductPlugin.Startup.Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder)")] diff --git a/Plugins/Resources.Plugin/GlobalSuppressions.cs b/Plugins/Resources.Plugin/GlobalSuppressions.cs index f15d11f64..999fe3479 100644 --- a/Plugins/Resources.Plugin/GlobalSuppressions.cs +++ b/Plugins/Resources.Plugin/GlobalSuppressions.cs @@ -7,3 +7,6 @@ [assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "static uri that is unlikely to change", Scope = "member", Target = "~F:Resources.Plugin.Controllers.ResourcesController.TikTokBaseUri")] [assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "static uri that is unlikely to change>", Scope = "member", Target = "~F:Resources.Plugin.Controllers.ResourcesController.YouTubeImgBaseUri")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:Resources.Plugin.Startup.ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection)")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of original c# generated code", Scope = "member", Target = "~M:Resources.Plugin.Startup.Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder)")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Usage determines should not be static for backward compatibility", Scope = "member", Target = "~P:Resources.Plugin.Models.BaseResourceItemModel.AllResourceTypes")] diff --git a/Plugins/Search.Plugin/Classes/Search/DefaultSearchProvider.cs b/Plugins/Search.Plugin/Classes/Search/DefaultSearchProvider.cs index 72418ce20..8b3d1ff5a 100644 --- a/Plugins/Search.Plugin/Classes/Search/DefaultSearchProvider.cs +++ b/Plugins/Search.Plugin/Classes/Search/DefaultSearchProvider.cs @@ -40,7 +40,7 @@ namespace SearchPlugin.Classes.Search /// /// Default search provider to be used if no other search provider is registered /// - public class DefaultSearchProvider : ISearchProvider + public sealed class DefaultSearchProvider : ISearchProvider { #region Private Members diff --git a/Plugins/Search.Plugin/GlobalSuppressions.cs b/Plugins/Search.Plugin/GlobalSuppressions.cs new file mode 100644 index 000000000..148af18bc --- /dev/null +++ b/Plugins/Search.Plugin/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of design", Scope = "member", Target = "~P:SearchPlugin.Classes.Search.DefaultSearchProvider.GetCacheManager")] diff --git a/Plugins/ShoppingCart.Plugin/Controllers/CartController.Paypoint.cs b/Plugins/ShoppingCart.Plugin/Controllers/CartController.Paypoint.cs index d87598c90..33641d4a8 100644 --- a/Plugins/ShoppingCart.Plugin/Controllers/CartController.Paypoint.cs +++ b/Plugins/ShoppingCart.Plugin/Controllers/CartController.Paypoint.cs @@ -71,6 +71,7 @@ public IActionResult Paypoint() return RedirectToAction(nameof(Failed)); } +#pragma warning disable S6932 private bool ValidateHashCode() { bool Result = false; @@ -102,7 +103,7 @@ private bool ValidateHashCode() return (Result); } - +#pragma warning restore S6932 } } diff --git a/Plugins/ShoppingCart.Plugin/GlobalSuppressions.cs b/Plugins/ShoppingCart.Plugin/GlobalSuppressions.cs new file mode 100644 index 000000000..759933038 --- /dev/null +++ b/Plugins/ShoppingCart.Plugin/GlobalSuppressions.cs @@ -0,0 +1,9 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Part of initial c# implementation", Scope = "member", Target = "~M:ShoppingCartPlugin.Startup.ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection)")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Left as non static due to current usage and backwards compatibility", Scope = "member", Target = "~M:ShoppingCartPlugin.Startup.Configure(Microsoft.AspNetCore.Builder.IApplicationBuilder)")] diff --git a/Plugins/SystemAdmin.Plugin/GlobalSuppressions.cs b/Plugins/SystemAdmin.Plugin/GlobalSuppressions.cs index 6f3705c0a..f42b16f15 100644 --- a/Plugins/SystemAdmin.Plugin/GlobalSuppressions.cs +++ b/Plugins/SystemAdmin.Plugin/GlobalSuppressions.cs @@ -11,3 +11,6 @@ [assembly: SuppressMessage("Minor Code Smell", "S6602:\"Find\" method should be used instead of the \"FirstOrDefault\" extension", Justification = "Not possible on arrays", Scope = "member", Target = "~M:SystemAdmin.Plugin.Controllers.SystemAdminController.ValidateIncomingProperties(SystemAdmin.Plugin.Models.SettingsViewModel,SystemAdmin.Plugin.Classes.MenuItems.SettingsMenuItem,System.Collections.Generic.List{System.String})")] [assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Left as non static due to current usage and backwards compatibility", Scope = "member", Target = "~M:SystemAdmin.Plugin.Models.AvailableIconViewModel.GetMenuLink(SharedPluginFeatures.SystemAdminSubMenu@)~System.String")] [assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Left as non static due to current usage and backwards compatibility", Scope = "member", Target = "~M:SystemAdmin.Plugin.Models.AvailableIconViewModel.ProcessImage(System.String@)~System.String")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Left as non static due to current usage and backwards compatibility", Scope = "member", Target = "~M:SystemAdmin.Plugin.Models.AvailableIconViewModel.ProcessImage(System.String@)~System.String")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Left as non static due to current usage and backwards compatibility", Scope = "member", Target = "~M:SystemAdmin.Plugin.Models.AvailableIconViewModel.GetMenuLink(SharedPluginFeatures.SystemAdminSubMenu@)~System.String")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Left as non static due to current usage and backwards compatibility", Scope = "member", Target = "~M:SystemAdmin.Plugin.Startup.ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection)")] diff --git a/SharedPluginFeatures/AbstractClasses/DynamicContentTemplate.cs b/SharedPluginFeatures/AbstractClasses/DynamicContentTemplate.cs index addaa116f..a0654041f 100644 --- a/SharedPluginFeatures/AbstractClasses/DynamicContentTemplate.cs +++ b/SharedPluginFeatures/AbstractClasses/DynamicContentTemplate.cs @@ -306,7 +306,7 @@ protected void HtmlStart(StringBuilder stringBuilder, bool isEditing) /// /// StringBuilder instance where end block will be appended to. /// Raised if stringBuilder parameter is null - protected void HtmlEnd(StringBuilder stringBuilder) + protected static void HtmlEnd(StringBuilder stringBuilder) { if (stringBuilder == null) { diff --git a/SharedPluginFeatures/Attributes/ApiAuthorizationAttribute.cs b/SharedPluginFeatures/Attributes/ApiAuthorizationAttribute.cs index 24c26d963..d6cfb9b59 100644 --- a/SharedPluginFeatures/Attributes/ApiAuthorizationAttribute.cs +++ b/SharedPluginFeatures/Attributes/ApiAuthorizationAttribute.cs @@ -23,6 +23,8 @@ * 15/11/2020 Simon Carter Initially Created * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +using System; + using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; @@ -31,6 +33,7 @@ namespace SharedPluginFeatures /// /// Api authorization attribute used to verify the current user has the correct authorization for a route /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public sealed class ApiAuthorizationAttribute : ActionFilterAttribute { private readonly string _policyName; diff --git a/SharedPluginFeatures/BaseClasses/BaseController.cs b/SharedPluginFeatures/BaseClasses/BaseController.cs index 5a8d79734..008b6b0e7 100644 --- a/SharedPluginFeatures/BaseClasses/BaseController.cs +++ b/SharedPluginFeatures/BaseClasses/BaseController.cs @@ -480,7 +480,7 @@ protected string BuildPagination(in int itemCount, in int itemsPerPage, in int c /// First item in the list of items /// Last item in the list of items /// Number of available pages based on the list - protected void CalculatePageOffsets(in List items, in int page, in int pageSize, + protected static void CalculatePageOffsets(in List items, in int page, in int pageSize, out int startItem, out int endItem, out int availablePages) { if (items == null) @@ -503,7 +503,7 @@ protected void CalculatePageOffsets(in List items, in int page, in int pag /// First item in the list of items /// Last item in the list of items /// Number of available pages based on the itemCount - protected void CalculatePageOffsets(in int itemCount, in int page, in int pageSize, + protected static void CalculatePageOffsets(in int itemCount, in int page, in int pageSize, out int startItem, out int endItem, out int availablePages) { if (pageSize < 1) @@ -628,7 +628,7 @@ protected string GetSeoDescription() /// Name of the controller. /// Name of the view. /// string - protected string GetViewName(in string controller, in string viewName) + protected static string GetViewName(in string controller, in string viewName) { if (String.IsNullOrEmpty(controller)) throw new ArgumentNullException(nameof(controller)); diff --git a/SharedPluginFeatures/GlobalSuppressions.cs b/SharedPluginFeatures/GlobalSuppressions.cs index c2fe89d29..d58f68ac0 100644 --- a/SharedPluginFeatures/GlobalSuppressions.cs +++ b/SharedPluginFeatures/GlobalSuppressions.cs @@ -7,3 +7,10 @@ [assembly: SuppressMessage("Style", "IDE0041:Use 'is null' check", Justification = "System implementation", Scope = "member", Target = "~M:SharedPluginFeatures.SystemAdminSubMenu.op_GreaterThanOrEqual(SharedPluginFeatures.SystemAdminSubMenu,SharedPluginFeatures.SystemAdminSubMenu)~System.Boolean")] [assembly: SuppressMessage("Style", "IDE0041:Use 'is null' check", Justification = "System implementation", Scope = "member", Target = "~M:SharedPluginFeatures.SystemAdminSubMenu.op_GreaterThan(SharedPluginFeatures.SystemAdminSubMenu,SharedPluginFeatures.SystemAdminSubMenu)~System.Boolean")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "Method is accessed else where as part of implementation", Scope = "member", Target = "~M:SharedPluginFeatures.SystemAdminMainMenu.Area~System.String")] +[assembly: SuppressMessage("Major Code Smell", "S3966:Objects should not be disposed more than once", Justification = "False positive as may not be disposed in current implementation", Scope = "member", Target = "~M:SharedPluginFeatures.CaptchaImage.GenerateImage")] +[assembly: SuppressMessage("Minor Code Smell", "S1694:An abstract class should have both abstract and concrete methods", Justification = "This allows descendants to override all in this implementation or use interface if required", Scope = "type", Target = "~T:SharedPluginFeatures.BaseClasses.CronJob")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "No issue here, need to remain backwards compatibility", Scope = "member", Target = "~M:SharedPluginFeatures.BaseModel.RouteText(System.String@)~System.String")] +[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "No issue here, need to remain backwards compatibility", Scope = "member", Target = "~M:SharedPluginFeatures.BaseController.IsUriLocalToHost(System.String)~System.Boolean")] +[assembly: SuppressMessage("Minor Code Smell", "S1694:An abstract class should have both abstract and concrete methods", Justification = "No issue as fine as abstract class", Scope = "type", Target = "~T:SharedPluginFeatures.CarouselImage")] +[assembly: SuppressMessage("Minor Code Smell", "S1694:An abstract class should have both abstract and concrete methods", Justification = "No issue as fine as abstract class", Scope = "type", Target = "~T:SharedPluginFeatures.MainMenuItem")] diff --git a/Tests/AspNetCore.PluginManager.Tests/Plugins/ProductTests/ProductAdminControllerTests.cs b/Tests/AspNetCore.PluginManager.Tests/Plugins/ProductTests/ProductAdminControllerTests.cs index b979bda08..26f2cecc9 100644 --- a/Tests/AspNetCore.PluginManager.Tests/Plugins/ProductTests/ProductAdminControllerTests.cs +++ b/Tests/AspNetCore.PluginManager.Tests/Plugins/ProductTests/ProductAdminControllerTests.cs @@ -1091,12 +1091,12 @@ private ProductAdminController CreateProductAdminController( new MockStockProvider(), memoryCache ?? new MockMemoryCache()); - Result.ControllerContext = CreateTestControllerContext(breadcrumbs ?? GetBreadcrumbs()); + Result.ControllerContext = CreateTestControllerContext(breadcrumbs ?? CreateBreadcrumbs()); return Result; } - new private List GetBreadcrumbs() + private List CreateBreadcrumbs() { List breadcrumbs = new List(); breadcrumbs.Add(new BreadcrumbItem("Home", "/", false));