diff --git a/KInspector.Modules/Kentico.KInspector.Modules.csproj b/KInspector.Modules/Kentico.KInspector.Modules.csproj index e5ffc824..b6e378e9 100644 --- a/KInspector.Modules/Kentico.KInspector.Modules.csproj +++ b/KInspector.Modules/Kentico.KInspector.Modules.csproj @@ -114,8 +114,12 @@ + + + + @@ -139,6 +143,8 @@ + + @@ -202,6 +208,12 @@ Always + + Always + + + Always + Always @@ -211,9 +223,30 @@ Always + + Always + Always + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + Always @@ -244,7 +277,7 @@ Always - + Always @@ -348,7 +381,7 @@ Always - Always + PreserveNewest Always diff --git a/KInspector.Modules/Modules/Content/AttachmentsBySizeModule.cs b/KInspector.Modules/Modules/Content/AttachmentsBySizeModule.cs index 23811ac8..369c25d6 100644 --- a/KInspector.Modules/Modules/Content/AttachmentsBySizeModule.cs +++ b/KInspector.Modules/Modules/Content/AttachmentsBySizeModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Displays report of all attachments ordered by their size. diff --git a/KInspector.Modules/Modules/Content/DBFileConsistencyModule.cs b/KInspector.Modules/Modules/Content/DBFileConsistencyModule.cs index ec76b26c..d2f46b97 100644 --- a/KInspector.Modules/Modules/Content/DBFileConsistencyModule.cs +++ b/KInspector.Modules/Modules/Content/DBFileConsistencyModule.cs @@ -16,8 +16,6 @@ public ModuleMetadata GetModuleMetadata() { Name = "Form Attachments and Media Library Consistency Check", SupportedVersions = new[] { - new Version("6.0"), - new Version("7.0"), new Version("8.0"), new Version("8.1"), new Version("8.2"), @@ -368,14 +366,21 @@ public static FileInfo[] GetFiles(string baseUri, bool recursive, IInstanceInfo throw new ArgumentNullException($"baseUri value is null"); } - if(baseUri.StartsWith("~/")) + try + { + if(baseUri.StartsWith("~/")) + { + var absPath = Combine(info.Directory.FullName, baseUri.Substring(2)); + return Directory.Exists(absPath) ? new DirectoryInfo(absPath).GetFiles("*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly) : new FileInfo[] { }; + } + else + return Directory.Exists(baseUri) ? new DirectoryInfo(baseUri).GetFiles("*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly) : new FileInfo[] { }; + } + catch(Exception ex) { - var absPath = Combine(info.Directory.FullName, baseUri.Substring(2)); - return new DirectoryInfo(absPath).GetFiles("*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); + throw ex; } - else - return new DirectoryInfo(baseUri).GetFiles("*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); - } + } /// /// Combines a base url with a list of folders afterwards. diff --git a/KInspector.Modules/Modules/Content/DuplicatePageAliasesModule.cs b/KInspector.Modules/Modules/Content/DuplicatePageAliasesModule.cs index f860585a..b370d642 100644 --- a/KInspector.Modules/Modules/Content/DuplicatePageAliasesModule.cs +++ b/KInspector.Modules/Modules/Content/DuplicatePageAliasesModule.cs @@ -18,7 +18,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Checks that the CMS_DocumentAlias table does not contain any duplicates.", Category = "Content" diff --git a/KInspector.Modules/Modules/Content/NumberOfAliasesModule.cs b/KInspector.Modules/Modules/Content/NumberOfAliasesModule.cs index 74572a6c..de74f4c8 100644 --- a/KInspector.Modules/Modules/Content/NumberOfAliasesModule.cs +++ b/KInspector.Modules/Modules/Content/NumberOfAliasesModule.cs @@ -16,7 +16,9 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") }, + new Version("9.0"), + new Version("10.0") + }, Comment = @"Returns number of aliases per node + total count of aliases and documents for direct comparison. Having too many aliases per node may suggest problem with wrong API usage, decreased performance and SEO problems. diff --git a/KInspector.Modules/Modules/Content/PageTypeAssignedToSiteModule.cs b/KInspector.Modules/Modules/Content/PageTypeAssignedToSiteModule.cs index 3126bb12..ad5a901c 100644 --- a/KInspector.Modules/Modules/Content/PageTypeAssignedToSiteModule.cs +++ b/KInspector.Modules/Modules/Content/PageTypeAssignedToSiteModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Displays page types used by a certain site without being assigned to this site. diff --git a/KInspector.Modules/Modules/Content/SiteTemplatesModule.cs b/KInspector.Modules/Modules/Content/SiteTemplatesModule.cs index 122aac4a..90b77983 100644 --- a/KInspector.Modules/Modules/Content/SiteTemplatesModule.cs +++ b/KInspector.Modules/Modules/Content/SiteTemplatesModule.cs @@ -60,15 +60,16 @@ public ModuleMetadata GetModuleMetadata() { return new ModuleMetadata { - Name = "Site templates", + Name = "Page template overview", SupportedVersions = new[] { new Version("7.0"), new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, - Comment = @"Analyzes all templates used on sites.", + Comment = @"Shows the basic web part configuration for all page templates and lists all the documents that use that template.", }; } @@ -89,10 +90,13 @@ public ModuleResults GetResults(IInstanceInfo instanceInfo) if (results.Tables.Contains(templateName)) { // Page template code names should be unique - templateName += " - DUPLICATE CODENAME (ID: " + template["PageTemplateID"] + ")"; + templateName += $" - DUPLICATE CODENAME, ID: {template["PageTemplateID"]}"; duplicateTemplateCodeName = true; } - DataTable result = GetTableForTemplateResult(templateName); + + var tableHeader = $"{template["PageTemplateDisplayName"]} [{templateName}]"; + + DataTable result = GetTableForTemplateResult(tableHeader); if (templateWP.WebPartZones != null) { @@ -100,6 +104,10 @@ public ModuleResults GetResults(IInstanceInfo instanceInfo) { if (zone.WebParts == null || zone.WebParts.Length == 0) { + var row = result.NewRow(); + row["WebPartTitle"] = "No web parts"; + row["Zone"] = zone.ID; + result.Rows.Add(row); continue; } foreach (var wp in zone.WebParts) @@ -138,12 +146,18 @@ public ModuleResults GetResults(IInstanceInfo instanceInfo) } } } + else + { + var row = result.NewRow(); + row["WebPartTitle"] = "No web part zones"; + result.Rows.Add(row); + } results.Tables.Add(result); var documents = dbService.ExecuteAndGetTableFromFile("SiteTemplatesModule-Documents.sql", new SqlParameter("PageTemplateID", template["PageTemplateID"])); - documents.TableName = $"{templateName} - Documents"; + documents.TableName = $"{tableHeader} - Documents"; results.Tables.Add(documents.Copy()); } @@ -171,9 +185,9 @@ protected TemplateWebParts GetTemplateWebPartsFromXML(string xml) } } - protected DataTable GetTableForTemplateResult(string templateName) + protected DataTable GetTableForTemplateResult(string tableName) { - DataTable result = new DataTable(templateName); + DataTable result = new DataTable(tableName); result.Columns.Add("WebPartTitle"); result.Columns.Add("WebPartType"); result.Columns.Add("ID"); diff --git a/KInspector.Modules/Modules/Content/TreeNodeChildrenModule.cs b/KInspector.Modules/Modules/Content/TreeNodeChildrenModule.cs index 98ad3c04..a5167a9e 100644 --- a/KInspector.Modules/Modules/Content/TreeNodeChildrenModule.cs +++ b/KInspector.Modules/Modules/Content/TreeNodeChildrenModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Displays TreeNodes having more than 1000 children. diff --git a/KInspector.Modules/Modules/Content/UnusedPageTypesModule.cs b/KInspector.Modules/Modules/Content/UnusedPageTypesModule.cs new file mode 100644 index 00000000..69f29f0d --- /dev/null +++ b/KInspector.Modules/Modules/Content/UnusedPageTypesModule.cs @@ -0,0 +1,41 @@ +using System; +using System.Data; +using System.Data.SqlClient; +using System.IO; +using System.Linq; +using System.Xml.Serialization; +using Kentico.KInspector.Core; + +namespace Kentico.KInspector.Modules +{ + public class UnusedPageTypesModule : IModule + { + public ModuleMetadata GetModuleMetadata() + { + return new ModuleMetadata + { + Name = "Unused page types", + SupportedVersions = new[] { + new Version("8.0"), + new Version("8.1"), + new Version("8.2"), + new Version("9.0"), + new Version("10.0") + }, + Comment = @"Looks for unused page types.", + }; + } + + + public ModuleResults GetResults(IInstanceInfo instanceInfo) + { + var dbService = instanceInfo.DBService; + var unusedTemplates = dbService.ExecuteAndGetTableFromFile("UnusedPageTypesModule.sql"); + + return new ModuleResults + { + Result = unusedTemplates + }; + } + } +} diff --git a/KInspector.Modules/Modules/Content/UnusedTemplatesModule.cs b/KInspector.Modules/Modules/Content/UnusedTemplatesModule.cs new file mode 100644 index 00000000..c8558e85 --- /dev/null +++ b/KInspector.Modules/Modules/Content/UnusedTemplatesModule.cs @@ -0,0 +1,41 @@ +using System; +using System.Data; +using System.Data.SqlClient; +using System.IO; +using System.Linq; +using System.Xml.Serialization; +using Kentico.KInspector.Core; + +namespace Kentico.KInspector.Modules +{ + public class UnusedTemplatesModule : IModule + { + public ModuleMetadata GetModuleMetadata() + { + return new ModuleMetadata + { + Name = "Unused templates", + SupportedVersions = new[] { + new Version("8.0"), + new Version("8.1"), + new Version("8.2"), + new Version("9.0"), + new Version("10.0") + }, + Comment = @"Looks for unused templates.", + }; + } + + + public ModuleResults GetResults(IInstanceInfo instanceInfo) + { + var dbService = instanceInfo.DBService; + var unusedTemplates = dbService.ExecuteAndGetTableFromFile("UnusedTemplatesModule.sql"); + + return new ModuleResults + { + Result = unusedTemplates + }; + } + } +} diff --git a/KInspector.Modules/Modules/Content/WebPartsInTransformationsModule.cs b/KInspector.Modules/Modules/Content/WebPartsInTransformationsModule.cs index 4eda38eb..0f4d1de4 100644 --- a/KInspector.Modules/Modules/Content/WebPartsInTransformationsModule.cs +++ b/KInspector.Modules/Modules/Content/WebPartsInTransformationsModule.cs @@ -27,7 +27,8 @@ You should use hierarchical transformation instead (see https://docs.kentico.com new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Content", }; diff --git a/KInspector.Modules/Modules/Content/WorkflowConsistencyModule.cs b/KInspector.Modules/Modules/Content/WorkflowConsistencyModule.cs index bbbafb6c..39086f0f 100644 --- a/KInspector.Modules/Modules/Content/WorkflowConsistencyModule.cs +++ b/KInspector.Modules/Modules/Content/WorkflowConsistencyModule.cs @@ -24,12 +24,14 @@ public ModuleMetadata GetModuleMetadata() return new ModuleMetadata { Name = "Workflow consistency", - SupportedVersions = new[] { + SupportedVersions = new[] { new Version("7.0"), - new Version("8.0"), + new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") }, + new Version("9.0"), + new Version("10.0") + }, Comment = @"Checks if there are any inconsistencies between published data and data in CMS_Version history. Checks only custom fields stored in coupled table (excludes Document/Node properties) Inconsistency can occur when a PUBLISHED document under WORKFLOW is updated in the API (when not creating/managing versions manually) @@ -92,6 +94,12 @@ private List FindDocumentsWithInconsistencies() { var classItem = GetClassItem(document.ClassName); + if (!classItem.ClassIsDocumentType || !classItem.ClassIsCoupledClass) + { + // Skip processing of document that has no coupled table + continue; + } + // Get published data values var publishedValues = GetDictionaryWithValues(classItem, document.DocumentForeignKeyValue); @@ -227,13 +235,13 @@ private List GetDocuments() { list.Add(new DocumentItem { - DocumentID = Convert.ToInt32(documentItem["DocumentID"]), - DocumentName = documentItem["DocumentName"].ToString(), - ClassName = documentItem["ClassName"].ToString(), - DocumentForeignKeyValue = Convert.ToInt32(documentItem["DocumentForeignKeyValue"]), + DocumentID = Convert.IsDBNull(documentItem["DocumentID"]) ? 0 : Convert.ToInt32(documentItem["DocumentID"]), + DocumentName = documentItem["DocumentName"]?.ToString(), + ClassName = documentItem["ClassName"]?.ToString(), + DocumentForeignKeyValue = Convert.IsDBNull(documentItem["DocumentForeignKeyValue"]) ? 0 : Convert.ToInt32(documentItem["DocumentForeignKeyValue"]), NodeXML = documentItem["NodeXML"].ToString(), - NodeAliasPath = documentItem["NodeAliasPath"].ToString(), - DocumentCulture = documentItem["DocumentCulture"].ToString() + NodeAliasPath = documentItem["NodeAliasPath"]?.ToString(), + DocumentCulture = documentItem["DocumentCulture"]?.ToString() }); } @@ -242,7 +250,7 @@ private List GetDocuments() private void InitializeClassNames() { - var sql = "select ClassName, ClassFormDefinition, ClassTableName from CMS_Class where ClassIsDocumentType = '1'"; + var sql = "select ClassName, ClassFormDefinition, ClassTableName, ClassIsCoupledClass, ClassIsDocumentType from CMS_Class"; var result = InstanceInfo.DBService.ExecuteAndGetDataSet(sql); var list = new List(); @@ -253,7 +261,9 @@ private void InitializeClassNames() { ClassName = classItem["ClassName"].ToString(), TableName = classItem["ClassTableName"].ToString(), - ClassFormDefinition = classItem["ClassFormDefinition"].ToString() + ClassFormDefinition = classItem["ClassFormDefinition"].ToString(), + ClassIsCoupledClass = Convert.ToBoolean(classItem["ClassIsCoupledClass"]), + ClassIsDocumentType = Convert.ToBoolean(classItem["ClassIsDocumentType"]), }); } @@ -301,6 +311,8 @@ private class DocumentItem private class ClassItem { + public bool ClassIsDocumentType { get; set; } + public bool ClassIsCoupledClass { get; set; } public string ClassName { get; set; } public string TableName { get; set; } public string ClassFormDefinition { get; set; } diff --git a/KInspector.Modules/Modules/EventLog/ApplicationRestartsModule.cs b/KInspector.Modules/Modules/EventLog/ApplicationRestartsModule.cs index 63067089..0ddfb124 100644 --- a/KInspector.Modules/Modules/EventLog/ApplicationRestartsModule.cs +++ b/KInspector.Modules/Modules/EventLog/ApplicationRestartsModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Displays information about application restarts. diff --git a/KInspector.Modules/Modules/EventLog/EventLogErrorsModule.cs b/KInspector.Modules/Modules/EventLog/EventLogErrorsModule.cs index b31a968c..9c091349 100644 --- a/KInspector.Modules/Modules/EventLog/EventLogErrorsModule.cs +++ b/KInspector.Modules/Modules/EventLog/EventLogErrorsModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Displays all errors from the event log. diff --git a/KInspector.Modules/Modules/EventLog/EventLogSizeModule.cs b/KInspector.Modules/Modules/EventLog/EventLogSizeModule.cs index 16399d74..adf032d7 100644 --- a/KInspector.Modules/Modules/EventLog/EventLogSizeModule.cs +++ b/KInspector.Modules/Modules/EventLog/EventLogSizeModule.cs @@ -25,7 +25,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Event log" }; diff --git a/KInspector.Modules/Modules/EventLog/PageNotFoundsModule.cs b/KInspector.Modules/Modules/EventLog/PageNotFoundsModule.cs index 9806ad2d..5d925006 100644 --- a/KInspector.Modules/Modules/EventLog/PageNotFoundsModule.cs +++ b/KInspector.Modules/Modules/EventLog/PageNotFoundsModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Displays all the 404 errors from the event log. diff --git a/KInspector.Modules/Modules/General/BigTablesModule.cs b/KInspector.Modules/Modules/General/BigTablesModule.cs index e024b978..6d480deb 100644 --- a/KInspector.Modules/Modules/General/BigTablesModule.cs +++ b/KInspector.Modules/Modules/General/BigTablesModule.cs @@ -1,4 +1,4 @@ -using System; +using System; using Kentico.KInspector.Core; namespace Kentico.KInspector.Modules @@ -9,16 +9,18 @@ public ModuleMetadata GetModuleMetadata() { return new ModuleMetadata { - Name = "Top 25 tables by size", + Name = "Top 25 tables by size (MB)", SupportedVersions = new[] { new Version("6.0"), new Version("7.0"), new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Displays top 25 biggest tables from the database.", + Category = "Database" }; } @@ -36,4 +38,4 @@ public ModuleResults GetResults(IInstanceInfo instanceInfo) ResultComment = $"The overall database size is {databaseSizeInMB} MB"}; } } -} +} \ No newline at end of file diff --git a/KInspector.Modules/Modules/General/DatabaseConsistencyCheckModule.cs b/KInspector.Modules/Modules/General/DatabaseConsistencyCheckModule.cs index 8a06754a..4129fe7a 100644 --- a/KInspector.Modules/Modules/General/DatabaseConsistencyCheckModule.cs +++ b/KInspector.Modules/Modules/General/DatabaseConsistencyCheckModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Runs DBCC CHECKDB on current database which checks all consistency issues (https://msdn.microsoft.com/en-us/library/ms176064.aspx).", Category = "Consistency issues" diff --git a/KInspector.Modules/Modules/General/DebugCheckModule.cs b/KInspector.Modules/Modules/General/DebugCheckModule.cs new file mode 100644 index 00000000..54476330 --- /dev/null +++ b/KInspector.Modules/Modules/General/DebugCheckModule.cs @@ -0,0 +1,117 @@ +using Kentico.KInspector.Core; +using System; +using System.Web.Configuration; +using System.Data; +using System.Collections.Generic; +using System.Configuration; + +namespace Kentico.KInspector.Modules +{ + public class DebugCheckModule : IModule + { + public ModuleMetadata GetModuleMetadata() + { + return new ModuleMetadata + { + Category = "General", + Name = "Debug Check", + SupportedVersions = new[] { + new Version("7.0"), + new Version("8.0"), + new Version("8.1"), + new Version("8.2"), + new Version("9.0"), + new Version("10.0") + }, + Comment = @"Ensures that all debug keys in the CMS_SettingsKey table and the web.config file are set to false." + }; + } + + public ModuleResults GetResults(IInstanceInfo instanceInfo) + { + var disableAllDatabaseDebugs = false; + var enabledDatabaseDebugs = new List(); + + bool compilationDebugActive = IsCompilationDebugActive(instanceInfo); + + var databaseDebugSettings = GetDatabaseDebugSettings(instanceInfo.DBService); + foreach (var setting in databaseDebugSettings) + { + if (setting.Key == "CMSDisableDebug") + { + disableAllDatabaseDebugs = setting.Value; + } + else if (setting.Value) + { + enabledDatabaseDebugs.Add(string.Format("The {0} setting is enabled", setting.Key)); + } + } + + var databaseDebugsActive = !disableAllDatabaseDebugs && enabledDatabaseDebugs.Count > 0; + + if (compilationDebugActive || databaseDebugsActive) + { + var result = new List(); + + if (compilationDebugActive) + { + result.Add("Compilation debug is enabled in the web.config"); + } + + if (databaseDebugsActive) + { + result.AddRange(enabledDatabaseDebugs); + } + + return new ModuleResults + { + Status = Status.Error, + Result = result, + ResultComment = "Debug settings should be disabled on production instances!" + }; + } + else + { + return new ModuleResults + { + Status = Status.Good, + ResultComment = "Debug settings have been disabled!" + }; + } + } + + private static bool IsCompilationDebugActive(IInstanceInfo instanceInfo) + { + Version kenticoVersion = instanceInfo.Version; + string pathToWebConfig = instanceInfo.Directory.ToString(); + + if ((kenticoVersion >= new Version("8.0")) && !(instanceInfo.Directory.ToString().EndsWith("\\CMS\\") || instanceInfo.Directory.ToString().EndsWith("\\CMS"))) + { + pathToWebConfig += "\\CMS"; + } + + ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap { ExeConfigFilename = pathToWebConfig + "\\web.config" }; + Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); + + CompilationSection compilationSection = (CompilationSection)configuration.GetSection(@"system.web/compilation"); + var compilationDebugActive = compilationSection != null ? compilationSection.Debug : false; + return compilationDebugActive; + } + + private Dictionary GetDatabaseDebugSettings(IDatabaseService databaseService) + { + var debugSettings = new Dictionary(); + + var results = databaseService.ExecuteAndGetTableFromFile("DebugCheckModule.sql"); + foreach (DataRow debugSetting in results.Rows) + { + var key = debugSetting["Key"].ToString(); + var value = Boolean.Parse(debugSetting["Value"].ToString()); + + debugSettings.Add(key, value); + } + + return debugSettings; + } + } +} diff --git a/KInspector.Modules/Modules/General/DisabledWebPartAnalyzer.cs b/KInspector.Modules/Modules/General/DisabledWebPartAnalyzer.cs new file mode 100644 index 00000000..8508ed7a --- /dev/null +++ b/KInspector.Modules/Modules/General/DisabledWebPartAnalyzer.cs @@ -0,0 +1,53 @@ +using System; +using System.Data; +using System.Linq; +using System.IO; +using Kentico.KInspector.Core; + +namespace Kentico.KInspector.Modules +{ + public class DisabledWebPartAnalyzerModule : IModule + { + public ModuleMetadata GetModuleMetadata() + { + return new ModuleMetadata + { + Name = "Disabled web parts and web part zones", + SupportedVersions = new[] { + new Version("7.0"), + new Version("8.0"), + new Version("8.1"), + new Version("8.2"), + new Version("9.0"), + new Version("10.0") + }, + Category = "General", + Comment = @"Displays all page templates with disabled web parts and web part zones, meaning templates which have property 'visible' set to 'false'." + }; + } + + public ModuleResults GetResults(IInstanceInfo instanceInfo) + { + var dbService = instanceInfo.DBService; + var results = dbService.ExecuteAndGetTableFromFile("DisabledWebPartAnalyzerModule.sql"); + + if (results.Rows.Count > 0) + { + return new ModuleResults + { + Result = results, + ResultComment = "Page templates with disabled web parts found, check the table for the template names.", + Status = Status.Warning + }; + } + else + { + return new ModuleResults + { + ResultComment = "No page templates with disabled web parts found.", + Status = Status.Good + }; + } + } + } +} diff --git a/KInspector.Modules/Modules/General/DocumentsConsistencyIssuesModule.cs b/KInspector.Modules/Modules/General/DocumentsConsistencyIssuesModule.cs index aa405c75..dff18dda 100644 --- a/KInspector.Modules/Modules/General/DocumentsConsistencyIssuesModule.cs +++ b/KInspector.Modules/Modules/General/DocumentsConsistencyIssuesModule.cs @@ -18,7 +18,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Checks that CMS_Tree and CMS_Document tables are without any consistency issues.", Category = "Consistency issues" diff --git a/KInspector.Modules/Modules/General/MediaLibraryAzureLimitModule.cs b/KInspector.Modules/Modules/General/MediaLibraryAzureLimitModule.cs index c9e90b4c..a569a706 100644 --- a/KInspector.Modules/Modules/General/MediaLibraryAzureLimitModule.cs +++ b/KInspector.Modules/Modules/General/MediaLibraryAzureLimitModule.cs @@ -16,8 +16,9 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") - }, + new Version("9.0"), + new Version("10.0") + }, Category = "Performance", Comment = @"Web sites utilizing Azure Blob storage should limit media library folder size to maximum 100 items per folder to achieve good performance.", }; diff --git a/KInspector.Modules/Modules/General/PageTypeFieldsDataTypeMismatchModule.cs b/KInspector.Modules/Modules/General/PageTypeFieldsDataTypeMismatchModule.cs index 4fcf048e..58533ec9 100644 --- a/KInspector.Modules/Modules/General/PageTypeFieldsDataTypeMismatchModule.cs +++ b/KInspector.Modules/Modules/General/PageTypeFieldsDataTypeMismatchModule.cs @@ -17,6 +17,7 @@ public ModuleMetadata GetModuleMetadata() new Version("8.1"), new Version("8.2"), new Version("9.0"), + new Version("10.0") }, Comment = @"You may face this error when exporting/importing a site or when working with web parts / widgets that list more than one-page type. This error is caused by at least two different page types (for example A and B) having a field named in the same way (for example FieldName) but in each page type the field data is stored as a different data type (for example for A, it is 'Text' and for B it is 'GUID'). diff --git a/KInspector.Modules/Modules/General/PagesAnalyzerModule.cs b/KInspector.Modules/Modules/General/PagesAnalyzerModule.cs index ab4ea0bd..73f13904 100644 --- a/KInspector.Modules/Modules/General/PagesAnalyzerModule.cs +++ b/KInspector.Modules/Modules/General/PagesAnalyzerModule.cs @@ -66,12 +66,23 @@ It is a good practice to provide explicit touch icons in the markup since only s public ModuleResults GetResults(IInstanceInfo instanceInfo) { + var results = new ModuleResults(); + var dbService = instanceInfo.DBService; - var siteID = dbService.ExecuteAndGetScalar(string.Format(@"SELECT s.SiteID FROM CMS_Site AS s LEFT JOIN CMS_SiteDomainAlias AS sa ON s.SiteID = sa.SiteID -WHERE ('{0}' LIKE '%' + s.SiteDomainName + '%' -OR '{0}' LIKE '%' + sa.SiteDomainAliasName + '%') AND s.SiteStatus = N'RUNNING'", instanceInfo.Uri)); + var sql = $@"SELECT s.SiteID FROM CMS_Site AS s LEFT JOIN CMS_SiteDomainAlias AS sa ON s.SiteID = sa.SiteID + WHERE ('{instanceInfo.Uri}' LIKE '%' + s.SiteDomainName + '%' + OR '{instanceInfo.Uri}' LIKE '%' + sa.SiteDomainAliasName + '%') AND s.SiteStatus = N'RUNNING'"; - var results = new ModuleResults(); + var siteIDRaw = dbService.ExecuteAndGetScalar(sql); + int siteID = 0; + if(!int.TryParse(siteIDRaw, out siteID)) + { + results.Result = $"No site found matching the URL: {instanceInfo.Uri}"; + results.Status = Status.Error; + return results; + } + + var aliases = dbService.ExecuteAndGetTableFromFile("PagesAnalyzerModule.sql", new SqlParameter("SiteId", siteID.ToString())); var allLinks = new Dictionary>(); @@ -84,20 +95,17 @@ public ModuleResults GetResults(IInstanceInfo instanceInfo) foreach (DataRow alias in aliases.Rows) { - var redirected = alias["Redirected"].ToString(); + var redirected = alias["Redirected"].ToString().ToLower(); switch (redirected) { // If version 8 and higher is used and page is redirected to first child case "1": + case "true": + alias["Redirected"] = "True"; continue; - - // If version 7 and lower is used, database column does not exist - case "DOESNOTEXIST": - alias["Redirected"] = "N/A"; - break; - + case "doesnotexist": // If version 7 and lower is used, database column does not exist default: - alias["Redirected"] = "NO"; + alias["Redirected"] = "False"; break; } diff --git a/KInspector.Modules/Modules/General/ScheduledTasksModule.cs b/KInspector.Modules/Modules/General/ScheduledTasksModule.cs index a68245b0..13ac5791 100644 --- a/KInspector.Modules/Modules/General/ScheduledTasksModule.cs +++ b/KInspector.Modules/Modules/General/ScheduledTasksModule.cs @@ -17,7 +17,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Selects important scheduled tasks", diff --git a/KInspector.Modules/Modules/General/ScreenshotterModule.cs b/KInspector.Modules/Modules/General/ScreenshotterModule.cs index 01eb014c..006a60d7 100644 --- a/KInspector.Modules/Modules/General/ScreenshotterModule.cs +++ b/KInspector.Modules/Modules/General/ScreenshotterModule.cs @@ -26,7 +26,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"It takes a screenshot of all published pages on the website. - All screenshots are saved into your desktop folder diff --git a/KInspector.Modules/Modules/General/SettingsModule.cs b/KInspector.Modules/Modules/General/SettingsModule.cs index ea236dad..1fb3d029 100644 --- a/KInspector.Modules/Modules/General/SettingsModule.cs +++ b/KInspector.Modules/Modules/General/SettingsModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Selects important settings from the database", diff --git a/KInspector.Modules/Modules/General/TaskProcessingIssuesModule.cs b/KInspector.Modules/Modules/General/TaskProcessingIssuesModule.cs new file mode 100644 index 00000000..98b3d158 --- /dev/null +++ b/KInspector.Modules/Modules/General/TaskProcessingIssuesModule.cs @@ -0,0 +1,53 @@ +using System; +using System.Data; +using Kentico.KInspector.Core; + +namespace Kentico.KInspector.Modules +{ + public class TaskProcessingIssues : IModule + { + public ModuleMetadata GetModuleMetadata() + { + return new ModuleMetadata + { + Name = "Task processing issues", + SupportedVersions = new[] { + new Version("9.0"), + new Version("10.0") + }, + Comment = @"Checks for possible issues with processing system, workflow, marketing automation, smart search, and web farm tasks.", + Category = "Database" + }; + } + + + public ModuleResults GetResults(IInstanceInfo instanceInfo) + { + var dbService = instanceInfo.DBService; + var results = dbService.ExecuteAndGetTableFromFile("TaskProcessingIssueModule.sql"); + + var hasUnprocessedTasks = false; + if (results != null && results.Rows.Count > 0) + { + var row = results.Rows[0]; + + foreach (DataColumn column in results.Columns) + { + var value = int.Parse(row[column].ToString()); + if (value > 0) + { + hasUnprocessedTasks = true; + break; + } + } + } + + return new ModuleResults + { + Result = results, + Status = hasUnprocessedTasks ? Status.Warning : Status.Good, + ResultComment = hasUnprocessedTasks ? "There are unprocessed tasks that should be reviewed." : "All tasks have been processed." + }; + } + } +} \ No newline at end of file diff --git a/KInspector.Modules/Modules/OnlineMarketing/OMContactGroupsWithManualMacro.cs b/KInspector.Modules/Modules/OnlineMarketing/OMContactGroupsWithManualMacro.cs index 55e2f41c..b38e4836 100644 --- a/KInspector.Modules/Modules/OnlineMarketing/OMContactGroupsWithManualMacro.cs +++ b/KInspector.Modules/Modules/OnlineMarketing/OMContactGroupsWithManualMacro.cs @@ -13,7 +13,8 @@ public ModuleMetadata GetModuleMetadata() SupportedVersions = new[] { new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Contact groups that have macro condition set via plain macro are always just slower and should be rewritten into MacroRuleDesigner, so that they can be translated into SQL queries to decrease recalculation time. For more, see https://docs.kentico.com/display/K82/Improving+custom+macro+performance+in+scoring+and+contact+groups diff --git a/KInspector.Modules/Modules/OnlineMarketing/OMInactiveContactsDeletion.cs b/KInspector.Modules/Modules/OnlineMarketing/OMInactiveContactsDeletion.cs index 66039f48..c647dfb7 100644 --- a/KInspector.Modules/Modules/OnlineMarketing/OMInactiveContactsDeletion.cs +++ b/KInspector.Modules/Modules/OnlineMarketing/OMInactiveContactsDeletion.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Checks whether there is Online marketing module enabled and if so, checks the old contacts deletion settings. These are important to keep OM database smaller.", Category = "Online marketing", diff --git a/KInspector.Modules/Modules/OnlineMarketing/OMTablesSize.cs b/KInspector.Modules/Modules/OnlineMarketing/OMTablesSize.cs index 7fc75bee..5f742e10 100644 --- a/KInspector.Modules/Modules/OnlineMarketing/OMTablesSize.cs +++ b/KInspector.Modules/Modules/OnlineMarketing/OMTablesSize.cs @@ -15,7 +15,8 @@ public ModuleMetadata GetModuleMetadata() SupportedVersions = new[] { new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Comment = @"Checks whether Online marketing tables aren't too big. diff --git a/KInspector.Modules/Modules/Security/ClickJackingModule.cs b/KInspector.Modules/Modules/Security/ClickJackingModule.cs new file mode 100644 index 00000000..ccbf864b --- /dev/null +++ b/KInspector.Modules/Modules/Security/ClickJackingModule.cs @@ -0,0 +1,67 @@ +using System; +using System.Configuration; +using System.Linq; +using Kentico.KInspector.Core; + +namespace Kentico.KInspector.Modules +{ + public class ClickJackingModule : IModule + { + public ModuleMetadata GetModuleMetadata() + { + return new ModuleMetadata + { + Name = "ClickJacking Protection", + Comment = + @"This module checks to see if protection against click jacking attacks is disabled for any paths. If the appSettings section of web.config file contains an etry CMSXFrameOptionsExclude, that means that the protection is disabled for the paths specified in the result . https://docs.kentico.com/display/K9/Clickjacking", + SupportedVersions = new[] + { + new Version("7.0"), + new Version("8.0"), + new Version("8.1"), + new Version("8.2"), + new Version("9.0"), + new Version("10.0") + }, + Category = "Security", + }; + } + + public ModuleResults GetResults(IInstanceInfo instanceInfo) + { + ModuleResults result; + + Version kenticoVersion = instanceInfo.Version; + string pathToWebConfig = instanceInfo.Directory.ToString(); + + if ((kenticoVersion >= new Version("8.0")) && !(instanceInfo.Directory.ToString().EndsWith("\\CMS\\") || instanceInfo.Directory.ToString().EndsWith("\\CMS"))) + { + pathToWebConfig += "\\CMS"; + } + + ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap { ExeConfigFilename = pathToWebConfig + "\\web.config" }; + Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); + + var entry = configuration.AppSettings.Settings["CMSXFrameOptionsExcluded"]; + bool hasEntry = entry != null; + + if (hasEntry) + { + result = new ModuleResults(); + result.Result = entry.Value; + result.Status = Status.Warning; + result.ResultComment = + @"Click jacking protection is disabled for the paths specified in ModuleResults.Result. See https://docs.kentico.com/display/K9/Clickjacking"; + } + else + { + result = new ModuleResults(); + result.Status = Status.Good; + result.ResultComment = + @"Click jacking protection is enabled by default. See https://docs.kentico.com/display/K9/Clickjacking"; + } + + return result; + } + } +} diff --git a/KInspector.Modules/Modules/Security/FloodProtectionModule.cs b/KInspector.Modules/Modules/Security/FloodProtectionModule.cs index 642d46bc..9c67ecbe 100644 --- a/KInspector.Modules/Modules/Security/FloodProtectionModule.cs +++ b/KInspector.Modules/Modules/Security/FloodProtectionModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Security", }; diff --git a/KInspector.Modules/Modules/Security/PasswordPolicyModule.cs b/KInspector.Modules/Modules/Security/PasswordPolicyModule.cs index 43f3e59e..6af34933 100644 --- a/KInspector.Modules/Modules/Security/PasswordPolicyModule.cs +++ b/KInspector.Modules/Modules/Security/PasswordPolicyModule.cs @@ -19,7 +19,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Security", }; diff --git a/KInspector.Modules/Modules/Security/SecurityAppSettingsModule.cs b/KInspector.Modules/Modules/Security/SecurityAppSettingsModule.cs index 2a061dc8..8c9a8c00 100644 --- a/KInspector.Modules/Modules/Security/SecurityAppSettingsModule.cs +++ b/KInspector.Modules/Modules/Security/SecurityAppSettingsModule.cs @@ -12,20 +12,31 @@ public class SecurityAppSettingsModule : IModule { private const string RECOMMENDED_VALUE_TRUE = "True"; private const string RECOMMENDED_VALUE_FALSE = "False"; - private const string VALUE_NOT_SET = "Settings was not set at all."; + private const string VALUE_NOT_SET = "No value set"; public ModuleMetadata GetModuleMetadata() { return new ModuleMetadata { - Name = "Security web.config settings", - Comment = "Checks security settings in web.config.", - SupportedVersions = new[] { + Name = "Security settings in web.config", + Comment = @"Checks the following security settings in web.config: +- Compilation debug +- Tracing +- Custom errors +- Cookieless authentication +- Session fixation +- Http only cookies +- Viewstate (MAC) validation +- Hash string salt +- SA in CMSConnectionString", + + SupportedVersions = new[] { new Version("7.0"), - new Version("8.0"), - new Version("8.1"), + new Version("8.0"), + new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Security", }; @@ -52,11 +63,11 @@ public ModuleResults GetResults(IInstanceInfo instanceInfo) var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); # region "Debug mode" - var compilationNode = (CompilationSection) configuration.GetSection("system.web/compilation"); + var compilationNode = (CompilationSection)configuration.GetSection("system.web/compilation"); bool debugMode = compilationNode.Debug; if (debugMode) - { + { result.Rows.Add("Debug ( 0) diff --git a/KInspector.Modules/Modules/Security/SecuritySettingsModule.cs b/KInspector.Modules/Modules/Security/SecuritySettingsModule.cs index eedcd6c6..b42e1aa7 100644 --- a/KInspector.Modules/Modules/Security/SecuritySettingsModule.cs +++ b/KInspector.Modules/Modules/Security/SecuritySettingsModule.cs @@ -19,7 +19,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Security", }; diff --git a/KInspector.Modules/Modules/Security/SslInAdministrationModule.cs b/KInspector.Modules/Modules/Security/SslInAdministrationModule.cs index 44c8717f..d0cac990 100644 --- a/KInspector.Modules/Modules/Security/SslInAdministrationModule.cs +++ b/KInspector.Modules/Modules/Security/SslInAdministrationModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Security", }; diff --git a/KInspector.Modules/Modules/Security/TransformationAnalyzerModule.cs b/KInspector.Modules/Modules/Security/TransformationAnalyzerModule.cs index 805ac945..c3b08ac3 100644 --- a/KInspector.Modules/Modules/Security/TransformationAnalyzerModule.cs +++ b/KInspector.Modules/Modules/Security/TransformationAnalyzerModule.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; @@ -12,50 +13,15 @@ namespace Kentico.KInspector.Modules { public class TransformationAnalyzerModule : IModule { - #region "Constants" - - private static readonly Regex queryRegex = new Regex("QueryHelper\\.GetString"); - private static readonly Regex requestRegex = new Regex("Request\\.QueryString"); - private static readonly Regex cookieRegex = new Regex("CookieHelper\\.GetValue"); - private static readonly Regex getQueryRegex = new Regex("URLHelper\\.GetQueryValue"); - private static readonly Regex getQuery = new Regex("URLHelper\\.GetQuery"); - private static readonly Regex currentUrlRegex = new Regex("currenturl"); - private static readonly Regex getStringRegex = new Regex("ScriptHelper\\.GetScript"); - - - /// - /// Array of regular expressions used for transformation analysis. - /// - private static readonly Regex[] patterns = { queryRegex, requestRegex, cookieRegex, getQueryRegex, getQuery, currentUrlRegex, getStringRegex }; - - #endregion - - - #region "Fields" - - private IDatabaseService mDatabaseService; - private string mInstancePath; - HashSet mTransformationFullNames; - #endregion - - - #region "Properties" - - /// - /// Constraints transformation analysis on transformations used in web parts, - /// which are located on page templates with display name like this one. - /// - /// - /// The current modules implementation does not allow the user to provide - /// module parameters (unless they are in the global configuration object). - /// This should be improved to be able to set the value of this property - /// based on what the user wants. - /// - public string LikePageTemplateDisplayName { get; set; } = "%"; - #endregion - - - #region "IModule interface methods" + private static readonly Regex regexForCookie = new Regex("CookieHelper\\.GetValue"); + private static readonly Regex regexForCurrentUrl = new Regex("currenturl"); + private static readonly Regex regexForGetQuery = new Regex("URLHelper\\.GetQuery"); + private static readonly Regex regexForGetQueryValue = new Regex("URLHelper\\.GetQueryValue"); + private static readonly Regex regexForGetScript = new Regex("ScriptHelper\\.GetScript"); + private static readonly Regex regexForGetSring = new Regex("QueryHelper\\.GetString"); + private static readonly Regex regexForQueryString = new Regex("Request\\.QueryString"); + private static readonly Regex[] regexPatterns = { regexForQueryString, regexForGetSring, regexForCookie, regexForGetQueryValue, regexForGetQuery, regexForCurrentUrl, regexForGetScript }; + private IInstanceInfo instanceInfo; public ModuleMetadata GetModuleMetadata() { @@ -68,7 +34,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Security", }; @@ -76,65 +43,22 @@ public ModuleMetadata GetModuleMetadata() public ModuleResults GetResults(IInstanceInfo instanceInfo) { - List report = new List(); + this.instanceInfo = instanceInfo; + List report = new List(); List xssReport = new List(); List customMacrosReport = new List(); - mDatabaseService = instanceInfo.DBService; - mInstancePath = instanceInfo.Directory.FullName; + var webPartConfigurations = GetWebPartConfigurationsForTemplates(); - HashSet transformationNames = new HashSet(); - mTransformationFullNames = new HashSet(); + var transformationInfos = GetTransformationInfo(webPartConfigurations); + var checkForCustomMacros = MacroValidator.Current.CheckForCustomMacros(instanceInfo.Version); - DataTable webPartsInTransformationsTable = GetPageTemplateWebParts(LikePageTemplateDisplayName); - foreach (DataRow webPart in webPartsInTransformationsTable.Rows) - { - XmlDocument xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(webPart["PageTemplateWebParts"] as string); - - IEnumerable templateTransformationFullNames = GetTransformationNamesInPageTemplateWebParts(xmlDoc); - - foreach (string templateTransformationFullName in templateTransformationFullNames) - { - mTransformationFullNames.Add(templateTransformationFullName); - string transformationName = templateTransformationFullName.Substring(templateTransformationFullName.LastIndexOf('.') + 1); - transformationNames.Add(transformationName); - } - } - - DataTable transformationCodesTable = GetTransformationCodes(transformationNames); - bool checkForCustomMacros = MacroValidator.Current.CheckForCustomMacros(instanceInfo.Version); - foreach (DataRow transformation in transformationCodesTable.Rows) - { - int transformationId = (int)transformation["TransformationID"]; - string transformationName = transformation["TransformationName"] as string; - string transformationCode = transformation["TransformationCode"] as string; - - string xssResult = null; - AnalyseXss(transformationId, transformationName, transformationCode, ref xssResult); - if (!string.IsNullOrEmpty(xssResult)) - { - xssReport.Add(xssResult); - } + PerformAnalysis(transformationInfos, checkForCustomMacros, xssReport, customMacrosReport); - if (checkForCustomMacros) - { - string customMacroResult = null; - AnalyseCustomMacros(transformationId, transformationName, transformationCode, ref customMacroResult); - if (!string.IsNullOrEmpty(customMacroResult)) - { - customMacrosReport.Add(customMacroResult); - } - } - } - - if (xssReport.Count > 0) - { - report.Add("------------------------ Transformations - XSS Analysis report -----------------"); - report.AddRange(xssReport); - report.Add("

"); - } + report.Add("------------------------ Transformations - XSS Analysis report -----------------"); + report.AddRange(xssReport); + report.Add("

"); if (customMacrosReport.Count > 0) { @@ -142,16 +66,7 @@ public ModuleResults GetResults(IInstanceInfo instanceInfo) report.AddRange(customMacrosReport); report.Add("

"); } - - if (report.Count == 0) - { - return new ModuleResults - { - ResultComment = "No problems in transformations found.", - Status = Status.Good - }; - } - + return new ModuleResults { Result = report, @@ -159,105 +74,159 @@ public ModuleResults GetResults(IInstanceInfo instanceInfo) }; } - #endregion + private void PerformAnalysis(List transformationInfos, bool checkForCustomMacros, List xssReport, List customMacrosReport) + { + foreach (var transformationInfo in transformationInfos) + { + var xssResult = string.Empty; + AnalyseXss(transformationInfo, xssReport); - #region "Methods" + if (checkForCustomMacros) + { + AnalyseCustomMacros(transformationInfo, customMacrosReport); + } + } + } /// - /// Analysis transformation code for XSS vulnerabilities. + /// Analyse transformation for deprecated custom macros. /// /// ID of the transformation. /// Name of the transformation. /// Code of the transformation. - /// Result of XSS vulnerability analysis (not modified if none found). - private void AnalyseXss(int transformationId, string transformationName, string transformationCode, ref string result) + /// Result of deprecated custom macro analysis (not modified if none found). + private void AnalyseCustomMacros(TransformationInfo transformationInfo, List report) { - // Check if transformation code contains the malicious input - bool potentialXssFound = patterns.Any(p => p.IsMatch(transformationCode)); - - // If potential XSS has been found, set appropriate result - if (potentialXssFound) + if (!string.IsNullOrWhiteSpace(transformationInfo.Code)) { - result = GetTransformationReportLink(transformationId, transformationName, transformationCode); + // Check if transformation code contains deprecated custom macros + bool customMacrosFound = MacroValidator.Current.ContainsMacros(transformationInfo.Code, MacroValidator.MacroType.Custom); + + // If custom macros have been found, set appropriate result + UpdateReport(transformationInfo, report, customMacrosFound); } } - /// - /// Analyse transformation for deprecated custom macros. + /// Analysis transformation code for XSS vulnerabilities. /// /// ID of the transformation. /// Name of the transformation. /// Code of the transformation. - /// Result of deprecated custom macro analysis (not modified if none found). - private void AnalyseCustomMacros(int transformationId, string transformationName, string transformationCode, ref string result) + /// Result of XSS vulnerability analysis (not modified if none found). + private void AnalyseXss(TransformationInfo transformationInfo, List report) { - // Check if transformation code contains deprecated custom macros - bool customMacrosFound = MacroValidator.Current.ContainsMacros(transformationCode, MacroValidator.MacroType.Custom); + var result = string.Empty; - // If custom macros have been found, set appropriate result - if (customMacrosFound) + if (!string.IsNullOrWhiteSpace(transformationInfo.Code)) { - result = GetTransformationReportLink(transformationId, transformationName, transformationCode); + // Check if transformation code contains the malicious input + bool potentialXssFound = regexPatterns.Any(p => p.IsMatch(transformationInfo.Code)); + + // If potential XSS has been found, set appropriate result + + UpdateReport(transformationInfo, report, potentialXssFound); } } + private void UpdateReport(TransformationInfo transformationInfo, List report, bool issueFound) + { + if (issueFound) + { + report.Add(GetTransformationReportLink(transformationInfo)); + } + else + { + report.Add($"Identified no issues in {transformationInfo.FullName} ({transformationInfo.ID})"); + } + } - /// - /// Gets page template web parts where page template display name - /// is like given pattern. - /// - /// Like pattern for page template display name. - /// DataTable containing page template web parts in its 'PageTemplateWebParts' column. - private DataTable GetPageTemplateWebParts(string likePageTemplateDisplayName) + private Dictionary GetClassInfo(IEnumerable classNames) { - return mDatabaseService.ExecuteAndGetTableFromFile("TransformationAnalyzerModule-PageTemplateWebParts.sql", - new SqlParameter("PageTemplateDisplayName", likePageTemplateDisplayName)); + var classData = GetDataWhereInTable("KI_ClassNames", "ClassName", classNames); + var classInfo = new Dictionary(); + + foreach (DataRow row in classData.Rows) + { + var classID = int.Parse(row["ClassID"].ToString()); + var className = row["ClassName"].ToString().ToLower(); + classInfo.Add(className, classID); + } + + return classInfo; } + private DataTable GetDataWhereInTable(DataTable table) + { + var tableValueParameter = new SqlParameter(); + tableValueParameter.ParameterName = "@TableValueParameter"; + tableValueParameter.SqlDbType = SqlDbType.Structured; + tableValueParameter.TypeName = table.TableName; + tableValueParameter.Value = table; + + instanceInfo.DBService.ExecuteAndGetTableFromFile($"TransformationAnalyzerModule-Initialize-{table.TableName}.sql"); + return instanceInfo.DBService.ExecuteAndGetTableFromFile($"TransformationAnalyzerModule-GetDataWhereIn-{table.TableName}.sql", tableValueParameter); + } + + private DataTable GetDataWhereInTable(string dataTableName, string columnName, IEnumerable items) + { + if (!items.Any()) + { + return null; + } + + var tableDefinition = new DataTable(dataTableName); + tableDefinition.Columns.Add(columnName); + + foreach (var item in items) + { + tableDefinition.Rows.Add(item); + } + + return GetDataWhereInTable(tableDefinition); + } /// /// Gets full names of transformations used in page template web parts. /// /// Content of PageTemplateWebParts column from CMS_PageTemplate table. /// Enumeration of transformation full names. - private IEnumerable GetTransformationNamesInPageTemplateWebParts(XmlDocument pageTemplateWebParts) + private HashSet GetFullTransformationNamesFromWebPartConfiguration(XmlDocument webPartConfiguration) { - HashSet res = new HashSet(); + HashSet results = new HashSet(); - foreach (XmlNode webPartPropertyNode in pageTemplateWebParts.SelectNodes("/page/webpartzone/webpart/property")) + foreach (XmlNode webPartPropertyNode in webPartConfiguration.SelectNodes("/page/webpartzone/webpart/property")) { XmlAttribute nameAttribute = webPartPropertyNode.Attributes["name"]; - if ((nameAttribute != null) && nameAttribute.Value.Contains("transformation") && !string.IsNullOrEmpty(webPartPropertyNode.InnerText)) + + var isValidAttribute = nameAttribute != null && nameAttribute.Value.Contains("transformation"); + var hasValue = !string.IsNullOrEmpty(webPartPropertyNode.InnerText); + + if (isValidAttribute && hasValue) { - res.Add(webPartPropertyNode.InnerText); + results.Add(webPartPropertyNode.InnerText.ToLower()); } } - return res; + return results; } - - /// - /// Gets table with transformation codes. - /// - /// Enumeration of transformation names. - /// Table of transformation codes, or null if does not contain any item). - private DataTable GetTransformationCodes(IEnumerable transformationNames) + private HashSet GetFullTransformationNamesFromWebPartConfigurations(IEnumerable webPartConfigurations) { - if (!transformationNames.Any()) + var fullTransformationNames = new HashSet(); + foreach (var configurationXml in webPartConfigurations) { - return null; + var fullTransformationNamesInWebPartConfiguration = GetFullTransformationNamesFromWebPartConfiguration(configurationXml); + foreach (var fullTransformationName in fullTransformationNamesInWebPartConfiguration) + { + fullTransformationNames.Add(fullTransformationName); + } } - string listOfNames = "'" + string.Join("', '", transformationNames) + "'"; - - return mDatabaseService.ExecuteAndGetTableFromFile("TransformationAnalyzerModule-TransformationCodes.sql", - new SqlParameter("ListOfNames", listOfNames)); + return fullTransformationNames; } - /// /// Gets enumeration of possible full names for given transformation name /// (the mapping can be ambiguous in some cases, but the original power shell script @@ -271,6 +240,76 @@ private IEnumerable GetTransformationFullNamesForName(string transformat return transformationFullNames.Where(it => it.EndsWith("." + transformationName)); } + private List GetTransformationInfo(IEnumerable webPartConfigurations) + { + HashSet fullTransformationNames = GetFullTransformationNamesFromWebPartConfigurations(webPartConfigurations); + return GetTransformationInfo(fullTransformationNames); + } + + private List GetTransformationInfo(IEnumerable fullTransformationNames) + { + var transformationInfos = new List(); + foreach (var fullTransformationName in fullTransformationNames) + { + var name = fullTransformationName.Substring(fullTransformationName.LastIndexOf('.') + 1); + var className = fullTransformationName.Substring(0, fullTransformationName.LastIndexOf('.')); + + var transformationInfo = new TransformationInfo() + { + FullName = fullTransformationName, + Name = name, + ClassName = className, + }; + + transformationInfos.Add(transformationInfo); + } + + var classNames = transformationInfos.Select(x => x.ClassName).Distinct(); + var classDetails = GetClassInfo(classNames); + + foreach (var transformationInfo in transformationInfos) + { + int classID = 0; + classDetails.TryGetValue(transformationInfo.ClassName, out classID); + transformationInfo.ClassID = classID; + } + + var transformationTable = GetTransformationListTable(transformationInfos); + var transformationInfoData = GetDataWhereInTable(transformationTable); + + foreach (DataRow item in transformationInfoData.Rows) + { + var id = int.Parse(item["TransformationID"].ToString()); + var classID = int.Parse(item["TransformationClassID"].ToString()); + var name = item["TransformationName"].ToString(); + var code = item["TransformationCode"].ToString(); + + var index = transformationInfos.FindIndex(ti => ti.Name.ToLower() == name.ToLower() && ti.ClassID == classID); + transformationInfos[index].ID = id; + transformationInfos[index].Code = code; + } + + return transformationInfos; + } + + private DataTable GetTransformationListTable(List transformationInfos) + { + if (!transformationInfos.Any()) + { + return null; + } + + var table = new DataTable("KI_TransformationList"); + table.Columns.Add("TransformationName"); + table.Columns.Add("TransformationClassID"); + + foreach (var transformationInfo in transformationInfos) + { + table.Rows.Add(transformationInfo.Name, transformationInfo.ClassID); + } + + return table; + } /// /// Gets the transformation report links. @@ -279,23 +318,50 @@ private IEnumerable GetTransformationFullNamesForName(string transformat /// Name of the transformation. /// Code of the transformation. /// Report with possible links for given transformation. - private string GetTransformationReportLink(int transformationId, string transformationName, string transformationCode) + private string GetTransformationReportLink(TransformationInfo transformationInfo) { - IEnumerable fullNames = GetTransformationFullNamesForName(transformationName, mTransformationFullNames); StringBuilder res = new StringBuilder(); - res.Append(transformationName).Append(" "); - foreach (string fullName in fullNames) + res.Append("") + .Append(transformationInfo.FullName) + .Append(" "); + + return res.ToString(); + } + + /// + /// Gets web part configurations for page templates where display name + /// is like . + /// + /// SQL Like pattern for page template display name. Default is all + /// DataTable containing page template web parts in its 'PageTemplateWebParts' column. + private List GetWebPartConfigurationsForTemplates(string pageTemplateDisplayNameLike = "%") + { + var results = new List(); + + var sqlFile = "TransformationAnalyzerModule-PageTemplateWebParts.sql"; + var sqlParameter = new SqlParameter("PageTemplateDisplayName", pageTemplateDisplayNameLike); + var webPartConfigurationsData = instanceInfo.DBService.ExecuteAndGetTableFromFile(sqlFile, sqlParameter); + foreach (DataRow webPartConfiguration in webPartConfigurationsData.Rows) { - res.Append("") - .Append(fullName) - .Append(" "); + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(webPartConfiguration["PageTemplateWebParts"].ToString()); + results.Add(xmlDoc); } - return res.ToString(); + + return results; } + } - #endregion + public class TransformationInfo + { + public int ClassID { get; set; } + public string ClassName { get; set; } + public string Code { get; set; } + public string FullName { get; set; } + public int ID { get; set; } + public string Name { get; set; } } } \ No newline at end of file diff --git a/KInspector.Modules/Modules/Security/UsersWithEmptyPasswordsModule.cs b/KInspector.Modules/Modules/Security/UsersWithEmptyPasswordsModule.cs index 1906c674..e67b8355 100644 --- a/KInspector.Modules/Modules/Security/UsersWithEmptyPasswordsModule.cs +++ b/KInspector.Modules/Modules/Security/UsersWithEmptyPasswordsModule.cs @@ -17,7 +17,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Security", }; diff --git a/KInspector.Modules/Modules/Security/UsersWithPlaintextPasswordsModule.cs b/KInspector.Modules/Modules/Security/UsersWithPlaintextPasswordsModule.cs index 9d502a6a..57320274 100644 --- a/KInspector.Modules/Modules/Security/UsersWithPlaintextPasswordsModule.cs +++ b/KInspector.Modules/Modules/Security/UsersWithPlaintextPasswordsModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Security", Comment = @"Displays a list of all users with passwords that are stored in plain text. diff --git a/KInspector.Modules/Modules/Security/WebPartAnalyzerModule.cs b/KInspector.Modules/Modules/Security/WebPartAnalyzerModule.cs index 67aabee5..754ce734 100644 --- a/KInspector.Modules/Modules/Security/WebPartAnalyzerModule.cs +++ b/KInspector.Modules/Modules/Security/WebPartAnalyzerModule.cs @@ -47,7 +47,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Security", }; diff --git a/KInspector.Modules/Modules/Setup/GlobalAdminSetupModule.cs b/KInspector.Modules/Modules/Setup/GlobalAdminSetupModule.cs index 159e4072..b16e9620 100644 --- a/KInspector.Modules/Modules/Setup/GlobalAdminSetupModule.cs +++ b/KInspector.Modules/Modules/Setup/GlobalAdminSetupModule.cs @@ -16,7 +16,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Setup", }; @@ -25,7 +26,10 @@ public ModuleMetadata GetModuleMetadata() public ModuleResults GetResults(IInstanceInfo instanceInfo) { var dbService = instanceInfo.DBService; - var results = dbService.ExecuteAndGetDataSetFromFile("Setup/GlobalAdminSetupModule.sql"); + + var sqlFile = instanceInfo.Version.Major != 10 ? "Setup/GlobalAdminSetupModule.sql" : "Setup/GlobalAdminSetupModule-V10.sql"; + + var results = dbService.ExecuteAndGetDataSetFromFile(sqlFile); return new ModuleResults { diff --git a/KInspector.Modules/Modules/Setup/LicenseSetupModule.cs b/KInspector.Modules/Modules/Setup/LicenseSetupModule.cs index 183dc4a8..adfeb85a 100644 --- a/KInspector.Modules/Modules/Setup/LicenseSetupModule.cs +++ b/KInspector.Modules/Modules/Setup/LicenseSetupModule.cs @@ -16,8 +16,7 @@ public ModuleMetadata GetModuleMetadata() new Version("7.0"), new Version("8.0"), new Version("8.1"), - new Version("8.2"), - new Version("9.0") + new Version("8.2") }, Category = "Setup", }; diff --git a/KInspector.Modules/Modules/Setup/SiteDomainAliasesSetupModule.cs b/KInspector.Modules/Modules/Setup/SiteDomainAliasesSetupModule.cs index 25d09b04..c456d6e6 100644 --- a/KInspector.Modules/Modules/Setup/SiteDomainAliasesSetupModule.cs +++ b/KInspector.Modules/Modules/Setup/SiteDomainAliasesSetupModule.cs @@ -15,7 +15,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Setup", }; diff --git a/KInspector.Modules/Modules/Setup/SitesSetupModule.cs b/KInspector.Modules/Modules/Setup/SitesSetupModule.cs index 8d44d9bf..3c43cbef 100644 --- a/KInspector.Modules/Modules/Setup/SitesSetupModule.cs +++ b/KInspector.Modules/Modules/Setup/SitesSetupModule.cs @@ -15,7 +15,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Setup", }; diff --git a/KInspector.Modules/Modules/Setup/SmtpServersSetupModule.cs b/KInspector.Modules/Modules/Setup/SmtpServersSetupModule.cs index bdc522b6..54d10d8c 100644 --- a/KInspector.Modules/Modules/Setup/SmtpServersSetupModule.cs +++ b/KInspector.Modules/Modules/Setup/SmtpServersSetupModule.cs @@ -17,7 +17,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Setup", }; diff --git a/KInspector.Modules/Modules/Setup/StagingServersSetupModule.cs b/KInspector.Modules/Modules/Setup/StagingServersSetupModule.cs index 8a649033..d18180a9 100644 --- a/KInspector.Modules/Modules/Setup/StagingServersSetupModule.cs +++ b/KInspector.Modules/Modules/Setup/StagingServersSetupModule.cs @@ -18,7 +18,8 @@ Setting the Enabled state of all servers to false would result in UI not being a new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Setup", }; diff --git a/KInspector.Modules/Modules/Setup/WebFarmServersSetupModule.cs b/KInspector.Modules/Modules/Setup/WebFarmServersSetupModule.cs index f1e94339..e60b1d16 100644 --- a/KInspector.Modules/Modules/Setup/WebFarmServersSetupModule.cs +++ b/KInspector.Modules/Modules/Setup/WebFarmServersSetupModule.cs @@ -17,7 +17,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, Category = "Setup", }; diff --git a/KInspector.Modules/Modules/SocialMarketing/ExpiredTokensModule.cs b/KInspector.Modules/Modules/SocialMarketing/ExpiredTokensModule.cs index 04da0854..2444ddad 100644 --- a/KInspector.Modules/Modules/SocialMarketing/ExpiredTokensModule.cs +++ b/KInspector.Modules/Modules/SocialMarketing/ExpiredTokensModule.cs @@ -17,7 +17,8 @@ public ModuleMetadata GetModuleMetadata() new Version("8.0"), new Version("8.1"), new Version("8.2"), - new Version("9.0") + new Version("9.0"), + new Version("10.0") }, }; } diff --git a/KInspector.Modules/Scripts/BigTablesModule.sql b/KInspector.Modules/Scripts/BigTablesModule.sql index b31d7808..9de3e42e 100644 --- a/KInspector.Modules/Scripts/BigTablesModule.sql +++ b/KInspector.Modules/Scripts/BigTablesModule.sql @@ -6,4 +6,4 @@ FROM sys.dm_db_partition_stats s, sys.objects o WHERE o.object_id = s.object_id GROUP BY o.Name -ORDER BY 'Rows' DESC \ No newline at end of file +ORDER BY 'Size [MB]' DESC \ No newline at end of file diff --git a/KInspector.Modules/Scripts/DebugCheckModule.sql b/KInspector.Modules/Scripts/DebugCheckModule.sql new file mode 100644 index 00000000..d8e5c3e5 --- /dev/null +++ b/KInspector.Modules/Scripts/DebugCheckModule.sql @@ -0,0 +1,11 @@ +SELECT KeyName AS 'Key',KeyValue AS 'Value' +FROM CMS_SettingsKey +WHERE KeyName = 'CMSDisableDebug' OR + ( + KeyName LIKE 'CMSDebug%' and + KeyType = 'boolean' and + KeyName not like '%live%' and + KeyName not like '%stack%' and + KeyName != 'CMSDebugMacrosDetailed' and + KeyName not like '%all%' + ) \ No newline at end of file diff --git a/KInspector.Modules/Scripts/DisabledWebPartAnalyzerModule.sql b/KInspector.Modules/Scripts/DisabledWebPartAnalyzerModule.sql new file mode 100644 index 00000000..415c34d4 --- /dev/null +++ b/KInspector.Modules/Scripts/DisabledWebPartAnalyzerModule.sql @@ -0,0 +1,3 @@ +SELECT PageTemplateDisplayName, PageTemplateCodeName +FROM CMS_PageTemplate +WHERE PageTemplateWebParts LIKE '%False%' \ No newline at end of file diff --git a/KInspector.Modules/Scripts/GetLibraryAndAttachmentFiles.sql b/KInspector.Modules/Scripts/GetLibraryAndAttachmentFiles.sql index 5f747ef5..7f02a5bd 100644 --- a/KInspector.Modules/Scripts/GetLibraryAndAttachmentFiles.sql +++ b/KInspector.Modules/Scripts/GetLibraryAndAttachmentFiles.sql @@ -56,6 +56,6 @@ select @sql = @sql + 'Select [' + columnname + '] as AttachmentGUID, ' + siteID --remove the trailing 'union' -Select @sql = substring(@sql, 1, len(@sql) - 6) +Select @sql = CASE WHEN len(@sql) - 6 >= 0 THEN substring(@sql, 1, len(@sql) - 6) ELSE 'Select top 0 newid() as AttachmentGUID, 0 as SiteID, '''' as TableName' END exec (@sql) \ No newline at end of file diff --git a/KInspector.Modules/Scripts/Setup/GlobalAdminSetupModule-V10.sql b/KInspector.Modules/Scripts/Setup/GlobalAdminSetupModule-V10.sql new file mode 100644 index 00000000..0781da64 --- /dev/null +++ b/KInspector.Modules/Scripts/Setup/GlobalAdminSetupModule-V10.sql @@ -0,0 +1,8 @@ +--clear the password for the admin account +UPDATE CMS_User + SET UserName = 'administrator', UserPrivilegeLevel = 3, UserPassword = '', UserEnabled = 1 + WHERE UserID = 53 + +UPDATE CMS_UserSettings + SET UserPasswordLastChanged = GETDATE() + WHERE UserSettingsUserID = 53 \ No newline at end of file diff --git a/KInspector.Modules/Scripts/SiteTemplatesModule-Templates.sql b/KInspector.Modules/Scripts/SiteTemplatesModule-Templates.sql index d76172a1..3ae27b86 100644 --- a/KInspector.Modules/Scripts/SiteTemplatesModule-Templates.sql +++ b/KInspector.Modules/Scripts/SiteTemplatesModule-Templates.sql @@ -1,4 +1,4 @@ -SELECT PageTemplateID, PageTemplateCodeName, PageTemplateWebParts +SELECT PageTemplateID, PageTemplateDisplayName, PageTemplateCodeName, PageTemplateWebParts FROM [CMS_PageTemplate] WHERE PageTemplateID IN ( SELECT DISTINCT DocumentPageTemplateID diff --git a/KInspector.Modules/Scripts/TaskProcessingIssueModule.sql b/KInspector.Modules/Scripts/TaskProcessingIssueModule.sql new file mode 100644 index 00000000..c2e6cf2d --- /dev/null +++ b/KInspector.Modules/Scripts/TaskProcessingIssueModule.sql @@ -0,0 +1,6 @@ +SELECT + (SELECT count(*) FROM [CMS_ScheduledTask] WHERE [TaskDeleteAfterLastRun] = 1 AND [TaskNextRunTime] < DATEADD(hour, -24, GETDATE())) AS SystemTasks, + (SELECT count(*) FROM [CMS_WebFarmTask] WHERE TaskCreated < DATEADD(hour, -24, GETDATE())) AS WebFarmTasks, + (SELECT count(*) FROM [Integration_Task] WHERE TaskTime < DATEADD(hour, -24, GETDATE())) AS IntegrationTasks, + (SELECT count(*) FROM [Staging_Task] WHERE TaskTime < DATEADD(hour, -24, GETDATE())) AS StagingTasks, + (SELECT count(*) FROM [CMS_SearchTask] WHERE SearchTaskCreated < DATEADD(hour, -24, GETDATE())) AS SearchTasks \ No newline at end of file diff --git a/KInspector.Modules/Scripts/TransformationAnalyzerModule-GetDataWhereIn-KI_ClassNames.sql b/KInspector.Modules/Scripts/TransformationAnalyzerModule-GetDataWhereIn-KI_ClassNames.sql new file mode 100644 index 00000000..0491ac1a --- /dev/null +++ b/KInspector.Modules/Scripts/TransformationAnalyzerModule-GetDataWhereIn-KI_ClassNames.sql @@ -0,0 +1,5 @@ +SELECT ClassID, ClassName + FROM CMS_Class + WHERE ClassName IN (SELECT * FROM @TableValueParameter) + +DROP TYPE [dbo].[KI_ClassNames] \ No newline at end of file diff --git a/KInspector.Modules/Scripts/TransformationAnalyzerModule-GetDataWhereIn-KI_TransformationList.sql b/KInspector.Modules/Scripts/TransformationAnalyzerModule-GetDataWhereIn-KI_TransformationList.sql new file mode 100644 index 00000000..72318500 --- /dev/null +++ b/KInspector.Modules/Scripts/TransformationAnalyzerModule-GetDataWhereIn-KI_TransformationList.sql @@ -0,0 +1,7 @@ +SELECT ct.TransformationID, ct.TransformationClassID, ct.TransformationName, ct.TransformationCode + FROM CMS_Transformation ct + INNER JOIN @TableValueParameter tvp + ON tvp.TransformationClassID = ct.TransformationClassID + AND tvp.TransformationName = ct.TransformationName + +DROP TYPE [dbo].[KI_TransformationList] \ No newline at end of file diff --git a/KInspector.Modules/Scripts/TransformationAnalyzerModule-Initialize-KI_ClassNames.sql b/KInspector.Modules/Scripts/TransformationAnalyzerModule-Initialize-KI_ClassNames.sql new file mode 100644 index 00000000..243fa26f --- /dev/null +++ b/KInspector.Modules/Scripts/TransformationAnalyzerModule-Initialize-KI_ClassNames.sql @@ -0,0 +1,4 @@ +IF NOT EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name ='KI_ClassNames') + CREATE TYPE dbo.KI_ClassNames AS TABLE( + ClassName VARCHAR(MAX) + ) \ No newline at end of file diff --git a/KInspector.Modules/Scripts/TransformationAnalyzerModule-Initialize-KI_TransformationList.sql b/KInspector.Modules/Scripts/TransformationAnalyzerModule-Initialize-KI_TransformationList.sql new file mode 100644 index 00000000..c21aaeb3 --- /dev/null +++ b/KInspector.Modules/Scripts/TransformationAnalyzerModule-Initialize-KI_TransformationList.sql @@ -0,0 +1,5 @@ +IF NOT EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name ='KI_TransformationList') + CREATE TYPE dbo.KI_TransformationList AS TABLE( + TransformationName VARCHAR(MAX), + TransformationClassID VARCHAR(MAX) + ) \ No newline at end of file diff --git a/KInspector.Modules/Scripts/TransformationAnalyzerModule-PageTemplateWebParts.sql b/KInspector.Modules/Scripts/TransformationAnalyzerModule-PageTemplateWebParts.sql index 1fb7046f..40ef4de9 100644 --- a/KInspector.Modules/Scripts/TransformationAnalyzerModule-PageTemplateWebParts.sql +++ b/KInspector.Modules/Scripts/TransformationAnalyzerModule-PageTemplateWebParts.sql @@ -1,3 +1,3 @@ SELECT PageTemplateWebParts -FROM CMS_PageTemplate -WHERE PageTemplateDisplayName LIKE @PageTemplateDisplayName \ No newline at end of file + FROM CMS_PageTemplate + WHERE PageTemplateDisplayName LIKE @PageTemplateDisplayName \ No newline at end of file diff --git a/KInspector.Modules/Scripts/TransformationAnalyzerModule-TransformationCodes.sql b/KInspector.Modules/Scripts/TransformationAnalyzerModule-TransformationCodes.sql deleted file mode 100644 index 55c8b6f9..00000000 --- a/KInspector.Modules/Scripts/TransformationAnalyzerModule-TransformationCodes.sql +++ /dev/null @@ -1,3 +0,0 @@ -SELECT TransformationID, TransformationName, TransformationCode -FROM CMS_Transformation -WHERE TransformationName IN (@ListOfNames) \ No newline at end of file diff --git a/KInspector.Modules/Scripts/UnusedPageTypesModule.sql b/KInspector.Modules/Scripts/UnusedPageTypesModule.sql new file mode 100644 index 00000000..0a92766a --- /dev/null +++ b/KInspector.Modules/Scripts/UnusedPageTypesModule.sql @@ -0,0 +1,5 @@ +SELECT ClassDisplayName, ClassName + FROM CMS_Class + WHERE + ClassIsDocumentType = 1 AND + ClassID not in (SELECT DISTINCT NodeClassID FROM View_CMS_Tree_Joined) \ No newline at end of file diff --git a/KInspector.Modules/Scripts/UnusedTemplatesModule.sql b/KInspector.Modules/Scripts/UnusedTemplatesModule.sql new file mode 100644 index 00000000..2655939b --- /dev/null +++ b/KInspector.Modules/Scripts/UnusedTemplatesModule.sql @@ -0,0 +1,5 @@ +SELECT PageTemplateDisplayName,PageTemplateCodeName, PageTemplateType, PageTemplateDescription + FROM CMS_PageTemplate + WHERE PageTemplateID not in (SELECT DISTINCT NodeTemplateID FROM View_CMS_Tree_Joined WHERE NodeTemplateID is not NULL) + AND PageTemplateType not in ('dashboard','ui') + ORDER BY PageTemplateDisplayName \ No newline at end of file diff --git a/KInspector.Tests/Modules/Security/PasswordPolicyModuleTests.cs b/KInspector.Tests/Modules/Security/PasswordPolicyModuleTests.cs index 99117df5..d8ae98b1 100644 --- a/KInspector.Tests/Modules/Security/PasswordPolicyModuleTests.cs +++ b/KInspector.Tests/Modules/Security/PasswordPolicyModuleTests.cs @@ -29,7 +29,7 @@ public void Should_BeInSecurityCategory_When_ReturningModuleMetadata() public void Should_HaveCorrectSupportedVersions_When_ReturningModuleMetadata() { // arrange... - List expectedVersions = new List { new Version("7.0"), new Version("8.0"), new Version("8.1"), new Version("8.2"), new Version("9.0") }; + List expectedVersions = new List { new Version("7.0"), new Version("8.0"), new Version("8.1"), new Version("8.2"), new Version("9.0"), new Version("10.0") }; PasswordPolicyModule mod = new PasswordPolicyModule(); // act... diff --git a/README.md b/README.md index 7a485651..ad5afa52 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Join the chat at https://gitter.im/Kentico/KInspector](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Kentico/KInspector?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build status](https://ci.appveyor.com/api/projects/status/udykjx510v83w9y6?svg=true)](https://ci.appveyor.com/project/kentico/kinspector) [![first-timers-only](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](http://www.firsttimersonly.com/) +[![Github All Releases](https://img.shields.io/github/downloads/kentico/kinspector/total.svg)](https://github.com/Kentico/KInspector/releases) KInspector is an application for analyzing health, performance and security of your **Kentico** solution.