diff --git a/LICENSE.md b/LICENSE.md index fa83dba963..b8bda9d7a3 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # The MIT License (MIT) # -Copyright (c) 2013-present Umbraco +Copyright (c) 2005-present Umbraco Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/build/templates/UmbracoPackage/.template.config/template.json b/build/templates/UmbracoPackage/.template.config/template.json index 3758621968..b650e59a49 100644 --- a/build/templates/UmbracoPackage/.template.config/template.json +++ b/build/templates/UmbracoPackage/.template.config/template.json @@ -24,7 +24,7 @@ "version": { "type": "parameter", "datatype": "string", - "defaultValue": "9.0.0-rc003", + "defaultValue": "9.0.0-rc004", "description": "The version of Umbraco to load using NuGet", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, diff --git a/build/templates/UmbracoProject/.template.config/dotnetcli.host.json b/build/templates/UmbracoProject/.template.config/dotnetcli.host.json index d0548110fd..d357188ed7 100644 --- a/build/templates/UmbracoProject/.template.config/dotnetcli.host.json +++ b/build/templates/UmbracoProject/.template.config/dotnetcli.host.json @@ -32,6 +32,10 @@ "NoNodesViewPath":{ "longName": "no-nodes-view-path", "shortName": "" + }, + "UseHttpsRedirect": { + "longName": "use-https-redirect", + "shortName": "" } }, "usageExamples": [ diff --git a/build/templates/UmbracoProject/.template.config/ide.host.json b/build/templates/UmbracoProject/.template.config/ide.host.json index 8b8d2608cd..1ee7a492aa 100644 --- a/build/templates/UmbracoProject/.template.config/ide.host.json +++ b/build/templates/UmbracoProject/.template.config/ide.host.json @@ -62,6 +62,13 @@ "text": "Optional: Path to a custom view presented with the Umbraco installation contains no published content" }, "isVisible": "true" + }, + { + "id": "UseHttpsRedirect", + "name": { + "text": "Optional: Adds code to Startup.cs to redirect HTTP to HTTPS and enables the UseHttps setting." + }, + "isVisible": "true" } ] } diff --git a/build/templates/UmbracoProject/.template.config/template.json b/build/templates/UmbracoProject/.template.config/template.json index 3d4f197164..8a07e29d2e 100644 --- a/build/templates/UmbracoProject/.template.config/template.json +++ b/build/templates/UmbracoProject/.template.config/template.json @@ -57,7 +57,7 @@ "version": { "type": "parameter", "datatype": "string", - "defaultValue": "9.0.0-rc003", + "defaultValue": "9.0.0-rc004", "description": "The version of Umbraco to load using NuGet", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, @@ -293,6 +293,12 @@ "UsingUnattenedInstall":{ "type": "computed", "value": "(FriendlyName != \"\" && Email != \"\" && Password != \"\" && ConnectionString != \"\")" + }, + "UseHttpsRedirect":{ + "type": "parameter", + "datatype":"bool", + "defaultValue": "false", + "description": "Adds code to Startup.cs to redirect HTTP to HTTPS and enables the UseHttps setting (Default: false)" } } } diff --git a/build/templates/UmbracoProject/appsettings.json b/build/templates/UmbracoProject/appsettings.json index 915671ce4b..feb6b07d95 100644 --- a/build/templates/UmbracoProject/appsettings.json +++ b/build/templates/UmbracoProject/appsettings.json @@ -15,9 +15,16 @@ }, "Umbraco": { "CMS": { - //#if (HasNoNodesViewPath) + //#if (HasNoNodesViewPath || UseHttpsRedirect) "Global": { + //#if (!HasNoNodesViewPath && UseHttpsRedirect) + "UseHttps": true + //#elseif (UseHttpsRedirect) + "UseHttps": true, + //#endif + //#if (HasNoNodesViewPath) "NoNodesViewPath": "NO_NODES_VIEW_PATH_FROM_TEMPLATE" + //#endif }, //#endif "Hosting": { diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 6f5eb39964..6445e6ea5f 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,7 +2,7 @@ 9.0.0 9.0.0 - 9.0.0-rc003 + 9.0.0-rc004 9.0.0 9.0 en-US diff --git a/src/Umbraco.Core/Configuration/ConfigConnectionString.cs b/src/Umbraco.Core/Configuration/ConfigConnectionString.cs index e88d1f4d01..116b96df9c 100644 --- a/src/Umbraco.Core/Configuration/ConfigConnectionString.cs +++ b/src/Umbraco.Core/Configuration/ConfigConnectionString.cs @@ -5,69 +5,88 @@ namespace Umbraco.Cms.Core.Configuration { public class ConfigConnectionString { + public string Name { get; } + + public string ConnectionString { get; } + + public string ProviderName { get; } + public ConfigConnectionString(string name, string connectionString, string providerName = null) { Name = name ?? throw new ArgumentNullException(nameof(name)); - ConnectionString = connectionString; - - ProviderName = string.IsNullOrEmpty(providerName) ? ParseProvider(connectionString) : providerName; + ConnectionString = ParseConnectionString(connectionString, ref providerName); + ProviderName = providerName; } - public string ConnectionString { get; } - public string ProviderName { get; } - public string Name { get; } - - private static bool IsSqlCe(DbConnectionStringBuilder builder) => (builder.TryGetValue("Data Source", out var ds) - || builder.TryGetValue("DataSource", out ds)) && - ds is string dataSource && - dataSource.EndsWith(".sdf"); - - private static bool IsSqlServer(DbConnectionStringBuilder builder) => - !string.IsNullOrEmpty(GetServer(builder)) && - ((builder.TryGetValue("Database", out var db) && db is string database && - !string.IsNullOrEmpty(database)) || - (builder.TryGetValue("AttachDbFileName", out var a) && a is string attachDbFileName && - !string.IsNullOrEmpty(attachDbFileName)) || - (builder.TryGetValue("Initial Catalog", out var i) && i is string initialCatalog && - !string.IsNullOrEmpty(initialCatalog))); - - private static string GetServer(DbConnectionStringBuilder builder) + private static string ParseConnectionString(string connectionString, ref string providerName) { - if(builder.TryGetValue("Server", out var s) && s is string server) + if (string.IsNullOrEmpty(connectionString)) { - return server; + return connectionString; } - if ((builder.TryGetValue("Data Source", out var ds) - || builder.TryGetValue("DataSource", out ds)) && ds is string dataSource) + var builder = new DbConnectionStringBuilder { - return dataSource; + ConnectionString = connectionString + }; + + // Replace data directory placeholder + const string attachDbFileNameKey = "AttachDbFileName"; + const string dataDirectoryPlaceholder = "|DataDirectory|"; + if (builder.TryGetValue(attachDbFileNameKey, out var attachDbFileNameValue) && + attachDbFileNameValue is string attachDbFileName && + attachDbFileName.Contains(dataDirectoryPlaceholder)) + { + var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString(); + if (!string.IsNullOrEmpty(dataDirectory)) + { + builder[attachDbFileNameKey] = attachDbFileName.Replace(dataDirectoryPlaceholder, dataDirectory); + + // Mutate the existing connection string (note: the builder also lowercases the properties) + connectionString = builder.ToString(); + } } - return ""; + // Also parse provider name now we already have a builder + if (string.IsNullOrEmpty(providerName)) + { + providerName = ParseProviderName(builder); + } + + return connectionString; } - private static string ParseProvider(string connectionString) + /// + /// Parses the connection string to get the provider name. + /// + /// The connection string. + /// + /// The provider name or null is the connection string is empty. + /// + public static string ParseProviderName(string connectionString) { if (string.IsNullOrEmpty(connectionString)) { return null; } - var builder = new DbConnectionStringBuilder {ConnectionString = connectionString}; - if (IsSqlCe(builder)) + var builder = new DbConnectionStringBuilder + { + ConnectionString = connectionString + }; + + return ParseProviderName(builder); + } + + private static string ParseProviderName(DbConnectionStringBuilder builder) + { + if ((builder.TryGetValue("Data Source", out var dataSource) || builder.TryGetValue("DataSource", out dataSource)) && + dataSource?.ToString().EndsWith(".sdf", StringComparison.OrdinalIgnoreCase) == true) { return Constants.DbProviderNames.SqlCe; } - - if (IsSqlServer(builder)) - { - return Constants.DbProviderNames.SqlServer; - } - - throw new ArgumentException("Cannot determine provider name from connection string", - nameof(connectionString)); + return Constants.DbProviderNames.SqlServer; } } } diff --git a/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs b/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs index bfcb41d992..c0421be7e3 100644 --- a/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs +++ b/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs @@ -26,6 +26,6 @@ namespace Umbraco.Cms.Core.Configuration.Models /// /// Gets or sets a value for the Umbraco database connection string.. /// - public ConfigConnectionString UmbracoConnectionString { get; set; } + public ConfigConnectionString UmbracoConnectionString { get; set; } = new ConfigConnectionString(Constants.System.UmbracoConnectionName, null); } } diff --git a/src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs b/src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs index 64625f153b..ef67d40102 100644 --- a/src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Core.Configuration.Models public int? MaxQueryStringLength { get; set; } /// - /// Gets or sets a value for the maximum request length. + /// Gets or sets a value for the maximum request length in kb. /// public int? MaxRequestLength { get; set; } } diff --git a/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs b/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs index 57c69ee9aa..9b3674b07b 100644 --- a/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs +++ b/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Security.Claims; using System.Security.Principal; @@ -267,7 +268,7 @@ namespace Umbraco.Extensions /// Array of start content nodes public static int[] GetStartContentNodes(this ClaimsIdentity identity) => identity.FindAll(x => x.Type == Constants.Security.StartContentNodeIdClaimType) - .Select(node => int.TryParse(node.Value, out var i) ? i : default) + .Select(node => int.TryParse(node.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? i : default) .Where(x => x != default).ToArray(); /// @@ -277,7 +278,7 @@ namespace Umbraco.Extensions /// Array of start media nodes public static int[] GetStartMediaNodes(this ClaimsIdentity identity) => identity.FindAll(x => x.Type == Constants.Security.StartMediaNodeIdClaimType) - .Select(node => int.TryParse(node.Value, out var i) ? i : default) + .Select(node => int.TryParse(node.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? i : default) .Where(x => x != default).ToArray(); /// @@ -293,7 +294,7 @@ namespace Umbraco.Extensions /// /// /// User ID as integer - public static int GetId(this ClaimsIdentity identity) => int.Parse(identity.FindFirstValue(ClaimTypes.NameIdentifier)); + public static int GetId(this ClaimsIdentity identity) => int.Parse(identity.FindFirstValue(ClaimTypes.NameIdentifier), CultureInfo.InvariantCulture); /// /// Get the real name belonging to the user from a ClaimsIdentity diff --git a/src/Umbraco.Core/Extensions/ConfigConnectionStringExtensions.cs b/src/Umbraco.Core/Extensions/ConfigConnectionStringExtensions.cs index c1b788c0b9..329c9e8202 100644 --- a/src/Umbraco.Core/Extensions/ConfigConnectionStringExtensions.cs +++ b/src/Umbraco.Core/Extensions/ConfigConnectionStringExtensions.cs @@ -1,10 +1,6 @@ // Copyright (c) Umbraco. // See LICENSE for more details. -using System; -using System.IO; -using System.Linq; -using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; namespace Umbraco.Extensions @@ -12,35 +8,8 @@ namespace Umbraco.Extensions public static class ConfigConnectionStringExtensions { public static bool IsConnectionStringConfigured(this ConfigConnectionString databaseSettings) - { - var dbIsSqlCe = false; - if (databaseSettings?.ProviderName != null) - { - dbIsSqlCe = databaseSettings.ProviderName == Constants.DbProviderNames.SqlCe; - } - - var sqlCeDatabaseExists = false; - if (dbIsSqlCe) - { - var parts = databaseSettings.ConnectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - var dataSourcePart = parts.FirstOrDefault(x => x.InvariantStartsWith("Data Source=")); - if (dataSourcePart != null) - { - var datasource = dataSourcePart.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory").ToString()); - var filePath = datasource.Replace("Data Source=", string.Empty); - sqlCeDatabaseExists = File.Exists(filePath); - } - } - - // Either the connection details are not fully specified or it's a SQL CE database that doesn't exist yet - if (databaseSettings == null - || string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) || string.IsNullOrWhiteSpace(databaseSettings.ProviderName) - || (dbIsSqlCe && sqlCeDatabaseExists == false)) - { - return false; - } - - return true; - } + => databaseSettings != null && + !string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) && + !string.IsNullOrWhiteSpace(databaseSettings.ProviderName); } } diff --git a/src/Umbraco.Core/Extensions/ObjectExtensions.cs b/src/Umbraco.Core/Extensions/ObjectExtensions.cs index db2d63b643..d666046e4b 100644 --- a/src/Umbraco.Core/Extensions/ObjectExtensions.cs +++ b/src/Umbraco.Core/Extensions/ObjectExtensions.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -94,8 +95,8 @@ namespace Umbraco.Extensions { // sure, null can be any object return Attempt.Succeed((T)input); - } - } + } + } // just try to cast try @@ -293,7 +294,7 @@ namespace Umbraco.Extensions { if (target == typeof(int)) { - if (int.TryParse(input, out var value)) + if (int.TryParse(input, out var value)) { return Attempt.Succeed(value); } @@ -301,7 +302,7 @@ namespace Umbraco.Extensions // Because decimal 100.01m will happily convert to integer 100, it // makes sense that string "100.01" *also* converts to integer 100. var input2 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2)); + return Attempt.If(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2)); } if (target == typeof(long)) @@ -320,7 +321,7 @@ namespace Umbraco.Extensions if (target == typeof(bool)) { - if (bool.TryParse(input, out var value)) + if (bool.TryParse(input, out var value)) { return Attempt.Succeed(value); } @@ -337,11 +338,11 @@ namespace Umbraco.Extensions case TypeCode.Double: var input2 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(double.TryParse(input2, out var valueD), valueD); + return Attempt.If(double.TryParse(input2, out var valueD), valueD); case TypeCode.Single: var input3 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(float.TryParse(input3, out var valueF), valueF); + return Attempt.If(float.TryParse(input3, out var valueF), valueF); case TypeCode.Char: return Attempt.If(char.TryParse(input, out var valueC), valueC); @@ -353,13 +354,13 @@ namespace Umbraco.Extensions return Attempt.If(sbyte.TryParse(input, out var valueSb), valueSb); case TypeCode.UInt32: - return Attempt.If(uint.TryParse(input, out var valueU), valueU); + return Attempt.If(uint.TryParse(input, out var valueU), valueU); case TypeCode.UInt16: - return Attempt.If(ushort.TryParse(input, out var valueUs), valueUs); + return Attempt.If(ushort.TryParse(input, out var valueUs), valueUs); case TypeCode.UInt64: - return Attempt.If(ulong.TryParse(input, out var valueUl), valueUl); + return Attempt.If(ulong.TryParse(input, out var valueUl), valueUl); } } else if (target == typeof(Guid)) diff --git a/src/Umbraco.Core/Extensions/VersionExtensions.cs b/src/Umbraco.Core/Extensions/VersionExtensions.cs index 06451ce8a0..24326ef327 100644 --- a/src/Umbraco.Core/Extensions/VersionExtensions.cs +++ b/src/Umbraco.Core/Extensions/VersionExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using Umbraco.Cms.Core.Semver; namespace Umbraco.Extensions @@ -12,7 +13,7 @@ namespace Umbraco.Extensions public static Version GetVersion(this SemVersion semVersion, int maxParts = 4) { int build = 0; - int.TryParse(semVersion.Build, out build); + int.TryParse(semVersion.Build, NumberStyles.Integer, CultureInfo.InvariantCulture, out build); if (maxParts >= 4) { diff --git a/src/Umbraco.Core/HealthChecks/Checks/Security/HttpsCheck.cs b/src/Umbraco.Core/HealthChecks/Checks/Security/HttpsCheck.cs index 2e3ef9f5c8..02c726c0c7 100644 --- a/src/Umbraco.Core/HealthChecks/Checks/Security/HttpsCheck.cs +++ b/src/Umbraco.Core/HealthChecks/Checks/Security/HttpsCheck.cs @@ -1,4 +1,4 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. using System; @@ -17,7 +17,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Core.HealthChecks.Checks.Security { /// - /// Health checks for the recommended production setup regarding https. + /// Health checks for the recommended production setup regarding HTTPS. /// [HealthCheck( "EB66BB3B-1BCD-4314-9531-9DA2C1D6D9A7", @@ -26,17 +26,26 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security Group = "Security")] public class HttpsCheck : HealthCheck { + private const int NumberOfDaysForExpiryWarning = 14; + private const string HttpPropertyKeyCertificateDaysToExpiry = "CertificateDaysToExpiry"; + private readonly ILocalizedTextService _textService; private readonly IOptionsMonitor _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private static HttpClient s_httpClient; - private static HttpClientHandler s_httpClientHandler; - private static int s_certificateDaysToExpiry; + + private static HttpClient HttpClient => s_httpClient ??= new HttpClient(new HttpClientHandler() + { + ServerCertificateCustomValidationCallback = ServerCertificateCustomValidation + }); /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// + /// The text service. + /// The global settings. + /// The hosting environment. public HttpsCheck( ILocalizedTextService textService, IOptionsMonitor globalSettings, @@ -47,33 +56,22 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security _hostingEnvironment = hostingEnvironment; } - private static HttpClient HttpClient => s_httpClient ??= new HttpClient(HttpClientHandler); - - private static HttpClientHandler HttpClientHandler => s_httpClientHandler ??= new HttpClientHandler() - { - ServerCertificateCustomValidationCallback = ServerCertificateCustomValidation - }; - - /// - /// Get the status for this health check - /// + /// public override async Task> GetStatus() => await Task.WhenAll( CheckIfCurrentSchemeIsHttps(), CheckHttpsConfigurationSetting(), CheckForValidCertificate()); - /// - /// Executes the action and returns it's status - /// + /// public override HealthCheckStatus ExecuteAction(HealthCheckAction action) => throw new InvalidOperationException("HttpsCheck action requested is either not executable or does not exist"); private static bool ServerCertificateCustomValidation(HttpRequestMessage requestMessage, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslErrors) { - if (!(certificate is null) && s_certificateDaysToExpiry == default) + if (certificate is not null) { - s_certificateDaysToExpiry = (int)Math.Floor((certificate.NotAfter - DateTime.Now).TotalDays); + requestMessage.Properties[HttpPropertyKeyCertificateDaysToExpiry] = (int)Math.Floor((certificate.NotAfter - DateTime.Now).TotalDays); } return sslErrors == SslPolicyErrors.None; @@ -84,30 +82,37 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security string message; StatusResultType result; - // Attempt to access the site over HTTPS to see if it HTTPS is supported - // and a valid certificate has been configured - var url = _hostingEnvironment.ApplicationMainUrl.ToString().Replace("http:", "https:"); + // Attempt to access the site over HTTPS to see if it HTTPS is supported and a valid certificate has been configured + var urlBuilder = new UriBuilder(_hostingEnvironment.ApplicationMainUrl) + { + Scheme = Uri.UriSchemeHttps + }; + var url = urlBuilder.Uri; var request = new HttpRequestMessage(HttpMethod.Head, url); try { using HttpResponseMessage response = await HttpClient.SendAsync(request); + if (response.StatusCode == HttpStatusCode.OK) { - // Got a valid response, check now for if certificate expiring within 14 days - // Hat-tip: https://stackoverflow.com/a/15343898/489433 - const int numberOfDaysForExpiryWarning = 14; + // Got a valid response, check now if the certificate is expiring within the specified amount of days + int daysToExpiry = 0; + if (request.Properties.TryGetValue(HttpPropertyKeyCertificateDaysToExpiry, out var certificateDaysToExpiry)) + { + daysToExpiry = (int)certificateDaysToExpiry; + } - if (s_certificateDaysToExpiry <= 0) + if (daysToExpiry <= 0) { result = StatusResultType.Error; message = _textService.Localize("healthcheck","httpsCheckExpiredCertificate"); } - else if (s_certificateDaysToExpiry < numberOfDaysForExpiryWarning) + else if (daysToExpiry < NumberOfDaysForExpiryWarning) { result = StatusResultType.Warning; - message = _textService.Localize("healthcheck","httpsCheckExpiringCertificate", new[] { s_certificateDaysToExpiry.ToString() }); + message = _textService.Localize("healthcheck","httpsCheckExpiringCertificate", new[] { daysToExpiry.ToString() }); } else { @@ -118,21 +123,20 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security else { result = StatusResultType.Error; - message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url, response.ReasonPhrase }); + message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url.AbsoluteUri, response.ReasonPhrase }); } } catch (Exception ex) { - var exception = ex as WebException; - if (exception != null) + if (ex is WebException exception) { message = exception.Status == WebExceptionStatus.TrustFailure - ? _textService.Localize("healthcheck","httpsCheckInvalidCertificate", new[] { exception.Message }) - : _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url, exception.Message }); + ? _textService.Localize("healthcheck", "httpsCheckInvalidCertificate", new[] { exception.Message }) + : _textService.Localize("healthcheck", "healthCheckInvalidUrl", new[] { url.AbsoluteUri, exception.Message }); } else { - message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url, ex.Message }); + message = _textService.Localize("healthcheck", "healthCheckInvalidUrl", new[] { url.AbsoluteUri, ex.Message }); } result = StatusResultType.Error; @@ -150,7 +154,7 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security private Task CheckIfCurrentSchemeIsHttps() { Uri uri = _hostingEnvironment.ApplicationMainUrl; - var success = uri.Scheme == "https"; + var success = uri.Scheme == Uri.UriSchemeHttps; return Task.FromResult(new HealthCheckStatus(_textService.Localize("healthcheck","httpsCheckIsCurrentSchemeHttps", new[] { success ? string.Empty : "not" })) { @@ -166,16 +170,14 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security string resultMessage; StatusResultType resultType; - if (uri.Scheme != "https") + if (uri.Scheme != Uri.UriSchemeHttps) { resultMessage = _textService.Localize("healthcheck","httpsCheckConfigurationRectifyNotPossible"); resultType = StatusResultType.Info; } else { - resultMessage = _textService.Localize( - "healthcheck","httpsCheckConfigurationCheckResult", - new[] { httpsSettingEnabled.ToString(), httpsSettingEnabled ? string.Empty : "not" }); + resultMessage = _textService.Localize("healthcheck","httpsCheckConfigurationCheckResult", new[] { httpsSettingEnabled.ToString(), httpsSettingEnabled ? string.Empty : "not" }); resultType = httpsSettingEnabled ? StatusResultType.Success : StatusResultType.Error; } diff --git a/src/Umbraco.Core/Install/Models/DatabaseModel.cs b/src/Umbraco.Core/Install/Models/DatabaseModel.cs index c7f4ce0aab..b87941e590 100644 --- a/src/Umbraco.Core/Install/Models/DatabaseModel.cs +++ b/src/Umbraco.Core/Install/Models/DatabaseModel.cs @@ -1,18 +1,12 @@ -using System.Runtime.Serialization; +using System.Runtime.Serialization; namespace Umbraco.Cms.Core.Install.Models { [DataContract(Name = "database", Namespace = "")] public class DatabaseModel { - public DatabaseModel() - { - //defaults - DatabaseType = DatabaseType.SqlCe; - } - [DataMember(Name = "dbType")] - public DatabaseType DatabaseType { get; set; } + public DatabaseType DatabaseType { get; set; } = DatabaseType.SqlServer; [DataMember(Name = "server")] public string Server { get; set; } diff --git a/src/Umbraco.Core/Install/Models/DatabaseType.cs b/src/Umbraco.Core/Install/Models/DatabaseType.cs index 5eef471562..bc0616620f 100644 --- a/src/Umbraco.Core/Install/Models/DatabaseType.cs +++ b/src/Umbraco.Core/Install/Models/DatabaseType.cs @@ -1,7 +1,8 @@ -namespace Umbraco.Cms.Core.Install.Models +namespace Umbraco.Cms.Core.Install.Models { public enum DatabaseType { + SqlLocalDb, SqlCe, SqlServer, SqlAzure, diff --git a/src/Umbraco.Core/Media/Exif/ExifBitConverter.cs b/src/Umbraco.Core/Media/Exif/ExifBitConverter.cs index 900c9b1b43..74465a6684 100644 --- a/src/Umbraco.Core/Media/Exif/ExifBitConverter.cs +++ b/src/Umbraco.Core/Media/Exif/ExifBitConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Text; namespace Umbraco.Cms.Core.Media.Exif @@ -65,12 +66,12 @@ namespace Umbraco.Cms.Core.Media.Exif // yyyy:MM:dd HH:mm:ss // This is the expected format though some cameras // can use single digits. See Issue 21. - return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]), int.Parse(parts[4]), int.Parse(parts[5])); + return new DateTime(int.Parse(parts[0], CultureInfo.InvariantCulture), int.Parse(parts[1], CultureInfo.InvariantCulture), int.Parse(parts[2], CultureInfo.InvariantCulture), int.Parse(parts[3], CultureInfo.InvariantCulture), int.Parse(parts[4], CultureInfo.InvariantCulture), int.Parse(parts[5], CultureInfo.InvariantCulture)); } else if (!hastime && parts.Length == 3) { // yyyy:MM:dd - return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2])); + return new DateTime(int.Parse(parts[0], CultureInfo.InvariantCulture), int.Parse(parts[1], CultureInfo.InvariantCulture), int.Parse(parts[2], CultureInfo.InvariantCulture)); } else { diff --git a/src/Umbraco.Core/Media/Exif/MathEx.cs b/src/Umbraco.Core/Media/Exif/MathEx.cs index dfad9ae7de..5262aa18a8 100644 --- a/src/Umbraco.Core/Media/Exif/MathEx.cs +++ b/src/Umbraco.Core/Media/Exif/MathEx.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Text; namespace Umbraco.Cms.Core.Media.Exif @@ -701,7 +702,7 @@ namespace Umbraco.Cms.Core.Media.Exif if (sa.Length == 1) { // Try to parse as int - if (int.TryParse(sa[0], out numerator)) + if (int.TryParse(sa[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out numerator)) { denominator = 1; } @@ -714,8 +715,8 @@ namespace Umbraco.Cms.Core.Media.Exif } else if (sa.Length == 2) { - numerator = int.Parse(sa[0]); - denominator = int.Parse(sa[1]); + numerator = int.Parse(sa[0], CultureInfo.InvariantCulture); + denominator = int.Parse(sa[1], CultureInfo.InvariantCulture); } else throw new FormatException("The input string must be formatted as n/d where n and d are integers"); @@ -1329,7 +1330,7 @@ namespace Umbraco.Cms.Core.Media.Exif if (sa.Length == 1) { // Try to parse as uint - if (uint.TryParse(sa[0], out numerator)) + if (uint.TryParse(sa[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out numerator)) { denominator = 1; } @@ -1342,8 +1343,8 @@ namespace Umbraco.Cms.Core.Media.Exif } else if (sa.Length == 2) { - numerator = uint.Parse(sa[0]); - denominator = uint.Parse(sa[1]); + numerator = uint.Parse(sa[0], CultureInfo.InvariantCulture); + denominator = uint.Parse(sa[1], CultureInfo.InvariantCulture); } else throw new FormatException("The input string must be formatted as n/d where n and d are integers"); diff --git a/src/Umbraco.Core/Media/Exif/SvgFile.cs b/src/Umbraco.Core/Media/Exif/SvgFile.cs index 00516eecb8..b83aebe1fb 100644 --- a/src/Umbraco.Core/Media/Exif/SvgFile.cs +++ b/src/Umbraco.Core/Media/Exif/SvgFile.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Globalization; +using System.IO; using System.Linq; using System.Xml.Linq; @@ -16,9 +17,9 @@ namespace Umbraco.Cms.Core.Media.Exif var height = document.Root?.Attributes().Where(x => x.Name == "height").Select(x => x.Value).FirstOrDefault(); Properties.Add(new ExifSInt(ExifTag.PixelYDimension, - height == null ? Constants.Conventions.Media.DefaultSize : int.Parse(height))); + height == null ? Constants.Conventions.Media.DefaultSize : int.Parse(height, CultureInfo.InvariantCulture))); Properties.Add(new ExifSInt(ExifTag.PixelXDimension, - width == null ? Constants.Conventions.Media.DefaultSize : int.Parse(width))); + width == null ? Constants.Conventions.Media.DefaultSize : int.Parse(width, CultureInfo.InvariantCulture))); Format = ImageFileFormat.SVG; } diff --git a/src/Umbraco.Core/Models/IServerRegistration.cs b/src/Umbraco.Core/Models/IServerRegistration.cs index 4aba9b10c0..12319da6c8 100644 --- a/src/Umbraco.Core/Models/IServerRegistration.cs +++ b/src/Umbraco.Core/Models/IServerRegistration.cs @@ -1,4 +1,4 @@ -using System; +using System; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Sync; @@ -19,9 +19,9 @@ namespace Umbraco.Cms.Core.Models bool IsActive { get; set; } /// - /// Gets or sets a value indicating whether the server is master. + /// Gets or sets a value indicating whether the server is has the SchedulingPublisher role. /// - bool IsMaster { get; set; } + bool IsSchedulingPublisher { get; set; } /// /// Gets the date and time the registration was created. diff --git a/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs index 7449a6f778..d3269c2c0b 100644 --- a/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -601,7 +602,7 @@ namespace Umbraco.Cms.Core.Models.Mapping return Enumerable.Empty(); var aliases = new List(); - var ancestorIds = parent.Path.Split(Constants.CharArrays.Comma).Select(int.Parse); + var ancestorIds = parent.Path.Split(Constants.CharArrays.Comma).Select(s => int.Parse(s, CultureInfo.InvariantCulture)); // loop through all content types and return ordered aliases of ancestors var allContentTypes = _contentTypeService.GetAll().ToArray(); foreach (var ancestorId in ancestorIds) diff --git a/src/Umbraco.Core/Models/ServerRegistration.cs b/src/Umbraco.Core/Models/ServerRegistration.cs index 5aa926bdaa..dae691812b 100644 --- a/src/Umbraco.Core/Models/ServerRegistration.cs +++ b/src/Umbraco.Core/Models/ServerRegistration.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Extensions; @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Core.Models private string _serverAddress; private string _serverIdentity; private bool _isActive; - private bool _isMaster; + private bool _isSchedulingPublisher; /// /// Initializes a new instance of the class. @@ -31,7 +31,7 @@ namespace Umbraco.Cms.Core.Models /// The date and time the registration was last accessed. /// A value indicating whether the registration is active. /// A value indicating whether the registration is master. - public ServerRegistration(int id, string serverAddress, string serverIdentity, DateTime registered, DateTime accessed, bool isActive, bool isMaster) + public ServerRegistration(int id, string serverAddress, string serverIdentity, DateTime registered, DateTime accessed, bool isActive, bool isSchedulingPublisher) { UpdateDate = accessed; CreateDate = registered; @@ -40,7 +40,7 @@ namespace Umbraco.Cms.Core.Models ServerAddress = serverAddress; ServerIdentity = serverIdentity; IsActive = isActive; - IsMaster = isMaster; + IsSchedulingPublisher = isSchedulingPublisher; } /// @@ -86,12 +86,12 @@ namespace Umbraco.Cms.Core.Models } /// - /// Gets or sets a value indicating whether the server is master. + /// Gets or sets a value indicating whether the server has the SchedulingPublisher role /// - public bool IsMaster + public bool IsSchedulingPublisher { - get => _isMaster; - set => SetPropertyValueAndDetectChanges(value, ref _isMaster, nameof(IsMaster)); + get => _isSchedulingPublisher; + set => SetPropertyValueAndDetectChanges(value, ref _isSchedulingPublisher, nameof(IsSchedulingPublisher)); } /// @@ -118,7 +118,7 @@ namespace Umbraco.Cms.Core.Models /// public override string ToString() { - return string.Format("{{\"{0}\", \"{1}\", {2}active, {3}master}}", ServerAddress, ServerIdentity, IsActive ? "" : "!", IsMaster ? "" : "!"); + return string.Format("{{\"{0}\", \"{1}\", {2}active, {3}master}}", ServerAddress, ServerIdentity, IsActive ? "" : "!", IsSchedulingPublisher ? "" : "!"); } } } diff --git a/src/Umbraco.Core/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Packaging/InstallationSummary.cs index 005d5859fb..2aa74474d1 100644 --- a/src/Umbraco.Core/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Packaging/InstallationSummary.cs @@ -13,9 +13,9 @@ namespace Umbraco.Cms.Core.Packaging public class InstallationSummary { public InstallationSummary(string packageName) - { - PackageName = packageName; - } + => PackageName = packageName; + + public string PackageName { get; } public InstallWarnings Warnings { get; set; } = new InstallWarnings(); @@ -23,6 +23,7 @@ namespace Umbraco.Cms.Core.Packaging public IEnumerable LanguagesInstalled { get; set; } = Enumerable.Empty(); public IEnumerable DictionaryItemsInstalled { get; set; } = Enumerable.Empty(); public IEnumerable MacrosInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable MacroPartialViewsInstalled { get; set; } = Enumerable.Empty(); public IEnumerable TemplatesInstalled { get; set; } = Enumerable.Empty(); public IEnumerable DocumentTypesInstalled { get; set; } = Enumerable.Empty(); public IEnumerable MediaTypesInstalled { get; set; } = Enumerable.Empty(); @@ -31,73 +32,55 @@ namespace Umbraco.Cms.Core.Packaging public IEnumerable PartialViewsInstalled { get; set; } = Enumerable.Empty(); public IEnumerable ContentInstalled { get; set; } = Enumerable.Empty(); public IEnumerable MediaInstalled { get; set; } = Enumerable.Empty(); - public string PackageName { get; } public override string ToString() { var sb = new StringBuilder(); - var macroConflicts = Warnings.ConflictingMacros.ToList(); - if (macroConflicts.Count > 0) + + void WriteConflicts(IEnumerable source, Func selector, string message, bool appendLine = true) { - sb.Append("Conflicting macros found, they will be overwritten:"); - foreach(IMacro m in macroConflicts) + var result = source?.Select(selector).ToList(); + if (result?.Count > 0) { - sb.Append(m.Alias); - sb.Append(','); + sb.Append(message); + sb.Append(string.Join(", ", result)); + + if (appendLine) + { + sb.AppendLine(); + } } - sb.AppendLine(". "); - } - var templateConflicts = Warnings.ConflictingTemplates.ToList(); - if (templateConflicts.Count > 0) - { - sb.Append("Conflicting templates found, they will be overwritten:"); - foreach (ITemplate m in templateConflicts) - { - sb.Append(m.Alias); - sb.Append(','); - } - sb.AppendLine(". "); - } - var stylesheetConflicts = Warnings.ConflictingStylesheets.ToList(); - if (stylesheetConflicts.Count > 0) - { - sb.Append("Conflicting stylesheets found, they will be overwritten:"); - foreach (IFile m in stylesheetConflicts) - { - sb.Append(m.Alias); - sb.Append(','); - } - sb.AppendLine(". "); } - sb.Append("Content items installed: "); - sb.Append(ContentInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Media items installed: "); - sb.Append(MediaInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Dictionary items installed: "); - sb.Append(DictionaryItemsInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Macros installed: "); - sb.Append(MacrosInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Stylesheets installed: "); - sb.Append(StylesheetsInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Templates installed: "); - sb.Append(TemplatesInstalled.Count()); - sb.AppendLine(); - sb.Append("Document types installed: "); - sb.Append(DocumentTypesInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Media types installed: "); - sb.Append(MediaTypesInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Data types items installed: "); - sb.Append(DataTypesInstalled.Count()); + void WriteCount(string message, IEnumerable source, bool appendLine = true) + { + sb.Append(message); + sb.Append(source?.Count() ?? 0); + + if (appendLine) + { + sb.AppendLine(); + } + } + + WriteConflicts(Warnings?.ConflictingMacros, x => x.Alias, "Conflicting macros found, they will be overwritten: "); + WriteConflicts(Warnings?.ConflictingTemplates, x => x.Alias, "Conflicting templates found, they will be overwritten: "); + WriteConflicts(Warnings?.ConflictingStylesheets, x => x.Alias, "Conflicting stylesheets found, they will be overwritten: "); + WriteCount("Data types installed: ", DataTypesInstalled); + WriteCount("Languages installed: ", LanguagesInstalled); + WriteCount("Dictionary items installed: ", DictionaryItemsInstalled); + WriteCount("Macros installed: ", MacrosInstalled); + WriteCount("Macro partial views installed: ", MacroPartialViewsInstalled); + WriteCount("Templates installed: ", TemplatesInstalled); + WriteCount("Document types installed: ", DocumentTypesInstalled); + WriteCount("Media types installed: ", MediaTypesInstalled); + WriteCount("Stylesheets installed: ", StylesheetsInstalled); + WriteCount("Scripts installed: ", ScriptsInstalled); + WriteCount("Partial views installed: ", PartialViewsInstalled); + WriteCount("Content items installed: ", ContentInstalled); + WriteCount("Media items installed: ", MediaInstalled, false); + return sb.ToString(); } } - } diff --git a/src/Umbraco.Core/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Packaging/PackageDefinition.cs index 345d669b15..ae12a914b3 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinition.cs @@ -28,7 +28,7 @@ namespace Umbraco.Cms.Core.Packaging public string Name { get; set; } = string.Empty; /// - /// The full path to the package's xml file + /// The full path to the package's XML file. /// [ReadOnly(true)] [DataMember(Name = "packagePath")] @@ -71,12 +71,9 @@ namespace Umbraco.Cms.Core.Packaging public IList DataTypes { get; set; } = new List(); [DataMember(Name = "mediaUdis")] - public IList MediaUdis { get; set; } = Array.Empty(); + public IList MediaUdis { get; set; } = new List(); [DataMember(Name = "mediaLoadChildNodes")] public bool MediaLoadChildNodes { get; set; } - - } - } diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index a24890d5f2..2ab24fa593 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; @@ -294,7 +295,7 @@ namespace Umbraco.Cms.Core.Packaging var dataTypes = new XElement("DataTypes"); foreach (var dtId in definition.DataTypes) { - if (!int.TryParse(dtId, out var outInt)) + if (!int.TryParse(dtId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) continue; var dataType = _dataTypeService.GetDataType(outInt); if (dataType == null) @@ -309,7 +310,7 @@ namespace Umbraco.Cms.Core.Packaging var languages = new XElement("Languages"); foreach (var langId in definition.Languages) { - if (!int.TryParse(langId, out var outInt)) + if (!int.TryParse(langId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) continue; var lang = _languageService.GetLanguageById(outInt); if (lang == null) @@ -326,7 +327,7 @@ namespace Umbraco.Cms.Core.Packaging foreach (var dictionaryId in definition.DictionaryItems) { - if (!int.TryParse(dictionaryId, out var outInt)) + if (!int.TryParse(dictionaryId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) { continue; } @@ -397,7 +398,7 @@ namespace Umbraco.Cms.Core.Packaging var macros = new XElement("Macros"); foreach (var macroId in definition.Macros) { - if (!int.TryParse(macroId, out int outInt)) + if (!int.TryParse(macroId, NumberStyles.Integer, CultureInfo.InvariantCulture, out int outInt)) { continue; } @@ -414,9 +415,10 @@ namespace Umbraco.Cms.Core.Packaging root.Add(macros); - // get the partial views for macros and package those - IEnumerable views = packagedMacros.Select(x => x.MacroSource).Where(x => x.EndsWith(".cshtml")); - PackageMacroPartialViews(views, root); + // Get the partial views for macros and package those (exclude views outside of the default directory, e.g. App_Plugins\*\Views) + IEnumerable views = packagedMacros.Where(x => x.MacroSource.StartsWith(Constants.SystemDirectories.MacroPartials)) + .Select(x => x.MacroSource.Substring(Constants.SystemDirectories.MacroPartials.Length).Replace('/', '\\')); + PackageStaticFiles(views, root, "MacroPartialViews", "View", _fileSystems.MacroPartialsFileSystem); } private void PackageStylesheets(PackageDefinition definition, XContainer root) @@ -477,7 +479,7 @@ namespace Umbraco.Cms.Core.Packaging var templatesXml = new XElement("Templates"); foreach (var templateId in definition.Templates) { - if (!int.TryParse(templateId, out var outInt)) + if (!int.TryParse(templateId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) continue; var template = _fileService.GetTemplate(outInt); if (template == null) @@ -487,40 +489,13 @@ namespace Umbraco.Cms.Core.Packaging root.Add(templatesXml); } - private void PackageMacroPartialViews(IEnumerable viewPaths, XContainer root) - { - var viewsXml = new XElement("MacroPartialViews"); - foreach (var viewPath in viewPaths) - { - // TODO: See TODO note in MacrosController about the inconsistencies of usages of partial views - // and how paths are saved. We have no choice currently but to assume that all views are 100% always - // on the content path. - - var physicalPath = _hostingEnvironment.MapPathContentRoot(viewPath); - if (!File.Exists(physicalPath)) - { - throw new InvalidOperationException("Could not find partial view at path " + viewPath); - } - - var fileContents = File.ReadAllText(physicalPath, Encoding.UTF8); - - viewsXml.Add( - new XElement( - "View", - new XAttribute("path", viewPath), - new XCData(fileContents))); - } - - root.Add(viewsXml); - } - private void PackageDocumentTypes(PackageDefinition definition, XContainer root) { var contentTypes = new HashSet(); var docTypesXml = new XElement("DocumentTypes"); foreach (var dtId in definition.DocumentTypes) { - if (!int.TryParse(dtId, out var outInt)) + if (!int.TryParse(dtId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) continue; var contentType = _contentTypeService.Get(outInt); if (contentType == null) @@ -539,7 +514,7 @@ namespace Umbraco.Cms.Core.Packaging var mediaTypesXml = new XElement("MediaTypes"); foreach (var mediaTypeId in definition.MediaTypes) { - if (!int.TryParse(mediaTypeId, out var outInt)) + if (!int.TryParse(mediaTypeId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) continue; var mediaType = _mediaTypeService.Get(outInt); if (mediaType == null) @@ -555,7 +530,7 @@ namespace Umbraco.Cms.Core.Packaging private void PackageDocumentsAndTags(PackageDefinition definition, XContainer root) { //Documents and tags - if (string.IsNullOrEmpty(definition.ContentNodeId) == false && int.TryParse(definition.ContentNodeId, out var contentNodeId)) + if (string.IsNullOrEmpty(definition.ContentNodeId) == false && int.TryParse(definition.ContentNodeId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var contentNodeId)) { if (contentNodeId > 0) { diff --git a/src/Umbraco.Core/PropertyEditors/MediaPicker3Configuration.cs b/src/Umbraco.Core/PropertyEditors/MediaPicker3Configuration.cs index 7fa2753be9..87e097883f 100644 --- a/src/Umbraco.Core/PropertyEditors/MediaPicker3Configuration.cs +++ b/src/Umbraco.Core/PropertyEditors/MediaPicker3Configuration.cs @@ -39,7 +39,7 @@ namespace Umbraco.Cms.Core.PropertyEditors [ConfigurationField("enableLocalFocalPoint", "Enable Focal Point", "boolean")] public bool EnableLocalFocalPoint { get; set; } - [ConfigurationField("crops", "Image Crops", "views/propertyeditors/MediaPicker3/prevalue/mediapicker3.crops.html", Description = "Local crops, stored on document")] + [ConfigurationField("crops", "Image Crops", "views/propertyeditors/mediapicker3/prevalue/mediapicker3.crops.html", Description = "Local crops, stored on document")] public CropConfiguration[] Crops { get; set; } [DataContract] diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs index 637039faa9..c873b29b98 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs @@ -71,7 +71,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters case ValueTypes.Integer: if (source is int sourceInt) return sourceInt; if (source is string sourceIntString) - return int.TryParse(sourceIntString, out var i) ? i : 0; + return int.TryParse(sourceIntString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? i : 0; return 0; case ValueTypes.Bigint: if (source is string sourceLongString) diff --git a/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs index 13a3d8c973..d8093aed1b 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs @@ -1,3 +1,4 @@ +using System.Globalization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; @@ -60,7 +61,7 @@ namespace Umbraco.Cms.Core.Routing { var noSlashPath = path.Substring(1); - if (int.TryParse(noSlashPath, out nodeId) == false) + if (int.TryParse(noSlashPath, NumberStyles.Integer, CultureInfo.InvariantCulture, out nodeId) == false) { nodeId = -1; } diff --git a/src/Umbraco.Core/Routing/ContentFinderByPageIdQuery.cs b/src/Umbraco.Core/Routing/ContentFinderByPageIdQuery.cs index b5b80d7b9e..7a71cfc5cd 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByPageIdQuery.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByPageIdQuery.cs @@ -1,3 +1,4 @@ +using System.Globalization; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Web; using Umbraco.Extensions; @@ -32,7 +33,7 @@ namespace Umbraco.Cms.Core.Routing { return false; } - if (int.TryParse(_requestAccessor.GetRequestValue("umbPageID"), out int pageId)) + if (int.TryParse(_requestAccessor.GetRequestValue("umbPageID"), NumberStyles.Integer, CultureInfo.InvariantCulture, out int pageId)) { IPublishedContent doc = umbracoContext.Content.GetById(pageId); diff --git a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs index 4e5d854250..16248854e5 100644 --- a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs +++ b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; @@ -56,7 +57,7 @@ namespace Umbraco.Cms.Core.Routing var path = pos == 0 ? route : route.Substring(pos); var domainUri = pos == 0 ? null - : DomainUtilities.DomainForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, int.Parse(route.Substring(0, pos)), current, culture); + : DomainUtilities.DomainForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, int.Parse(route.Substring(0, pos), CultureInfo.InvariantCulture), current, culture); // assemble the URL from domainUri (maybe null) and path var url = AssembleUrl(domainUri, path, current, mode).ToString(); diff --git a/src/Umbraco.Core/Routing/DomainUtilities.cs b/src/Umbraco.Core/Routing/DomainUtilities.cs index 035e57c43a..2e36e8c0ef 100644 --- a/src/Umbraco.Core/Routing/DomainUtilities.cs +++ b/src/Umbraco.Core/Routing/DomainUtilities.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Web; @@ -47,7 +48,7 @@ namespace Umbraco.Cms.Core.Routing var pos = route.IndexOf('/'); var domain = pos == 0 ? null - : DomainForNode(umbracoContext.Domains, siteDomainMapper, int.Parse(route.Substring(0, pos)), current); + : DomainForNode(umbracoContext.Domains, siteDomainMapper, int.Parse(route.Substring(0, pos), CultureInfo.InvariantCulture), current); var rootContentId = domain?.ContentId ?? -1; var wcDomain = FindWildcardDomainInPath(umbracoContext.Domains.GetAll(true), contentPath, rootContentId); @@ -329,7 +330,7 @@ namespace Umbraco.Cms.Core.Routing return path.Split(Constants.CharArrays.Comma) .Reverse() - .Select(int.Parse) + .Select(s => int.Parse(s, CultureInfo.InvariantCulture)) .TakeWhile(id => id != stopNodeId) .Select(id => domains.FirstOrDefault(d => d.ContentId == id && d.IsWildcard == false)) .SkipWhile(domain => domain == null) @@ -350,7 +351,7 @@ namespace Umbraco.Cms.Core.Routing return path.Split(Constants.CharArrays.Comma) .Reverse() - .Select(int.Parse) + .Select(s => int.Parse(s, CultureInfo.InvariantCulture)) .TakeWhile(id => id != stopNodeId) .Select(id => domains.FirstOrDefault(d => d.ContentId == id && d.IsWildcard)) .FirstOrDefault(domain => domain != null); diff --git a/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs b/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs index 3c4d8a2b47..340de80c96 100644 --- a/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs +++ b/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Core.Sync /// /// /// This is the default service which determines a server's role by using a master election process. - /// The master election process doesn't occur until just after startup so this election process doesn't really affect the primary startup phase. + /// The scheduling publisher election process doesn't occur until just after startup so this election process doesn't really affect the primary startup phase. /// public sealed class ElectedServerRoleAccessor : IServerRoleAccessor { diff --git a/src/Umbraco.Core/Sync/ServerRole.cs b/src/Umbraco.Core/Sync/ServerRole.cs index 27358608a4..9bfd4469b3 100644 --- a/src/Umbraco.Core/Sync/ServerRole.cs +++ b/src/Umbraco.Core/Sync/ServerRole.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Cms.Core.Sync +namespace Umbraco.Cms.Core.Sync { /// /// The role of a server in an application environment. @@ -16,13 +16,13 @@ Single = 1, /// - /// In a multi-servers environment, the server is a replica server. + /// In a multi-servers environment, the server is a Subscriber server. /// - Replica = 2, + Subscriber = 2, /// - /// In a multi-servers environment, the server is the master server. + /// In a multi-servers environment, the server is the Scheduling Publisher. /// - Master = 3 + SchedulingPublisher = 3 } } diff --git a/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs b/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs index 43fd421ac5..2f4e85c5b1 100644 --- a/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs +++ b/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Core.Sync /// /// /// The micro optimization is specifically to avoid a DB query just after the app starts up to determine the - /// which by default is done with master election by a database query. The master election process doesn't occur until just after startup + /// which by default is done with scheduling publisher election by a database query. The master election process doesn't occur until just after startup /// so this micro optimization doesn't really affect the primary startup phase. /// public class SingleServerRoleAccessor : IServerRoleAccessor diff --git a/src/Umbraco.Core/Templates/HtmlLocalLinkParser.cs b/src/Umbraco.Core/Templates/HtmlLocalLinkParser.cs index a92548ea18..a75fd3dee9 100644 --- a/src/Umbraco.Core/Templates/HtmlLocalLinkParser.cs +++ b/src/Umbraco.Core/Templates/HtmlLocalLinkParser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Text.RegularExpressions; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Web; @@ -114,7 +115,7 @@ namespace Umbraco.Cms.Core.Templates yield return (null, guidUdi, tag.Value); } - if (int.TryParse(id, out var intId)) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) { yield return (intId, null, tag.Value); } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 9055030875..734ed2261d 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -16,7 +16,7 @@ - + @@ -29,7 +29,7 @@ - + all diff --git a/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs b/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs index e92aa8e147..5d72221391 100644 --- a/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs +++ b/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; namespace Umbraco.Cms.Core.Xml @@ -49,9 +50,9 @@ namespace Umbraco.Cms.Core.Xml foreach (var i in path) { int idAsInt; - if (int.TryParse(i, out idAsInt)) + if (int.TryParse(i, NumberStyles.Integer, CultureInfo.InvariantCulture, out idAsInt)) { - var exists = publishedContentExists(int.Parse(i)); + var exists = publishedContentExists(int.Parse(i, CultureInfo.InvariantCulture)); if (exists) return idAsInt; } diff --git a/src/Umbraco.Core/Xml/XPath/NavigableNavigator.cs b/src/Umbraco.Core/Xml/XPath/NavigableNavigator.cs index 68dfb9bb67..5ebc575243 100644 --- a/src/Umbraco.Core/Xml/XPath/NavigableNavigator.cs +++ b/src/Umbraco.Core/Xml/XPath/NavigableNavigator.cs @@ -300,7 +300,7 @@ namespace Umbraco.Cms.Core.Xml.XPath public XPathNavigator CloneWithNewRoot(string id, int maxDepth = int.MaxValue) { int i; - if (int.TryParse(id, out i) == false) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out i) == false) throw new ArgumentException("Not a valid identifier.", nameof(id)); return CloneWithNewRoot(id); } @@ -679,7 +679,7 @@ namespace Umbraco.Cms.Core.Xml.XPath var navRootId = state.Content.Id; int contentId; - if (int.TryParse(id, out contentId)) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out contentId)) { if (contentId == navRootId) { diff --git a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs index 27fdf1f2f7..5e2b66c720 100644 --- a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs +++ b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -335,7 +336,7 @@ namespace Umbraco.Cms.Infrastructure.Examine UdiParser.TryParse(searchFrom, true, out var udi); searchFrom = udi == null ? searchFrom : entityService.GetId(udi).Result.ToString(); - var entityPath = int.TryParse(searchFrom, out var searchFromId) && searchFromId > 0 + var entityPath = int.TryParse(searchFrom, NumberStyles.Integer, CultureInfo.InvariantCulture, out var searchFromId) && searchFromId > 0 ? entityService.GetAllPaths(objectType, searchFromId).FirstOrDefault() : null; if (entityPath != null) diff --git a/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj b/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj index baa843247d..118a895073 100644 --- a/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj +++ b/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj @@ -21,12 +21,12 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all diff --git a/src/Umbraco.Infrastructure/Events/RelateOnTrashNotificationHandler.cs b/src/Umbraco.Infrastructure/Events/RelateOnTrashNotificationHandler.cs index df0f074ea3..4222ac800e 100644 --- a/src/Umbraco.Infrastructure/Events/RelateOnTrashNotificationHandler.cs +++ b/src/Umbraco.Infrastructure/Events/RelateOnTrashNotificationHandler.cs @@ -1,6 +1,7 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System.Globalization; using System.Linq; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Notifications; @@ -72,7 +73,7 @@ namespace Umbraco.Cms.Core.Events { var originalPath = item.OriginalPath.ToDelimitedList(); var originalParentId = originalPath.Count > 2 - ? int.Parse(originalPath[originalPath.Count - 2]) + ? int.Parse(originalPath[originalPath.Count - 2], CultureInfo.InvariantCulture) : Constants.System.Root; //before we can create this relation, we need to ensure that the original parent still exists which @@ -130,7 +131,7 @@ namespace Umbraco.Cms.Core.Events { var originalPath = item.OriginalPath.ToDelimitedList(); var originalParentId = originalPath.Count > 2 - ? int.Parse(originalPath[originalPath.Count - 2]) + ? int.Parse(originalPath[originalPath.Count - 2], CultureInfo.InvariantCulture) : Constants.System.Root; //before we can create this relation, we need to ensure that the original parent still exists which //may not be the case if the encompassing transaction also deleted it when this item was moved to the bin diff --git a/src/Umbraco.Infrastructure/Examine/ExamineExtensions.cs b/src/Umbraco.Infrastructure/Examine/ExamineExtensions.cs index d0f65fe6a4..b2b025b5a6 100644 --- a/src/Umbraco.Infrastructure/Examine/ExamineExtensions.cs +++ b/src/Umbraco.Infrastructure/Examine/ExamineExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using Examine; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; @@ -32,7 +33,7 @@ namespace Umbraco.Extensions foreach (var result in results) { - if (int.TryParse(result.Id, out var contentId) && + if (int.TryParse(result.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var contentId) && cache.GetById(contentId) is IPublishedContent content) { publishedSearchResults.Add(new PublishedSearchResult(content, result.Score)); @@ -62,7 +63,7 @@ namespace Umbraco.Extensions foreach (var result in results) { - if (int.TryParse(result.Id, out var contentId) && + if (int.TryParse(result.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var contentId) && result.Values.TryGetValue(ExamineFieldNames.CategoryFieldName, out var indexType)) { IPublishedContent content; diff --git a/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs b/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs index 5afe010b82..4fbbb35a6d 100644 --- a/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs +++ b/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs @@ -198,7 +198,7 @@ namespace Umbraco.Cms.Infrastructure.Examine foreach (ISearchResult item in paged) { - if (int.TryParse(item.Id, out int contentId)) + if (int.TryParse(item.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out int contentId)) { DeleteIndexForEntity(contentId, false); } @@ -411,7 +411,7 @@ namespace Umbraco.Cms.Infrastructure.Examine else { Execute(_examineUmbracoIndexingHandler, _ids, _keepIfUnpublished); - } + } } public static void Execute(ExamineUmbracoIndexingHandler examineUmbracoIndexingHandler, int id, bool keepIfUnpublished) diff --git a/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs b/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs index 78dc3f533b..6a0828fad3 100644 --- a/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs +++ b/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs @@ -89,8 +89,8 @@ namespace Umbraco.Cms.Infrastructure.HostedServices switch (_serverRegistrar.CurrentServerRole) { - case ServerRole.Replica: - _logger.LogDebug("Does not run on replica servers."); + case ServerRole.Subscriber: + _logger.LogDebug("Does not run on subscriber servers."); return; case ServerRole.Unknown: _logger.LogDebug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs b/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs index 644b2c278f..b564e7948d 100644 --- a/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs +++ b/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs @@ -69,8 +69,8 @@ namespace Umbraco.Cms.Infrastructure.HostedServices // Don't run on replicas nor unknown role servers switch (_serverRegistrar.CurrentServerRole) { - case ServerRole.Replica: - _logger.LogDebug("Does not run on replica servers."); + case ServerRole.Subscriber: + _logger.LogDebug("Does not run on subscriber servers."); return; case ServerRole.Unknown: _logger.LogDebug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs b/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs index 39f638000a..27d9c29e8d 100644 --- a/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs +++ b/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs @@ -63,8 +63,8 @@ namespace Umbraco.Cms.Infrastructure.HostedServices { switch (_serverRegistrar.CurrentServerRole) { - case ServerRole.Replica: - _logger.LogDebug("Does not run on replica servers."); + case ServerRole.Subscriber: + _logger.LogDebug("Does not run on subscriber servers."); return Task.CompletedTask; case ServerRole.Unknown: _logger.LogDebug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs index 089afa4e07..d59ea4fad3 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs @@ -69,8 +69,8 @@ namespace Umbraco.Cms.Infrastructure.HostedServices switch (_serverRegistrar.CurrentServerRole) { - case ServerRole.Replica: - _logger.LogDebug("Does not run on replica servers."); + case ServerRole.Subscriber: + _logger.LogDebug("Does not run on subscriber servers."); return Task.CompletedTask; case ServerRole.Unknown: _logger.LogDebug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Infrastructure/HostedServices/TempFileCleanup.cs b/src/Umbraco.Infrastructure/HostedServices/TempFileCleanup.cs index b126de9467..e59cca5fbd 100644 --- a/src/Umbraco.Infrastructure/HostedServices/TempFileCleanup.cs +++ b/src/Umbraco.Infrastructure/HostedServices/TempFileCleanup.cs @@ -14,8 +14,8 @@ namespace Umbraco.Cms.Infrastructure.HostedServices /// Used to cleanup temporary file locations. /// /// - /// Will run on all servers - even though file upload should only be handled on the master, this will - /// ensure that in the case it happes on replicas that they are cleaned up too. + /// Will run on all servers - even though file upload should only be handled on the scheduling publisher, this will + /// ensure that in the case it happens on subscribers that they are cleaned up too. /// public class TempFileCleanup : RecurringHostedServiceBase { diff --git a/src/Umbraco.Infrastructure/IPublishedContentQuery.cs b/src/Umbraco.Infrastructure/IPublishedContentQuery.cs index 24bd7ba44c..77ca873638 100644 --- a/src/Umbraco.Infrastructure/IPublishedContentQuery.cs +++ b/src/Umbraco.Infrastructure/IPublishedContentQuery.cs @@ -77,28 +77,6 @@ namespace Umbraco.Cms.Core /// IEnumerable Search(string term, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName); - /// - /// Searches content. - /// - /// The term to search. - /// The amount of results to skip. - /// The amount of results to take/return. - /// The total amount of records. - /// The culture (defaults to a culture insensitive search). - /// The name of the index to search (defaults to ). - /// - /// The search results. - /// - /// - /// - /// When the is not specified or is *, all cultures are searched. - /// To search for only invariant documents and fields use null. - /// When searching on a specific culture, all culture specific fields are searched for the provided culture and all invariant fields for all documents. - /// - /// While enumerating results, the ambient culture is changed to be the searched culture. - /// - IEnumerable Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName); - /// /// Executes the query and converts the results to . /// diff --git a/src/Umbraco.Infrastructure/Install/InstallHelper.cs b/src/Umbraco.Infrastructure/Install/InstallHelper.cs index 944ebbb586..cd7dfcbf0c 100644 --- a/src/Umbraco.Infrastructure/Install/InstallHelper.cs +++ b/src/Umbraco.Infrastructure/Install/InstallHelper.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -10,7 +7,6 @@ using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Core.Net; -using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.Migrations.Install; @@ -50,14 +46,11 @@ namespace Umbraco.Cms.Infrastructure.Install _userAgentProvider = userAgentProvider; _umbracoDatabaseFactory = umbracoDatabaseFactory; - //We need to initialize the type already, as we can't detect later, if the connection string is added on the fly. + // We need to initialize the type already, as we can't detect later, if the connection string is added on the fly. GetInstallationType(); } - public InstallationType GetInstallationType() - { - return _installationType ?? (_installationType = IsBrandNewInstall ? InstallationType.NewInstall : InstallationType.Upgrade).Value; - } + public InstallationType GetInstallationType() => _installationType ??= IsBrandNewInstall ? InstallationType.NewInstall : InstallationType.Upgrade; public async Task SetInstallStatusAsync(bool isCompleted, string errorMsg) { @@ -65,25 +58,14 @@ namespace Umbraco.Cms.Infrastructure.Install { var userAgent = _userAgentProvider.GetUserAgent(); - // Check for current install Id - var installId = Guid.NewGuid(); - + // Check for current install ID var installCookie = _cookieManager.GetCookieValue(Constants.Web.InstallerCookieName); - if (string.IsNullOrEmpty(installCookie) == false) + if (!Guid.TryParse(installCookie, out var installId)) { - if (Guid.TryParse(installCookie, out installId)) - { - // check that it's a valid Guid - if (installId == Guid.Empty) - installId = Guid.NewGuid(); - } - else - { - installId = Guid.NewGuid(); // Guid.TryParse will have reset installId to Guid.Empty - } - } + installId = Guid.NewGuid(); - _cookieManager.SetCookieValue(Constants.Web.InstallerCookieName, installId.ToString()); + _cookieManager.SetCookieValue(Constants.Web.InstallerCookieName, installId.ToString()); + } var dbProvider = string.Empty; if (IsBrandNewInstall == false) @@ -108,29 +90,14 @@ namespace Umbraco.Cms.Infrastructure.Install } /// - /// Checks if this is a brand new install meaning that there is no configured version and there is no configured database connection + /// Checks if this is a brand new install, meaning that there is no configured database connection or the database is empty. /// - private bool IsBrandNewInstall - { - get - { - var databaseSettings = _connectionStrings.CurrentValue.UmbracoConnectionString; - if (databaseSettings.IsConnectionStringConfigured() == false) - { - //no version or conn string configured, must be a brand new install - return true; - } - - //now we have to check if this is really a new install, the db might be configured and might contain data - - if (databaseSettings.IsConnectionStringConfigured() == false - || _databaseBuilder.IsDatabaseConfigured == false) - { - return true; - } - - return _databaseBuilder.IsUmbracoInstalled() == false; - } - } + /// + /// true if this is a brand new install; otherwise, false. + /// + private bool IsBrandNewInstall => _connectionStrings.CurrentValue.UmbracoConnectionString?.IsConnectionStringConfigured() != true || + _databaseBuilder.IsDatabaseConfigured == false || + _databaseBuilder.CanConnectToDatabase == false || + _databaseBuilder.IsUmbracoInstalled() == false; } } diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs index 7b02ea786e..a25151bda2 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -7,6 +8,7 @@ using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Install; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Infrastructure.Migrations.Install; +using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Install.InstallSteps @@ -33,13 +35,24 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps if (database == null) { database = new DatabaseModel(); + + if (IsLocalDbAvailable()) + { + database.DatabaseType = DatabaseType.SqlLocalDb; + } + else if (IsSqlCeAvailable()) + { + database.DatabaseType = DatabaseType.SqlCe; + } } if (_databaseBuilder.CanConnect(database.DatabaseType.ToString(), database.ConnectionString, database.Server, database.DatabaseName, database.Login, database.Password, database.IntegratedAuth) == false) { throw new InstallException("Could not connect to the database"); } + ConfigureConnection(database); + return Task.FromResult(null); } @@ -49,6 +62,10 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps { _databaseBuilder.ConfigureDatabaseConnection(database.ConnectionString); } + else if (database.DatabaseType == DatabaseType.SqlLocalDb) + { + _databaseBuilder.ConfigureSqlLocalDbDatabaseConnection(); + } else if (database.DatabaseType == DatabaseType.SqlCe) { _databaseBuilder.ConfigureEmbeddedDatabaseConnection(); @@ -62,9 +79,7 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps var password = database.Password.Replace("'", "''"); password = string.Format("'{0}'", password); - _databaseBuilder.ConfigureDatabaseConnection( - database.Server, database.DatabaseName, database.Login, password, - database.DatabaseType.ToString()); + _databaseBuilder.ConfigureDatabaseConnection(database.Server, database.DatabaseName, database.Login, password, database.DatabaseType.ToString()); } } @@ -84,28 +99,32 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps databases.Insert(0, new { name = "Microsoft SQL Server Compact (SQL CE)", id = DatabaseType.SqlCe.ToString() }); } + if (IsLocalDbAvailable()) + { + // Ensure this is always inserted as first when available + databases.Insert(0, new { name = "Microsoft SQL Server Express (LocalDB)", id = DatabaseType.SqlLocalDb.ToString() }); + } + return new { - databases = databases + databases }; } } - public static bool IsSqlCeAvailable() - { + public static bool IsLocalDbAvailable() => new LocalDb().IsAvailable; + + public static bool IsSqlCeAvailable() => // NOTE: Type.GetType will only return types that are currently loaded into the appdomain. In this case // that is ok because we know if this is availalbe we will have manually loaded it into the appdomain. // Else we'd have to use Assembly.LoadFrom and need to know the DLL location here which we don't need to do. - return !(Type.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeSyntaxProvider, Umbraco.Persistence.SqlCe") is null); - } + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && + !(Type.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeSyntaxProvider, Umbraco.Persistence.SqlCe") is null); public override string View => ShouldDisplayView() ? base.View : ""; - public override bool RequiresExecution(DatabaseModel model) - { - return ShouldDisplayView(); - } + public override bool RequiresExecution(DatabaseModel model) => ShouldDisplayView(); private bool ShouldDisplayView() { @@ -118,6 +137,7 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps { //Since a connection string was present we verify the db can connect and query _ = _databaseBuilder.ValidateSchema(); + return false; } catch (Exception ex) diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs index 61d78173fa..96d2a7c996 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; using Umbraco.Cms.Core; @@ -9,17 +9,16 @@ using Umbraco.Cms.Infrastructure.Migrations.Install; namespace Umbraco.Cms.Infrastructure.Install.InstallSteps { - [InstallSetupStep(InstallationType.NewInstall | InstallationType.Upgrade, - "DatabaseInstall", 11, "")] + [InstallSetupStep(InstallationType.NewInstall | InstallationType.Upgrade, "DatabaseInstall", 11, "")] public class DatabaseInstallStep : InstallSetupStep { - private readonly DatabaseBuilder _databaseBuilder; private readonly IRuntimeState _runtime; + private readonly DatabaseBuilder _databaseBuilder; - public DatabaseInstallStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime) + public DatabaseInstallStep(IRuntimeState runtime, DatabaseBuilder databaseBuilder) { - _databaseBuilder = databaseBuilder; _runtime = runtime; + _databaseBuilder = databaseBuilder; } public override Task ExecuteAsync(object model) @@ -27,6 +26,11 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps if (_runtime.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); + if (_runtime.Reason == RuntimeLevelReason.InstallMissingDatabase) + { + _databaseBuilder.CreateDatabase(); + } + var result = _databaseBuilder.CreateSchemaAndData(); if (result.Success == false) @@ -39,16 +43,13 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps return Task.FromResult(null); } - //upgrade is required so set the flag for the next step + // Upgrade is required, so set the flag for the next step return Task.FromResult(new InstallSetupResult(new Dictionary { - {"upgrade", true} + { "upgrade", true} })); } - public override bool RequiresExecution(object model) - { - return true; - } + public override bool RequiresExecution(object model) => true; } } diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs index fdcef20943..73b9d702b7 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs @@ -73,11 +73,11 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps _userService.Save(admin); - var membershipUser = await _userManager.FindByIdAsync(Constants.Security.SuperUserId.ToString()); + var membershipUser = await _userManager.FindByIdAsync(Constants.Security.SuperUserIdAsString); if (membershipUser == null) { throw new InvalidOperationException( - $"No user found in membership provider with id of {Constants.Security.SuperUserId}."); + $"No user found in membership provider with id of {Constants.Security.SuperUserIdAsString}."); } //To change the password here we actually need to reset it since we don't have an old one to use to change diff --git a/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs b/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs index babf882e1b..94a6646086 100644 --- a/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs +++ b/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Exceptions; @@ -20,7 +21,7 @@ namespace Umbraco.Cms.Infrastructure.Install private readonly DatabaseSchemaCreatorFactory _databaseSchemaCreatorFactory; private readonly IEventAggregator _eventAggregator; private readonly IUmbracoDatabaseFactory _databaseFactory; - private readonly IOptions _globalSettings; + private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; private readonly ILogger _logger; private readonly IRuntimeState _runtimeState; @@ -29,7 +30,7 @@ namespace Umbraco.Cms.Infrastructure.Install IEventAggregator eventAggregator, IOptions unattendedSettings, IUmbracoDatabaseFactory databaseFactory, - IOptions globalSettings, + IDbProviderFactoryCreator dbProviderFactoryCreator, ILogger logger, IRuntimeState runtimeState) { @@ -37,7 +38,7 @@ namespace Umbraco.Cms.Infrastructure.Install _eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator)); _unattendedSettings = unattendedSettings; _databaseFactory = databaseFactory; - _globalSettings = globalSettings; + _dbProviderFactoryCreator = dbProviderFactoryCreator; _logger = logger; _runtimeState = runtimeState; } @@ -56,7 +57,11 @@ namespace Umbraco.Cms.Infrastructure.Install return Task.CompletedTask; } - var tries = _globalSettings.Value.InstallMissingDatabase ? 2 : 5; + _runtimeState.DetermineRuntimeLevel(); + if (_runtimeState.Reason == RuntimeLevelReason.InstallMissingDatabase) + { + _dbProviderFactoryCreator.CreateDatabase(_databaseFactory.ProviderName, _databaseFactory.ConnectionString); + } bool connect; try @@ -64,12 +69,13 @@ namespace Umbraco.Cms.Infrastructure.Install for (var i = 0; ;) { connect = _databaseFactory.CanConnect; - if (connect || ++i == tries) + if (connect || ++i == 5) { break; } _logger.LogDebug("Could not immediately connect to database, trying again."); + Thread.Sleep(1000); } } diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index b7437f4c2d..78dbdddc84 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -1,10 +1,9 @@ using System; -using System.IO; -using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; -using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Migrations; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; @@ -22,14 +21,13 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install { private readonly IUmbracoDatabaseFactory _databaseFactory; private readonly IScopeProvider _scopeProvider; - private readonly IRuntimeState _runtime; - private readonly IMigrationBuilder _migrationBuilder; + private readonly IRuntimeState _runtimeState; private readonly IKeyValueService _keyValueService; - private readonly IHostingEnvironment _hostingEnvironment; private readonly ILogger _logger; - private readonly ILoggerFactory _loggerFactory; private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; private readonly IConfigManipulator _configManipulator; + private readonly IOptionsMonitor _globalSettings; + private readonly IOptionsMonitor _connectionStrings; private readonly IMigrationPlanExecutor _migrationPlanExecutor; private readonly DatabaseSchemaCreatorFactory _databaseSchemaCreatorFactory; @@ -41,26 +39,25 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install public DatabaseBuilder( IScopeProvider scopeProvider, IUmbracoDatabaseFactory databaseFactory, - IRuntimeState runtime, + IRuntimeState runtimeState, ILoggerFactory loggerFactory, - IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, - IHostingEnvironment hostingEnvironment, IDbProviderFactoryCreator dbProviderFactoryCreator, IConfigManipulator configManipulator, + IOptionsMonitor globalSettings, + IOptionsMonitor connectionStrings, IMigrationPlanExecutor migrationPlanExecutor, DatabaseSchemaCreatorFactory databaseSchemaCreatorFactory) { _scopeProvider = scopeProvider; _databaseFactory = databaseFactory; - _runtime = runtime; + _runtimeState = runtimeState; _logger = loggerFactory.CreateLogger(); - _loggerFactory = loggerFactory; - _migrationBuilder = migrationBuilder; _keyValueService = keyValueService; - _hostingEnvironment = hostingEnvironment; _dbProviderFactoryCreator = dbProviderFactoryCreator; _configManipulator = configManipulator; + _globalSettings = globalSettings; + _connectionStrings = connectionStrings; _migrationPlanExecutor = migrationPlanExecutor; _databaseSchemaCreatorFactory = databaseSchemaCreatorFactory; } @@ -84,15 +81,15 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// public bool CanConnect(string databaseType, string connectionString, string server, string database, string login, string password, bool integratedAuth) { - // we do not test SqlCE connection - if (databaseType.InvariantContains("sqlce")) + // we do not test SqlCE or LocalDB connections + if (databaseType.InvariantContains("SqlCe") || databaseType.InvariantContains("SqlLocalDb")) return true; string providerName; if (string.IsNullOrWhiteSpace(connectionString) == false) { - providerName = DbConnectionExtensions.DetectProviderNameFromConnectionString(connectionString); + providerName = ConfigConnectionString.ParseProviderName(connectionString); } else if (integratedAuth) { @@ -146,30 +143,29 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install #region Configure Connection String - public const string EmbeddedDatabaseConnectionString = @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;"; + public const string EmbeddedDatabaseConnectionString = @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1"; /// /// Configures a connection string for the embedded database. /// public void ConfigureEmbeddedDatabaseConnection() { - ConfigureEmbeddedDatabaseConnection(_databaseFactory); + const string connectionString = EmbeddedDatabaseConnectionString; + const string providerName = Constants.DbProviderNames.SqlCe; + + _configManipulator.SaveConnectionString(connectionString, providerName); + Configure(connectionString, providerName, true); } - private void ConfigureEmbeddedDatabaseConnection(IUmbracoDatabaseFactory factory) + public const string LocalDbConnectionString = @"Data Source=(localdb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Umbraco.mdf;Integrated Security=True"; + + public void ConfigureSqlLocalDbDatabaseConnection() { - _configManipulator.SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe); + string connectionString = LocalDbConnectionString; + const string providerName = Constants.DbProviderNames.SqlServer; - var path = _hostingEnvironment.MapPathContentRoot(Path.Combine(Constants.SystemDirectories.Data, "Umbraco.sdf")); - if (File.Exists(path) == false) - { - // this should probably be in a "using (new SqlCeEngine)" clause but not sure - // of the side effects and it's been like this for quite some time now - - _dbProviderFactoryCreator.CreateDatabase(Constants.DbProviderNames.SqlCe); - } - - factory.Configure(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe); + _configManipulator.SaveConnectionString(connectionString, providerName); + Configure(connectionString, providerName, true); } /// @@ -179,10 +175,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// Has to be SQL Server public void ConfigureDatabaseConnection(string connectionString) { - const string providerName = Constants.DbProviderNames.SqlServer; - - _configManipulator.SaveConnectionString(connectionString, providerName); - _databaseFactory.Configure(connectionString, providerName); + _configManipulator.SaveConnectionString(connectionString, null); + Configure(connectionString, null, _globalSettings.CurrentValue.InstallMissingDatabase); } /// @@ -198,7 +192,21 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install var connectionString = GetDatabaseConnectionString(server, databaseName, user, password, databaseProvider, out var providerName); _configManipulator.SaveConnectionString(connectionString, providerName); - _databaseFactory.Configure(connectionString, providerName); + Configure(connectionString, providerName, _globalSettings.CurrentValue.InstallMissingDatabase); + } + + private void Configure(string connectionString, string providerName, bool installMissingDatabase) + { + // Update existing connection string + var umbracoConnectionString = new ConfigConnectionString(Constants.System.UmbracoConnectionName, connectionString, providerName); + _connectionStrings.CurrentValue.UmbracoConnectionString = umbracoConnectionString; + + _databaseFactory.Configure(umbracoConnectionString.ConnectionString, umbracoConnectionString.ProviderName); + + if (installMissingDatabase) + { + CreateDatabase(); + } } /// @@ -214,9 +222,10 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install public static string GetDatabaseConnectionString(string server, string databaseName, string user, string password, string databaseProvider, out string providerName) { providerName = Constants.DbProviderNames.SqlServer; - var provider = databaseProvider.ToLower(); - if (provider.InvariantContains("azure")) + + if (databaseProvider.InvariantContains("Azure")) return GetAzureConnectionString(server, databaseName, user, password); + return $"server={server};database={databaseName};user id={user};password={password}"; } @@ -228,8 +237,10 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install public void ConfigureIntegratedSecurityDatabaseConnection(string server, string databaseName) { var connectionString = GetIntegratedSecurityDatabaseConnectionString(server, databaseName); - _configManipulator.SaveConnectionString(connectionString, Constants.DbProviderNames.SqlServer); - _databaseFactory.Configure(connectionString, Constants.DbProviderNames.SqlServer); + const string providerName = Constants.DbProviderNames.SqlServer; + + _configManipulator.SaveConnectionString(connectionString, providerName); + _databaseFactory.Configure(connectionString, providerName); } /// @@ -292,18 +303,14 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install return $"Server={server};Database={databaseName};User ID={user};Password={password}"; } - private static bool ServerStartsWithTcp(string server) - { - return server.ToLower().StartsWith("tcp:".ToLower()); - } - - - + private static bool ServerStartsWithTcp(string server) => server.InvariantStartsWith("tcp:"); #endregion #region Database Schema + public void CreateDatabase() => _dbProviderFactoryCreator.CreateDatabase(_databaseFactory.ProviderName, _databaseFactory.ConnectionString); + /// /// Validates the database schema. /// @@ -375,7 +382,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install //If the determined version is "empty" its a new install - otherwise upgrade the existing if (!hasInstalledVersion) { - if (_runtime.Level == RuntimeLevel.Run) + if (_runtimeState.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); var creator = _databaseSchemaCreatorFactory.Create(database); diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs index 4e277262a7..70f5b6f0bf 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Runtime.Serialization; using Newtonsoft.Json; @@ -68,7 +69,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0 if (linkIsUdi == false) { // oh no.. probably an integer, yikes! - if (int.TryParse(relatedLink.Link, out var intId)) + if (int.TryParse(relatedLink.Link, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) { var sqlNodeData = Sql() .Select() diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/ListViewPreValueMigrator.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/ListViewPreValueMigrator.cs index 01cd171b6b..0b9bb4519c 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/ListViewPreValueMigrator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/ListViewPreValueMigrator.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Linq; using Newtonsoft.Json; using Umbraco.Extensions; @@ -18,7 +19,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes protected override object GetPreValueValue(PreValueDto preValue) { if (preValue.Alias == "pageSize") - return int.TryParse(preValue.Value, out var i) ? (int?)i : null; + return int.TryParse(preValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? (int?)i : null; return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value; } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/NestedContentPreValueMigrator.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/NestedContentPreValueMigrator.cs index aba3e3f407..98eac62f15 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/NestedContentPreValueMigrator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/NestedContentPreValueMigrator.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using System.Globalization; +using Newtonsoft.Json; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes @@ -25,7 +26,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes if (preValue.Alias == "minItems" || preValue.Alias == "maxItems") - return int.TryParse(preValue.Value, out var i) ? (int?)i : null; + return int.TryParse(preValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? (int?)i : null; return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value; } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs index b5e50d2248..f24cfc1142 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using Newtonsoft.Json; @@ -35,7 +36,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0 var splitVals = val.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries); var intVals = splitVals - .Select(x => int.TryParse(x, out var i) ? i : int.MinValue) + .Select(x => int.TryParse(x, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? i : int.MinValue) .Where(x => x != int.MinValue) .ToArray(); diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs index cea0fbdd23..3cbc7357e5 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -33,7 +34,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0 { var config = JsonConvert.DeserializeObject(datatype.Configuration); var startNodeId = config.Value("startNodeId"); - if (!startNodeId.IsNullOrWhiteSpace() && int.TryParse(startNodeId, out var intStartNode)) + if (!startNodeId.IsNullOrWhiteSpace() && int.TryParse(startNodeId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intStartNode)) { var guid = intStartNode <= 0 ? null @@ -65,7 +66,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0 var objectType = startNodeConfig.Value("type"); if (!objectType.IsNullOrWhiteSpace() && !startNodeId.IsNullOrWhiteSpace() - && int.TryParse(startNodeId, out var intStartNode)) + && int.TryParse(startNodeId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intStartNode)) { var guid = intStartNode <= 0 ? null diff --git a/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs b/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs index e96e96f521..2b52a93741 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using Examine; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models.ContentEditing; @@ -224,7 +225,7 @@ namespace Umbraco.Cms.Core.Models.Mapping if (source.Values.ContainsKey("parentID")) { - if (int.TryParse(source.Values["parentID"], out var parentId)) + if (int.TryParse(source.Values["parentID"], NumberStyles.Integer, CultureInfo.InvariantCulture,out var parentId)) { target.ParentId = parentId; } diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs index 05ceef6697..f63df1d0d2 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Net; -using System.Text; using System.Xml.Linq; using System.Xml.XPath; using Microsoft.Extensions.Logging; @@ -94,19 +94,20 @@ namespace Umbraco.Cms.Infrastructure.Packaging DataTypesInstalled = ImportDataTypes(compiledPackage.DataTypes.ToList(), userId), LanguagesInstalled = ImportLanguages(compiledPackage.Languages, userId), DictionaryItemsInstalled = ImportDictionaryItems(compiledPackage.DictionaryItems, userId), - MacrosInstalled = ImportMacros(compiledPackage.Macros, compiledPackage.MacroPartialViews, userId), + MacrosInstalled = ImportMacros(compiledPackage.Macros, userId), + MacroPartialViewsInstalled = ImportMacroPartialViews(compiledPackage.MacroPartialViews, userId), TemplatesInstalled = ImportTemplates(compiledPackage.Templates.ToList(), userId), DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId), MediaTypesInstalled = ImportMediaTypes(compiledPackage.MediaTypes, userId), + StylesheetsInstalled = ImportStylesheets(compiledPackage.Stylesheets, userId), + ScriptsInstalled = ImportScripts(compiledPackage.Scripts, userId), + PartialViewsInstalled = ImportPartialViews(compiledPackage.PartialViews, userId) }; - //we need a reference to the imported doc types to continue + // We need a reference to the imported doc types to continue var importedDocTypes = installationSummary.DocumentTypesInstalled.ToDictionary(x => x.Alias, x => x); var importedMediaTypes = installationSummary.MediaTypesInstalled.ToDictionary(x => x.Alias, x => x); - installationSummary.StylesheetsInstalled = ImportStylesheets(compiledPackage.Stylesheets, userId); - installationSummary.PartialViewsInstalled = ImportPartialViews(compiledPackage.PartialViews, userId); - installationSummary.ScriptsInstalled = ImportScripts(compiledPackage.Scripts, userId); installationSummary.ContentInstalled = ImportContentBase(compiledPackage.Documents, importedDocTypes, userId, _contentTypeService, _contentService); installationSummary.MediaInstalled = ImportContentBase(compiledPackage.Media, importedMediaTypes, userId, _mediaTypeService, _mediaService); @@ -122,31 +123,21 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// Optional id of the User performing the operation. Default is zero (admin). /// An enumerable list of generated ContentTypes public IReadOnlyList ImportMediaTypes(IEnumerable docTypeElements, int userId) - { - return ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService); - } + => ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService); #endregion #region Content - public IReadOnlyList ImportContentBase( + public IReadOnlyList ImportContentBase( IEnumerable docs, - IDictionary importedDocumentTypes, + IDictionary importedDocumentTypes, int userId, - IContentTypeBaseService typeService, - IContentServiceBase service) - where T : class, IContentBase - where S : IContentTypeComposition - { - return docs.SelectMany(x => ImportContentBase( - x.XmlData.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty), - -1, - importedDocumentTypes, - userId, - typeService, - service)).ToList(); - } + IContentTypeBaseService typeService, + IContentServiceBase service) + where TContentBase : class, IContentBase + where TContentTypeComposition : IContentTypeComposition + => docs.SelectMany(x => ImportContentBase(x.XmlData.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty), -1, importedDocumentTypes, userId, typeService, service)).ToList(); /// /// Imports and saves package xml as @@ -156,17 +147,16 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// A dictionary of already imported document types (basically used as a cache) /// Optional Id of the user performing the import /// An enumerable list of generated content - public IEnumerable ImportContentBase( + public IEnumerable ImportContentBase( IEnumerable roots, int parentId, - IDictionary importedDocumentTypes, + IDictionary importedDocumentTypes, int userId, - IContentTypeBaseService typeService, - IContentServiceBase service) - where T : class, IContentBase - where S : IContentTypeComposition + IContentTypeBaseService typeService, + IContentServiceBase service) + where TContentBase : class, IContentBase + where TContentTypeComposition : IContentTypeComposition { - var contents = ParseContentBaseRootXml(roots, parentId, importedDocumentTypes, typeService, service).ToList(); if (contents.Any()) { @@ -213,74 +203,72 @@ namespace Umbraco.Cms.Infrastructure.Packaging { throw new InvalidOperationException("Could not find content type with alias " + contentTypeAlias); } + importedContentTypes.Add(contentTypeAlias, contentType); } - if (TryCreateContentFromXml(root, importedContentTypes[contentTypeAlias], default, parentId, service, - out TContentBase content)) + if (TryCreateContentFromXml(root, importedContentTypes[contentTypeAlias], default, parentId, service, out TContentBase content)) { contents.Add(content); } - var children = root.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty) - .ToList(); - + var children = root.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty).ToList(); if (children.Count > 0) { contents.AddRange(CreateContentFromXml(children, content, importedContentTypes, typeService, service).WhereNotNull()); } } + return contents; } - private IEnumerable CreateContentFromXml( + private IEnumerable CreateContentFromXml( IEnumerable children, - T parent, - IDictionary importedContentTypes, - IContentTypeBaseService typeService, - IContentServiceBase service) - where T : class, IContentBase - where S : IContentTypeComposition + TContentBase parent, + IDictionary importedContentTypes, + IContentTypeBaseService typeService, + IContentServiceBase service) + where TContentBase : class, IContentBase + where TContentTypeComposition : IContentTypeComposition { - var list = new List(); + var list = new List(); + foreach (var child in children) { string contentTypeAlias = child.Name.LocalName; - if (importedContentTypes.ContainsKey(contentTypeAlias) == false) { var contentType = FindContentTypeByAlias(contentTypeAlias, typeService); + importedContentTypes.Add(contentTypeAlias, contentType); } - //Create and add the child to the list + // Create and add the child to the list if (TryCreateContentFromXml(child, importedContentTypes[contentTypeAlias], parent, default, service, out var content)) { list.Add(content); } - //Recursive call - var child1 = child; - var grandChildren = (from grand in child1.Elements() - where (string)grand.Attribute("isDoc") == "" - select grand).ToList(); - + // Recursive call + var grandChildren = child.Elements().Where(x => (string)x.Attribute("isDoc") == string.Empty).ToList(); if (grandChildren.Any()) + { list.AddRange(CreateContentFromXml(grandChildren, content, importedContentTypes, typeService, service)); + } } return list; } - private bool TryCreateContentFromXml( + private bool TryCreateContentFromXml( XElement element, - S contentType, - T parent, + TContentTypeComposition contentType, + TContentBase parent, int parentId, - IContentServiceBase service, - out T output) - where T : class, IContentBase - where S : IContentTypeComposition + IContentServiceBase service, + out TContentBase output) + where TContentBase : class, IContentBase + where TContentTypeComposition : IContentTypeComposition { Guid key = element.RequiredAttributeValue("key"); @@ -317,14 +305,14 @@ namespace Umbraco.Cms.Infrastructure.Packaging } } - T content = CreateContent( + TContentBase content = CreateContent( nodeName, parent, parentId, contentType, key, - int.Parse(level), - int.Parse(sortOrder), + int.Parse(level, CultureInfo.InvariantCulture), + int.Parse(sortOrder, CultureInfo.InvariantCulture), template?.Id); // Handle culture specific node names @@ -384,34 +372,34 @@ namespace Umbraco.Cms.Infrastructure.Packaging return true; } - private T CreateContent(string name, T parent, int parentId, S contentType, Guid key, int level, int sortOrder, int? templateId) - where T : class, IContentBase - where S : IContentTypeComposition + private TContentBase CreateContent(string name, TContentBase parent, int parentId, TContentTypeComposition contentType, Guid key, int level, int sortOrder, int? templateId) + where TContentBase : class, IContentBase + where TContentTypeComposition : IContentTypeComposition { switch (contentType) { case IContentType c: if (parent is null) { - return new Content(name, parentId, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as T; + return new Content(name, parentId, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as TContentBase; } else { - return new Content(name, (IContent)parent, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as T; + return new Content(name, (IContent)parent, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as TContentBase; } case IMediaType m: if (parent is null) { - return new Core.Models.Media(name, parentId, m) { Key = key, Level = level, SortOrder = sortOrder, } as T; + return new Core.Models.Media(name, parentId, m) { Key = key, Level = level, SortOrder = sortOrder, } as TContentBase; } else { - return new Core.Models.Media(name, (IMedia)parent, m) { Key = key, Level = level, SortOrder = sortOrder, } as T; + return new Core.Models.Media(name, (IMedia)parent, m) { Key = key, Level = level, SortOrder = sortOrder, } as TContentBase; } default: - throw new NotSupportedException($"Type {typeof(S)} is not supported"); + throw new NotSupportedException($"Type {typeof(TContentTypeComposition)} is not supported"); } } @@ -420,9 +408,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging #region DocumentTypes public IReadOnlyList ImportDocumentType(XElement docTypeElement, int userId) - { - return ImportDocumentTypes(new[] { docTypeElement }, userId); - } + => ImportDocumentTypes(new[] { docTypeElement }, userId); /// /// Imports and saves package xml as @@ -431,9 +417,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// Optional id of the User performing the operation. Default is zero (admin). /// An enumerable list of generated ContentTypes public IReadOnlyList ImportDocumentTypes(IEnumerable docTypeElements, int userId) - { - return ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService); - } + => ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService); /// /// Imports and saves package xml as @@ -443,7 +427,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// Optional id of the User performing the operation. Default is zero (admin). /// An enumerable list of generated ContentTypes public IReadOnlyList ImportDocumentTypes(IReadOnlyCollection unsortedDocumentTypes, bool importStructure, int userId, IContentTypeBaseService service) - where T : class, IContentTypeComposition + where T : class, IContentTypeComposition { var importedContentTypes = new Dictionary(); @@ -768,8 +752,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging return contentType; } - private void UpdateContentTypesAllowedTemplates(IContentType contentType, - XElement allowedTemplatesElement, XElement defaultTemplateElement) + private void UpdateContentTypesAllowedTemplates(IContentType contentType, XElement allowedTemplatesElement, XElement defaultTemplateElement) { if (allowedTemplatesElement != null && allowedTemplatesElement.Elements("Template").Any()) { @@ -837,7 +820,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging propertyGroup.Type = type; } - if (int.TryParse(propertyGroupElement.Element("SortOrder")?.Value, out var sortOrder)) + if (int.TryParse(propertyGroupElement.Element("SortOrder")?.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var sortOrder)) { // Override the sort order with the imported value propertyGroup.SortOrder = sortOrder; @@ -901,7 +884,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging var sortOrderElement = property.Element("SortOrder"); if (sortOrderElement != null) { - int.TryParse(sortOrderElement.Value, out sortOrder); + int.TryParse(sortOrderElement.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out sortOrder); } var propertyType = new PropertyType(_shortStringHelper, dataTypeDefinition, property.Element("Alias").Value) @@ -953,7 +936,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging } private T UpdateContentTypesStructure(T contentType, XElement structureElement, IReadOnlyDictionary importedContentTypes, IContentTypeBaseService service) - where T : IContentTypeComposition + where T : IContentTypeComposition { var allowedChildren = contentType.AllowedContentTypes.ToList(); int sortOrder = allowedChildren.Any() ? allowedChildren.Last().SortOrder : 0; @@ -986,8 +969,8 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// /// /// - private S FindContentTypeByAlias(string contentTypeAlias, IContentTypeBaseService typeService) - where S : IContentTypeComposition + private T FindContentTypeByAlias(string contentTypeAlias, IContentTypeBaseService typeService) + where T : IContentTypeComposition { var contentType = typeService.Get(contentTypeAlias); @@ -1207,12 +1190,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging } private static bool DictionaryValueIsNew(IEnumerable translations, XElement valueElement) - { - return translations.All(t => - string.Compare(t.Language.IsoCode, valueElement.Attribute("LanguageCultureAlias").Value, - StringComparison.InvariantCultureIgnoreCase) != 0 - ); - } + => translations.All(t => string.Compare(t.Language.IsoCode, valueElement.Attribute("LanguageCultureAlias").Value, StringComparison.InvariantCultureIgnoreCase) != 0); private static void AddDictionaryTranslation(ICollection translations, XElement valueElement, IEnumerable languages) { @@ -1231,7 +1209,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging #region Languages - /// /// Imports and saves the 'Languages' part of a package xml as a list of /// @@ -1270,7 +1247,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// public IReadOnlyList ImportMacros( IEnumerable macroElements, - IEnumerable macroPartialViewsElements, int userId) { var macros = macroElements.Select(ParseMacroElement).ToList(); @@ -1280,29 +1256,46 @@ namespace Umbraco.Cms.Infrastructure.Packaging _macroService.Save(macro, userId); } - ImportMacroPartialViews(macroPartialViewsElements); - return macros; } - private void ImportMacroPartialViews(IEnumerable viewElements) + public IReadOnlyList ImportMacroPartialViews(IEnumerable macroPartialViewsElements, int userId) { - foreach (XElement element in viewElements) + var result = new List(); + + foreach (XElement macroPartialViewXml in macroPartialViewsElements) { - var path = element.AttributeValue("path"); + var path = macroPartialViewXml.AttributeValue("path"); if (path == null) { throw new InvalidOperationException("No path attribute found"); } - var contents = element.Value ?? string.Empty; - var physicalPath = _hostingEnvironment.MapPathContentRoot(path); - // TODO: Do we overwrite? IMO I don't think so since these will be views a user will change. - if (!System.IO.File.Exists(physicalPath)) + // Remove prefix to maintain backwards compatibility + if (path.StartsWith(Constants.SystemDirectories.MacroPartials)) { - System.IO.File.WriteAllText(physicalPath, contents, Encoding.UTF8); + path = path.Substring(Constants.SystemDirectories.MacroPartials.Length); + } + else if (path.StartsWith("~")) + { + _logger.LogWarning("Importing macro partial views outside of the Views/MacroPartials directory is not supported: {Path}", path); + continue; + } + + IPartialView macroPartialView = _fileService.GetPartialViewMacro(path); + + // only update if it doesn't exist + if (macroPartialView == null) + { + var content = macroPartialViewXml.Value ?? string.Empty; + + macroPartialView = new PartialView(PartialViewType.PartialViewMacro, path) { Content = content }; + _fileService.SavePartialViewMacro(macroPartialView, userId); + result.Add(macroPartialView); } } + + return result; } private IMacro ParseMacroElement(XElement macroElement) @@ -1319,24 +1312,28 @@ namespace Umbraco.Cms.Infrastructure.Packaging { useInEditor = bool.Parse(useInEditorElement.Value); } + var cacheDurationElement = macroElement.Element("refreshRate"); var cacheDuration = 0; if (cacheDurationElement != null && string.IsNullOrEmpty((string)cacheDurationElement) == false) { - cacheDuration = int.Parse(cacheDurationElement.Value); + cacheDuration = int.Parse(cacheDurationElement.Value, CultureInfo.InvariantCulture); } + var cacheByMemberElement = macroElement.Element("cacheByMember"); var cacheByMember = false; if (cacheByMemberElement != null && string.IsNullOrEmpty((string)cacheByMemberElement) == false) { cacheByMember = bool.Parse(cacheByMemberElement.Value); } + var cacheByPageElement = macroElement.Element("cacheByPage"); var cacheByPage = false; if (cacheByPageElement != null && string.IsNullOrEmpty((string)cacheByPageElement) == false) { cacheByPage = bool.Parse(cacheByPageElement.Value); } + var dontRenderElement = macroElement.Element("dontRender"); var dontRender = true; if (dontRenderElement != null && string.IsNullOrEmpty((string)dontRenderElement) == false) @@ -1364,7 +1361,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging XAttribute sortOrderAttribute = property.Attribute("sortOrder"); if (sortOrderAttribute != null) { - sortOrder = int.Parse(sortOrderAttribute.Value); + sortOrder = int.Parse(sortOrderAttribute.Value, CultureInfo.InvariantCulture); } if (macro.Properties.Values.Any(x => string.Equals(x.Alias, propertyAlias, StringComparison.OrdinalIgnoreCase))) @@ -1380,6 +1377,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging sortOrder++; } } + return macro; } @@ -1392,7 +1390,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging foreach (XElement scriptXml in scriptElements) { var path = scriptXml.AttributeValue("path"); - if (path.IsNullOrWhiteSpace()) { continue; @@ -1456,7 +1453,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging foreach (XElement n in stylesheetElements) { var stylesheetPath = n.Element("FileName")?.Value; - if (stylesheetPath.IsNullOrWhiteSpace()) { continue; @@ -1497,9 +1493,11 @@ namespace Umbraco.Cms.Infrastructure.Packaging sp = newProp; } } + sp.Alias = alias; sp.Value = prop.Element("Value")?.Value; } + _fileService.SaveStylesheet(s, userId); result.Add(s); } @@ -1512,9 +1510,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging #region Templates public IEnumerable ImportTemplate(XElement templateElement, int userId) - { - return ImportTemplates(new[] { templateElement }, userId); - } + => ImportTemplates(new[] { templateElement }, userId); /// /// Imports and saves package xml as @@ -1564,6 +1560,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging var existingTemplate = _fileService.GetTemplate(alias) as Template; var template = existingTemplate ?? new Template(_shortStringHelper, templateName, alias); template.Content = design; + if (masterElement != null && string.IsNullOrEmpty((string)masterElement) == false) { template.MasterTemplateAlias = masterElement.Value; @@ -1571,6 +1568,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging if (masterTemplate != null) template.MasterTemplateId = new Lazy(() => masterTemplate.Id); } + templates.Add(template); } diff --git a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs index 5138a4c630..0af21b7eb2 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs @@ -41,23 +41,41 @@ namespace Umbraco.Cms.Infrastructure.Packaging InstallationSummary installationSummary = _packageDataInstallation.InstallPackageData(compiledPackage, userId); - //make sure the definition is up to date with everything + // Make sure the definition is up to date with everything (note: macro partial views are embedded in macros) foreach (var x in installationSummary.DataTypesInstalled) packageDefinition.DataTypes.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.LanguagesInstalled) packageDefinition.Languages.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.DictionaryItemsInstalled) packageDefinition.DictionaryItems.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.MacrosInstalled) packageDefinition.Macros.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.TemplatesInstalled) packageDefinition.Templates.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.DocumentTypesInstalled) packageDefinition.DocumentTypes.Add(x.Id.ToInvariantString()); + + foreach (var x in installationSummary.MediaTypesInstalled) + packageDefinition.MediaTypes.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.StylesheetsInstalled) - packageDefinition.Stylesheets.Add(x.Id.ToInvariantString()); - var contentInstalled = installationSummary.ContentInstalled.ToList(); - packageDefinition.ContentNodeId = contentInstalled.Count > 0 ? contentInstalled[0].Id.ToInvariantString() : null; + packageDefinition.Stylesheets.Add(x.Path); + + foreach (var x in installationSummary.ScriptsInstalled) + packageDefinition.Scripts.Add(x.Path); + + foreach (var x in installationSummary.PartialViewsInstalled) + packageDefinition.PartialViews.Add(x.Path); + + packageDefinition.ContentNodeId = installationSummary.ContentInstalled.FirstOrDefault()?.Id.ToInvariantString(); + + foreach (var x in installationSummary.MediaInstalled) + packageDefinition.MediaUdis.Add(x.GetUdi()); return installationSummary; } diff --git a/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs b/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs index c4876aef7c..fb5d00abfd 100644 --- a/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs @@ -1,35 +1,17 @@ -using System; +using System; using System.Data; using System.Data.Common; -using System.Linq; using Microsoft.Extensions.Logging; using StackExchange.Profiling.Data; using Umbraco.Cms.Core; using Umbraco.Cms.Infrastructure.Persistence.FaultHandling; -using Umbraco.Extensions; namespace Umbraco.Extensions { public static class DbConnectionExtensions { - public static string DetectProviderNameFromConnectionString(string connectionString) + public static bool IsConnectionAvailable(string connectionString, DbProviderFactory factory) { - var builder = new DbConnectionStringBuilder { ConnectionString = connectionString }; - var allKeys = builder.Keys.Cast(); - - if (allKeys.InvariantContains("Data Source") - //this dictionary is case insensitive - && builder["Data source"].ToString().InvariantContains(".sdf")) - { - return Cms.Core.Constants.DbProviderNames.SqlCe; - } - - return Cms.Core.Constants.DbProviderNames.SqlServer; - } - - public static bool IsConnectionAvailable(string connectionString, DbProviderFactory factory) - { - var connection = factory?.CreateConnection(); if (connection == null) @@ -42,7 +24,6 @@ namespace Umbraco.Extensions } } - public static bool IsAvailable(this IDbConnection connection) { try @@ -68,17 +49,25 @@ namespace Umbraco.Extensions internal static IDbConnection UnwrapUmbraco(this IDbConnection connection) { var unwrapped = connection; + IDbConnection c; do { c = unwrapped; - if (unwrapped is ProfiledDbConnection profiled) unwrapped = profiled.WrappedConnection; - if (unwrapped is RetryDbConnection retrying) unwrapped = retrying.Inner; - } while (c != unwrapped); + if (unwrapped is ProfiledDbConnection profiled) + { + unwrapped = profiled.WrappedConnection; + } + + if (unwrapped is RetryDbConnection retrying) + { + unwrapped = retrying.Inner; + } + } + while (c != unwrapped); return unwrapped; } - } } diff --git a/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs index 942368f5cb..e54c1f5fbc 100644 --- a/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Data.Common; using System.Linq; using NPoco; -using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; namespace Umbraco.Cms.Infrastructure.Persistence @@ -11,7 +10,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence public class DbProviderFactoryCreator : IDbProviderFactoryCreator { private readonly Func _getFactory; - private readonly IDictionary _embeddedDatabaseCreators; + private readonly IDictionary _databaseCreators; private readonly IDictionary _syntaxProviders; private readonly IDictionary _bulkSqlInsertProviders; private readonly IDictionary _providerSpecificMapperFactories; @@ -20,11 +19,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence Func getFactory, IEnumerable syntaxProviders, IEnumerable bulkSqlInsertProviders, - IEnumerable embeddedDatabaseCreators, + IEnumerable databaseCreators, IEnumerable providerSpecificMapperFactories) { _getFactory = getFactory; - _embeddedDatabaseCreators = embeddedDatabaseCreators.ToDictionary(x => x.ProviderName); + _databaseCreators = databaseCreators.ToDictionary(x => x.ProviderName); _syntaxProviders = syntaxProviders.ToDictionary(x => x.ProviderName); _bulkSqlInsertProviders = bulkSqlInsertProviders.ToDictionary(x => x.ProviderName); _providerSpecificMapperFactories = providerSpecificMapperFactories.ToDictionary(x => x.ProviderName); @@ -60,11 +59,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence return result; } - public void CreateDatabase(string providerName) + public void CreateDatabase(string providerName, string connectionString) { - if (_embeddedDatabaseCreators.TryGetValue(providerName, out var creator)) + if (_databaseCreators.TryGetValue(providerName, out var creator)) { - creator.Create(); + creator.Create(connectionString); } } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs index 26e371dbaf..a82a5ca748 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs @@ -1,4 +1,4 @@ -using System; +using System; using NPoco; using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; using Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions; @@ -35,6 +35,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos public bool IsActive { get; set; } [Column("isMaster")] - public bool IsMaster { get; set; } + public bool IsSchedulingPublisher { get; set; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs index 58819f306a..82bbb4a40a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Infrastructure.Persistence.Dtos; @@ -8,7 +9,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories { public static IIdentityUserToken BuildEntity(ExternalLoginTokenDto dto) { - var entity = new IdentityUserToken(dto.Id, dto.ExternalLoginDto.LoginProvider, dto.Name, dto.Value, dto.ExternalLoginDto.UserId.ToString(), dto.CreateDate); + var entity = new IdentityUserToken(dto.Id, dto.ExternalLoginDto.LoginProvider, dto.Name, dto.Value, dto.ExternalLoginDto.UserId.ToString(CultureInfo.InvariantCulture), dto.CreateDate); // reset dirty initial properties (U4-1946) entity.ResetDirtyProperties(false); @@ -17,7 +18,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories public static IIdentityUserLogin BuildEntity(ExternalLoginDto dto) { - var entity = new IdentityUserLogin(dto.Id, dto.LoginProvider, dto.ProviderKey, dto.UserId.ToString(), dto.CreateDate) + var entity = new IdentityUserLogin(dto.Id, dto.LoginProvider, dto.ProviderKey, dto.UserId.ToString(CultureInfo.InvariantCulture), dto.CreateDate) { UserData = dto.UserData }; @@ -35,7 +36,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories CreateDate = entity.CreateDate, LoginProvider = entity.LoginProvider, ProviderKey = entity.ProviderKey, - UserId = int.Parse(entity.UserId), // TODO: This is temp until we change the ext logins to use GUIDs + UserId = int.Parse(entity.UserId, CultureInfo.InvariantCulture), // TODO: This is temp until we change the ext logins to use GUIDs UserData = entity.UserData }; diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs index 960b809c74..7f73abacaa 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs @@ -50,7 +50,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories }; if (entity.HasIdentity) - dto.Id = int.Parse(entity.Id.ToString(CultureInfo.InvariantCulture)); + dto.Id = entity.Id; return dto; } diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs index 730c24f2f2..8df6d654b0 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Repositories; @@ -53,7 +54,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories { dto.IntegerValue = value != null && string.IsNullOrEmpty(value.ToString()) ? 0 : Convert.ToInt32(value); } - else if (value != null && string.IsNullOrWhiteSpace(value.ToString()) == false && int.TryParse(value.ToString(), out var val)) + else if (value != null && string.IsNullOrWhiteSpace(value.ToString()) == false && int.TryParse(value.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var val)) { dto.IntegerValue = val; } diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/ServerRegistrationFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/ServerRegistrationFactory.cs index 6a1aa48162..f662faf561 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/ServerRegistrationFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/ServerRegistrationFactory.cs @@ -1,4 +1,4 @@ -using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Infrastructure.Persistence.Dtos; namespace Umbraco.Cms.Infrastructure.Persistence.Factories @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories { public static ServerRegistration BuildEntity(ServerRegistrationDto dto) { - var model = new ServerRegistration(dto.Id, dto.ServerAddress, dto.ServerIdentity, dto.DateRegistered, dto.DateAccessed, dto.IsActive, dto.IsMaster); + var model = new ServerRegistration(dto.Id, dto.ServerAddress, dto.ServerIdentity, dto.DateRegistered, dto.DateAccessed, dto.IsActive, dto.IsSchedulingPublisher); // reset dirty initial properties (U4-1946) model.ResetDirtyProperties(false); return model; @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories ServerAddress = entity.ServerAddress, DateRegistered = entity.CreateDate, IsActive = entity.IsActive, - IsMaster = ((ServerRegistration) entity).IsMaster, + IsSchedulingPublisher = ((ServerRegistration) entity).IsSchedulingPublisher, DateAccessed = entity.UpdateDate, ServerIdentity = entity.ServerIdentity }; diff --git a/src/Umbraco.Infrastructure/Persistence/FaultHandling/ThrottlingCondition.cs b/src/Umbraco.Infrastructure/Persistence/FaultHandling/ThrottlingCondition.cs index 9905a35696..9155937fe0 100644 --- a/src/Umbraco.Infrastructure/Persistence/FaultHandling/ThrottlingCondition.cs +++ b/src/Umbraco.Infrastructure/Persistence/FaultHandling/ThrottlingCondition.cs @@ -263,7 +263,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling var match = sqlErrorCodeRegEx.Match(error.Message); int reasonCode; - if (match.Success && int.TryParse(match.Groups[1].Value, out reasonCode)) + if (match.Success && int.TryParse(match.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out reasonCode)) { return FromReasonCode(reasonCode); } diff --git a/src/Umbraco.Infrastructure/Persistence/IDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/IDatabaseCreator.cs new file mode 100644 index 0000000000..2d97cfbcd3 --- /dev/null +++ b/src/Umbraco.Infrastructure/Persistence/IDatabaseCreator.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Cms.Infrastructure.Persistence +{ + public interface IDatabaseCreator + { + string ProviderName { get; } + + void Create(string connectionString); + } +} diff --git a/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs index 99b7469085..6a38dc3c06 100644 --- a/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence DbProviderFactory CreateFactory(string providerName); ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName); IBulkSqlInsertProvider CreateBulkSqlInsertProvider(string providerName); - void CreateDatabase(string providerName); + void CreateDatabase(string providerName, string connectionString); NPocoMapperCollection ProviderSpecificMappers(string providerName); } } diff --git a/src/Umbraco.Infrastructure/Persistence/IEmbeddedDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/IEmbeddedDatabaseCreator.cs deleted file mode 100644 index 2461644d0a..0000000000 --- a/src/Umbraco.Infrastructure/Persistence/IEmbeddedDatabaseCreator.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Umbraco.Cms.Infrastructure.Persistence -{ - public interface IEmbeddedDatabaseCreator - { - string ProviderName { get; } - string ConnectionString { get; set; } - void Create(); - } -} diff --git a/src/Umbraco.Infrastructure/Persistence/Mappers/ServerRegistrationMapper.cs b/src/Umbraco.Infrastructure/Persistence/Mappers/ServerRegistrationMapper.cs index f35116ee81..61b597be46 100644 --- a/src/Umbraco.Infrastructure/Persistence/Mappers/ServerRegistrationMapper.cs +++ b/src/Umbraco.Infrastructure/Persistence/Mappers/ServerRegistrationMapper.cs @@ -1,4 +1,4 @@ -using System; +using System; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Infrastructure.Persistence.Dtos; @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Mappers { DefineMap(nameof(ServerRegistration.Id), nameof(ServerRegistrationDto.Id)); DefineMap(nameof(ServerRegistration.IsActive), nameof(ServerRegistrationDto.IsActive)); - DefineMap(nameof(ServerRegistration.IsMaster), nameof(ServerRegistrationDto.IsMaster)); + DefineMap(nameof(ServerRegistration.IsSchedulingPublisher), nameof(ServerRegistrationDto.IsSchedulingPublisher)); DefineMap(nameof(ServerRegistration.ServerAddress), nameof(ServerRegistrationDto.ServerAddress)); DefineMap(nameof(ServerRegistration.CreateDate), nameof(ServerRegistrationDto.DateRegistered)); DefineMap(nameof(ServerRegistration.UpdateDate), nameof(ServerRegistrationDto.DateAccessed)); diff --git a/src/Umbraco.Infrastructure/Persistence/NoopEmbeddedDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/NoopEmbeddedDatabaseCreator.cs deleted file mode 100644 index fd378d44bc..0000000000 --- a/src/Umbraco.Infrastructure/Persistence/NoopEmbeddedDatabaseCreator.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Umbraco.Cms.Infrastructure.Persistence -{ - public class NoopEmbeddedDatabaseCreator : IEmbeddedDatabaseCreator - { - public string ProviderName => Cms.Core.Constants.DatabaseProviders.SqlServer; - - public string ConnectionString { get; set; } - - public void Create() - { - - } - } -} diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs index c72e11f595..239f0a89ed 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; @@ -532,7 +533,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement currentParentIds.Add(node.NodeId); // paths parts without the roots - var pathParts = node.Path.Split(Constants.CharArrays.Comma).Where(x => !rootIds.Contains(int.Parse(x))).ToArray(); + var pathParts = node.Path.Split(Constants.CharArrays.Comma).Where(x => !rootIds.Contains(int.Parse(x, CultureInfo.InvariantCulture))).ToArray(); if (!prevParentIds.Contains(node.ParentId)) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index f9e8316f70..d93c2c8322 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -1344,7 +1344,7 @@ WHERE cmsContentType." + aliasColumn + @" LIKE @pattern", /// public bool HasContainerInPath(string contentPath) { - var ids = contentPath.Split(Constants.CharArrays.Comma).Select(int.Parse).ToArray(); + var ids = contentPath.Split(Constants.CharArrays.Comma).Select(s => int.Parse(s, CultureInfo.InvariantCulture)).ToArray(); return HasContainerInPath(ids); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs index 0353106e17..1ed8404f78 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using NPoco; @@ -941,7 +942,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement if (content.ParentId == -1) return content.Published; - var ids = content.Path.Split(Constants.CharArrays.Comma).Skip(1).Select(int.Parse); + var ids = content.Path.Split(Constants.CharArrays.Comma).Skip(1).Select(s => int.Parse(s, CultureInfo.InvariantCulture)); var sql = SqlContext.Sql() .SelectCount(x => x.NodeId) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs index 8dc8a7783d..116ec356b7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using Umbraco.Extensions; @@ -188,7 +189,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { var match = matches[0]; Text = match.Groups[1].Value; - int number = int.TryParse(match.Groups[2].Value, out number) ? number : 0; + int number = int.TryParse(match.Groups[2].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out number) ? number : 0; Suffix = (uint?)(number); return; diff --git a/src/Umbraco.Infrastructure/Persistence/SqlServerDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/SqlServerDatabaseCreator.cs new file mode 100644 index 0000000000..e7f5934e78 --- /dev/null +++ b/src/Umbraco.Infrastructure/Persistence/SqlServerDatabaseCreator.cs @@ -0,0 +1,63 @@ +using System; +using System.Data.SqlClient; +using System.IO; +using Umbraco.Cms.Core; + +namespace Umbraco.Cms.Infrastructure.Persistence +{ + public class SqlServerDatabaseCreator : IDatabaseCreator + { + public string ProviderName => Constants.DatabaseProviders.SqlServer; + + public void Create(string connectionString) + { + var builder = new SqlConnectionStringBuilder(connectionString); + + // Get connection string without database specific information + var masterBuilder = new SqlConnectionStringBuilder(builder.ConnectionString) + { + AttachDBFilename = string.Empty, + InitialCatalog = string.Empty + }; + var masterConnectionString = masterBuilder.ConnectionString; + + string fileName = builder.AttachDBFilename, + database = builder.InitialCatalog; + + // Create database + if (!string.IsNullOrEmpty(fileName) && !File.Exists(fileName)) + { + if (string.IsNullOrWhiteSpace(database)) + { + // Use a temporary database name + database = "Umbraco-" + Guid.NewGuid(); + } + + using var connection = new SqlConnection(masterConnectionString); + connection.Open(); + + using var command = new SqlCommand( + $"CREATE DATABASE [{database}] ON (NAME='{database}', FILENAME='{fileName}');" + + $"ALTER DATABASE [{database}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;" + + $"EXEC sp_detach_db @dbname='{database}';", + connection); + command.ExecuteNonQuery(); + + connection.Close(); + } + else if (!string.IsNullOrEmpty(database)) + { + using var connection = new SqlConnection(masterConnectionString); + connection.Open(); + + using var command = new SqlCommand( + $"IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = '{database}') " + + $"CREATE DATABASE [{database}];", + connection); + command.ExecuteNonQuery(); + + connection.Close(); + } + } + } +} diff --git a/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs index 756490c531..c16e5a75ab 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs @@ -3,12 +3,12 @@ using System.Data.Common; using System.Linq; using Microsoft.Extensions.Options; using NPoco; -using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; namespace Umbraco.Cms.Infrastructure.Persistence { + [Obsolete("This is only used for integration tests and should be moved into a test project.")] public class SqlServerDbProviderFactoryCreator : IDbProviderFactoryCreator { private readonly Func _getFactory; @@ -23,35 +23,29 @@ namespace Umbraco.Cms.Infrastructure.Persistence public DbProviderFactory CreateFactory(string providerName) { if (string.IsNullOrEmpty(providerName)) return null; + return _getFactory(providerName); } // gets the sql syntax provider that corresponds, from attribute public ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName) - { - return providerName switch + => providerName switch { Cms.Core.Constants.DbProviderNames.SqlCe => throw new NotSupportedException("SqlCe is not supported"), Cms.Core.Constants.DbProviderNames.SqlServer => new SqlServerSyntaxProvider(_globalSettings), _ => throw new InvalidOperationException($"Unknown provider name \"{providerName}\""), }; - } public IBulkSqlInsertProvider CreateBulkSqlInsertProvider(string providerName) - { - switch (providerName) + => providerName switch { - case Cms.Core.Constants.DbProviderNames.SqlCe: - throw new NotSupportedException("SqlCe is not supported"); - case Cms.Core.Constants.DbProviderNames.SqlServer: - return new SqlServerBulkSqlInsertProvider(); - default: - return new BasicBulkSqlInsertProvider(); - } - } + Cms.Core.Constants.DbProviderNames.SqlCe => throw new NotSupportedException("SqlCe is not supported"), + Cms.Core.Constants.DbProviderNames.SqlServer => new SqlServerBulkSqlInsertProvider(), + _ => new BasicBulkSqlInsertProvider(), + }; - public void CreateDatabase(string providerName) - => throw new NotSupportedException("Embedded databases are not supported"); + public void CreateDatabase(string providerName, string connectionString) + => throw new NotSupportedException("Embedded databases are not supported"); // TODO But LocalDB is? public NPocoMapperCollection ProviderSpecificMappers(string providerName) => new NPocoMapperCollection(() => Enumerable.Empty()); diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs index 529144953d..80970ec637 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs @@ -7,7 +7,6 @@ using System.Text; using Microsoft.Extensions.Logging; using NPoco; using StackExchange.Profiling; -using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Infrastructure.Migrations.Install; using Umbraco.Cms.Infrastructure.Persistence.FaultHandling; using Umbraco.Extensions; @@ -62,6 +61,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence _connectionRetryPolicy = connectionRetryPolicy; _commandRetryPolicy = commandRetryPolicy; _mapperCollection = mapperCollection; + Init(); } @@ -79,6 +79,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence SqlContext = sqlContext; _logger = logger; _bulkSqlInsertProvider = bulkSqlInsertProvider; + Init(); } @@ -86,6 +87,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence { EnableSqlTrace = EnableSqlTraceDefault; NPocoDatabaseExtensions.ConfigureNPocoBulkExtensions(); + if (_mapperCollection != null) { Mappers.AddRange(_mapperCollection); @@ -104,11 +106,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence { var command = base.CreateCommand(connection, commandType, sql, args); - if (!DatabaseType.IsSqlCe()) return command; + if (!DatabaseType.IsSqlCe()) + return command; foreach (DbParameter parameter in command.Parameters) + { if (parameter.Value == DBNull.Value) parameter.DbType = DbType.String; + } return command; } @@ -128,17 +133,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence #endif /// - public string InstanceId - { - get - { + public string InstanceId => #if DEBUG_DATABASES - return _instanceGuid.ToString("N").Substring(0, 8) + ':' + _spid; + _instanceGuid.ToString("N").Substring(0, 8) + ':' + _spid; #else - return _instanceId ?? (_instanceId = _instanceGuid.ToString("N").Substring(0, 8)); + _instanceId ??= _instanceGuid.ToString("N").Substring(0, 8); #endif - } - } /// public bool InTransaction { get; private set; } @@ -175,8 +175,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence set { _enableCount = value; + if (_enableCount == false) + { SqlCount = 0; + } } } @@ -193,11 +196,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence internal IEnumerable Commands => _commands; - public int BulkInsertRecords(IEnumerable records) - { - return _bulkSqlInsertProvider.BulkInsertRecords(this, records); - - } + public int BulkInsertRecords(IEnumerable records) => _bulkSqlInsertProvider.BulkInsertRecords(this, records); /// /// Returns the for the database @@ -206,6 +205,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence { var dbSchema = _databaseSchemaCreatorFactory.Create(this); var databaseSchemaValidationResult = dbSchema.ValidateSchema(); + return databaseSchemaValidationResult; } @@ -263,8 +263,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence { _logger.LogError(ex, "Exception ({InstanceId}).", InstanceId); _logger.LogDebug("At:\r\n{StackTrace}", Environment.StackTrace); + if (EnableSqlTrace == false) _logger.LogDebug("Sql:\r\n{Sql}", CommandToString(LastSQL, LastArgs)); + base.OnException(ex); } @@ -287,22 +289,22 @@ namespace Umbraco.Cms.Infrastructure.Persistence #endif _cmd = cmd; + base.OnExecutingCommand(cmd); } - private string CommandToString(DbCommand cmd) - { - return CommandToString(cmd.CommandText, cmd.Parameters.Cast().Select(x => x.Value).ToArray()); - } + private string CommandToString(DbCommand cmd) => CommandToString(cmd.CommandText, cmd.Parameters.Cast().Select(x => x.Value).ToArray()); private string CommandToString(string sql, object[] args) { var text = new StringBuilder(); #if DEBUG_DATABASES - text.Append(InstanceId); - text.Append(": "); + text.Append(InstanceId); + text.Append(": "); #endif + NPocoSqlExtensions.ToText(sql, args, text); + return text.ToString(); } @@ -325,11 +327,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence { Text = cmd.CommandText; var parameters = new List(); - foreach (IDbDataParameter parameter in cmd.Parameters) parameters.Add(new ParameterInfo(parameter)); + foreach (IDbDataParameter parameter in cmd.Parameters) + parameters.Add(new ParameterInfo(parameter)); + Parameters = parameters.ToArray(); } public string Text { get; } + public ParameterInfo[] Parameters { get; } } diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs index 6dfe2ada6b..299aff2caa 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs @@ -96,7 +96,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence _loggerFactory = loggerFactory; var settings = connectionStrings.CurrentValue.UmbracoConnectionString; - if (settings == null) { logger.LogDebug("Missing connection string, defer configuration."); @@ -105,9 +104,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence // could as well be // so need to test the values too - var connectionString = settings.ConnectionString; - var providerName = settings.ProviderName; - if (string.IsNullOrWhiteSpace(connectionString) || string.IsNullOrWhiteSpace(providerName)) + if (settings.IsConnectionStringConfigured() == false) { logger.LogDebug("Empty connection string or provider name, defer configuration."); return; // not configured @@ -148,7 +145,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence private void UpdateSqlServerDatabaseType() { // replace NPoco database type by a more efficient one - var setting = _globalSettings.Value.DatabaseFactoryServerVersion; var fromSettings = false; @@ -188,6 +184,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence { // must be initialized to have a context EnsureInitialized(); + return _sqlContext; } } @@ -199,15 +196,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence { // must be initialized to have a bulk insert provider EnsureInitialized(); + return _bulkSqlInsertProvider; } } /// - public void ConfigureForUpgrade() - { - _upgrading = true; - } + public void ConfigureForUpgrade() => _upgrading = true; /// public void Configure(string connectionString, string providerName) @@ -248,13 +243,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence throw new Exception($"Can't find a provider factory for provider name \"{_providerName}\"."); } - // cannot initialize without being able to talk to the database - // TODO: Why not? - if (!DbConnectionExtensions.IsConnectionAvailable(ConnectionString, DbProviderFactory)) - { - throw new Exception("Cannot connect to the database."); - } - _connectionRetryPolicy = RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(ConnectionString); _commandRetryPolicy = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(ConnectionString); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs index 82b1305fe4..4c85277781 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using System; +using System.Globalization; using System.Linq; using System.Text; using HtmlAgilityPack; @@ -110,7 +111,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters foreach (var img in imgNodes) { var nodeId = img.GetAttributeValue("rel", string.Empty); - if (int.TryParse(nodeId, out _)) + if (int.TryParse(nodeId, NumberStyles.Integer, CultureInfo.InvariantCulture, out _)) { img.Attributes.Remove("rel"); modified = true; diff --git a/src/Umbraco.Infrastructure/PublishedContentQuery.cs b/src/Umbraco.Infrastructure/PublishedContentQuery.cs index 14298cbb4e..e149e092d8 100644 --- a/src/Umbraco.Infrastructure/PublishedContentQuery.cs +++ b/src/Umbraco.Infrastructure/PublishedContentQuery.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Xml.XPath; using Examine; @@ -43,7 +44,7 @@ namespace Umbraco.Cms.Infrastructure switch (id) { case string s: - return int.TryParse(s, out intId); + return int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out intId); case int i: intId = i; @@ -233,11 +234,6 @@ namespace Umbraco.Cms.Infrastructure string indexName = Constants.UmbracoIndexes.ExternalIndexName) => Search(term, 0, 0, out _, culture, indexName); - /// - public IEnumerable Search(string term, int skip, int take, out long totalRecords, - string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName) - => Search(term, skip, take, out totalRecords, culture, indexName, null); - /// public IEnumerable Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName, ISet loadedFields = null) { diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index 597a8901da..86f4e070c2 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -12,8 +12,6 @@ using Umbraco.Cms.Core.Logging; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Runtime; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.Migrations.Install; -using Umbraco.Cms.Infrastructure.Migrations.Upgrade; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Extensions; @@ -96,8 +94,6 @@ namespace Umbraco.Cms.Infrastructure.Runtime _logger.LogError(exception, msg); }; - AppDomain.CurrentDomain.SetData("DataDirectory", _hostingEnvironment?.MapPathContentRoot(Constants.SystemDirectories.Data)); - // acquire the main domain - if this fails then anything that should be registered with MainDom will not operate AcquireMainDom(); diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs index d91a3de4bf..8eab08bfee 100644 --- a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -13,6 +12,7 @@ using Umbraco.Cms.Core.Semver; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Migrations.Upgrade; using Umbraco.Cms.Infrastructure.Persistence; +using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Runtime { @@ -110,7 +110,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime // cannot connect to configured database, this is bad, fail _logger.LogDebug("Could not connect to database."); - if (_globalSettings.Value.InstallMissingDatabase) + if (_globalSettings.Value.InstallMissingDatabase || CanAutoInstallMissingDatabase(_databaseFactory)) { // ok to install on a configured but missing database Level = RuntimeLevel.Install; @@ -173,6 +173,17 @@ namespace Umbraco.Cms.Infrastructure.Runtime } } + public void Configure(RuntimeLevel level, RuntimeLevelReason reason, Exception bootFailedException = null) + { + Level = level; + Reason = reason; + + if (bootFailedException != null) + { + BootFailedException = new BootFailedException(bootFailedException.Message, bootFailedException); + } + } + private enum UmbracoDatabaseState { Ok, @@ -233,17 +244,6 @@ namespace Umbraco.Cms.Infrastructure.Runtime } } - public void Configure(RuntimeLevel level, RuntimeLevelReason reason, Exception bootFailedException = null) - { - Level = level; - Reason = reason; - - if (bootFailedException != null) - { - BootFailedException = new BootFailedException(bootFailedException.Message, bootFailedException); - } - } - private bool DoesUmbracoRequireUpgrade(IReadOnlyDictionary keyValues) { var upgrader = new Upgrader(new UmbracoPlan(_umbracoVersion)); @@ -277,6 +277,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime return canConnect; } - + private bool CanAutoInstallMissingDatabase(IUmbracoDatabaseFactory databaseFactory) + => databaseFactory.ProviderName == Constants.DatabaseProviders.SqlCe || + databaseFactory.ConnectionString?.InvariantContains("(localdb)") == true; } } diff --git a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs index 5e4597903a..845a0f506e 100644 --- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs @@ -40,7 +40,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime private bool _errorDuringAcquiring; private readonly object _locker = new object(); private bool _hasTable = false; - + private bool _acquireWhenTablesNotAvailable = false; + public SqlMainDomLock( ILogger logger, ILoggerFactory loggerFactory, @@ -99,7 +100,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime _hasTable = db.HasTable(Cms.Core.Constants.DatabaseSchema.Tables.KeyValue); if (!_hasTable) { - // the Db does not contain the required table, we must be in an install state we have no choice but to assume we can acquire + _logger.LogDebug("The DB does not contain the required table so we must be in an install state. We have no choice but to assume we can acquire."); + _acquireWhenTablesNotAvailable = true; return true; } @@ -225,6 +227,13 @@ namespace Umbraco.Cms.Infrastructure.Runtime } } + // In case we acquired the main dom doing install when there was no database. We therefore have to insert our lockId now, but only handle this once. + if (_acquireWhenTablesNotAvailable) + { + _acquireWhenTablesNotAvailable = false; + InsertLockRecord(_lockId, db); + } + db.BeginTransaction(IsolationLevel.ReadCommitted); // get a read lock _sqlServerSyntax.ReadLock(db, Cms.Core.Constants.Locks.MainDom); @@ -434,7 +443,10 @@ namespace Umbraco.Cms.Infrastructure.Runtime private bool IsMainDomValue(string val, IUmbracoDatabase db) { return db.ExecuteScalar("SELECT COUNT(*) FROM umbracoKeyValue WHERE [key] = @key AND [value] = @val", - new { key = MainDomKey, val = val }) == 1; + new { key = MainDomKey, val = val }) == 1; + + + } /// @@ -447,6 +459,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime #region IDisposable Support private bool _disposedValue = false; // To detect redundant calls + protected virtual void Dispose(bool disposing) { if (!_disposedValue) diff --git a/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs b/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs index e3ddc69e6f..ebd12719e1 100644 --- a/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Identity; using Umbraco.Cms.Core.Configuration.Models; @@ -157,6 +158,6 @@ namespace Umbraco.Cms.Core.Security Roles = roles; } - private static string UserIdToString(int userId) => string.Intern(userId.ToString()); + private static string UserIdToString(int userId) => string.Intern(userId.ToString(CultureInfo.InvariantCulture)); } } diff --git a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs index deb85ff496..e656e68193 100644 --- a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; +using System.Globalization; using System.Linq; using System.Security.Claims; using System.Threading; @@ -133,15 +134,14 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(user)); } - Attempt asInt = user.Id.TryConvertTo(); - if (asInt == false) + if (!int.TryParse(user.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var asInt)) { throw new InvalidOperationException("The user id must be an integer to work with the Umbraco"); } using (IScope scope = _scopeProvider.CreateScope()) { - IUser found = _userService.GetUserById(asInt.Result); + IUser found = _userService.GetUserById(asInt); if (found != null) { // we have to remember whether Logins property is dirty, since the UpdateMemberProperties will reset it. @@ -441,7 +441,7 @@ namespace Umbraco.Cms.Core.Security if (identityUser.IsPropertyDirty(nameof(BackOfficeIdentityUser.InviteDateUtc)) || (user.InvitedDate?.ToUniversalTime() != identityUser.InviteDateUtc)) { - anythingChanged = true; + anythingChanged = true; user.InvitedDate = identityUser.InviteDateUtc?.ToLocalTime(); } @@ -482,6 +482,12 @@ namespace Umbraco.Cms.Core.Security user.FailedPasswordAttempts = identityUser.AccessFailedCount; } + if (user.IsApproved != identityUser.IsApproved) + { + anythingChanged = true; + user.IsApproved = identityUser.IsApproved; + } + if (user.IsLockedOut != identityUser.IsLockedOut) { anythingChanged = true; diff --git a/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs b/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs index 724eb77030..9e29316056 100644 --- a/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs +++ b/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Extensions; @@ -11,7 +12,7 @@ namespace Umbraco.Cms.Core.Security /// public class MemberIdentityUser : UmbracoIdentityUser { - private string _comments; + private string _comments; // Custom comparer for enumerables private static readonly DelegateEqualityComparer> s_groupsComparer = new DelegateEqualityComparer>( @@ -77,7 +78,7 @@ namespace Umbraco.Cms.Core.Security /// public string MemberTypeAlias { get; set; } - private static string UserIdToString(int userId) => string.Intern(userId.ToString()); + private static string UserIdToString(int userId) => string.Intern(userId.ToString(CultureInfo.InvariantCulture)); // TODO: Should we support custom member properties for persistence/retrieval? } diff --git a/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs b/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs index 685a21d175..03339fbd33 100644 --- a/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs +++ b/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -71,7 +72,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(role)); } - if (!int.TryParse(role.Id, out int roleId)) + if (!int.TryParse(role.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out int roleId)) { return Task.FromResult(IdentityResult.Failed(_intParseError)); } @@ -103,7 +104,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(role)); } - if (!int.TryParse(role.Id, out int roleId)) + if (!int.TryParse(role.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out int roleId)) { throw new ArgumentException("The Id of the role is not an integer"); } @@ -184,7 +185,7 @@ namespace Umbraco.Cms.Core.Security IMemberGroup memberGroup; // member group can be found by int or Guid, so try both - if (!int.TryParse(roleId, out int id)) + if (!int.TryParse(roleId, NumberStyles.Integer, CultureInfo.InvariantCulture, out int id)) { if (!Guid.TryParse(roleId, out Guid guid)) { diff --git a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs index 70cfcc3bfb..086ff6a66c 100644 --- a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -116,16 +117,14 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(user)); } - Attempt asInt = user.Id.TryConvertTo(); - if (asInt == false) + if (!int.TryParse(user.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var asInt)) { //TODO: should this be thrown, or an identity result? - throw new InvalidOperationException("The user id must be an integer to work with Umbraco"); + throw new InvalidOperationException("The user id must be an integer to work with the Umbraco"); } - using IScope scope = _scopeProvider.CreateScope(autoComplete: true); - IMember found = _memberService.GetById(asInt.Result); + IMember found = _memberService.GetById(asInt); if (found != null) { // we have to remember whether Logins property is dirty, since the UpdateMemberProperties will reset it. diff --git a/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs b/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs index 3884ee31a1..6a2325c316 100644 --- a/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Security.Claims; using System.Threading; @@ -28,16 +29,15 @@ namespace Umbraco.Cms.Core.Security protected static int UserIdToInt(string userId) { - Attempt attempt = userId.TryConvertTo(); - if (attempt.Success) + if(int.TryParse(userId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { - return attempt.Result; + return result; } - throw new InvalidOperationException("Unable to convert user ID to int", attempt.Exception); + throw new InvalidOperationException($"Unable to convert user ID ({userId})to int using InvariantCulture"); } - protected static string UserIdToString(int userId) => string.Intern(userId.ToString()); + protected static string UserIdToString(int userId) => string.Intern(userId.ToString(CultureInfo.InvariantCulture)); /// /// Not supported in Umbraco diff --git a/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs b/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs index e0c0f56244..a037cd1095 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs @@ -151,7 +151,7 @@ namespace Umbraco.Cms.Core.Services.Implement switch (serverRole) { case ServerRole.Single: - case ServerRole.Master: + case ServerRole.SchedulingPublisher: PruneOldInstructions(); instructionsWerePruned = true; break; diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs index dceae58446..15490bcd04 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs @@ -535,7 +535,8 @@ namespace Umbraco.Cms.Core.Services.Implement var rootId = Cms.Core.Constants.System.RootString; var ids = content.Path.Split(Constants.CharArrays.Comma) - .Where(x => x != rootId && x != content.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray(); + .Where(x => x != rootId && x != content.Id.ToString(CultureInfo.InvariantCulture)).Select(s => + int.Parse(s, CultureInfo.InvariantCulture)).ToArray(); if (ids.Any() == false) return new List(); diff --git a/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs b/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs index 259d6e8739..079971be24 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.Events; @@ -25,7 +26,7 @@ namespace Umbraco.Cms.Core.Services.Implement using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { // TODO: This is temp until we update the external service to support guids for both users and members - var asString = userId.ToString(); + var asString = userId.ToString(CultureInfo.InvariantCulture); return _externalLoginRepository.Get(Query().Where(x => x.UserId == asString)) .ToList(); } @@ -36,7 +37,7 @@ namespace Umbraco.Cms.Core.Services.Implement using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { // TODO: This is temp until we update the external service to support guids for both users and members - var asString = userId.ToString(); + var asString = userId.ToString(CultureInfo.InvariantCulture); return _externalLoginRepository.Get(Query().Where(x => x.UserId == asString)) .ToList(); } diff --git a/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs b/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs index 0239ad8e60..0aa49cde44 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs @@ -485,7 +485,7 @@ namespace Umbraco.Cms.Core.Services.Implement var rootId = Cms.Core.Constants.System.RootString; var ids = media.Path.Split(Constants.CharArrays.Comma) .Where(x => x != rootId && x != media.Id.ToString(CultureInfo.InvariantCulture)) - .Select(int.Parse) + .Select(s => int.Parse(s, CultureInfo.InvariantCulture)) .ToArray(); if (ids.Any() == false) return new List(); diff --git a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs index dc45319d12..447143092a 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs @@ -83,7 +83,7 @@ namespace Umbraco.Cms.Core.Services.Implement if (entitiesL.Count == 0) return; //put all entity's paths into a list with the same indices - var paths = entitiesL.Select(x => x.Path.Split(Constants.CharArrays.Comma).Select(int.Parse).ToArray()).ToArray(); + var paths = entitiesL.Select(x => x.Path.Split(Constants.CharArrays.Comma).Select(s => int.Parse(s, CultureInfo.InvariantCulture)).ToArray()).ToArray(); // lazily get versions var prevVersionDictionary = new Dictionary(); diff --git a/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs b/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs index 419881fe1c..90184cd258 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.Events; @@ -57,7 +58,7 @@ namespace Umbraco.Cms.Core.Services.Implement //Get all ids in the path for the content item and ensure they all // parse to ints that are not -1. var ids = contentPath.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries) - .Select(x => int.TryParse(x, out int val) ? val : -1) + .Select(x => int.TryParse(x, NumberStyles.Integer, CultureInfo.InvariantCulture, out int val) ? val : -1) .Where(x => x != -1) .ToList(); diff --git a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs index 248de428a8..92968510fa 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs @@ -53,7 +53,7 @@ namespace Umbraco.Cms.Core.Services.Implement ((ServerRegistrationRepository) _serverRegistrationRepository).ClearCache(); // ensure we have up-to-date cache var regs = _serverRegistrationRepository.GetMany().ToArray(); - var hasMaster = regs.Any(x => ((ServerRegistration) x).IsMaster); + var hasSchedulingPublisher = regs.Any(x => ((ServerRegistration) x).IsSchedulingPublisher); var server = regs.FirstOrDefault(x => x.ServerIdentity.InvariantEquals(serverIdentity)); if (server == null) @@ -67,22 +67,20 @@ namespace Umbraco.Cms.Core.Services.Implement } server.IsActive = true; - if (hasMaster == false) - server.IsMaster = true; + if (hasSchedulingPublisher == false) + server.IsSchedulingPublisher = true; _serverRegistrationRepository.Save(server); _serverRegistrationRepository.DeactiveStaleServers(staleTimeout); // triggers a cache reload // reload - cheap, cached - // default role is single server, but if registrations contain more - // than one active server, then role is master or replica regs = _serverRegistrationRepository.GetMany().ToArray(); // default role is single server, but if registrations contain more - // than one active server, then role is master or replica + // than one active server, then role is scheduling publisher or subscriber _currentServerRole = regs.Count(x => x.IsActive) > 1 - ? (server.IsMaster ? ServerRole.Master : ServerRole.Replica) + ? (server.IsSchedulingPublisher ? ServerRole.SchedulingPublisher : ServerRole.Subscriber) : ServerRole.Single; scope.Complete(); @@ -105,7 +103,7 @@ namespace Umbraco.Cms.Core.Services.Implement var server = _serverRegistrationRepository.GetMany().FirstOrDefault(x => x.ServerIdentity.InvariantEquals(serverIdentity)); if (server == null) return; - server.IsActive = server.IsMaster = false; + server.IsActive = server.IsSchedulingPublisher = false; _serverRegistrationRepository.Save(server); // will trigger a cache reload // will trigger a cache reload scope.Complete(); diff --git a/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs b/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs index 3b3351fd93..462eb88239 100644 --- a/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs +++ b/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs @@ -52,7 +52,7 @@ namespace Umbraco.Cms.Infrastructure.Sync if (File.Exists(distCacheFilePath)) { var content = File.ReadAllText(distCacheFilePath); - if (int.TryParse(content, out var last)) + if (int.TryParse(content, NumberStyles.Integer, CultureInfo.InvariantCulture, out var last)) { return last; } diff --git a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj index 67adb9907c..1d2f8bc505 100644 --- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj +++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj @@ -19,16 +19,16 @@ - - + + - + - + @@ -46,12 +46,12 @@ - + - - + + all diff --git a/src/Umbraco.Persistence.SqlCe/SqlCeDatabaseCreator.cs b/src/Umbraco.Persistence.SqlCe/SqlCeDatabaseCreator.cs new file mode 100644 index 0000000000..fd360be13a --- /dev/null +++ b/src/Umbraco.Persistence.SqlCe/SqlCeDatabaseCreator.cs @@ -0,0 +1,16 @@ +using Umbraco.Cms.Infrastructure.Persistence; +using Constants = Umbraco.Cms.Core.Constants; + +namespace Umbraco.Cms.Persistence.SqlCe +{ + public class SqlCeDatabaseCreator : IDatabaseCreator + { + public string ProviderName => Constants.DatabaseProviders.SqlCe; + + public void Create(string connectionString) + { + using var engine = new System.Data.SqlServerCe.SqlCeEngine(connectionString); + engine.CreateDatabase(); + } + } +} diff --git a/src/Umbraco.Persistence.SqlCe/SqlCeEmbeddedDatabaseCreator.cs b/src/Umbraco.Persistence.SqlCe/SqlCeEmbeddedDatabaseCreator.cs deleted file mode 100644 index ee2d888109..0000000000 --- a/src/Umbraco.Persistence.SqlCe/SqlCeEmbeddedDatabaseCreator.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Umbraco.Cms.Infrastructure.Migrations.Install; -using Umbraco.Cms.Infrastructure.Persistence; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Cms.Persistence.SqlCe -{ - public class SqlCeEmbeddedDatabaseCreator : IEmbeddedDatabaseCreator - { - public string ProviderName => Constants.DatabaseProviders.SqlCe; - - public string ConnectionString { get; set; } = DatabaseBuilder.EmbeddedDatabaseConnectionString; - public void Create() - { - var engine = new System.Data.SqlServerCe.SqlCeEngine(ConnectionString); - engine.CreateDatabase(); - } - } -} diff --git a/src/Umbraco.Persistence.SqlCe/Umbraco.Persistence.SqlCe.csproj b/src/Umbraco.Persistence.SqlCe/Umbraco.Persistence.SqlCe.csproj index 508bcf3ccb..70366707e7 100644 --- a/src/Umbraco.Persistence.SqlCe/Umbraco.Persistence.SqlCe.csproj +++ b/src/Umbraco.Persistence.SqlCe/Umbraco.Persistence.SqlCe.csproj @@ -19,7 +19,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + all diff --git a/src/Umbraco.PublishedCache.NuCache/ContentCache.cs b/src/Umbraco.PublishedCache.NuCache/ContentCache.cs index f26b53775f..875e6d2ffc 100644 --- a/src/Umbraco.PublishedCache.NuCache/ContentCache.cs +++ b/src/Umbraco.PublishedCache.NuCache/ContentCache.cs @@ -82,7 +82,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache var pos = route.IndexOf('/'); var path = pos == 0 ? route : route.Substring(pos); - var startNodeId = pos == 0 ? 0 : int.Parse(route.Substring(0, pos)); + var startNodeId = pos == 0 ? 0 : int.Parse(route.Substring(0, pos), CultureInfo.InvariantCulture); var parts = path.Split(Constants.CharArrays.ForwardSlash, StringSplitOptions.RemoveEmptyEntries); IPublishedContent content; diff --git a/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj b/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj index 7d6ff54c25..2115eab398 100644 --- a/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj +++ b/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj @@ -22,7 +22,7 @@ - + all diff --git a/src/Umbraco.TestData/Umbraco.TestData.csproj b/src/Umbraco.TestData/Umbraco.TestData.csproj index 22c9ca9131..eedf6e5668 100644 --- a/src/Umbraco.TestData/Umbraco.TestData.csproj +++ b/src/Umbraco.TestData/Umbraco.TestData.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts index 3daf907c99..77729912a6 100644 --- a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts +++ b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts @@ -379,7 +379,12 @@ context('Tabs', () => { cy.saveDocumentType(tabsDocType); OpenDocTypeFolder(); cy.get('[alias="reorder"]').click(); - cy.get('.umb-group-builder__tabs-overflow--right > .caret').click().click(); + cy.get('body') + .then(($body) => { + while($body.find('.umb-group-builder__tabs-overflow--right > .caret').hasClass('active')){ + cy.click(); + } + }); cy.get('.umb-group-builder__tab').last().click(); cy.get('.umb-group-builder__group-title-icon').last().trigger('mousedown', { which: 1 }) cy.get('.umb-group-builder__tab').eq(1).trigger('mousemove', {which: 1, force: true}); @@ -426,7 +431,12 @@ context('Tabs', () => { OpenDocTypeFolder(); cy.get('[alias="reorder"]').click(); //Scroll right so we can see tab 2 - cy.get('.umb-group-builder__tabs-overflow--right > .caret').click().click(); + cy.get('body') + .then(($body) => { + while($body.find('.umb-group-builder__tabs-overflow--right > .caret').hasClass('active')){ + cy.click(); + } + }); cy.get('.umb-group-builder__tab-title-icon').eq(1).trigger('mousedown', { which: 1 }) cy.get('.umb-group-builder__tab').eq(1).trigger('mousemove', {which: 1, force: true}); cy.get('.umb-group-builder__tab').eq(1).should('have.class', 'is-active').trigger('mouseup', {force:true}); @@ -473,7 +483,12 @@ context('Tabs', () => { OpenDocTypeFolder(); cy.get('[alias="reorder"]').click(); //Scroll so we are sure we see tab 2 - cy.get('.umb-group-builder__tabs-overflow--right > .caret').click().click(); + cy.get('body') + .then(($body) => { + while($body.find('.umb-group-builder__tabs-overflow--right > .caret').hasClass('active')){ + cy.click(); + } + }); //Navigate to tab 2 cy.get('.umb-group-builder__tab').last().click(); cy.get('.umb-group-builder__property-meta > .flex > .icon').eq(1).trigger('mousedown', {which: 1}) diff --git a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs index e8269fafa9..500d71dddc 100644 --- a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs +++ b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs @@ -23,7 +23,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence { private IDbProviderFactoryCreator DbProviderFactoryCreator => GetRequiredService(); private IUmbracoDatabaseFactory UmbracoDatabaseFactory => GetRequiredService(); - private IEmbeddedDatabaseCreator EmbeddedDatabaseCreator => GetRequiredService(); + private IDatabaseCreator EmbeddedDatabaseCreator => GetRequiredService(); public DatabaseBuilderTests() { @@ -42,10 +42,10 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence if (File.Exists(filePath)) File.Delete(filePath); - EmbeddedDatabaseCreator.ConnectionString = $"Datasource=|DataDirectory|{dbFile};Flush Interval=1"; + var connectionString = $"Datasource=|DataDirectory|{dbFile};Flush Interval=1"; - UmbracoDatabaseFactory.Configure(EmbeddedDatabaseCreator.ConnectionString, Constants.DbProviderNames.SqlCe); - DbProviderFactoryCreator.CreateDatabase(Constants.DbProviderNames.SqlCe); + UmbracoDatabaseFactory.Configure(connectionString, Constants.DbProviderNames.SqlCe); + DbProviderFactoryCreator.CreateDatabase(Constants.DbProviderNames.SqlCe, connectionString); UmbracoDatabaseFactory.CreateDatabase(); // test get database type (requires an actual database) diff --git a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj index 2eff2802a4..a1f6ecd78d 100644 --- a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj +++ b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj @@ -6,9 +6,9 @@ - + - + @@ -17,7 +17,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageDataInstallationTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageDataInstallationTests.cs index 14a52cead7..6e45d1708a 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageDataInstallationTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageDataInstallationTests.cs @@ -650,7 +650,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Packaging // Act var macros = PackageDataInstallation.ImportMacros( macrosElement.Elements("macro"), - Enumerable.Empty(), 0).ToList(); // Assert @@ -674,7 +673,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Packaging // Act var macros = PackageDataInstallation.ImportMacros( macrosElement.Elements("macro"), - Enumerable.Empty(), 0).ToList(); // Assert diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoBulkInsertTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoBulkInsertTests.cs index 471586c715..290d018df9 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoBulkInsertTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoBulkInsertTests.cs @@ -191,7 +191,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.NPoco DateRegistered = DateTime.Now, IsActive = true, DateAccessed = DateTime.Now, - IsMaster = true + IsSchedulingPublisher = true }); } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Security/BackOfficeUserStoreTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Security/BackOfficeUserStoreTests.cs new file mode 100644 index 0000000000..665bb2f079 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Security/BackOfficeUserStoreTests.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using NUnit.Framework; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Mapping; +using Umbraco.Cms.Core.Models.Membership; +using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Security; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Tests.Common.Testing; +using Umbraco.Cms.Tests.Integration.Testing; + +namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Security +{ + [TestFixture] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] + public class BackOfficeUserStoreTests : UmbracoIntegrationTest + { + private IUserService UserService => GetRequiredService(); + private IEntityService EntityService => GetRequiredService(); + private IExternalLoginService ExternalLoginService => GetRequiredService(); + private IUmbracoMapper UmbracoMapper => GetRequiredService(); + private ILocalizedTextService TextService => GetRequiredService(); + + private BackOfficeUserStore GetUserStore() + => new BackOfficeUserStore( + ScopeProvider, + UserService, + EntityService, + ExternalLoginService, + Options.Create(GlobalSettings), + UmbracoMapper, + new BackOfficeErrorDescriber(TextService), + AppCaches); + + [Test] + public async Task Can_Persist_Is_Approved() + { + var userStore = GetUserStore(); + var user = new BackOfficeIdentityUser(GlobalSettings, 1, new List()) + { + Name = "Test", + Email = "test@test.com", + UserName = "test@test.com" + }; + IdentityResult createResult = await userStore.CreateAsync(user); + Assert.IsTrue(createResult.Succeeded); + Assert.IsFalse(user.IsApproved); + + // update + user.IsApproved = true; + var saveResult = await userStore.UpdateAsync(user); + Assert.IsTrue(saveResult.Succeeded); + Assert.IsTrue(user.IsApproved); + + // get get + user = await userStore.FindByIdAsync(user.Id); + Assert.IsTrue(user.IsApproved); + } + } +} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index 1bd0fbd7f2..89012e7d6c 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -74,9 +74,9 @@ - + - + @@ -85,7 +85,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs index 0525a24173..2c399d0e93 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs @@ -1,7 +1,8 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. using System; +using System.Globalization; using NUnit.Framework; using Umbraco.Extensions; @@ -46,10 +47,23 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.CoreThings Assert.AreEqual(false, conv.Result); } + [Test] - public void ConvertToIntegerTest() + [TestCase("en-US")] + [TestCase(null)] + [TestCase("da-DK")] + [TestCase("tr-TR")] + public void ConvertToIntegerTest(string culture) { - var conv = "100".TryConvertTo(); + if (culture is not null) + { + CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo(culture); + } + var conv = "-1".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(-1, conv.Result); + + conv = "100".TryConvertTo(); Assert.IsTrue(conv); Assert.AreEqual(100, conv.Result); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs index f128d49128..be581122a1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs @@ -53,9 +53,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices } [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Replica() + public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() { - HealthCheckNotifier sut = CreateHealthCheckNotifier(serverRole: ServerRole.Replica); + HealthCheckNotifier sut = CreateHealthCheckNotifier(serverRole: ServerRole.Subscriber); await sut.PerformExecuteAsync(null); VerifyNotificationsNotSent(); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs index 557e87fb0c..3cc23cfb45 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs @@ -37,9 +37,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices } [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Replica() + public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() { - KeepAlive sut = CreateKeepAlive(serverRole: ServerRole.Replica); + KeepAlive sut = CreateKeepAlive(serverRole: ServerRole.Subscriber); await sut.PerformExecuteAsync(null); VerifyKeepAliveRequestNotSent(); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs index a3a7b95210..2057167653 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs @@ -27,9 +27,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices private const int MaxLogAgeInMinutes = 60; [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Replica() + public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() { - LogScrubber sut = CreateLogScrubber(serverRole: ServerRole.Replica); + LogScrubber sut = CreateLogScrubber(serverRole: ServerRole.Subscriber); await sut.PerformExecuteAsync(null); VerifyLogsNotScrubbed(); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs index efbd0c9e98..2a8f006ab6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs @@ -44,9 +44,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices } [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Replica() + public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() { - ScheduledPublishing sut = CreateScheduledPublishing(serverRole: ServerRole.Replica); + ScheduledPublishing sut = CreateScheduledPublishing(serverRole: ServerRole.Subscriber); await sut.PerformExecuteAsync(null); VerifyScheduledPublishingNotPerformed(); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Authorization/AdminUsersHandlerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Authorization/AdminUsersHandlerTests.cs index 191381d8c5..7b638c29d1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Authorization/AdminUsersHandlerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Authorization/AdminUsersHandlerTests.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using System.Collections.Generic; +using System.Globalization; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; @@ -59,7 +60,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization public async Task Editing_Single_Admin_User_By_Admin_User_Is_Authorized() { AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(); - AdminUsersHandler sut = CreateHandler(queryStringValue: Admin2UserId.ToString(), editingWithAdmin: true); + AdminUsersHandler sut = CreateHandler(queryStringValue: Admin2UserId.ToString(CultureInfo.InvariantCulture), editingWithAdmin: true); await sut.HandleAsync(authHandlerContext); @@ -70,7 +71,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization public async Task Editing_Single_Admin_User_By_Non_Admin_User_Is_Not_Authorized() { AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(); - AdminUsersHandler sut = CreateHandler(queryStringValue: Admin2UserId.ToString()); + AdminUsersHandler sut = CreateHandler(queryStringValue: Admin2UserId.ToString(CultureInfo.InvariantCulture)); await sut.HandleAsync(authHandlerContext); @@ -81,7 +82,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization public async Task Editing_Single_Non_Admin_User_By_Non_Admin_User_Is_Authorized() { AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(); - AdminUsersHandler sut = CreateHandler(queryStringValue: NonAdmin2UserId.ToString()); + AdminUsersHandler sut = CreateHandler(queryStringValue: NonAdmin2UserId.ToString(CultureInfo.InvariantCulture)); await sut.HandleAsync(authHandlerContext); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs index 47fcbd010c..11a2423051 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs @@ -14,6 +14,7 @@ using NUnit.Framework; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; @@ -47,6 +48,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing IPublishedRouter router = null, IUmbracoRouteValuesFactory routeValuesFactory = null) { + var publicAccessRequestHandler = new Mock(); + publicAccessRequestHandler.Setup(x => x.RewriteForPublishedContentAccessAsync(It.IsAny(), It.IsAny())) + .Returns((HttpContext ctx, UmbracoRouteValues routeVals) => Task.FromResult(routeVals)); + var transformer = new UmbracoRouteValueTransformer( new NullLogger(), ctx, @@ -58,7 +63,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing filter ?? Mock.Of(x => x.IsDocumentRequest(It.IsAny()) == true), Mock.Of(), Mock.Of(), - Mock.Of()); + Mock.Of(), + publicAccessRequestHandler.Object); return transformer; } @@ -92,28 +98,28 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing => Mock.Of(x => x.RouteRequestAsync(It.IsAny(), It.IsAny()) == Task.FromResult(request)); [Test] - public async Task Noop_When_Runtime_Level_Not_Run() + public async Task Null_When_Runtime_Level_Not_Run() { UmbracoRouteValueTransformer transformer = GetTransformer( Mock.Of(), Mock.Of()); RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); - Assert.AreEqual(0, result.Count); + Assert.IsNull(result); } [Test] - public async Task Noop_When_No_Umbraco_Context() + public async Task Null_When_No_Umbraco_Context() { UmbracoRouteValueTransformer transformer = GetTransformerWithRunState( Mock.Of()); RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); - Assert.AreEqual(0, result.Count); + Assert.IsNull(result); } [Test] - public async Task Noop_When_Not_Document_Request() + public async Task Null_When_Not_Document_Request() { var umbracoContext = Mock.Of(); UmbracoRouteValueTransformer transformer = GetTransformerWithRunState( @@ -121,7 +127,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing Mock.Of(x => x.IsDocumentRequest(It.IsAny()) == false)); RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); - Assert.AreEqual(0, result.Count); + Assert.IsNull(result); } [Test] @@ -154,7 +160,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing } [Test] - public async Task Assigns_UmbracoRouteValues_To_HttpContext_Feature() + public async Task Null_When_No_Content_On_PublishedRequest() { IUmbracoContext umbracoContext = GetUmbracoContext(true); IPublishedRequest request = Mock.Of(); @@ -167,16 +173,34 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing var httpContext = new DefaultHttpContext(); RouteValueDictionary result = await transformer.TransformAsync(httpContext, new RouteValueDictionary()); + UmbracoRouteValues routeVals = httpContext.Features.Get(); + Assert.IsNull(routeVals); + } + + [Test] + public async Task Assigns_UmbracoRouteValues_To_HttpContext_Feature() + { + IUmbracoContext umbracoContext = GetUmbracoContext(true); + IPublishedRequest request = Mock.Of(x => x.PublishedContent == Mock.Of()); + + UmbracoRouteValueTransformer transformer = GetTransformerWithRunState( + Mock.Of(x => x.TryGetUmbracoContext(out umbracoContext)), + router: GetRouter(request), + routeValuesFactory: GetRouteValuesFactory(request)); + + var httpContext = new DefaultHttpContext(); + RouteValueDictionary result = await transformer.TransformAsync(httpContext, new RouteValueDictionary()); + UmbracoRouteValues routeVals = httpContext.Features.Get(); Assert.IsNotNull(routeVals); Assert.AreEqual(routeVals.PublishedRequest, umbracoContext.PublishedRequest); } [Test] - public async Task Assigns_Values_To_RouteValueDictionary() + public async Task Assigns_Values_To_RouteValueDictionary_When_Content() { IUmbracoContext umbracoContext = GetUmbracoContext(true); - IPublishedRequest request = Mock.Of(); + IPublishedRequest request = Mock.Of(x => x.PublishedContent == Mock.Of()); UmbracoRouteValues routeValues = GetRouteValues(request); UmbracoRouteValueTransformer transformer = GetTransformerWithRunState( @@ -190,6 +214,23 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing Assert.AreEqual(routeValues.ActionName, result[ActionToken]); } + [Test] + public async Task Returns_Null_RouteValueDictionary_When_No_Content() + { + IUmbracoContext umbracoContext = GetUmbracoContext(true); + IPublishedRequest request = Mock.Of(x => x.PublishedContent == null); + UmbracoRouteValues routeValues = GetRouteValues(request); + + UmbracoRouteValueTransformer transformer = GetTransformerWithRunState( + Mock.Of(x => x.TryGetUmbracoContext(out umbracoContext)), + router: GetRouter(request), + routeValuesFactory: GetRouteValuesFactory(request)); + + RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); + + Assert.IsNull(result); + } + private class TestController : RenderController { public TestController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor) diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 53f42555a4..1daa6c2395 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -83,10 +83,10 @@ - 2.0.0-alpha.20200128.15 + 2.0.0 - + 1.11.31 diff --git a/src/Umbraco.Web.BackOffice/Authorization/AdminUsersHandler.cs b/src/Umbraco.Web.BackOffice/Authorization/AdminUsersHandler.cs index 64649ac274..1f760de4fd 100644 --- a/src/Umbraco.Web.BackOffice/Authorization/AdminUsersHandler.cs +++ b/src/Umbraco.Web.BackOffice/Authorization/AdminUsersHandler.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; @@ -55,7 +56,7 @@ namespace Umbraco.Cms.Web.BackOffice.Authorization } int[] userIds; - if (int.TryParse(queryString, out var userId)) + if (int.TryParse(queryString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var userId)) { userIds = new[] { userId }; } diff --git a/src/Umbraco.Web.BackOffice/Authorization/PermissionsQueryStringHandler.cs b/src/Umbraco.Web.BackOffice/Authorization/PermissionsQueryStringHandler.cs index 531b92a7e9..e8433dd1a8 100644 --- a/src/Umbraco.Web.BackOffice/Authorization/PermissionsQueryStringHandler.cs +++ b/src/Umbraco.Web.BackOffice/Authorization/PermissionsQueryStringHandler.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using System; +using System.Globalization; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Umbraco.Cms.Core; @@ -61,7 +62,7 @@ namespace Umbraco.Cms.Web.BackOffice.Authorization // It might be a udi, so check that next. // Otherwise treat it as a guid - unlikely we ever get here. // Failing that, we can't parse it. - if (int.TryParse(argument, out int parsedId)) + if (int.TryParse(argument, NumberStyles.Integer, CultureInfo.InvariantCulture, out int parsedId)) { nodeId = parsedId; return true; diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index e79b49ace3..f159011d80 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; @@ -510,7 +511,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [AllowAnonymous] public async Task PostSetPassword(SetPasswordModel model) { - var identityUser = await _userManager.FindByIdAsync(model.UserId.ToString()); + var identityUser = await _userManager.FindByIdAsync(model.UserId.ToString(CultureInfo.InvariantCulture)); var result = await _userManager.ResetPasswordAsync(identityUser, model.ResetCode, model.Password); if (result.Succeeded) @@ -560,7 +561,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers } } - _userManager.NotifyForgotPasswordChanged(User, model.UserId.ToString()); + _userManager.NotifyForgotPasswordChanged(User, model.UserId.ToString(CultureInfo.InvariantCulture)); return Ok(); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs index 237aad6bd3..b6df2ebf4a 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs @@ -348,7 +348,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [AllowAnonymous] public async Task ValidatePasswordResetCode([Bind(Prefix = "u")]int userId, [Bind(Prefix = "r")]string resetCode) { - var user = await _userManager.FindByIdAsync(userId.ToString()); + var user = await _userManager.FindByIdAsync(userId.ToString(CultureInfo.InvariantCulture)); if (user != null) { var result = await _userManager.VerifyUserTokenAsync(user, "Default", "ResetPassword", resetCode); diff --git a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs index 1435eb6c52..ba6ca36085 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs @@ -250,7 +250,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [ValidateAngularAntiForgeryToken] public async Task> GetCurrentUserLinkedLogins() { - var identityUser = await _backOfficeUserManager.FindByIdAsync(_backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0).ToString()); + var identityUser = await _backOfficeUserManager.FindByIdAsync(_backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0).ToString(CultureInfo.InvariantCulture)); // deduplicate in case there are duplicates (there shouldn't be now since we have a unique constraint on the external logins // but there didn't used to be) diff --git a/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs b/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs index 8ee4ee1182..4d0e2cfe14 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Net.Http; using Microsoft.AspNetCore.Authorization; @@ -202,7 +203,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers public ActionResult PostSave(DictionarySave dictionary) { var dictionaryItem = - _localizationService.GetDictionaryItemById(int.Parse(dictionary.Id.ToString())); + _localizationService.GetDictionaryItemById(int.Parse(dictionary.Id.ToString(), CultureInfo.InvariantCulture)); if (dictionaryItem == null) return ValidationProblem("Dictionary item does not exist"); diff --git a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs index 944f1946bf..2eaeee3d12 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Http; @@ -218,7 +219,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers return foundContentResult; } - return new ActionResult>(foundContent.Path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse)); + return new ActionResult>(foundContent.Path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select( + s => int.Parse(s, CultureInfo.InvariantCulture))); } /// @@ -236,7 +238,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers return foundContentResult; } - return new ActionResult>(foundContent.Path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse)); + return new ActionResult>(foundContent.Path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select( + s => int.Parse(s, CultureInfo.InvariantCulture))); } /// @@ -576,7 +579,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers string filter = "", Guid? dataTypeKey = null) { - if (int.TryParse(id, out var intId)) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) { return GetPagedChildren(intId, type, pageNumber, pageSize, orderBy, orderDirection, filter); } @@ -859,7 +862,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers { // TODO: Need to check for Object types that support hierarchic here, some might not. - var ids = _entityService.Get(id).Path.Split(Constants.CharArrays.Comma).Select(int.Parse).Distinct().ToArray(); + var ids = _entityService.Get(id).Path.Split(Constants.CharArrays.Comma).Select(s => int.Parse(s, CultureInfo.InvariantCulture)).Distinct().ToArray(); var ignoreUserStartNodes = IsDataTypeIgnoringUserStartNodes(queryStrings?.GetValue("dataTypeId")); if (ignoreUserStartNodes == false) diff --git a/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs b/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs index 84ff7565cc..834d8cc565 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; @@ -184,7 +185,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers return ValidationProblem("Name cannnot be more than 255 characters in length."); } - var macro = _macroService.GetById(int.Parse(macroDisplay.Id.ToString())); + var macro = _macroService.GetById(int.Parse(macroDisplay.Id.ToString(), CultureInfo.InvariantCulture)); if (macro == null) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs index e8947dbf17..d54bd7a093 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Net.Mime; @@ -898,7 +899,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers } //if it's not an INT then we'll check for GUID - if (int.TryParse(parentId, out intParentId) == false) + if (int.TryParse(parentId, NumberStyles.Integer, CultureInfo.InvariantCulture, out intParentId) == false) { // if a guid then try to look up the entity Guid idGuid; diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs index 81303ba55e..fb5286505e 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -122,7 +123,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers public ActionResult PostSave(MemberGroupSave saveModel) { - var id = int.Parse(saveModel.Id.ToString()); + var id = int.Parse(saveModel.Id.ToString(), CultureInfo.InvariantCulture); IMemberGroup memberGroup = id > 0 ? _memberGroupService.GetById(id) : new MemberGroup(); if (memberGroup == null) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/TemplateQueryController.cs b/src/Umbraco.Web.BackOffice/Controllers/TemplateQueryController.cs index 7f5298066a..d0aadac744 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TemplateQueryController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TemplateQueryController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.Linq; using System.Text; using Umbraco.Cms.Core; @@ -189,7 +190,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers switch (condition.Property.Type) { case "int": - return int.Parse(condition.ConstraintValue); + return int.Parse(condition.ConstraintValue, CultureInfo.InvariantCulture); case "datetime": DateTime dt; return DateTime.TryParse(condition.ConstraintValue, out dt) ? dt : DateTime.Today; diff --git a/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs index 39432703a7..178d9d50f0 100644 --- a/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs @@ -168,9 +168,6 @@ namespace Umbraco.Cms.Web.BackOffice.Filters BackOfficeIdentityUser backOfficeIdentityUser = _umbracoMapper.Map(user); await _backOfficeSignInManager.SignInAsync(backOfficeIdentityUser, isPersistent: true); - // ensure the remainder of the request has the correct principal set - actionContext.HttpContext.SetPrincipalForRequest(ClaimsPrincipal.Current); - // flag that we've made changes _requestCache.Set(nameof(CheckIfUserTicketDataIsStaleFilter), true); } diff --git a/src/Umbraco.Web.BackOffice/Install/CreateUnattendedUserNotificationHandler.cs b/src/Umbraco.Web.BackOffice/Install/CreateUnattendedUserNotificationHandler.cs index 3990f42aa7..6eaed2f42d 100644 --- a/src/Umbraco.Web.BackOffice/Install/CreateUnattendedUserNotificationHandler.cs +++ b/src/Umbraco.Web.BackOffice/Install/CreateUnattendedUserNotificationHandler.cs @@ -76,10 +76,10 @@ namespace Umbraco.Cms.Web.BackOffice.Install // Uses same approach as NewInstall Step using IServiceScope scope = _serviceScopeFactory.CreateScope(); IBackOfficeUserManager backOfficeUserManager = scope.ServiceProvider.GetRequiredService(); - BackOfficeIdentityUser membershipUser = await backOfficeUserManager.FindByIdAsync(Core.Constants.Security.SuperUserId.ToString()); + BackOfficeIdentityUser membershipUser = await backOfficeUserManager.FindByIdAsync(Core.Constants.Security.SuperUserIdAsString); if (membershipUser == null) { - throw new InvalidOperationException($"No user found in membership provider with id of {Core.Constants.Security.SuperUserId}."); + throw new InvalidOperationException($"No user found in membership provider with id of {Core.Constants.Security.SuperUserIdAsString}."); } //To change the password here we actually need to reset it since we don't have an old one to use to change diff --git a/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs b/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs index 0dd19d7db9..e234fa1115 100644 --- a/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs +++ b/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core; @@ -330,7 +331,7 @@ namespace Umbraco.Cms.Web.BackOffice.Mapping if (parent == null) return false; - var pathParts = parent.Path.Split(Constants.CharArrays.Comma).Select(x => int.TryParse(x, out var i) ? i : 0).ToList(); + var pathParts = parent.Path.Split(Constants.CharArrays.Comma).Select(x => int.TryParse(x, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? i : 0).ToList(); // reduce the path parts so we exclude top level content items that // are higher up than a user's start nodes diff --git a/src/Umbraco.Web.BackOffice/PropertyEditors/NestedContentController.cs b/src/Umbraco.Web.BackOffice/PropertyEditors/NestedContentController.cs index 25d120d807..b975a0114b 100644 --- a/src/Umbraco.Web.BackOffice/PropertyEditors/NestedContentController.cs +++ b/src/Umbraco.Web.BackOffice/PropertyEditors/NestedContentController.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Web.BackOffice.Controllers; using Umbraco.Cms.Web.Common.Attributes; @@ -23,9 +24,7 @@ namespace Umbraco.Cms.Web.BackOffice.PropertyEditors } [HttpGet] - public IEnumerable GetContentTypes() - { - return _contentTypeService + public IEnumerable GetContentTypes() => _contentTypeService .GetAllElementTypes() .OrderBy(x => x.SortOrder) .Select(x => new @@ -35,8 +34,7 @@ namespace Umbraco.Cms.Web.BackOffice.PropertyEditors name = x.Name, alias = x.Alias, icon = x.Icon, - tabs = x.CompositionPropertyGroups.Select(y => y.Name).Distinct() + tabs = x.CompositionPropertyGroups.Where(x => x.Type == PropertyGroupType.Group && x.GetParentAlias() is null).Select(y => y.Name).Distinct() }); - } } } diff --git a/src/Umbraco.Web.BackOffice/Security/BackOfficeUserManagerAuditer.cs b/src/Umbraco.Web.BackOffice/Security/BackOfficeUserManagerAuditer.cs index a47987667f..75cd5ab5a1 100644 --- a/src/Umbraco.Web.BackOffice/Security/BackOfficeUserManagerAuditer.cs +++ b/src/Umbraco.Web.BackOffice/Security/BackOfficeUserManagerAuditer.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Notifications; @@ -55,7 +56,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security private void WriteAudit(string performingId, string affectedId, string ipAddress, string eventType, string eventDetails, string affectedDetails = null) { IUser performingUser = null; - if (int.TryParse(performingId, out int asInt)) + if (int.TryParse(performingId, NumberStyles.Integer, CultureInfo.InvariantCulture, out int asInt)) { performingUser = _userService.GetUserById(asInt); } @@ -64,12 +65,12 @@ namespace Umbraco.Cms.Web.BackOffice.Security ? $"User UNKNOWN:{performingId}" : $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}"; - if (!int.TryParse(performingId, out int performingIdAsInt)) + if (!int.TryParse(performingId, NumberStyles.Integer, CultureInfo.InvariantCulture, out int performingIdAsInt)) { performingIdAsInt = 0; } - if (!int.TryParse(affectedId, out int affectedIdAsInt)) + if (!int.TryParse(affectedId, NumberStyles.Integer, CultureInfo.InvariantCulture, out int affectedIdAsInt)) { affectedIdAsInt = 0; } diff --git a/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs b/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs index 1457732c53..1767386088 100644 --- a/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs +++ b/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; @@ -190,7 +191,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security // occurs when sign in is successful and after the ticket is written to the outbound cookie // When we are signed in with the cookie, assign the principal to the current HttpContext - ctx.HttpContext.User = ctx.Principal; + ctx.HttpContext.SetPrincipalForRequest(ctx.Principal); return Task.CompletedTask; }, diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentBlueprintTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentBlueprintTreeController.cs index 9b6ccf91f6..abf3854f5b 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentBlueprintTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentBlueprintTreeController.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -130,7 +131,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees menu.Items.Add(new RefreshNode(LocalizedTextService, true)); return menu; } - var cte = _entityService.Get(int.Parse(id), UmbracoObjectTypes.DocumentType); + var cte = _entityService.Get(int.Parse(id, CultureInfo.InvariantCulture), UmbracoObjectTypes.DocumentType); //only refresh & create if it's a content type if (cte != null) { diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs index 011cbe74e6..74c456026d 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -187,7 +188,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees //return a normal node menu: int iid; - if (int.TryParse(id, out iid) == false) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out iid) == false) { return NotFound(); } diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs index e84338fc9b..2f27f8adac 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -71,7 +72,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { int asInt; Guid asGuid = Guid.Empty; - if (int.TryParse(id, out asInt) == false) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out asInt) == false) { if (Guid.TryParse(id, out asGuid) == false) { @@ -264,7 +265,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { int id; var parts = entity.Path.Split(Comma, StringSplitOptions.RemoveEmptyEntries); - return parts.Length >= 2 && int.TryParse(parts[1], out id) ? id : 0; + return parts.Length >= 2 && int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out id) ? id : 0; } protected abstract ActionResult PerformGetMenuForNode(string id, FormCollection queryStrings); @@ -275,7 +276,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { // try to parse id as an integer else use GetEntityFromId // which will grok Guids, Udis, etc and let use obtain the id - if (!int.TryParse(id, out var entityId)) + if (!int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var entityId)) { var entity = GetEntityFromId(id); if (entity == null) @@ -544,7 +545,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { return new Tuple(idGuid, null); } - if (int.TryParse(id, out idInt)) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out idInt)) { return new Tuple(null, idInt); } @@ -576,7 +577,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { entity = _entityService.Get(idGuid, UmbracoObjectType); } - else if (int.TryParse(s, out var idInt)) + else if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var idInt)) { entity = _entityService.Get(idInt, UmbracoObjectType); } diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs index 2ba9e5f6c7..2be23f69e2 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -54,13 +55,15 @@ namespace Umbraco.Cms.Web.BackOffice.Trees protected override ActionResult GetTreeNodes(string id, FormCollection queryStrings) { - var intId = id.TryConvertTo(); - if (intId == false) throw new InvalidOperationException("Id must be an integer"); + if (!int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) + { + throw new InvalidOperationException("Id must be an integer"); + } var nodes = new TreeNodeCollection(); nodes.AddRange( - _entityService.GetChildren(intId.Result, UmbracoObjectTypes.DocumentTypeContainer) + _entityService.GetChildren(intId, UmbracoObjectTypes.DocumentTypeContainer) .OrderBy(entity => entity.Name) .Select(dt => { @@ -75,7 +78,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees //if the request is for folders only then just return if (queryStrings["foldersonly"].ToString().IsNullOrWhiteSpace() == false && queryStrings["foldersonly"] == "1") return nodes; - var children = _entityService.GetChildren(intId.Result, UmbracoObjectTypes.DocumentType).ToArray(); + var children = _entityService.GetChildren(intId, UmbracoObjectTypes.DocumentType).ToArray(); var contentTypes = _contentTypeService.GetAll(children.Select(c => c.Id).ToArray()).ToDictionary(c => c.Id); nodes.AddRange( children @@ -125,7 +128,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var container = _entityService.Get(int.Parse(id), UmbracoObjectTypes.DocumentTypeContainer); + var container = _entityService.Get(int.Parse(id, CultureInfo.InvariantCulture), UmbracoObjectTypes.DocumentTypeContainer); if (container != null) { //set the default to create @@ -147,7 +150,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees } else { - var ct = _contentTypeService.Get(int.Parse(id)); + var ct = _contentTypeService.Get(int.Parse(id, CultureInfo.InvariantCulture)); var parent = ct == null ? null : _contentTypeService.Get(ct.ParentId); menu.Items.Add(LocalizedTextService, opensDialog: true); diff --git a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs index bddf823c43..2a2c4bed0c 100644 --- a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -42,14 +43,16 @@ namespace Umbraco.Cms.Web.BackOffice.Trees protected override ActionResult GetTreeNodes(string id, FormCollection queryStrings) { - var intId = id.TryConvertTo(); - if (intId == false) throw new InvalidOperationException("Id must be an integer"); + if (!int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) + { + throw new InvalidOperationException("Id must be an integer"); + } var nodes = new TreeNodeCollection(); //Folders first nodes.AddRange( - _entityService.GetChildren(intId.Result, UmbracoObjectTypes.DataTypeContainer) + _entityService.GetChildren(intId, UmbracoObjectTypes.DataTypeContainer) .OrderBy(entity => entity.Name) .Select(dt => { @@ -67,7 +70,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees //System ListView nodes var systemListViewDataTypeIds = GetNonDeletableSystemListViewDataTypeIds(); - var children = _entityService.GetChildren(intId.Result, UmbracoObjectTypes.DataType).ToArray(); + var children = _entityService.GetChildren(intId, UmbracoObjectTypes.DataType).ToArray(); var dataTypes = Enumerable.ToDictionary(_dataTypeService.GetAll(children.Select(c => c.Id).ToArray()), dt => dt.Id); nodes.AddRange( @@ -134,7 +137,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var container = _entityService.Get(int.Parse(id), UmbracoObjectTypes.DataTypeContainer); + var container = _entityService.Get(int.Parse(id, CultureInfo.InvariantCulture), UmbracoObjectTypes.DataTypeContainer); if (container != null) { //set the default to create @@ -158,7 +161,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { var nonDeletableSystemDataTypeIds = GetNonDeletableSystemDataTypeIds(); - if (nonDeletableSystemDataTypeIds.Contains(int.Parse(id)) == false) + if (nonDeletableSystemDataTypeIds.Contains(int.Parse(id, CultureInfo.InvariantCulture)) == false) menu.Items.Add(LocalizedTextService, opensDialog: true); menu.Items.Add(LocalizedTextService, hasSeparator: true, opensDialog: true); diff --git a/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs index 0722a095b3..c61fabfa7b 100644 --- a/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -69,9 +70,10 @@ namespace Umbraco.Cms.Web.BackOffice.Trees /// protected override ActionResult GetTreeNodes(string id, FormCollection queryStrings) { - var intId = id.TryConvertTo(); - if (intId == false) + if (!int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) + { throw new InvalidOperationException("Id must be an integer"); + } var nodes = new TreeNodeCollection(); @@ -92,7 +94,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees else { // maybe we should use the guid as URL param to avoid the extra call for getting dictionary item - var parentDictionary = _localizationService.GetDictionaryItemById(intId.Result); + var parentDictionary = _localizationService.GetDictionaryItemById(intId); if (parentDictionary == null) return nodes; diff --git a/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs index c29518473d..d90a53c8e2 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -79,7 +80,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var macro = _macroService.GetById(int.Parse(id)); + var macro = _macroService.GetById(int.Parse(id, CultureInfo.InvariantCulture)); if (macro == null) return menu; //add delete option for all macros diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs index 2ff354410c..a1a83bc5f3 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -122,7 +123,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - if (int.TryParse(id, out var iid) == false) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var iid) == false) { return NotFound(); } diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs index 2cda5802b8..c19c9a800a 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -41,13 +42,15 @@ namespace Umbraco.Cms.Web.BackOffice.Trees protected override ActionResult GetTreeNodes(string id, FormCollection queryStrings) { - var intId = id.TryConvertTo(); - if (intId == false) throw new InvalidOperationException("Id must be an integer"); + if (!int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) + { + throw new InvalidOperationException("Id must be an integer"); + } var nodes = new TreeNodeCollection(); nodes.AddRange( - _entityService.GetChildren(intId.Result, UmbracoObjectTypes.MediaTypeContainer) + _entityService.GetChildren(intId, UmbracoObjectTypes.MediaTypeContainer) .OrderBy(entity => entity.Name) .Select(dt => { @@ -65,7 +68,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees var mediaTypes = _mediaTypeService.GetAll(); nodes.AddRange( - _entityService.GetChildren(intId.Result, UmbracoObjectTypes.MediaType) + _entityService.GetChildren(intId, UmbracoObjectTypes.MediaType) .OrderBy(entity => entity.Name) .Select(dt => { @@ -97,7 +100,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var container = _entityService.Get(int.Parse(id), UmbracoObjectTypes.MediaTypeContainer); + var container = _entityService.Get(int.Parse(id, CultureInfo.InvariantCulture), UmbracoObjectTypes.MediaTypeContainer); if (container != null) { // set the default to create @@ -119,7 +122,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees } else { - var ct = _mediaTypeService.Get(int.Parse(id)); + var ct = _mediaTypeService.Get(int.Parse(id, CultureInfo.InvariantCulture)); var parent = ct == null ? null : _mediaTypeService.Get(ct.ParentId); menu.Items.Add(LocalizedTextService, opensDialog: true); diff --git a/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs index 6da2298e03..22f96fa7c8 100644 --- a/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -51,7 +52,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var relationType = _relationService.GetRelationTypeById(int.Parse(id)); + var relationType = _relationService.GetRelationTypeById(int.Parse(id, CultureInfo.InvariantCulture)); if (relationType == null) return menu; if (relationType.IsSystemRelationType() == false) diff --git a/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs index 4c91edbf45..e017f0e6d0 100644 --- a/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs @@ -76,7 +76,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees var found = id == Constants.System.RootString ? _fileService.GetTemplates(-1) - : _fileService.GetTemplates(int.Parse(id)); + : _fileService.GetTemplates(int.Parse(id, CultureInfo.InvariantCulture)); nodes.AddRange(found.Select(template => CreateTreeNode( template.Id.ToString(CultureInfo.InvariantCulture), @@ -115,7 +115,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var template = _fileService.GetTemplate(int.Parse(id)); + var template = _fileService.GetTemplate(int.Parse(id, CultureInfo.InvariantCulture)); if (template == null) return menu; var entity = FromTemplate(template); diff --git a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj index 8de2b2e248..56c1eb5492 100644 --- a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj +++ b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj @@ -18,14 +18,14 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 5073eefe2f..c63c57dc5b 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -94,6 +94,9 @@ namespace Umbraco.Extensions services.AddLogger(tempHostingEnvironment, loggingConfig, config); + // The DataDirectory is used to resolve database file paths (directly supported by SQL CE and manually replaced for LocalDB) + AppDomain.CurrentDomain.SetData("DataDirectory", tempHostingEnvironment?.MapPathContentRoot(Constants.SystemDirectories.Data)); + // Manually create and register the HttpContextAccessor. In theory this should not be registered // again by the user but if that is the case it's not the end of the world since HttpContextAccessor // is just based on AsyncLocal, see https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http/src/HttpContextAccessor.cs @@ -103,6 +106,10 @@ namespace Umbraco.Extensions var requestCache = new HttpContextRequestAppCache(httpContextAccessor); var appCaches = AppCaches.Create(requestCache); + services.ConfigureOptions(); + services.ConfigureOptions(); + services.ConfigureOptions(); + IProfiler profiler = GetWebProfiler(config); ILoggerFactory loggerFactory = LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false)); @@ -150,7 +157,7 @@ namespace Umbraco.Extensions DbProviderFactories.GetFactory, factory.GetServices(), factory.GetServices(), - factory.GetServices(), + factory.GetServices(), factory.GetServices() )); @@ -357,17 +364,17 @@ namespace Umbraco.Extensions Type sqlCeSyntaxProviderType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeSyntaxProvider"); Type sqlCeBulkSqlInsertProviderType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeBulkSqlInsertProvider"); - Type sqlCeEmbeddedDatabaseCreatorType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeEmbeddedDatabaseCreator"); + Type sqlCeDatabaseCreatorType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeDatabaseCreator"); Type sqlCeSpecificMapperFactory = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeSpecificMapperFactory"); if (!(sqlCeSyntaxProviderType is null || sqlCeBulkSqlInsertProviderType is null - || sqlCeEmbeddedDatabaseCreatorType is null + || sqlCeDatabaseCreatorType is null || sqlCeSpecificMapperFactory is null)) { builder.Services.AddSingleton(typeof(ISqlSyntaxProvider), sqlCeSyntaxProviderType); builder.Services.AddSingleton(typeof(IBulkSqlInsertProvider), sqlCeBulkSqlInsertProviderType); - builder.Services.AddSingleton(typeof(IEmbeddedDatabaseCreator), sqlCeEmbeddedDatabaseCreatorType); + builder.Services.AddSingleton(typeof(IDatabaseCreator), sqlCeDatabaseCreatorType); builder.Services.AddSingleton(typeof(IProviderSpecificMapperFactory), sqlCeSpecificMapperFactory); } @@ -397,7 +404,7 @@ namespace Umbraco.Extensions builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); return builder; } diff --git a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs index b0a640b230..b83f647959 100644 --- a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs @@ -1,6 +1,11 @@ using System.Collections.Generic; +using System.Globalization; using System.Threading.Tasks; + +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Authorization; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.Security; @@ -42,6 +47,12 @@ namespace Umbraco.Cms.Web.Common.Filters public async Task OnAuthorizationAsync(AuthorizationFilterContext context) { + // Allow Anonymous skips all authorization + if (HasAllowAnonymous(context)) + { + return; + } + IMemberManager memberManager = context.HttpContext.RequestServices.GetRequiredService(); if (!await IsAuthorizedAsync(memberManager)) @@ -51,6 +62,32 @@ namespace Umbraco.Cms.Web.Common.Filters } } + /// + /// Copied from https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/Authorization/AuthorizeFilter.cs + /// + private bool HasAllowAnonymous(AuthorizationFilterContext context) + { + var filters = context.Filters; + for (var i = 0; i < filters.Count; i++) + { + if (filters[i] is IAllowAnonymousFilter) + { + return true; + } + } + + // When doing endpoint routing, MVC does not add AllowAnonymousFilters for AllowAnonymousAttributes that + // were discovered on controllers and actions. To maintain compat with 2.x, + // we'll check for the presence of IAllowAnonymous in endpoint metadata. + var endpoint = context.HttpContext.GetEndpoint(); + if (endpoint?.Metadata?.GetMetadata() != null) + { + return true; + } + + return false; + } + private async Task IsAuthorizedAsync(IMemberManager memberManager) { if (AllowMembers.IsNullOrWhiteSpace()) @@ -71,7 +108,7 @@ namespace Umbraco.Cms.Web.Common.Filters var members = new List(); foreach (var s in AllowMembers.Split(Core.Constants.CharArrays.Comma)) { - if (int.TryParse(s, out var id)) + if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var id)) { members.Add(id); } diff --git a/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs b/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs index d7d10fe67f..96022cdcc7 100644 --- a/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs +++ b/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs @@ -36,13 +36,20 @@ namespace Umbraco.Cms.Web.Common.Localization lock (_locker) { // We need to dynamically change the supported cultures since we won't ever know what languages are used since - // they are dynamic within Umbraco. + // they are dynamic within Umbraco. We have to handle this for both UI and Region cultures, in case people run different region and UI languages var cultureExists = _localizationOptions.SupportedCultures.Contains(culture); if (!cultureExists) { // add this as a supporting culture _localizationOptions.SupportedCultures.Add(culture); + } + + var uiCultureExists = _localizationOptions.SupportedCultures.Contains(culture); + + if (!uiCultureExists) + { + // add this as a supporting culture _localizationOptions.SupportedUICultures.Add(culture); } diff --git a/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs b/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs index ab3f4ccc77..50e8d859ea 100644 --- a/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs +++ b/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs @@ -36,7 +36,7 @@ namespace Umbraco.Cms.Web.Common.Localization lock (_locker) { // We need to dynamically change the supported cultures since we won't ever know what languages are used since - // they are dynamic within Umbraco. + // they are dynamic within Umbraco. We have to handle this for both UI and Region cultures, in case people run different region and UI languages // This code to check existence is borrowed from aspnetcore to avoid creating a CultureInfo // https://github.com/dotnet/aspnetcore/blob/b795ac3546eb3e2f47a01a64feb3020794ca33bb/src/Middleware/Localization/src/RequestLocalizationMiddleware.cs#L165 CultureInfo existingCulture = _localizationOptions.SupportedCultures.FirstOrDefault(supportedCulture => @@ -47,6 +47,15 @@ namespace Umbraco.Cms.Web.Common.Localization // add this as a supporting culture var ci = CultureInfo.GetCultureInfo(culture); _localizationOptions.SupportedCultures.Add(ci); + } + + CultureInfo existingUICulture = _localizationOptions.SupportedUICultures.FirstOrDefault(supportedCulture => + StringSegment.Equals(supportedCulture.Name, culture, StringComparison.OrdinalIgnoreCase)); + + if (existingUICulture == null) + { + // add this as a supporting culture + var ci = CultureInfo.GetCultureInfo(culture); _localizationOptions.SupportedUICultures.Add(ci); } } diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs index fe0029bd80..539c1c844f 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -13,10 +13,11 @@ using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Logging; +using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.PublishedCache; @@ -50,6 +51,8 @@ namespace Umbraco.Cms.Web.Common.Middleware private readonly UmbracoRequestPaths _umbracoRequestPaths; private readonly BackOfficeWebAssets _backOfficeWebAssets; private readonly IRuntimeState _runtimeState; + private readonly IVariationContextAccessor _variationContextAccessor; + private readonly IDefaultCultureAccessor _defaultCultureAccessor; private readonly SmidgeOptions _smidgeOptions; private readonly WebProfiler _profiler; @@ -77,7 +80,9 @@ namespace Umbraco.Cms.Web.Common.Middleware UmbracoRequestPaths umbracoRequestPaths, BackOfficeWebAssets backOfficeWebAssets, IOptions smidgeOptions, - IRuntimeState runtimeState) + IRuntimeState runtimeState, + IVariationContextAccessor variationContextAccessor, + IDefaultCultureAccessor defaultCultureAccessor) { _logger = logger; _umbracoContextFactory = umbracoContextFactory; @@ -88,6 +93,8 @@ namespace Umbraco.Cms.Web.Common.Middleware _umbracoRequestPaths = umbracoRequestPaths; _backOfficeWebAssets = backOfficeWebAssets; _runtimeState = runtimeState; + _variationContextAccessor = variationContextAccessor; + _defaultCultureAccessor = defaultCultureAccessor; _smidgeOptions = smidgeOptions.Value; _profiler = profiler as WebProfiler; // Ignore if not a WebProfiler } @@ -110,6 +117,7 @@ namespace Umbraco.Cms.Web.Common.Middleware EnsureContentCacheInitialized(); + _variationContextAccessor.VariationContext ??= new VariationContext(_defaultCultureAccessor.DefaultCulture); UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); Uri currentApplicationUrl = GetApplicationUrlFromCurrentRequest(context.Request); diff --git a/src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs new file mode 100644 index 0000000000..25427461d5 --- /dev/null +++ b/src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; + +namespace Umbraco.Cms.Web.Common.Security +{ + public class ConfigureFormOptions : IConfigureOptions + { + private readonly IOptions _runtimeSettings; + + public ConfigureFormOptions(IOptions runtimeSettings) => _runtimeSettings = runtimeSettings; + public void Configure(FormOptions options) + { + // convert from KB to bytes + options.MultipartBodyLengthLimit = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : long.MaxValue; + } + } +} diff --git a/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs new file mode 100644 index 0000000000..4141669c1c --- /dev/null +++ b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; + +namespace Umbraco.Cms.Web.Common.Security +{ + public class ConfigureIISServerOptions : IConfigureOptions + { + private readonly IOptions _runtimeSettings; + + public ConfigureIISServerOptions(IOptions runtimeSettings) => _runtimeSettings = runtimeSettings; + public void Configure(IISServerOptions options) + { + // convert from KB to bytes + options.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : uint.MaxValue; // ~4GB is the max supported value for IIS and IIS express. + } + } +} diff --git a/src/Umbraco.Web.Common/Security/ConfigureKestrelServerOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureKestrelServerOptions.cs new file mode 100644 index 0000000000..c11e0d8814 --- /dev/null +++ b/src/Umbraco.Web.Common/Security/ConfigureKestrelServerOptions.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; + +namespace Umbraco.Cms.Web.Common.Security +{ + public class ConfigureKestrelServerOptions : IConfigureOptions + { + private readonly IOptions _runtimeSettings; + + public ConfigureKestrelServerOptions(IOptions runtimeSettings) => _runtimeSettings = runtimeSettings; + public void Configure(KestrelServerOptions options) + { + // convert from KB to bytes + options.Limits.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : long.MaxValue; + } + } +} diff --git a/src/Umbraco.Web.Common/Security/MemberManager.cs b/src/Umbraco.Web.Common/Security/MemberManager.cs index f7d0c8e43e..9a0f26aff4 100644 --- a/src/Umbraco.Web.Common/Security/MemberManager.cs +++ b/src/Umbraco.Web.Common/Security/MemberManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -82,7 +83,7 @@ namespace Umbraco.Cms.Web.Common.Security return false; } - int memberId = int.Parse(currentMember.Id); + int memberId = int.Parse(currentMember.Id, CultureInfo.InvariantCulture); username = currentMember.UserName; // If types defined, check member is of one of those types @@ -192,7 +193,7 @@ namespace Umbraco.Cms.Web.Common.Security if (currentMember == null || !currentMember.IsApproved || currentMember.IsLockedOut) { return false; - } + } return await _publicAccessService.HasAccessAsync( path, @@ -231,7 +232,7 @@ namespace Umbraco.Cms.Web.Common.Security async () => await getUserRolesAsync()); } return result; - } + } public IPublishedContent AsPublishedMember(MemberIdentityUser user) => _store.GetPublishedMember(user); } diff --git a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj index 3a04ed1b22..ea4194431f 100644 --- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj +++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj @@ -25,8 +25,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -38,7 +38,7 @@ - + all diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index ad00c5b8b6..260a58a035 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -20,7 +20,7 @@ "@babel/core": { "version": "7.6.4", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.4.tgz", - "integrity": "sha1-br2f4Akl9sPhd7tyahiLX1eAiP8=", + "integrity": "sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==", "dev": true, "requires": { "@babel/code-frame": "^7.5.5", @@ -831,7 +831,7 @@ "@babel/preset-env": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.3.tgz", - "integrity": "sha1-nhvwWi4taHA20kxA5GOdxGzvInE=", + "integrity": "sha512-CWQkn7EVnwzlOdR5NOm2+pfgSNEZmvGjOhlCHBDq0J8/EStr+G+FvPEiz9B56dR6MoiUFjXhfE4hjLoAKKJtIQ==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", @@ -957,7 +957,7 @@ "@gulp-sourcemaps/identity-map": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz", - "integrity": "sha1-Hm/l2AJ7HyhdwNMXYvVmvM1z1ak=", + "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==", "dev": true, "requires": { "acorn": "^5.0.3", @@ -976,7 +976,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -1086,7 +1086,7 @@ "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "dev": true, "requires": { "mime-types": "~2.1.24", @@ -1096,7 +1096,7 @@ "accord": { "version": "0.29.0", "resolved": "https://registry.npmjs.org/accord/-/accord-0.29.0.tgz", - "integrity": "sha1-t0HBdtAENcWSnUZt/oz2vukzseQ=", + "integrity": "sha512-3OOR92FTc2p5/EcOzPcXp+Cbo+3C15nV9RXHlOUBCBpHhcB+0frbSNR9ehED/o7sTcyGVtqGJpguToEdlXhD0w==", "dev": true, "requires": { "convert-source-map": "^1.5.0", @@ -1143,7 +1143,7 @@ "ace-builds": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.2.tgz", - "integrity": "sha1-avwuQ6e17/3ETYQHQ2EShSVo6A0=" + "integrity": "sha512-M1JtZctO2Zg+1qeGUFZXtYKsyaRptqQtqpVzlj80I0NzGW9MF3um0DBuizIvQlrPYUlTdm+wcOPZpZoerkxQdA==" }, "acorn": { "version": "7.1.0", @@ -1240,12 +1240,12 @@ "angular-animate": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.7.5.tgz", - "integrity": "sha1-H/xsKpze4ieiunnMbNj3HsRNtdw=" + "integrity": "sha512-kU/fHIGf2a4a3bH7E1tzALTHk+QfoUSCK9fEcMFisd6ZWvNDwPzXWAilItqOC3EDiAXPmGHaNc9/aXiD9xrAxQ==" }, "angular-aria": { "version": "1.7.9", "resolved": "https://registry.npmjs.org/angular-aria/-/angular-aria-1.7.9.tgz", - "integrity": "sha1-kMYYlf+9h26VkVIisyp70AcK9+M=" + "integrity": "sha512-luI3Jemd1AbOQW0krdzfEG3fM0IFtLY0bSSqIDEx3POE0XjKIC1MkrO8Csyq9PPgueLphyAPofzUwZ8YeZ88SA==" }, "angular-chart.js": { "version": "1.1.1", @@ -1270,12 +1270,12 @@ "angular-cookies": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.7.5.tgz", - "integrity": "sha1-HFqzwFzcQ/F3e+lQbmRYfLNUNjQ=" + "integrity": "sha512-/8xvvSl/Z9Vwu8ChRm+OQE3vmli8Icwl8uTYkHqD7j7cknJP9kNaf7SgsENlsLVtOqLE/I7TCFYrSx3bmSeNQA==" }, "angular-dynamic-locale": { "version": "0.1.37", "resolved": "https://registry.npmjs.org/angular-dynamic-locale/-/angular-dynamic-locale-0.1.37.tgz", - "integrity": "sha1-fon70uxFvdaryJ82zaiJODjkk1Q=", + "integrity": "sha512-m5Kyk8W8/mOZSqRxuByOwHBjv8labLBAgvl0Z3iQx2xT/tWCqb94imKUPwumudszdPDjxeopwyucQvm8Sw7ogw==", "requires": { "@types/angular": "^1.6.25" } @@ -1283,7 +1283,7 @@ "angular-i18n": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-i18n/-/angular-i18n-1.7.5.tgz", - "integrity": "sha1-Lie2Thl3qMa2sFHFHQF1xtTcglI=" + "integrity": "sha512-52+Jpt8HRJV2bqSbSU6fWkwOvGzj/DxbNpKXxnTuCS9heuJrlm77BS/lhrF4BA8+Uudnh7npr5/yRELobP+8Yw==" }, "angular-local-storage": { "version": "0.7.1", @@ -1293,32 +1293,32 @@ "angular-messages": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-messages/-/angular-messages-1.7.5.tgz", - "integrity": "sha1-fC/XgTFaQ6GYOLEX2gFCqYhFThQ=" + "integrity": "sha512-YDpJpFLyrIgZjE/sIAjgww1y6r3QqXBJbNDI0QjftD37vHXLkwvAOo3A4bxPw8BikyGLcJrFrgf6hRAzntJIWA==" }, "angular-mocks": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.7.5.tgz", - "integrity": "sha1-yLq6WgbtYLk0aXAmtJIWliavOEs=" + "integrity": "sha512-I+Ue2Bkx6R9W5178DYrNvzjIdGh4wKKoCWsgz8dc7ysH4mA70Q3M9v5xRF0RUu7r+2CZj+nDeUecvh2paxcYvg==" }, "angular-route": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-route/-/angular-route-1.7.5.tgz", - "integrity": "sha1-NKNkjEB6FKAw0HXPSFMY4zuiPw4=" + "integrity": "sha512-7KfyEVVOWTI+jTY/j5rUNCIHGRyeCOx7YqZI/Ci3IbDK7GIsy6xH+hS5ai0Xi0sLjzDZ0PUDO4gBn+K0dVtlOg==" }, "angular-sanitize": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-sanitize/-/angular-sanitize-1.7.5.tgz", - "integrity": "sha1-ddSeFQccqccFgedtIJQPJjcuJNI=" + "integrity": "sha512-wjKCJOIwrkEvfD0keTnKGi6We13gtoCAQIHcdoqyoo3gwvcgNfYymVQIS3+iCGVcjfWz0jHuS3KgB4ysRWsTTA==" }, "angular-touch": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-touch/-/angular-touch-1.7.5.tgz", - "integrity": "sha1-7SYyKmhfApmyPLauqYNMEZQk2kY=" + "integrity": "sha512-XNAZNG0RA1mtdwBJheViCF1H/7wOygp4MLIfs5y1K+rne6AeaYKZcV6EJs9fvgfLKLO6ecm1+3J8hoCkdhhxQw==" }, "angular-ui-sortable": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/angular-ui-sortable/-/angular-ui-sortable-0.19.0.tgz", - "integrity": "sha1-SsQ5H8TU3lcRDbS10xp8GY0xT9A=", + "integrity": "sha512-u/uc981Nzg4XN1bMU9qKleMTSt7F1XjMWnyGw6gxPLIeQeLZm8jWNy7tj8y2r2HmvzXFbQVq2z6rObznFKAekQ==", "requires": { "angular": ">=1.2.x", "jquery": ">=3.1.x", @@ -1333,7 +1333,7 @@ "ansi-colors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha1-Y3S03V1HGP884npnGjscrQdxMqk=", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { "ansi-wrap": "^0.1.0" @@ -1381,7 +1381,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -1561,7 +1561,7 @@ "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" @@ -1585,7 +1585,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, "arr-map": { @@ -1635,7 +1635,7 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true } } @@ -1643,7 +1643,7 @@ "array-last": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha1-eqdwc/7FZd2rJJP1+IGF9ASp0zY=", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", "dev": true, "requires": { "is-number": "^4.0.0" @@ -1652,7 +1652,7 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true } } @@ -1660,13 +1660,13 @@ "array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha1-42jqFfibxwaff/uJrsOmx9SsItQ=", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, "array-sort": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha1-5MBTVkU/VvU1EqfR1hI/LFTAqIo=", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", "dev": true, "requires": { "default-compare": "^1.0.0", @@ -1677,7 +1677,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } @@ -1703,7 +1703,7 @@ "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", "dev": true }, "asap": { @@ -1716,7 +1716,7 @@ "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { "safer-buffer": "~2.1.0" } @@ -1735,13 +1735,13 @@ "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha1-bIw/uCfdQ+45GPJ7gngqt2WKb9k=", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, "async": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha1-1yYl4jRKNlbjo61Pp0n6gymdgv8=", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "dev": true, "requires": { "lodash": "^4.17.14" @@ -1758,7 +1758,7 @@ "async-done": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha1-XhWqcplipLB0FPUoqIzfGOCykKI=", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -1770,13 +1770,13 @@ "async-each": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha1-tyfb+H12UWAvBvTUrDh/R9kbDL8=", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha1-3TeelPDbgxCwgpH51kwyCXZmF/0=" + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, "async-settle": { "version": "1.0.0", @@ -1795,13 +1795,13 @@ "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k=", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, "autoprefixer": { "version": "9.6.5", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.5.tgz", - "integrity": "sha1-mPSv5+k8zPMjKHUV1CYBlhl3Xl4=", + "integrity": "sha512-rGd50YV8LgwFQ2WQp4XzOTG69u1qQsXn0amww7tjqV5jJuNazgFKYEVItEBngyyvVITKOg20zr2V+9VsrXJQ2g==", "dev": true, "requires": { "browserslist": "^4.7.0", @@ -1834,7 +1834,7 @@ "babel-plugin-dynamic-import-node": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", - "integrity": "sha1-8A9Qe9qjw+P/bn5emNkKesq5b38=", + "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", "dev": true, "requires": { "object.assign": "^4.1.0" @@ -1872,7 +1872,7 @@ "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { "cache-base": "^1.0.1", @@ -1896,7 +1896,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -1905,7 +1905,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -1914,7 +1914,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -2257,7 +2257,7 @@ "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha1-WYr+VHVbKGilMw0q/51Ou1Mgm2U=", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "bl": { @@ -2309,7 +2309,7 @@ "blob": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", - "integrity": "sha1-1oDu7yX4zZGtUz9bAe7UjmTK9oM=", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", "dev": true }, "bluebird": { @@ -2321,7 +2321,7 @@ "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "dev": true, "requires": { "bytes": "3.1.0", @@ -2339,7 +2339,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -2354,7 +2354,7 @@ "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", "dev": true } } @@ -2368,7 +2368,7 @@ "bootstrap": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", - "integrity": "sha1-w6NH1Bniia0R9AM+PEEyuHwIHXI=" + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==" }, "bootstrap-social": { "version": "5.1.1", @@ -2382,7 +2382,7 @@ "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -2392,7 +2392,7 @@ "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { "arr-flatten": "^1.1.0", @@ -2449,7 +2449,7 @@ "buffer-alloc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha1-iQ3ZDZI6hz4I4Q5f1RpX5bfM4Ow=", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", "dev": true, "requires": { "buffer-alloc-unsafe": "^1.1.0", @@ -2459,7 +2459,7 @@ "buffer-alloc-unsafe": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha1-vX3CauKXLQ7aJTvgYdupkjScGfA=", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", "dev": true }, "buffer-crc32": { @@ -2484,7 +2484,7 @@ "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8=", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, "bufferstreams": { @@ -2499,13 +2499,13 @@ "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", "dev": true }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { "collection-visit": "^1.0.0", @@ -2606,7 +2606,7 @@ }, "callsites": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", "dev": true }, @@ -2639,7 +2639,7 @@ "caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha1-Xk2Q4idJYdRikZl99Znj7QCO5MA=", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -2685,7 +2685,7 @@ "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -2696,7 +2696,7 @@ "chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha1-kAlISfCTfy7twkJdDSip5fDLrZ4=", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, "chart.js": { @@ -2720,7 +2720,7 @@ "chartjs-color-string": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", - "integrity": "sha1-HfCWYhwOcHIKZPQTXqFx0FFAL3E=", + "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", "requires": { "color-name": "^1.0.0" } @@ -2728,7 +2728,7 @@ "chokidar": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha1-gEs6e2qZNYw8XGHnHYco8EHP+Rc=", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -2778,7 +2778,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true } } @@ -2786,7 +2786,7 @@ "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -2809,7 +2809,7 @@ "clean-css": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", - "integrity": "sha1-LUEe92uFabbQyEBo2r6FsKpeXBc=", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", "dev": true, "requires": { "source-map": "~0.6.0" @@ -2818,7 +2818,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -2826,7 +2826,7 @@ "cli-color": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha1-fRBzj0hSaCT4/n2lGFfLD1cv4B8=", + "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", "dev": true, "requires": { "ansi-regex": "^2.1.1", @@ -2855,7 +2855,7 @@ "clipboard": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", - "integrity": "sha1-g22v1mzw/qXXHOXVsL9ulYAJES0=", + "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", "requires": { "good-listener": "^1.2.2", "select": "^1.1.2", @@ -2904,7 +2904,7 @@ "cloneable-readable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", - "integrity": "sha1-EgoAywU7+2OiIucJ+Wg+ouEdjOw=", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", "dev": true, "requires": { "inherits": "^2.0.1", @@ -2947,7 +2947,7 @@ "coa": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha1-Q/bCEVG07yv1cYfbDXPeIp4+fsM=", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", "dev": true, "requires": { "@types/q": "^1.5.1", @@ -2985,7 +2985,7 @@ "color": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", - "integrity": "sha1-aBSOf4XUGtdknF+oyBBvCY0inhA=", + "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", "dev": true, "requires": { "color-convert": "^1.9.1", @@ -3017,12 +3017,12 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "color-string": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", - "integrity": "sha1-ybvF8BtYtUkvPWhXRZy2WQziBMw=", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", "dev": true, "requires": { "color-name": "^1.0.0", @@ -3032,7 +3032,7 @@ "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true }, "colorette": { @@ -3050,13 +3050,13 @@ "colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha1-xQSRR51MG9rtLJztMs98fcI2D3g=", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, "colorspace": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", - "integrity": "sha1-4BKJUNCCuGohaFgHlqCqXWxo2MU=", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", "dev": true, "requires": { "color": "3.0.x", @@ -3066,7 +3066,7 @@ "color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha1-2SC0Mo1TSjrIKV1o971LpsQnvpo=", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", "dev": true, "requires": { "color-convert": "^1.9.1", @@ -3093,7 +3093,7 @@ "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "requires": { "delayed-stream": "~1.0.0" } @@ -3113,7 +3113,7 @@ "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, "component-inherit": { @@ -3131,7 +3131,7 @@ "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -3164,7 +3164,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -3175,7 +3175,7 @@ "concat-with-sourcemaps": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", - "integrity": "sha1-1OqT8FriV5CVG5nns7CeOQikCC4=", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", "dev": true, "requires": { "source-map": "^0.6.1" @@ -3184,7 +3184,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -3203,7 +3203,7 @@ "connect": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha1-XUk0iRDKpeB6AYALAw0MNfIEhPg=", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "requires": { "debug": "2.6.9", @@ -3215,7 +3215,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -3239,7 +3239,7 @@ "consolidate": { "version": "0.15.1", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", - "integrity": "sha1-IasEMjXHGgfUXZqtmFk7DbpWurc=", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", "dev": true, "requires": { "bluebird": "^3.1.1" @@ -3258,7 +3258,7 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, "convert-source-map": { @@ -3285,7 +3285,7 @@ "copy-props": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", - "integrity": "sha1-k7scrfr9MdpbuKnUtB9HHsOnLf4=", + "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", "dev": true, "requires": { "each-props": "^1.3.0", @@ -3344,7 +3344,7 @@ "cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha1-BA9yaAnFked6F8CjYmykW08Wixo=", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", "dev": true, "requires": { "import-fresh": "^2.0.0", @@ -3356,7 +3356,7 @@ "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -3369,7 +3369,7 @@ "css": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", - "integrity": "sha1-xkZ1XHOXHyu6amAeLPL9cbEpiSk=", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -3381,7 +3381,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -3395,7 +3395,7 @@ "css-declaration-sorter": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha1-wZiUD2OnbX42wecQGLABchBUyyI=", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", "dev": true, "requires": { "postcss": "^7.0.1", @@ -3417,7 +3417,7 @@ "css-select-base-adapter": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha1-Oy/0lyzDYquIVhUHqVQIoUMhNdc=", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", "dev": true }, "css-tree": { @@ -3451,7 +3451,7 @@ "cssnano": { "version": "4.1.10", "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", - "integrity": "sha1-CsQfCxPRPUZUh+ERt3jULaYxuLI=", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", "dev": true, "requires": { "cosmiconfig": "^5.0.0", @@ -3463,7 +3463,7 @@ "cssnano-preset-default": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", - "integrity": "sha1-UexmLM/KD4izltzZZ5zbkxvhf3Y=", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", "dev": true, "requires": { "css-declaration-sorter": "^4.0.1", @@ -3513,7 +3513,7 @@ "cssnano-util-raw-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha1-sm1f1fcqEd/np4RvtMZyYPlr8oI=", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -3522,7 +3522,7 @@ "cssnano-util-same-parent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha1-V0CC+yhZ0ttDOFWDXZqEVuoYu/M=", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", "dev": true }, "csso": { @@ -3594,7 +3594,7 @@ "d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha1-hpgJU3LVjb7jRv/Qxwk/mfj561o=", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", "dev": true, "requires": { "es5-ext": "^0.10.50", @@ -3635,7 +3635,7 @@ "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" @@ -3644,7 +3644,7 @@ "debug-fabulous": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", - "integrity": "sha1-r4oIYyRlIk70F0qfBjCMPCoevI4=", + "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", "dev": true, "requires": { "debug": "3.X", @@ -3849,7 +3849,7 @@ "default-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha1-y2ETGESthNhHiPto/QFoHKd4Gi8=", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", "dev": true, "requires": { "kind-of": "^5.0.2" @@ -3858,7 +3858,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } @@ -3872,7 +3872,7 @@ "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { "object-keys": "^1.0.12" @@ -3881,7 +3881,7 @@ "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { "is-descriptor": "^1.0.2", @@ -3891,7 +3891,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -3900,7 +3900,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -3909,7 +3909,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -3927,7 +3927,7 @@ "delegate": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha1-tmtxwxWFIuirV0T3INjKDCr1kWY=" + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" }, "depd": { "version": "1.1.2", @@ -3956,7 +3956,7 @@ "diagnostics": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", - "integrity": "sha1-yrasM99wydmnJ0kK5DrJladpsio=", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", "dev": true, "requires": { "colorspace": "1.1.x", @@ -3967,7 +3967,7 @@ "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=" + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, "dir-glob": { "version": "3.0.1", @@ -3989,7 +3989,7 @@ "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -4020,7 +4020,7 @@ "domelementtype": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", - "integrity": "sha1-H4vf6R9aeAYydOgDtL3O326U+U0=", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", "dev": true } } @@ -4028,7 +4028,7 @@ "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha1-0EjESzew0Qp/Kj1f7j9DM9eQSB8=", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", "dev": true }, "domexception": { @@ -4051,7 +4051,7 @@ "domhandler": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM=", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "dev": true, "requires": { "domelementtype": "1" @@ -4060,7 +4060,7 @@ "domutils": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha1-Vuo0HoNOBuZ0ivehyyXaZ+qfjCo=", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", "dev": true, "requires": { "dom-serializer": "0", @@ -4148,7 +4148,7 @@ "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk=", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "dev": true, "requires": { "end-of-stream": "^1.0.0", @@ -4192,7 +4192,7 @@ "each-props": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha1-6kWkFNFt1c+kGbGoFyDVygaJIzM=", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", "dev": true, "requires": { "is-plain-object": "^2.0.1", @@ -4250,7 +4250,7 @@ "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha1-WuZKX0UFe682JuwU2gyl5LJDHrA=", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { "once": "^1.4.0" @@ -4362,7 +4362,7 @@ "entities": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", - "integrity": "sha1-aNYITKsbB5dnVA2A5Wo5tCPkq/Q=", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", "dev": true }, "env-variable": { @@ -4374,7 +4374,7 @@ "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "dev": true, "optional": true, "requires": { @@ -4384,7 +4384,7 @@ "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { "is-arrayish": "^0.2.1" @@ -4444,7 +4444,7 @@ "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha1-TrIVlMlyvEBVPSduUQU5FD21Pgo=", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "dev": true }, "es6-symbol": { @@ -4460,7 +4460,7 @@ "es6-weak-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha1-ttofFswswNm+Q+a9v8Xn383zHVM=", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", "dev": true, "requires": { "d": "1", @@ -4509,7 +4509,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } @@ -4563,7 +4563,7 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "glob-parent": { @@ -4597,19 +4597,19 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { "ansi-regex": "^4.1.0" @@ -4630,7 +4630,7 @@ "eslint-utils": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha1-dP7HxU0Hdrb2fgJRBAtYBlZOmB8=", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" @@ -4656,7 +4656,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "esquery": { @@ -4698,13 +4698,13 @@ "estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0=", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "event-emitter": { @@ -4833,7 +4833,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -4877,7 +4877,7 @@ "fill-range": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", "dev": true, "requires": { "is-number": "^2.1.0", @@ -4955,7 +4955,7 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", @@ -4970,7 +4970,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -4981,7 +4981,7 @@ "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha1-ywP3QL764D6k0oPK7SdBqD8zVJU=", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, "requires": { "chardet": "^0.7.0", @@ -4992,7 +4992,7 @@ "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { "array-unique": "^0.3.2", @@ -5026,7 +5026,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -5035,7 +5035,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -5044,7 +5044,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -5062,7 +5062,7 @@ "fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha1-28GRVPVYaQFQojlToK29A1vkX8c=", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", "dev": true, "requires": { "ansi-gray": "^0.1.1", @@ -5201,7 +5201,7 @@ "file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha1-yg9u+m3T1WEzP7FFFQZcL6/fQ5w=", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", "dev": true, "requires": { "flat-cache": "^2.0.1" @@ -5264,7 +5264,7 @@ "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "requires": { "debug": "2.6.9", @@ -5279,7 +5279,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -5339,7 +5339,7 @@ "fined": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha1-0AvszxqitHXRbUI7Aji3E6LEo3s=", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", "dev": true, "requires": { "expand-tilde": "^2.0.2", @@ -5393,13 +5393,13 @@ "flagged-respawn": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha1-595vEnnd2cqarIpZcdYYYGs6q0E=", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", "dev": true }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha1-XSltbwS9pEpGMKMBQTvbwuwIXsA=", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, "requires": { "flatted": "^2.0.0", @@ -5415,13 +5415,13 @@ "flatted": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha1-aeV8qo8OrLwoHS4stFjUb9tEngg=", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, "flush-write-stream": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha1-jdfYc6G6vCB9lOrQwuDkQnbr8ug=", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -5508,7 +5508,7 @@ "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -5596,7 +5596,7 @@ "fs-readfile-promise": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/fs-readfile-promise/-/fs-readfile-promise-3.0.1.tgz", - "integrity": "sha1-0NMHt/au38kgwx+m5XEu+qKXyVg=", + "integrity": "sha512-LsSxMeaJdYH27XrW7Dmq0Gx63mioULCRel63B5VeELYLavi1wF5s0XfsIdKDFdCL9hsfQ2qBvXJszQtQJ9h17A==", "dev": true, "requires": { "graceful-fs": "^4.1.11" @@ -6159,7 +6159,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "functional-red-black-tree": { @@ -6171,7 +6171,7 @@ "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha1-+Xj6TJDR3+f/LWvtoqUV5xO9z0o=", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, "get-proxy": { @@ -6475,7 +6475,7 @@ "glob-watcher": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", - "integrity": "sha1-iKir8cTRMeuTkomUvEpZPC5d1iY=", + "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -6501,7 +6501,7 @@ "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { "global-prefix": "^1.0.1", @@ -6525,7 +6525,7 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4=", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "globby": { @@ -6561,7 +6561,7 @@ "glogg": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha1-LX3XAr7aIus7/634gGltpthGMT8=", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", "dev": true, "requires": { "sparkles": "^1.0.0" @@ -6622,7 +6622,7 @@ "gulp": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", - "integrity": "sha1-VDZRBw/Q9qsKBlDGo+b/WnywnKo=", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", "dev": true, "requires": { "glob-watcher": "^5.0.3", @@ -6655,7 +6655,7 @@ "gulp-babel": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/gulp-babel/-/gulp-babel-8.0.0.tgz", - "integrity": "sha1-4NqW9PLsSojdOjAw9HbjirISbYc=", + "integrity": "sha512-oomaIqDXxFkg7lbpBou/gnUkX51/Y/M2ZfSjL2hdqXTAlSWZcgZtd2o0cOH0r/eE8LWD0+Q/PsLsr2DKOoqToQ==", "dev": true, "requires": { "plugin-error": "^1.0.1", @@ -6675,7 +6675,7 @@ "gulp-clean-css": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.2.0.tgz", - "integrity": "sha1-kV7CWNxtPmpQBD9hAGbVwurE9U4=", + "integrity": "sha512-r4zQsSOAK2UYUL/ipkAVCTRg/2CLZ2A+oPVORopBximRksJ6qy3EX1KGrIWT4ZrHxz3Hlobb1yyJtqiut7DNjA==", "dev": true, "requires": { "clean-css": "4.2.1", @@ -6713,7 +6713,7 @@ "through2": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha1-OSducTwzAu3544jdnIEt07glvVo=", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", "dev": true, "requires": { "readable-stream": "2 || 3" @@ -6795,7 +6795,7 @@ "gulp-eslint": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-6.0.0.tgz", - "integrity": "sha1-fUArtF+KZ2UrhoJ3ARgSBXNwqDI=", + "integrity": "sha512-dCVPSh1sA+UVhn7JSQt7KEb4An2sQNbOdB3PA8UCfxsoPlAKjJHxYHGXdXC7eb+V1FAnilSFFqslPrq037l1ig==", "dev": true, "requires": { "eslint": "^6.0.0", @@ -6870,7 +6870,7 @@ "gulp-less": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/gulp-less/-/gulp-less-4.0.1.tgz", - "integrity": "sha1-NIwzpd3nogfFdxsdgmHRrBAhzu0=", + "integrity": "sha512-hmM2k0FfQp7Ptm3ZaqO2CkMX3hqpiIOn4OHtuSsCeFym63F7oWlEua5v6u1cIjVUKYsVIs9zPg9vbqTEb/udpA==", "dev": true, "requires": { "accord": "^0.29.0", @@ -6915,7 +6915,7 @@ }, "kind-of": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", "dev": true }, @@ -7047,7 +7047,7 @@ "gulp-notify": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/gulp-notify/-/gulp-notify-3.2.0.tgz", - "integrity": "sha1-KugiUAnfiB7vWb5d1aLxM3OHdk4=", + "integrity": "sha512-qEocs1UVoDKKUjfsxJNMNwkRla0PbsyJwsqNNXpzYWsLQ29LhxRMY3wnTGZcc4hMHtalnvah/Dwlwb4NijH/0A==", "dev": true, "requires": { "ansi-colors": "^1.0.1", @@ -7099,7 +7099,7 @@ "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha1-+XYZXPPzR9DV9SSDVp/oAxzM6Ks=", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", "dev": true, "requires": { "lodash._reinterpolate": "^3.0.0", @@ -7109,7 +7109,7 @@ "lodash.templatesettings": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha1-5IExDwSdPPbUfpEq0JMTsVTw+zM=", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", "dev": true, "requires": { "lodash._reinterpolate": "^3.0.0" @@ -7133,7 +7133,7 @@ "gulp-postcss": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/gulp-postcss/-/gulp-postcss-8.0.0.tgz", - "integrity": "sha1-jTdyzU0nvKVeyMtMjlduO95NxVA=", + "integrity": "sha512-Wtl6vH7a+8IS/fU5W9IbOpcaLqKxd5L1DUOzaPmlnCbX1CrG0aWdwVnC3Spn8th0m8D59YbysV5zPUe1n/GJYg==", "dev": true, "requires": { "fancy-log": "^1.3.2", @@ -7146,7 +7146,7 @@ "gulp-rename": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.4.0.tgz", - "integrity": "sha1-3hxxjnxAla6GH3KW708ySGSCQL0=", + "integrity": "sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg==", "dev": true }, "gulp-sort": { @@ -7161,7 +7161,7 @@ "gulp-sourcemaps": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz", - "integrity": "sha1-o/AC2HNG0sDzrsNq9+uHPyPeiuY=", + "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==", "dev": true, "requires": { "@gulp-sourcemaps/identity-map": "1.X", @@ -7186,7 +7186,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -7225,7 +7225,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -7247,7 +7247,7 @@ "gulp-watch": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/gulp-watch/-/gulp-watch-5.0.1.tgz", - "integrity": "sha1-g9N4dS9b+0baAj5zwX7R2nBmIV0=", + "integrity": "sha512-HnTSBdzAOFIT4wmXYPDUn783TaYAq9bpaN05vuZNP5eni3z3aRx0NAKbjhhMYtcq76x4R1wf4oORDGdlrEjuog==", "dev": true, "requires": { "ansi-colors": "1.1.0", @@ -7348,7 +7348,7 @@ "gulp-wrap": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/gulp-wrap/-/gulp-wrap-0.15.0.tgz", - "integrity": "sha1-6QFMm7hkOrMQ6TjURpuFaFUaVS8=", + "integrity": "sha512-f17zkGObA+hE/FThlg55gfA0nsXbdmHK1WqzjjB2Ytq1TuhLR7JiCBJ3K4AlMzCyoFaCjfowos+VkToUNE0WTQ==", "dev": true, "requires": { "consolidate": "^0.15.1", @@ -7392,7 +7392,7 @@ "through2": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha1-OSducTwzAu3544jdnIEt07glvVo=", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", "dev": true, "requires": { "readable-stream": "2 || 3" @@ -7457,7 +7457,7 @@ "har-validator": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha1-HvievT5JllV2de7ZiTEQ3DUPoIA=", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { "ajv": "^6.5.5", "har-schema": "^2.0.0" @@ -7466,7 +7466,7 @@ "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { "function-bind": "^1.1.1" @@ -7484,7 +7484,7 @@ "has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", "dev": true, "requires": { "isarray": "2.0.1" @@ -7577,13 +7577,13 @@ "hex-color-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha1-TAb8y0YC/iYCs8k9+C1+fb8aio4=", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", "dev": true }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha1-dDKYzvTlrz4ZQWH7rcwhUdOgWOg=", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, "requires": { "parse-passwd": "^1.0.0" @@ -7610,7 +7610,7 @@ "html-comment-regex": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", - "integrity": "sha1-l9RoiutcgYhqNk+qDK0d2hTUM6c=", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", "dev": true }, "html-encoding-sniffer": { @@ -7639,7 +7639,7 @@ "entities": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha1-vfpzUplmTfr9NFKe1PhSKidf6lY=", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", "dev": true }, "isarray": { @@ -7684,7 +7684,7 @@ "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", "dev": true, "requires": { "depd": "~1.1.2", @@ -7733,7 +7733,7 @@ "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -7749,7 +7749,7 @@ "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "image-size": { @@ -7993,13 +7993,13 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, "inquirer": { @@ -8095,7 +8095,7 @@ "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, "requires": { "loose-envify": "^1.0.0" @@ -8122,13 +8122,13 @@ "is": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", - "integrity": "sha1-Yc/23TxBk9uUo9YlggcrROVkXXk=", + "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==", "dev": true }, "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { "is-relative": "^1.0.0", @@ -8179,13 +8179,13 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "integrity": "sha1-HhrfIZ4e62hNaR+dagX/DTCiTXU=", "dev": true }, "is-color-stop": { @@ -8231,7 +8231,7 @@ "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", @@ -8242,7 +8242,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } @@ -8387,7 +8387,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { "isobject": "^3.0.1" @@ -8436,7 +8436,7 @@ "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { "is-unc-path": "^1.0.0" @@ -8445,7 +8445,7 @@ "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, "is-retry-allowed": { @@ -8465,7 +8465,7 @@ "is-svg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", - "integrity": "sha1-kyHb0pwhLlypnE+peUxxS8r6L3U=", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", "dev": true, "requires": { "html-comment-regex": "^1.1.0" @@ -8488,7 +8488,7 @@ "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { "unc-path-regex": "^0.1.2" @@ -8509,7 +8509,7 @@ "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, "is-wsl": { @@ -8564,7 +8564,7 @@ "jasmine-core": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.5.0.tgz", - "integrity": "sha1-Eywj5kWvlthci8oTyHWLGEKfweQ=", + "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", "dev": true }, "jquery": { @@ -8585,19 +8585,19 @@ "js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha1-xs7ljrNVA3LfjeuF+tXOZs4B1Z0=", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", "dev": true }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha1-r/FRswv9+o5J4F2iLnQV6d+jeEc=", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -8731,7 +8731,7 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, "json-buffer": { @@ -8744,7 +8744,7 @@ "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk=", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, "json-schema": { @@ -8755,7 +8755,7 @@ "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -8771,7 +8771,7 @@ "json5": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", - "integrity": "sha1-gbbLBOm6SW8ccAXQe0NoomOPkLY=", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -8837,7 +8837,7 @@ "anymatch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha1-xV7PAhheJGklk5kxDBc84xIzsUI=", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -8853,7 +8853,7 @@ "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -8878,7 +8878,7 @@ "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -8903,7 +8903,7 @@ "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "requires": { "binary-extensions": "^2.0.0" @@ -8921,7 +8921,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "mime": { @@ -8933,7 +8933,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, "readdirp": { @@ -8954,7 +8954,7 @@ "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -8965,7 +8965,7 @@ "karma-jasmine": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz", - "integrity": "sha1-JuPjHy+vJy3YDrsOGJiRTMOhl2M=", + "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==", "dev": true, "requires": { "jasmine-core": "^3.3" @@ -8980,7 +8980,7 @@ "karma-junit-reporter": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/karma-junit-reporter/-/karma-junit-reporter-2.0.1.tgz", - "integrity": "sha1-007vfwsv0GTgiWlU6IUakM8UyPM=", + "integrity": "sha512-VtcGfE0JE4OE1wn0LK8xxDKaTP7slN8DO3I+4xg6gAi1IoAHAXOJ1V9G/y45Xg6sxdxPOR3THCFtDlAfBo9Afw==", "dev": true, "requires": { "path-is-absolute": "^1.0.0", @@ -9009,13 +9009,13 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", "dev": true }, "kuler": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", - "integrity": "sha1-73x4TzbJ+24W3TFQ0VJneysCKKY=", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", "dev": true, "requires": { "colornames": "^1.1.1" @@ -9104,7 +9104,7 @@ "less": { "version": "3.10.3", "resolved": "https://registry.npmjs.org/less/-/less-3.10.3.tgz", - "integrity": "sha1-QXoJddXu7MUs/0vPo8CdNXgeZ5I=", + "integrity": "sha512-vz32vqfgmoxF1h3K4J+yKCtajH0PWmjkIFgbs5d78E/c/e+UQTnI+lWK+1eQRE95PXM2mC3rJlLSSP9VQHnaow==", "dev": true, "requires": { "clone": "^2.1.2", @@ -9127,7 +9127,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } @@ -9317,7 +9317,7 @@ "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo=", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "lodash.partialright": { @@ -9430,7 +9430,7 @@ "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -9470,7 +9470,7 @@ "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { "pseudomap": "^1.0.2", @@ -9506,7 +9506,7 @@ "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha1-KbM/MSqo9UfEpeSQ9Wr87JkTOtY=", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { "kind-of": "^6.0.2" @@ -9537,7 +9537,7 @@ "marked": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", - "integrity": "sha1-tkIB8FHScbHtwQoE0a6bdLuOXA4=", + "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", "dev": true }, "matchdep": { @@ -9569,13 +9569,13 @@ "math-random": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha1-XdaUPJOFSCZwFtTjTwV1gwgMUUw=", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", "dev": true }, "mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha1-aZs8OKxvHXKAkaZGULZdOIUC/Vs=", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", "dev": true }, "media-typer": { @@ -9587,7 +9587,7 @@ "memoizee": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha1-B6APIEaZ+alcLZ53IYJxx81hDVc=", + "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", "dev": true, "requires": { "d": "1", @@ -9631,7 +9631,7 @@ "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A=", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, "merge2": { @@ -9643,7 +9643,7 @@ "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -9664,7 +9664,7 @@ "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, "optional": true }, @@ -9697,7 +9697,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -9705,14 +9705,14 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, "minimize": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/minimize/-/minimize-2.2.0.tgz", - "integrity": "sha1-ixZ28wBR2FmNdDZGvRJpCwdNpMM=", + "integrity": "sha512-IxR2XMbw9pXCxApkdD9BTcH2U4XlXhbeySUrv71rmMS9XDA8BVXEsIuFu24LtwCfBgfbL7Fuh8/ZzkO5DaTLlQ==", "dev": true, "requires": { "argh": "^0.1.4", @@ -9727,7 +9727,7 @@ "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha1-ESC0PcNZp4Xc5ltVuC4lfM9HlWY=", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { "for-in": "^1.0.2", @@ -9737,7 +9737,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -9756,7 +9756,7 @@ "dependencies": { "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true } @@ -9782,7 +9782,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "multipipe": { @@ -9797,7 +9797,7 @@ "mute-stdout": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha1-rLAwDrTeI6fd7sAU4+lgRLNHIzE=", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", "dev": true }, "mute-stream": { @@ -9816,7 +9816,7 @@ "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -9841,12 +9841,12 @@ "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", "dev": true }, "next-tick": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, @@ -9858,13 +9858,13 @@ "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y=", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "node-notifier": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", - "integrity": "sha1-y3La+UyTkECY4oucWQ/YZuRkvVA=", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", "dev": true, "requires": { "growly": "^1.3.0", @@ -9886,7 +9886,7 @@ "node.extend": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-2.0.2.tgz", - "integrity": "sha1-tEBFJUlKzJl0DzcDxJa31Rgsxsw=", + "integrity": "sha512-pDT4Dchl94/+kkgdwyS2PauDFjZG0Hk0IcHIB+LkW27HLDtdoeMxHTxZh39DYbPP8UflWXWj9JcdDozF+YDOpQ==", "dev": true, "requires": { "has": "^1.0.3", @@ -9896,7 +9896,7 @@ "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg=", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", @@ -9923,7 +9923,7 @@ "normalize-url": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha1-suHE3E98bVd0PfczpPWXjRhlBVk=", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", "dev": true }, "nouislider": { @@ -9934,7 +9934,7 @@ "now-and-later": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha1-jlechoV2SnzALLaAOA6U9DzLH3w=", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", "dev": true, "requires": { "once": "^1.3.2" @@ -13067,7 +13067,7 @@ "nth-check": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha1-sr0pXDfj3VijvwcAN2Zjuk2c8Fw=", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", "dev": true, "requires": { "boolbase": "~1.0.0" @@ -13094,7 +13094,7 @@ "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=" + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "3.0.0", @@ -13148,7 +13148,7 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, "object-visit": { @@ -13163,7 +13163,7 @@ "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { "define-properties": "^1.1.2", @@ -13394,7 +13394,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -13474,7 +13474,7 @@ "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "requires": { "callsites": "^3.0.0" @@ -13483,7 +13483,7 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true } } @@ -13541,7 +13541,7 @@ "parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha1-4rXb7eAOf6m8NjYH9TMn6LBzGJs=", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true }, "parse-passwd": { @@ -13577,7 +13577,7 @@ "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, "pascalcase": { @@ -13616,7 +13616,7 @@ "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, "path-root": { @@ -13673,7 +13673,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -13695,7 +13695,7 @@ "plugin-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha1-dwFr2JGdCsN3/c3QMiMolTyleBw=", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", "dev": true, "requires": { "ansi-colors": "^1.0.1", @@ -13733,13 +13733,13 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -13762,7 +13762,7 @@ "postcss-colormin": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha1-rgYLzpPteUrHEmTwgTLVUJVr04E=", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -13775,7 +13775,7 @@ "postcss-convert-values": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha1-yjgT7U2g+BL51DcDWE5Enr4Ymn8=", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", "dev": true, "requires": { "postcss": "^7.0.0", @@ -13785,7 +13785,7 @@ "postcss-discard-comments": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha1-H7q9LCRr/2qq15l7KwkY9NevQDM=", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13794,7 +13794,7 @@ "postcss-discard-duplicates": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha1-P+EzzTyCKC5VD8myORdqkge3hOs=", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13803,7 +13803,7 @@ "postcss-discard-empty": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha1-yMlR6fc+2UKAGUWERKAq2Qu592U=", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13812,7 +13812,7 @@ "postcss-discard-overridden": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha1-ZSrvipZybwKfXj4AFG7npOdV/1c=", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13821,7 +13821,7 @@ "postcss-load-config": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", - "integrity": "sha1-yE1pK3u3tB3c7ZTuYuirMbQXsAM=", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", "dev": true, "requires": { "cosmiconfig": "^5.0.0", @@ -13831,7 +13831,7 @@ "postcss-merge-longhand": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha1-YvSaE+Sg7gTnuY9CuxYGLKJUniQ=", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", "dev": true, "requires": { "css-color-names": "0.0.4", @@ -13843,7 +13843,7 @@ "postcss-merge-rules": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha1-NivqT/Wh+Y5AdacTxsslrv75plA=", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -13870,7 +13870,7 @@ "postcss-minify-font-values": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha1-zUw0TM5HQ0P6xdgiBqssvLiv1aY=", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", "dev": true, "requires": { "postcss": "^7.0.0", @@ -13880,7 +13880,7 @@ "postcss-minify-gradients": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha1-k7KcL/UJnFNe7NpWxKpuZlpmNHE=", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -13892,7 +13892,7 @@ "postcss-minify-params": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha1-a5zvAwwR41Jh+V9hjJADbWgNuHQ=", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", "dev": true, "requires": { "alphanum-sort": "^1.0.0", @@ -13906,7 +13906,7 @@ "postcss-minify-selectors": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha1-4uXrQL/uUA0M2SQ1APX46kJi+9g=", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", "dev": true, "requires": { "alphanum-sort": "^1.0.0", @@ -13931,7 +13931,7 @@ "postcss-normalize-charset": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha1-izWt067oOhNrBHHg1ZvlilAoXdQ=", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13940,7 +13940,7 @@ "postcss-normalize-display-values": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha1-Db4EpM6QY9RmftK+R2u4MMglk1o=", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", @@ -13951,7 +13951,7 @@ "postcss-normalize-positions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha1-BfdX+E8mBDc3g2ipH4ky1LECkX8=", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -13963,7 +13963,7 @@ "postcss-normalize-repeat-style": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha1-xOu8KJ85kaAo1EdRy90RkYsXkQw=", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -13975,7 +13975,7 @@ "postcss-normalize-string": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha1-zUTECrB6DHo23F6Zqs4eyk7CaQw=", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", "dev": true, "requires": { "has": "^1.0.0", @@ -13986,7 +13986,7 @@ "postcss-normalize-timing-functions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha1-jgCcoqOUnNr4rSPmtquZy159KNk=", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", @@ -13997,7 +13997,7 @@ "postcss-normalize-unicode": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha1-hBvUj9zzAZrUuqdJOj02O1KuHPs=", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -14008,7 +14008,7 @@ "postcss-normalize-url": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha1-EOQ3+GvHx+WPe5ZS7YeNqqlfquE=", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", "dev": true, "requires": { "is-absolute-url": "^2.0.0", @@ -14020,7 +14020,7 @@ "postcss-normalize-whitespace": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha1-vx1AcP5Pzqh9E0joJdjMDF+qfYI=", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", "dev": true, "requires": { "postcss": "^7.0.0", @@ -14030,7 +14030,7 @@ "postcss-ordered-values": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha1-DPdcgg7H1cTSgBiVWeC1ceusDu4=", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -14041,7 +14041,7 @@ "postcss-reduce-initial": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha1-f9QuvqXpyBRgljniwuhK4nC6SN8=", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -14053,7 +14053,7 @@ "postcss-reduce-transforms": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha1-F++kBerMbge+NBSlyi0QdGgdTik=", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", @@ -14076,7 +14076,7 @@ "postcss-svgo": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", - "integrity": "sha1-F7mXvHEbMzurFDqu07jT1uPTglg=", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", "dev": true, "requires": { "is-svg": "^3.0.0", @@ -14088,7 +14088,7 @@ "postcss-unique-selectors": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha1-lEaRHzKJv9ZMbWgPBzwDsfnuS6w=", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", "dev": true, "requires": { "alphanum-sort": "^1.0.0", @@ -14129,32 +14129,32 @@ }, "pretty-hrtime": { "version": "1.0.3", - "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", "dev": true }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "dev": true, "optional": true, "requires": { @@ -14189,7 +14189,7 @@ "pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -14199,7 +14199,7 @@ "pumpify": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4=", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "dev": true, "requires": { "duplexify": "^3.6.0", @@ -14210,7 +14210,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=" + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "q": { "version": "1.5.1", @@ -14221,13 +14221,13 @@ "qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=" + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "query-string": { "version": "5.1.1", @@ -14258,7 +14258,7 @@ "randomatic": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha1-t3bvxZN1mE42xTey9RofCv8Noe0=", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", "dev": true, "requires": { "is-number": "^4.0.0", @@ -14269,7 +14269,7 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true } } @@ -14277,13 +14277,13 @@ "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true }, "raw-body": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", "dev": true, "requires": { "bytes": "3.1.0", @@ -14328,7 +14328,7 @@ "readdirp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -14366,7 +14366,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -14397,7 +14397,7 @@ "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha1-SoVuxLVuQHfFV1icroXnpMiGmhE=", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", "dev": true }, "regenerate-unicode-properties": { @@ -14421,7 +14421,7 @@ "regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha1-db3FiioUls7EihKDW8VMjVYjNt0=", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "dev": true, "requires": { "is-equal-shallow": "^0.1.3" @@ -14430,7 +14430,7 @@ "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { "extend-shallow": "^3.0.2", @@ -14440,7 +14440,7 @@ "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha1-jRnTHPYySCtYkEn4KB+T28uk0H8=", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, "regexpu-core": { @@ -14460,7 +14460,7 @@ "regjsgen": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", - "integrity": "sha1-SPC/Gl6iBRlpKcDZeYtC0e2YRDw=", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", "dev": true }, "regjsparser": { @@ -14483,7 +14483,7 @@ "remove-bom-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha1-wr8eN3Ug0yT2I4kuM8EMrCwlK1M=", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", "dev": true, "requires": { "is-buffer": "^1.1.5", @@ -14510,7 +14510,7 @@ "repeat-element": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4=", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", "dev": true }, "repeat-string": { @@ -14683,7 +14683,7 @@ "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, "reusify": { @@ -14695,7 +14695,7 @@ "rfdc": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", - "integrity": "sha1-unLME2egzNnPgahws7WL060H+MI=", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", "dev": true }, "rgb-regex": { @@ -14722,7 +14722,7 @@ "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha1-stEE/g2Psnz54KHNqCYt04M8bKs=", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { "glob": "^7.1.3" @@ -14746,7 +14746,7 @@ "run-sequence": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/run-sequence/-/run-sequence-2.2.1.tgz", - "integrity": "sha1-HOZD2jb9jH6n4akynaM/wriJhJU=", + "integrity": "sha512-qkzZnQWMZjcKbh3CNly2srtrkaO/2H/SI5f2eliMCapdRD3UhMrwjfOAZJAnZ2H8Ju4aBzFZkBGXUqFs9V0yxw==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -14784,7 +14784,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -14806,7 +14806,7 @@ }, "kind-of": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", "dev": true }, @@ -14843,7 +14843,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -14857,12 +14857,12 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, "saxes": { @@ -14892,7 +14892,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "semver-greatest-satisfied-range": { @@ -14930,7 +14930,7 @@ "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha1-oY1AUw5vB95CKMfe/kInr4ytAFs=", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -14953,7 +14953,7 @@ "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", "dev": true }, "shebang-command": { @@ -14974,7 +14974,7 @@ "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha1-1rkYHBpI05cyTISHHvvPxz/AZUs=", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true }, "signal-exit": { @@ -14995,7 +14995,7 @@ "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha1-RXSirlb3qyBolvtDHq7tBm/fjwM=", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", "dev": true } } @@ -15009,7 +15009,7 @@ "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha1-ys12k0YaY3pXiNkqfdT7oGjoFjY=", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, "requires": { "ansi-styles": "^3.2.0", @@ -15028,7 +15028,7 @@ "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { "base": "^0.11.1", @@ -15044,7 +15044,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -15079,7 +15079,7 @@ "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { "define-property": "^1.0.0", @@ -15099,7 +15099,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -15108,7 +15108,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -15117,7 +15117,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -15130,7 +15130,7 @@ "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { "kind-of": "^3.2.0" @@ -15335,13 +15335,13 @@ "sparkles": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha1-AI22XtzmxQ7sDF4ijhlFBh3QQ3w=", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", "dev": true }, "spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha1-+4PlBERSaPFUsHTiGMh8ADzTHfQ=", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -15351,7 +15351,7 @@ "spdx-exceptions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha1-LqRQrudPKom/uUUZwH/Nb0EyKXc=", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", "dev": true }, "spdx-expression-parse": { @@ -15367,7 +15367,7 @@ "spdx-license-ids": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha1-NpS1gEVnpFjTyARYQqY1hjL2JlQ=", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "spectrum-colorpicker2": { @@ -15378,7 +15378,7 @@ "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { "extend-shallow": "^3.0.0" @@ -15411,7 +15411,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "optional": true, @@ -15435,7 +15435,7 @@ "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha1-+2YcC+8ps520B2nuOfpwCT1vaHc=", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -15451,7 +15451,7 @@ "stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88=", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, "stack-trace": { @@ -15496,7 +15496,7 @@ "stream-exhaust": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", - "integrity": "sha1-rNrI2lnvK8HheiwMz2wyDRIOVV0=", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", "dev": true }, "stream-shift": { @@ -15680,7 +15680,7 @@ "stylehacks": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", - "integrity": "sha1-Zxj8r00eB9ihMYaQiB6NlnJqcdU=", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -15704,7 +15704,7 @@ "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -15750,7 +15750,7 @@ "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha1-EpLRlQDOP4YFOwXw6Ofko7shB54=", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { "ajv": "^6.10.2", @@ -15762,7 +15762,7 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "is-fullwidth-code-point": { @@ -15774,7 +15774,7 @@ "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { "emoji-regex": "^7.0.1", @@ -15785,7 +15785,7 @@ "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { "ansi-regex": "^4.1.0" @@ -15884,7 +15884,7 @@ "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha1-adycGxdEbueakr9biEu0uRJ1BvU=", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", "dev": true }, "text-table": { @@ -15902,7 +15902,7 @@ "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0=", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "requires": { "readable-stream": "~2.3.6", @@ -15953,7 +15953,7 @@ "through2-filter": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha1-cA54bfI2fCyIzYqlvkz5weeDElQ=", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", "dev": true, "requires": { "through2": "~2.0.0", @@ -15976,7 +15976,7 @@ "timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha1-b1ethXjgej+5+R2Th9ZWR1VeJcY=", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", "dev": true, "requires": { "es5-ext": "~0.10.46", @@ -15992,7 +15992,7 @@ "tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha1-HRpW7fxRxD6GPLtTgqcjMONVVCM=" + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" }, "tinymce": { "version": "4.9.11", @@ -16002,7 +16002,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { "os-tmpdir": "~1.0.2" @@ -16060,7 +16060,7 @@ "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { "define-property": "^2.0.2", @@ -16091,7 +16091,7 @@ "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", "dev": true }, "tough-cookie": { @@ -16165,7 +16165,7 @@ "type": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha1-hI3XaY2vo+VKbEeedZxLw/GIR6A=", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", "dev": true }, "type-check": { @@ -16180,7 +16180,7 @@ "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, "requires": { "media-typer": "0.3.0", @@ -16287,7 +16287,7 @@ "undertaker": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", - "integrity": "sha1-cBZi/4zjWHFTJN/UkqTwNgVd/ks=", + "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", "dev": true, "requires": { "arr-flatten": "^1.0.1", @@ -16310,13 +16310,13 @@ "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha1-JhmADEyCWADv3YNDr33Zkzy+KBg=", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", "dev": true }, "unicode-match-property-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha1-jtKjJWmWG86SJ9Cc0/+7j+1fAgw=", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", "dev": true, "requires": { "unicode-canonical-property-names-ecmascript": "^1.0.4", @@ -16338,7 +16338,7 @@ "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha1-C2/nuDWuzaYcbqTU8CwUIh4QmEc=", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -16362,7 +16362,7 @@ "unique-stream": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha1-xl0RDppK35psWUiygFPZqNBMvqw=", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", "dev": true, "requires": { "json-stable-stringify-without-jsonify": "^1.0.1", @@ -16372,7 +16372,7 @@ "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, "unpipe": { @@ -16436,13 +16436,13 @@ "upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha1-j2bbzVWog6za5ECK+LA1pQRMGJQ=", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "requires": { "punycode": "^2.1.0" } @@ -16482,7 +16482,7 @@ "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8=", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, "useragent": { @@ -16504,7 +16504,7 @@ "util.promisify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", "dev": true, "requires": { "define-properties": "^1.1.2", @@ -16540,7 +16540,7 @@ "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha1-/JH2uce6FchX9MssXe/uw51PQQo=", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { "spdx-correct": "^3.0.0", @@ -16619,7 +16619,7 @@ "vinyl-fs": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha1-yFhJQF9nQo/qu71cXb3WT0fTG8c=", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", "dev": true, "requires": { "fs-mkdirp-stream": "^1.0.0", @@ -16828,7 +16828,7 @@ "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -16859,7 +16859,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -16876,7 +16876,7 @@ "write": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha1-CADhRSO5I6OH5BUSPIZWFqrg9cM=", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, "requires": { "mkdirp": "^0.5.1" @@ -16902,7 +16902,7 @@ "xmlbuilder": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-12.0.0.tgz", - "integrity": "sha1-4u1nXgaDSgid37hNuW4sKwP3jBo=", + "integrity": "sha512-lMo8DJ8u6JRWp0/Y4XLa/atVDr75H9litKlb2E5j3V3MesoL50EBgZDWoLT3F/LztVnG67GjPXLZpqcky/UMnQ==", "dev": true }, "xmlchars": { @@ -16920,7 +16920,7 @@ "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q=", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, "y18n": { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js index 9350e04af9..51fc6284b8 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js @@ -65,7 +65,7 @@ angular.module("umbraco.directives") function _filesQueued(files, event) { //Push into the queue Utilities.forEach(files, file => { - if (_filterFile(file) === true) { + if (_filterFile(file) === true) { if (file.$error) { scope.rejected.push(file); @@ -192,7 +192,7 @@ angular.module("umbraco.directives") // if queue has no items so there is nothing to choose a type for return false; } - + if (scope.acceptedMediatypes.length === 1) { // if only one accepted type, then we wont ask to choose. return false; diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js index e72900cacd..f6b24dd12b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js @@ -75,7 +75,7 @@ }); saveModel.groups = _.map(realGroups, function (g) { - var saveGroup = _.pick(g, 'inherited', 'id', 'sortOrder', 'name', 'alias', 'type'); + var saveGroup = _.pick(g, 'inherited', 'id', 'sortOrder', 'name', 'key', 'alias', 'type'); var realProperties = _.reject(g.properties, function (p) { //do not include these properties diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/database.html b/src/Umbraco.Web.UI.Client/src/installer/steps/database.html index eee933b561..cf367b2ff2 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/steps/database.html +++ b/src/Umbraco.Web.UI.Client/src/installer/steps/database.html @@ -10,38 +10,48 @@ What type of database do you use?
-
-
+

