Merge remote-tracking branch 'origin/v10/dev' into v11/dev
# Conflicts: # src/Umbraco.Web.UI.Client/src/views/common/login.controller.js
This commit is contained in:
@@ -66,7 +66,17 @@ public class ExamineIndexRebuilder : IIndexRebuilder
|
||||
_logger.LogInformation("Starting async background thread for rebuilding index {indexName}.", indexName);
|
||||
|
||||
_backgroundTaskQueue.QueueBackgroundWorkItem(
|
||||
cancellationToken => Task.Run(() => RebuildIndex(indexName, delay.Value, cancellationToken)));
|
||||
cancellationToken =>
|
||||
{
|
||||
// Do not flow AsyncLocal to the child thread
|
||||
using (ExecutionContext.SuppressFlow())
|
||||
{
|
||||
Task.Run(() => RebuildIndex(indexName, delay.Value, cancellationToken));
|
||||
|
||||
// immediately return so the queue isn't waiting.
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -93,12 +103,16 @@ public class ExamineIndexRebuilder : IIndexRebuilder
|
||||
_backgroundTaskQueue.QueueBackgroundWorkItem(
|
||||
cancellationToken =>
|
||||
{
|
||||
// This is a fire/forget task spawned by the background thread queue (which means we
|
||||
// don't need to worry about ExecutionContext flowing).
|
||||
Task.Run(() => RebuildIndexes(onlyEmptyIndexes, delay.Value, cancellationToken));
|
||||
// Do not flow AsyncLocal to the child thread
|
||||
using (ExecutionContext.SuppressFlow())
|
||||
{
|
||||
// This is a fire/forget task spawned by the background thread queue (which means we
|
||||
// don't need to worry about ExecutionContext flowing).
|
||||
Task.Run(() => RebuildIndexes(onlyEmptyIndexes, delay.Value, cancellationToken));
|
||||
|
||||
// immediately return so the queue isn't waiting.
|
||||
return Task.CompletedTask;
|
||||
// immediately return so the queue isn't waiting.
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
|
||||
@@ -266,7 +266,12 @@ public class CreatedPackageSchemaRepository : ICreatedPackagesRepository
|
||||
definition.Name.Replace(' ', '_')));
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
var expectedRoot = _hostingEnvironment.MapPathContentRoot(_createdPackagesFolderPath);
|
||||
var finalPackagePath = Path.Combine(directoryName, fileName);
|
||||
if (finalPackagePath.StartsWith(expectedRoot) == false)
|
||||
{
|
||||
throw new IOException("Invalid path due to the package name");
|
||||
}
|
||||
|
||||
// Clean existing files
|
||||
foreach (var packagePath in new[] { definition.PackagePath, finalPackagePath })
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessSettings)]
|
||||
public class AnalyticsController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly IMetricsConsentService _metricsConsentService;
|
||||
|
||||
@@ -404,6 +404,9 @@ public class AuthenticationController : UmbracoApiControllerBase
|
||||
}
|
||||
|
||||
BackOfficeIdentityUser? identityUser = await _userManager.FindByEmailAsync(model.Email);
|
||||
|
||||
await Task.Delay(RandomNumberGenerator.GetInt32(400, 2500)); // To randomize response time preventing user enumeration
|
||||
|
||||
if (identityUser != null)
|
||||
{
|
||||
IUser? user = _userService.GetByEmail(model.Email);
|
||||
@@ -424,14 +427,20 @@ public class AuthenticationController : UmbracoApiControllerBase
|
||||
|
||||
var mailMessage = new EmailMessage(from, user.Email, subject, message, true);
|
||||
|
||||
await _emailSender.SendAsync(mailMessage, Constants.Web.EmailTypes.PasswordReset, true);
|
||||
try
|
||||
{
|
||||
await _emailSender.SendAsync(mailMessage, Constants.Web.EmailTypes.PasswordReset, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error sending email, please check your SMTP configuration: {ErrorMessage}", ex.Message);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
_userManager.NotifyForgotPasswordRequested(User, user.Id.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Delay(RandomNumberGenerator.GetInt32(400, 2500));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
/// Backoffice controller supporting the dashboard for language administration.
|
||||
/// </summary>
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessSettings)]
|
||||
public class LanguageController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly ILocalizationService _localizationService;
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.PublishedCache;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessSettings)]
|
||||
public class PublishedSnapshotCacheStatusController : UmbracoAuthorizedApiController
|
||||
{
|
||||
private readonly DistributedCache _distributedCache;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Security;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -14,11 +15,13 @@ using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessContent)]
|
||||
public class RedirectUrlManagementController : UmbracoAuthorizedApiController
|
||||
{
|
||||
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
|
||||
@@ -45,6 +48,8 @@ public class RedirectUrlManagementController : UmbracoAuthorizedApiController
|
||||
_configManipulator = configManipulator ?? throw new ArgumentNullException(nameof(configManipulator));
|
||||
}
|
||||
|
||||
private bool IsEnabled => _webRoutingSettings.CurrentValue.DisableRedirectUrlTracking == false;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true/false of whether redirect tracking is enabled or not
|
||||
/// </summary>
|
||||
@@ -52,9 +57,8 @@ public class RedirectUrlManagementController : UmbracoAuthorizedApiController
|
||||
[HttpGet]
|
||||
public IActionResult GetEnableState()
|
||||
{
|
||||
var enabled = _webRoutingSettings.CurrentValue.DisableRedirectUrlTracking == false;
|
||||
var userIsAdmin = _backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.IsAdmin() ?? false;
|
||||
return Ok(new { enabled, userIsAdmin });
|
||||
return Ok(new { enabled = IsEnabled, userIsAdmin });
|
||||
}
|
||||
|
||||
//add paging
|
||||
@@ -104,6 +108,11 @@ public class RedirectUrlManagementController : UmbracoAuthorizedApiController
|
||||
[HttpPost]
|
||||
public IActionResult DeleteRedirectUrl(Guid id)
|
||||
{
|
||||
if (IsEnabled is false)
|
||||
{
|
||||
return BadRequest("Redirect URL tracking is disabled, and therefore no URLs can be deleted.");
|
||||
}
|
||||
|
||||
_redirectUrlService.Delete(id);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
using Stylesheet = Umbraco.Cms.Core.Models.ContentEditing.Stylesheet;
|
||||
|
||||
@@ -12,6 +14,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
/// The API controller used for retrieving available stylesheets
|
||||
/// </summary>
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessSettings)]
|
||||
public class StylesheetController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly IFileService _fileService;
|
||||
|
||||
@@ -28,7 +28,7 @@ function authResource($q, $http, umbRequestHelper, angularHelper) {
|
||||
* });
|
||||
* </pre>
|
||||
* @returns {Promise} resourcePromise object
|
||||
*
|
||||
*
|
||||
*/
|
||||
get2FAProviders: function () {
|
||||
|
||||
@@ -203,7 +203,7 @@ function authResource($q, $http, umbRequestHelper, angularHelper) {
|
||||
"PostRequestPasswordReset"), {
|
||||
email: email
|
||||
}),
|
||||
'Request password reset failed for email ' + email);
|
||||
'An email with password reset instructions will be sent to the specified address if it matched our records');
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,11 +11,12 @@ angular.module('umbraco').controller("Umbraco.LoginController", function (events
|
||||
//check if there's a returnPath query string, if so redirect to it
|
||||
var locationObj = $location.search();
|
||||
if (locationObj.returnPath) {
|
||||
// decodeURIComponent(...) does not play nice with OAuth redirect URLs, so until we have a
|
||||
// dedicated login screen for the new back-office, we need to hardcode this exception
|
||||
path = locationObj.returnPath.indexOf("/security/back-office/authorize") > 0
|
||||
? locationObj.returnPath
|
||||
: decodeURIComponent(locationObj.returnPath);
|
||||
// ensure that the returnPath is a valid URL under the current origin (prevents DOM-XSS among other things)
|
||||
const returnPath = decodeURIComponent(locationObj.returnPath);
|
||||
const url = new URL(returnPath, window.location.origin);
|
||||
if (url.origin === window.location.origin) {
|
||||
path = returnPath;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure path is not absolute
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
</div>
|
||||
|
||||
<div ng-messages="vm.requestPasswordResetForm.$error" class="control-group" ng-show="vm.requestPasswordResetForm.$invalid">
|
||||
<p ng-message="auth" class="text-error" role="alert" tabindex="0">{{vm.errorMsg}}</p>
|
||||
<p ng-message="auth" class="text-info" role="alert" tabindex="0">{{vm.errorMsg}}</p>
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-show="vm.showEmailResetConfirmation">
|
||||
|
||||
Reference in New Issue
Block a user