Great! No need to configure anything, you can simply click the continue button below to continue to the next step

-
+
+

Great! No need to configure anything, you can simply click the continue button below to continue to the next step

+
+ +
What is the exact connection string we should use?
- +
- + Enter a valid database connection string.
-
+
Where do we find your database?
- +
- + Enter server domain or IP
@@ -49,11 +59,12 @@
- +
- + required + ng-model="installer.current.model.databaseName" /> Enter the name of the database
@@ -64,11 +75,12 @@ What credentials are used to access the database?
- +
- + required + ng-model="installer.current.model.login" /> Enter the database user name
@@ -76,21 +88,21 @@
- +
- + required + ng-model="installer.current.model.password" /> Enter the database password
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/tabs/umb-tabs-nav.html b/src/Umbraco.Web.UI.Client/src/views/components/tabs/umb-tabs-nav.html index b55555339b..df649a9e4a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/tabs/umb-tabs-nav.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/tabs/umb-tabs-nav.html @@ -1,6 +1,6 @@
  • - @@ -23,7 +23,7 @@ ng-class="{'dropdown-menu--active': tab.active}" ng-click="vm.clickTab($event, tab)" role="tab" - aria-selected="{tab.active}" > + aria-selected="{{tab.active}}" > {{ tab.label }}
    !
    diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js index 64fc40d84d..3510da73a6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js @@ -535,7 +535,7 @@ // remove all tabs except the specified tab var tabs = scaffold.variants[0].tabs; var tab = _.find(tabs, function (tab) { - return tab.id !== 0 && (tab.alias.toLowerCase() === contentType.ncTabAlias.toLowerCase() || contentType.ncTabAlias === ""); + return tab.id !== 0 && (tab.label.toLowerCase() === contentType.ncTabAlias.toLowerCase() || contentType.ncTabAlias === ""); }); scaffold.variants[0].tabs = []; if (tab) { diff --git a/src/Umbraco.Web.UI/Startup.cs b/src/Umbraco.Web.UI/Startup.cs index 0d263c7b6b..71c3dd008c 100644 --- a/src/Umbraco.Web.UI/Startup.cs +++ b/src/Umbraco.Web.UI/Startup.cs @@ -15,10 +15,10 @@ namespace Umbraco.Cms.Web.UI private readonly IConfiguration _config; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The Web Host Environment - /// The Configuration + /// The web hosting environment. + /// The configuration. /// /// Only a few services are possible to be injected here https://github.com/dotnet/aspnetcore/issues/9337 /// @@ -28,11 +28,10 @@ namespace Umbraco.Cms.Web.UI _config = config ?? throw new ArgumentNullException(nameof(config)); } - - /// - /// Configures the services + /// Configures the services. /// + /// The services. /// /// This method gets called by the runtime. Use this method to add services to the container. /// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 @@ -50,8 +49,10 @@ namespace Umbraco.Cms.Web.UI } /// - /// Configures the application + /// Configures the application. /// + /// The application builder. + /// The web hosting environment. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) @@ -59,6 +60,10 @@ namespace Umbraco.Cms.Web.UI app.UseDeveloperExceptionPage(); } +#if (UseHttpsRedirect) + app.UseHttpsRedirection(); + +#endif app.UseUmbraco() .WithMiddleware(u => { diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 7e2d51b12c..a050d22a16 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -66,12 +66,12 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs index 62ec5a9921..797a4b2202 100644 --- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs @@ -1,16 +1,17 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Infrastructure.DependencyInjection; using Umbraco.Cms.Web.Common.Middleware; using Umbraco.Cms.Web.Common.Routing; using Umbraco.Cms.Web.Website.Collections; -using Umbraco.Cms.Web.Website.Controllers; -using Umbraco.Cms.Web.Website.Middleware; using Umbraco.Cms.Web.Website.Models; using Umbraco.Cms.Web.Website.Routing; using Umbraco.Cms.Web.Website.ViewEngines; +using static Microsoft.Extensions.DependencyInjection.ServiceDescriptor; namespace Umbraco.Extensions { @@ -38,8 +39,9 @@ namespace Umbraco.Extensions builder.Services.AddDataProtection(); builder.Services.AddAntiforgery(); - builder.Services.AddScoped(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.TryAddEnumerable(Singleton()); builder.Services.AddSingleton(); builder.Services.AddSingleton(); @@ -47,7 +49,7 @@ namespace Umbraco.Extensions builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder diff --git a/src/Umbraco.Web.Website/Extensions/UmbracoApplicationBuilder.Website.cs b/src/Umbraco.Web.Website/Extensions/UmbracoApplicationBuilder.Website.cs index c549609397..33d42e07c9 100644 --- a/src/Umbraco.Web.Website/Extensions/UmbracoApplicationBuilder.Website.cs +++ b/src/Umbraco.Web.Website/Extensions/UmbracoApplicationBuilder.Website.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Web.Common.ApplicationBuilder; using Umbraco.Cms.Web.Common.Middleware; -using Umbraco.Cms.Web.Website.Middleware; using Umbraco.Cms.Web.Website.Routing; namespace Umbraco.Extensions @@ -20,7 +19,6 @@ namespace Umbraco.Extensions /// public static IUmbracoApplicationBuilderContext UseWebsite(this IUmbracoApplicationBuilderContext builder) { - builder.AppBuilder.UseMiddleware(); builder.AppBuilder.UseMiddleware(); return builder; } diff --git a/src/Umbraco.Web.Website/Routing/IPublicAccessRequestHandler.cs b/src/Umbraco.Web.Website/Routing/IPublicAccessRequestHandler.cs new file mode 100644 index 0000000000..0ce3ddad92 --- /dev/null +++ b/src/Umbraco.Web.Website/Routing/IPublicAccessRequestHandler.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Umbraco.Cms.Web.Common.Routing; + +namespace Umbraco.Cms.Web.Website.Routing +{ + public interface IPublicAccessRequestHandler + { + /// + /// Ensures that access to current node is permitted. + /// + /// + /// The current route values + /// Updated route values if public access changes the rendered content, else the original route values. + /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. + Task RewriteForPublishedContentAccessAsync(HttpContext httpContext, UmbracoRouteValues routeValues); + } +} diff --git a/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs b/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs new file mode 100644 index 0000000000..dbc06175fd --- /dev/null +++ b/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing.Matching; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Web.Common.Controllers; +using Umbraco.Cms.Web.Common.Routing; + +namespace Umbraco.Cms.Web.Website.Routing +{ + /// + /// Used to handle 404 routes that haven't been handled by the end user + /// + internal class NotFoundSelectorPolicy : MatcherPolicy, IEndpointSelectorPolicy + { + private readonly Lazy _notFound; + private readonly EndpointDataSource _endpointDataSource; + + public NotFoundSelectorPolicy(EndpointDataSource endpointDataSource) + { + _notFound = new Lazy(GetNotFoundEndpoint); + _endpointDataSource = endpointDataSource; + } + + // return the endpoint for the RenderController.Index action. + private Endpoint GetNotFoundEndpoint() + { + Endpoint e = _endpointDataSource.Endpoints.First(x => + { + // return the endpoint for the RenderController.Index action. + ControllerActionDescriptor descriptor = x.Metadata?.GetMetadata(); + return descriptor?.ControllerTypeInfo == typeof(RenderController) + && descriptor?.ActionName == nameof(RenderController.Index); + }); + return e; + } + + public override int Order => 0; + + public bool AppliesToEndpoints(IReadOnlyList endpoints) + { + // Don't apply this filter to any endpoint group that is a controller route + // i.e. only dynamic routes. + foreach (Endpoint endpoint in endpoints) + { + ControllerAttribute controller = endpoint.Metadata?.GetMetadata(); + if (controller != null) + { + return false; + } + } + + // then ensure this is only applied if all endpoints are IDynamicEndpointMetadata + return endpoints.All(x => x.Metadata?.GetMetadata() != null); + } + + public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates) + { + if (AllInvalid(candidates)) + { + UmbracoRouteValues umbracoRouteValues = httpContext.Features.Get(); + if (umbracoRouteValues?.PublishedRequest != null + && !umbracoRouteValues.PublishedRequest.HasPublishedContent() + && umbracoRouteValues.PublishedRequest.ResponseStatusCode == StatusCodes.Status404NotFound) + { + // not found/404 + httpContext.SetEndpoint(_notFound.Value); + } + } + + return Task.CompletedTask; + } + + private static bool AllInvalid(CandidateSet candidates) + { + for (int i = 0; i < candidates.Count; i++) + { + if (candidates.IsValidCandidate(i)) + { + return false; + } + } + return true; + } + } +} diff --git a/src/Umbraco.Web.Website/Middleware/PublicAccessMiddleware.cs b/src/Umbraco.Web.Website/Routing/PublicAccessRequestHandler.cs similarity index 77% rename from src/Umbraco.Web.Website/Middleware/PublicAccessMiddleware.cs rename to src/Umbraco.Web.Website/Routing/PublicAccessRequestHandler.cs index 8bbb4e13e4..88bb6622bd 100644 --- a/src/Umbraco.Web.Website/Middleware/PublicAccessMiddleware.cs +++ b/src/Umbraco.Web.Website/Routing/PublicAccessRequestHandler.cs @@ -10,22 +10,21 @@ using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Web.Common.Routing; -using Umbraco.Cms.Web.Website.Routing; using Umbraco.Extensions; -namespace Umbraco.Cms.Web.Website.Middleware +namespace Umbraco.Cms.Web.Website.Routing { - public class PublicAccessMiddleware : IMiddleware + public class PublicAccessRequestHandler : IPublicAccessRequestHandler { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IPublicAccessService _publicAccessService; private readonly IPublicAccessChecker _publicAccessChecker; private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IUmbracoRouteValuesFactory _umbracoRouteValuesFactory; private readonly IPublishedRouter _publishedRouter; - public PublicAccessMiddleware( - ILogger logger, + public PublicAccessRequestHandler( + ILogger logger, IPublicAccessService publicAccessService, IPublicAccessChecker publicAccessChecker, IUmbracoContextAccessor umbracoContextAccessor, @@ -40,23 +39,8 @@ namespace Umbraco.Cms.Web.Website.Middleware _publishedRouter = publishedRouter; } - public async Task InvokeAsync(HttpContext context, RequestDelegate next) - { - UmbracoRouteValues umbracoRouteValues = context.Features.Get(); - - if (umbracoRouteValues != null) - { - await EnsurePublishedContentAccess(context, umbracoRouteValues); - } - - await next(context); - } - - /// - /// Ensures that access to current node is permitted. - /// - /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. - private async Task EnsurePublishedContentAccess(HttpContext httpContext, UmbracoRouteValues routeValues) + /// + public async Task RewriteForPublishedContentAccessAsync(HttpContext httpContext, UmbracoRouteValues routeValues) { // because these might loop, we have to have some sort of infinite loop detection int i = 0; @@ -64,13 +48,13 @@ namespace Umbraco.Cms.Web.Website.Middleware PublicAccessStatus publicAccessStatus = PublicAccessStatus.AccessAccepted; do { - _logger.LogDebug(nameof(EnsurePublishedContentAccess) + ": Loop {LoopCounter}", i); + _logger.LogDebug(nameof(RewriteForPublishedContentAccessAsync) + ": Loop {LoopCounter}", i); IPublishedContent publishedContent = routeValues.PublishedRequest?.PublishedContent; if (publishedContent == null) { - return; + return routeValues; } var path = publishedContent.Path; @@ -117,8 +101,10 @@ namespace Umbraco.Cms.Web.Website.Middleware if (i == maxLoop) { - _logger.LogDebug(nameof(EnsurePublishedContentAccess) + ": Looks like we are running into an infinite loop, abort"); + _logger.LogDebug(nameof(RewriteForPublishedContentAccessAsync) + ": Looks like we are running into an infinite loop, abort"); } + + return routeValues; } @@ -139,17 +125,11 @@ namespace Umbraco.Cms.Web.Website.Middleware // we need to change the content item that is getting rendered so we have to re-create UmbracoRouteValues. UmbracoRouteValues updatedRouteValues = await _umbracoRouteValuesFactory.CreateAsync(httpContext, reRouted); - // Update the feature - httpContext.Features.Set(updatedRouteValues); - return updatedRouteValues; } else { - _logger.LogWarning("Public Access rule has a redirect node set to itself, nothing can be routed."); - // Update the feature to nothing - cannot continue - httpContext.Features.Set(null); - return null; + throw new InvalidOperationException("Public Access rule has a redirect node set to itself, nothing can be routed."); } } } diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs index 41fd20a69b..0bca8d7215 100644 --- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs +++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs @@ -28,6 +28,7 @@ using RouteDirection = Umbraco.Cms.Core.Routing.RouteDirection; namespace Umbraco.Cms.Web.Website.Routing { + /// /// The route value transformer for Umbraco front-end routes /// @@ -51,6 +52,7 @@ namespace Umbraco.Cms.Web.Website.Routing private readonly IDataProtectionProvider _dataProtectionProvider; private readonly IControllerActionSearcher _controllerActionSearcher; private readonly IEventAggregator _eventAggregator; + private readonly IPublicAccessRequestHandler _publicAccessRequestHandler; /// /// Initializes a new instance of the class. @@ -66,7 +68,8 @@ namespace Umbraco.Cms.Web.Website.Routing IRoutableDocumentFilter routableDocumentFilter, IDataProtectionProvider dataProtectionProvider, IControllerActionSearcher controllerActionSearcher, - IEventAggregator eventAggregator) + IEventAggregator eventAggregator, + IPublicAccessRequestHandler publicAccessRequestHandler) { if (globalSettings is null) { @@ -84,6 +87,7 @@ namespace Umbraco.Cms.Web.Website.Routing _dataProtectionProvider = dataProtectionProvider; _controllerActionSearcher = controllerActionSearcher; _eventAggregator = eventAggregator; + _publicAccessRequestHandler = publicAccessRequestHandler; } /// @@ -92,31 +96,54 @@ namespace Umbraco.Cms.Web.Website.Routing // If we aren't running, then we have nothing to route if (_runtime.Level != RuntimeLevel.Run) { - return values; + return null; } // will be null for any client side requests like JS, etc... - if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext)) + if (!_umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext umbracoContext)) { - return values; + return null; } if (!_routableDocumentFilter.IsDocumentRequest(httpContext.Request.Path)) { - return values; + return null; + } + + // Don't execute if there are already UmbracoRouteValues assigned. + // This can occur if someone else is dynamically routing and in which case we don't want to overwrite + // the routing work being done there. + UmbracoRouteValues umbracoRouteValues = httpContext.Features.Get(); + if (umbracoRouteValues != null) + { + return null; } // Check if there is no existing content and return the no content controller if (!umbracoContext.Content.HasContent()) { - values[ControllerToken] = ControllerExtensions.GetControllerName(); - values[ActionToken] = nameof(RenderNoContentController.Index); - - return values; + return new RouteValueDictionary + { + [ControllerToken] = ControllerExtensions.GetControllerName(), + [ActionToken] = nameof(RenderNoContentController.Index) + }; } - IPublishedRequest publishedRequest = await RouteRequestAsync(httpContext, umbracoContext); + IPublishedRequest publishedRequest = await RouteRequestAsync(umbracoContext); - UmbracoRouteValues umbracoRouteValues = await _routeValuesFactory.CreateAsync(httpContext, publishedRequest); + umbracoRouteValues = await _routeValuesFactory.CreateAsync(httpContext, publishedRequest); + + if (!umbracoRouteValues?.PublishedRequest?.HasPublishedContent() ?? false) + { + // No content was found, not by any registered 404 handlers and + // not by the IContentLastChanceFinder. In this case we want to return + // our default 404 page but we cannot return route values now because + // it's possible that a developer is handling dynamic routes too. + // Our 404 page will be handled with the NotFoundSelectorPolicy + return null; + } + + // now we need to do some public access checks + umbracoRouteValues = await _publicAccessRequestHandler.RewriteForPublishedContentAccessAsync(httpContext, umbracoRouteValues); // Store the route values as a httpcontext feature httpContext.Features.Set(umbracoRouteValues); @@ -125,19 +152,25 @@ namespace Umbraco.Cms.Web.Website.Routing PostedDataProxyInfo postedInfo = GetFormInfo(httpContext, values); if (postedInfo != null) { - return HandlePostedValues(postedInfo, httpContext, values); + return HandlePostedValues(postedInfo, httpContext); } - values[ControllerToken] = umbracoRouteValues.ControllerName; + // See https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.routing.dynamicroutevaluetransformer.transformasync?view=aspnetcore-5.0#Microsoft_AspNetCore_Mvc_Routing_DynamicRouteValueTransformer_TransformAsync_Microsoft_AspNetCore_Http_HttpContext_Microsoft_AspNetCore_Routing_RouteValueDictionary_ + // We should apparenlty not be modified these values. + // So we create new ones. + var newValues = new RouteValueDictionary + { + [ControllerToken] = umbracoRouteValues.ControllerName + }; if (string.IsNullOrWhiteSpace(umbracoRouteValues.ActionName) == false) { - values[ActionToken] = umbracoRouteValues.ActionName; + newValues[ActionToken] = umbracoRouteValues.ActionName; } - return values; + return newValues; } - private async Task RouteRequestAsync(HttpContext httpContext, IUmbracoContext umbracoContext) + private async Task RouteRequestAsync(IUmbracoContext umbracoContext) { // ok, process @@ -196,11 +229,14 @@ namespace Umbraco.Cms.Web.Website.Routing }; } - private RouteValueDictionary HandlePostedValues(PostedDataProxyInfo postedInfo, HttpContext httpContext, RouteValueDictionary values) + private RouteValueDictionary HandlePostedValues(PostedDataProxyInfo postedInfo, HttpContext httpContext) { // set the standard route values/tokens - values[ControllerToken] = postedInfo.ControllerName; - values[ActionToken] = postedInfo.ActionName; + var values = new RouteValueDictionary + { + [ControllerToken] = postedInfo.ControllerName, + [ActionToken] = postedInfo.ActionName + }; ControllerActionDescriptor surfaceControllerDescriptor = _controllerActionSearcher.Find(httpContext, postedInfo.ControllerName, postedInfo.ActionName); diff --git a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj index d1bd53e5fe..7dab73b100 100644 --- a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj +++ b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj @@ -32,7 +32,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all