Merge remote-tracking branch 'origin/dev-v7' into temp8

# Conflicts:
#	build/Modules/Umbraco.Build/Get-UmbracoBuildEnv.ps1
#	build/NuSpecs/UmbracoCms.Core.nuspec
#	build/NuSpecs/UmbracoCms.nuspec
#	build/NuSpecs/tools/Readme.txt
#	src/Umbraco.Core/Configuration/UmbracoConfig.cs
#	src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs
#	src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
#	src/Umbraco.Core/Constants-Conventions.cs
#	src/Umbraco.Core/Constants-System.cs
#	src/Umbraco.Core/IO/MediaFileSystem.cs
#	src/Umbraco.Core/Media/Exif/ImageFile.cs
#	src/Umbraco.Core/Models/Property.cs
#	src/Umbraco.Core/Models/PropertyTagBehavior.cs
#	src/Umbraco.Core/Models/PropertyTags.cs
#	src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenTwelveZero/SetDefaultTagsStorageType.cs
#	src/Umbraco.Core/Persistence/Repositories/AuditRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/UserRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs
#	src/Umbraco.Core/Security/AuthenticationExtensions.cs
#	src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs
#	src/Umbraco.Core/Services/Implement/PackagingService.cs
#	src/Umbraco.Core/Services/ServerRegistrationService.cs
#	src/Umbraco.Core/StringExtensions.cs
#	src/Umbraco.Core/packages.config
#	src/Umbraco.Tests/ApplicationUrlHelperTests.cs
#	src/Umbraco.Tests/Persistence/Repositories/AuditRepositoryTest.cs
#	src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs
#	src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs
#	src/Umbraco.Tests/packages.config
#	src/Umbraco.Web.UI.Client/package.json
#	src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js
#	src/Umbraco.Web.UI.Client/src/common/directives/components/imaging/umbimagegravity.directive.js
#	src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreeitem.directive.js
#	src/Umbraco.Web.UI.Client/src/common/resources/log.resource.js
#	src/Umbraco.Web.UI.Client/src/common/services/user.service.js
#	src/Umbraco.Web.UI.Client/src/less/belle.less
#	src/Umbraco.Web.UI.Client/src/less/components/card.less
#	src/Umbraco.Web.UI.Client/src/less/navs.less
#	src/Umbraco.Web.UI.Client/src/less/panel.less
#	src/Umbraco.Web.UI.Client/src/less/property-editors.less
#	src/Umbraco.Web.UI.Client/src/less/tree.less
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/login.html
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/iconpicker/iconpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/iconpicker/iconpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.html
#	src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html
#	src/Umbraco.Web.UI.Client/src/views/components/notifications/umb-notifications.html
#	src/Umbraco.Web.UI.Client/src/views/components/umb-color-swatches.html
#	src/Umbraco.Web.UI.Client/src/views/components/umb-table.html
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.html
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/imagecropper/imagecropper.html
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/textarea/textarea.html
#	src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
#	src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
#	src/Umbraco.Web.UI/config/umbracoSettings.Release.config
#	src/Umbraco.Web.UI/packages.config
#	src/Umbraco.Web.UI/web.Template.Debug.config
#	src/Umbraco.Web.UI/web.Template.config
#	src/Umbraco.Web/Editors/AuthenticationController.cs
#	src/Umbraco.Web/Editors/BackOfficeController.cs
#	src/Umbraco.Web/Editors/CanvasDesignerController.cs
#	src/Umbraco.Web/Editors/ContentController.cs
#	src/Umbraco.Web/Editors/DashboardController.cs
#	src/Umbraco.Web/Editors/LogController.cs
#	src/Umbraco.Web/Editors/MediaController.cs
#	src/Umbraco.Web/Install/InstallHelper.cs
#	src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs
#	src/Umbraco.Web/Media/EmbedProviders/AbstractOEmbedProvider.cs
#	src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs
#	src/Umbraco.Web/Models/Mapping/PreValueDisplayResolver.cs
#	src/Umbraco.Web/Mvc/MasterControllerFactory.cs
#	src/Umbraco.Web/PropertyEditors/FileUploadPropertyValueEditor.cs
#	src/Umbraco.Web/PropertyEditors/ImageCropperPropertyValueEditor.cs
#	src/Umbraco.Web/PropertyEditors/TextAreaPropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/ValueConverters/MultiNodeTreePickerPropertyConverter.cs
#	src/Umbraco.Web/PublishedCache/MemberPublishedContent.cs
#	src/Umbraco.Web/Routing/RedirectTrackingEventHandler.cs
#	src/Umbraco.Web/Scheduling/HealthCheckNotifier.cs
#	src/Umbraco.Web/Scheduling/KeepAlive.cs
#	src/Umbraco.Web/Scheduling/LogScrubber.cs
#	src/Umbraco.Web/Scheduling/ScheduledPublishing.cs
#	src/Umbraco.Web/Scheduling/ScheduledTasks.cs
#	src/Umbraco.Web/Scheduling/Scheduler.cs
#	src/Umbraco.Web/Templates/TemplateUtilities.cs
#	src/Umbraco.Web/Trees/DataTypeTreeController.cs
#	src/Umbraco.Web/UmbracoModule.cs
#	src/Umbraco.Web/_Legacy/Packager/Installer.cs
#	src/Umbraco.Web/packages.config
#	src/Umbraco.Web/umbraco.presentation/keepAliveService.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/dashboard/FeedProxy.aspx.cs
#	src/umbraco.businesslogic/IO/IOHelper.cs
#	src/umbraco.cms/packages.config
#	src/umbraco.cms/umbraco.cms.csproj
#	src/umbraco.controls/packages.config
#	src/umbraco.controls/umbraco.controls.csproj
#	src/umbraco.editorControls/packages.config
#	src/umbraco.editorControls/umbraco.editorControls.csproj
This commit is contained in:
Shannon
2018-10-01 14:32:46 +02:00
84 changed files with 5276 additions and 323 deletions

View File

@@ -421,6 +421,34 @@ namespace Umbraco.Web.Editors
}
}
//They've successfully set their password, we can now update their user account to be confirmed
//if user was only invited, then they have not been approved
//but a successful forgot password flow (e.g. if their token had expired and they did a forgot password instead of request new invite)
//means we have verified their email
if (!UserManager.IsEmailConfirmed(model.UserId))
{
await UserManager.ConfirmEmailAsync(model.UserId, model.ResetCode);
}
//if the user is invited, enable their account on forgot password
var identityUser = await UserManager.FindByIdAsync(model.UserId);
//invited is not approved, never logged in, invited date present
/*
if (LastLoginDate == default && IsApproved == false && InvitedDate != null)
return UserState.Invited;
*/
if (identityUser != null && !identityUser.IsApproved)
{
var user = Services.UserService.GetByUsername(identityUser.UserName);
//also check InvitedDate and never logged in, otherwise this would allow a disabled user to reactivate their account with a forgot password
if (user.LastLoginDate == default && user.InvitedDate != null)
{
user.IsApproved = true;
user.InvitedDate = null;
Services.UserService.Save(user);
}
}
UserManager.RaiseForgotPasswordChangedSuccessEvent(model.UserId);
return Request.CreateResponse(HttpStatusCode.OK);
}

View File

@@ -82,6 +82,16 @@ namespace Umbraco.Web.Editors
[HttpGet]
public async Task<ActionResult> VerifyInvite(string invite)
{
//if you are hitting VerifyInvite, you're already signed in as a different user, and the token is invalid
//you'll exit on one of the return RedirectToAction("Default") but you're still logged in so you just get
//dumped at the default admin view with no detail
if(Security.IsAuthenticated())
{
AuthenticationManager.SignOut(
Core.Constants.Security.BackOfficeAuthenticationType,
Core.Constants.Security.BackOfficeExternalAuthenticationType);
}
if (invite == null)
{
Logger.Warn<BackOfficeController>("VerifyUser endpoint reached with invalid token: NULL");
@@ -125,16 +135,15 @@ namespace Umbraco.Web.Editors
if (result.Succeeded == false)
{
Logger.Warn<BackOfficeController>("Could not verify email, Error: " + string.Join(",", result.Errors) + ", Token: " + invite);
return RedirectToAction("Default");
return new RedirectResult(Url.Action("Default") + "#/login/false?invite=3");
}
//sign the user in
AuthenticationManager.SignOut(
Core.Constants.Security.BackOfficeAuthenticationType,
Core.Constants.Security.BackOfficeExternalAuthenticationType);
DateTime? previousLastLoginDate = identityUser.LastLoginDateUtc;
await SignInManager.SignInAsync(identityUser, false, false);
//reset the lastlogindate back to previous as the user hasn't actually logged in, to add a flag or similar to SignInManager would be a breaking change
identityUser.LastLoginDateUtc = previousLastLoginDate;
await UserManager.UpdateAsync(identityUser);
return new RedirectResult(Url.Action("Default") + "#/login/false?invite=1");
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
@@ -585,6 +586,17 @@ namespace Umbraco.Web.Editors
private ContentItemDisplay PostSaveInternal(ContentItemSave contentItem, Func<IContent, OperationResult> saveMethod)
{
//Recent versions of IE/Edge may send in the full clientside file path instead of just the file name.
//To ensure similar behavior across all browsers no matter what they do - we strip the FileName property of all
//uploaded files to being *only* the actual file name (as it should be).
if (contentItem.UploadedFiles != null && contentItem.UploadedFiles.Any())
{
foreach (var file in contentItem.UploadedFiles)
{
file.FileName = Path.GetFileName(file.FileName);
}
}
//If we've reached here it means:
// * Our model has been bound
// * and validated

View File

@@ -27,6 +27,8 @@ namespace Umbraco.Web.Editors
[WebApi.UmbracoAuthorize]
public class DashboardController : UmbracoApiController
{
//we have just one instance of HttpClient shared for the entire application
private static readonly HttpClient HttpClient = new HttpClient();
//we have baseurl as a param to make previewing easier, so we can test with a dev domain from client side
[ValidateAngularAntiForgeryToken]
public async Task<JObject> GetRemoteDashboardContent(string section, string baseUrl = "https://dashboard.umbraco.org/")
@@ -54,13 +56,10 @@ namespace Umbraco.Web.Editors
//content is null, go get it
try
{
using (var web = new HttpClient())
{
//fetch dashboard json and parse to JObject
var json = await web.GetStringAsync(url);
content = JObject.Parse(json);
result = content;
}
//fetch dashboard json and parse to JObject
var json = await HttpClient.GetStringAsync(url);
content = JObject.Parse(json);
result = content;
ApplicationCache.RuntimeCache.InsertCacheItem<JObject>(key, () => result, new TimeSpan(0, 30, 0));
}
@@ -93,17 +92,14 @@ namespace Umbraco.Web.Editors
//content is null, go get it
try
{
using (var web = new HttpClient())
{
//fetch remote css
content = await web.GetStringAsync(url);
//fetch remote css
content = await HttpClient.GetStringAsync(url);
//can't use content directly, modified closure problem
result = content;
//can't use content directly, modified closure problem
result = content;
//save server content for 30 mins
//save server content for 30 mins
ApplicationCache.RuntimeCache.InsertCacheItem<string>(key, () => result, new TimeSpan(0, 30, 0));
}
}
catch (HttpRequestException ex)
{

View File

@@ -7,20 +7,22 @@ using System.Threading.Tasks;
namespace Umbraco.Web.Editors
{
public class HelpController : UmbracoAuthorizedJsonController
{
{
private static HttpClient _httpClient;
public async Task<List<HelpPage>> GetContextHelpForPage(string section, string tree, string baseUrl = "https://our.umbraco.com")
{
var url = string.Format(baseUrl + "/Umbraco/Documentation/Lessons/GetContextHelpDocs?sectionAlias={0}&treeAlias={1}", section, tree);
using (var web = new HttpClient())
{
//fetch dashboard json and parse to JObject
var json = await web.GetStringAsync(url);
var result = JsonConvert.DeserializeObject<List<HelpPage>>(json);
if (result != null)
return result;
return new List<HelpPage>();
}
if (_httpClient == null)
_httpClient = new HttpClient();
//fetch dashboard json and parse to JObject
var json = await _httpClient.GetStringAsync(url);
var result = JsonConvert.DeserializeObject<List<HelpPage>>(json);
if (result != null)
return result;
return new List<HelpPage>();
}
}

View File

@@ -1,10 +1,11 @@
using System;
using AutoMapper;
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
namespace Umbraco.Web.Editors
@@ -45,7 +46,7 @@ namespace Umbraco.Web.Editors
var userId = Security.GetUserId().ResultOr(0);
var result = Services.AuditService.GetPagedItemsByUser(userId, pageNumber - 1, pageSize, out totalRecords, orderDirection, customFilter:dateQuery);
var mapped = Mapper.Map<IEnumerable<AuditLog>>(result);
return new PagedResult<AuditLog>(totalRecords, pageNumber + 1, pageSize)
return new PagedResult<AuditLog>(totalRecords, pageNumber, pageSize)
{
Items = MapAvatarsAndNames(mapped)
};

View File

@@ -439,6 +439,17 @@ namespace Umbraco.Web.Editors
[ModelBinder(typeof(MediaItemBinder))]
MediaItemSave contentItem)
{
//Recent versions of IE/Edge may send in the full clientside file path instead of just the file name.
//To ensure similar behavior across all browsers no matter what they do - we strip the FileName property of all
//uploaded files to being *only* the actual file name (as it should be).
if (contentItem.UploadedFiles != null && contentItem.UploadedFiles.Any())
{
foreach (var file in contentItem.UploadedFiles)
{
file.FileName = Path.GetFileName(file.FileName);
}
}
//If we've reached here it means:
// * Our model has been bound
// * and validated
@@ -688,15 +699,7 @@ namespace Umbraco.Web.Editors
mediaType = result.FormData["contentTypeAlias"];
}
//TODO: make the media item name "nice" since file names could be pretty ugly, we have
// string extensions to do much of this but we'll need:
// * Pascalcase the name (use string extensions)
// * strip the file extension
// * underscores to spaces
// * probably remove 'ugly' characters - let's discuss
// All of this logic should exist in a string extensions method and be unit tested
// http://issues.umbraco.org/issue/U4-5572
var mediaItemName = fileName;
var mediaItemName = fileName.ToFriendlyName();
var f = mediaService.CreateMedia(mediaItemName, parentId, mediaType, Security.CurrentUser.Id);
@@ -910,4 +913,4 @@ namespace Umbraco.Web.Editors
return hasPathAccess;
}
}
}
}

View File

@@ -12,6 +12,7 @@ using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
using File = System.IO.File;
using Umbraco.Core;
namespace Umbraco.Web.Editors
{
@@ -63,7 +64,28 @@ namespace Umbraco.Web.Editors
return searchResult;
}
/// <summary>
/// This lists the RedirectUrls for a particular content item
/// Do we need to consider paging here?
/// </summary>
/// <param name="contentUdi">Udi of content item to retrieve RedirectUrls for</param>
/// <returns></returns>
[HttpGet]
public RedirectUrlSearchResult RedirectUrlsForContentItem(string contentUdi)
{
var redirectsResult = new RedirectUrlSearchResult();
if (GuidUdi.TryParse(contentUdi, out var guidIdi))
{
var redirectUrlService = Services.RedirectUrlService;
var redirects = redirectUrlService.GetContentRedirectUrls(guidIdi.Guid);
redirectsResult.SearchResults = Mapper.Map<IEnumerable<ContentRedirectUrl>>(redirects).ToArray();
//not doing paging 'yet'
redirectsResult.TotalCount = redirects.Count();
redirectsResult.CurrentPage = 1;
redirectsResult.PageCount = 1;
}
return redirectsResult;
}
[HttpPost]
public IHttpActionResult DeleteRedirectUrl(Guid id)
{

View File

@@ -26,6 +26,7 @@ namespace Umbraco.Web.Install
{
public sealed class InstallHelper
{
private static HttpClient _httpClient;
private readonly DatabaseBuilder _databaseBuilder;
private readonly HttpContextBase _httpContext;
private readonly ILogger _logger;
@@ -168,16 +169,17 @@ namespace Umbraco.Web.Install
internal IEnumerable<Package> GetStarterKits()
{
var packages = new List<Package>();
if (_httpClient == null)
_httpClient = new HttpClient();
var packages = new List<Package>();
try
{
var requestUri = $"https://our.umbraco.com/webapi/StarterKit/Get/?umbracoVersion={UmbracoVersion.Current}";
using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
using (var httpClient = new HttpClient())
using (var response = httpClient.SendAsync(request).Result)
{
var response = _httpClient.SendAsync(request).Result;
packages = response.Content.ReadAsAsync<IEnumerable<Package>>().Result.ToList();
}
}

View File

@@ -1,13 +1,15 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Security;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Migrations.Install;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Web.Install.Models;
@@ -27,6 +29,7 @@ namespace Umbraco.Web.Install.InstallSteps
private readonly HttpContextBase _http;
private readonly IUserService _userService;
private readonly DatabaseBuilder _databaseBuilder;
private static HttpClient _httpClient;
private readonly IGlobalSettings _globalSettings;
public NewInstallStep(HttpContextBase http, IUserService userService, DatabaseBuilder databaseBuilder, IGlobalSettings globalSettings)
@@ -79,15 +82,18 @@ namespace Umbraco.Web.Install.InstallSteps
admin.Username = user.Email.Trim();
_userService.Save(admin);
if (user.SubscribeToNewsLetter)
{
if (_httpClient == null)
_httpClient = new HttpClient();
var values = new NameValueCollection { { "name", admin.Name }, { "email", admin.Email } };
var content = new StringContent(JsonConvert.SerializeObject(values), Encoding.UTF8, "application/json");
try
{
var client = new System.Net.WebClient();
var values = new NameValueCollection { { "name", admin.Name }, { "email", admin.Email} };
client.UploadValues("https://shop.umbraco.com/base/Ecom/SubmitEmail/installer.aspx", values);
var response = _httpClient.PostAsync("https://shop.umbraco.com/base/Ecom/SubmitEmail/installer.aspx", content).Result;
}
catch { /* fail in silence */ }
}
@@ -114,11 +120,14 @@ namespace Umbraco.Web.Install.InstallSteps
public override string View
{
get { return RequiresExecution(null)
//the user UI
get
{
return RequiresExecution(null)
//the user UI
? "user"
//the continue install UI
: "continueinstall"; }
//the continue install UI
: "continueinstall";
}
}
public override bool RequiresExecution(UserModel model)

View File

@@ -12,18 +12,20 @@ namespace Umbraco.Web.Media.EmbedProviders
{
//TODO: Make all Http calls async
public abstract class AbstractOEmbedProvider: IEmbedProvider
public abstract class AbstractOEmbedProvider : IEmbedProvider
{
private static HttpClient _httpClient;
public virtual bool SupportsDimensions
{
get { return true; }
}
[ProviderSetting]
public string APIEndpoint{ get;set; }
public string APIEndpoint { get; set; }
[ProviderSetting]
public Dictionary<string, string> RequestParams{ get;set; }
public Dictionary<string, string> RequestParams { get; set; }
public abstract string GetMarkup(string url, int maxWidth, int maxHeight);
@@ -51,9 +53,13 @@ namespace Umbraco.Web.Media.EmbedProviders
public virtual string DownloadResponse(string url)
{
using (var webClient = new WebClient())
if (_httpClient == null)
_httpClient = new HttpClient();
using (var request = new HttpRequestMessage(HttpMethod.Get, url))
{
return webClient.DownloadString(url);
var response = _httpClient.SendAsync(request).Result;
return response.Content.ReadAsStringAsync().Result;
}
}

View File

@@ -17,5 +17,9 @@
/// The file is a TIFF File.
/// </summary>
TIFF,
/// <summary>
/// The file is a SVG File.
/// </summary>
SVG,
}
}

View File

@@ -38,7 +38,7 @@ namespace Umbraco.Web.Scheduling
switch (_runtimeState.ServerRole)
{
case ServerRole.Replica:
_logger.Debug<HealthCheckNotifier>("Does not run on slave servers.");
_logger.Debug<HealthCheckNotifier>("Does not run on replica servers.");
return true; // DO repeat, server role can change
case ServerRole.Unknown:
_logger.Debug<HealthCheckNotifier>("Does not run on servers with unknown role.");

View File

@@ -32,7 +32,7 @@ namespace Umbraco.Web.Scheduling
switch (_runtime.ServerRole)
{
case ServerRole.Replica:
_logger.Debug<KeepAlive>("Does not run on slave servers.");
_logger.Debug<KeepAlive>("Does not run on replica servers.");
return true; // role may change!
case ServerRole.Unknown:
_logger.Debug<KeepAlive>("Does not run on servers with unknown role.");

View File

@@ -69,7 +69,7 @@ namespace Umbraco.Web.Scheduling
switch (_runtime.ServerRole)
{
case ServerRole.Replica:
_logger.Debug<LogScrubber>("Does not run on slave servers.");
_logger.Debug<LogScrubber>("Does not run on replica servers.");
return true; // DO repeat, server role can change
case ServerRole.Unknown:
_logger.Debug<LogScrubber>("Does not run on servers with unknown role.");

View File

@@ -32,7 +32,7 @@ namespace Umbraco.Web.Scheduling
switch (_runtime.ServerRole)
{
case ServerRole.Replica:
_logger.Debug<ScheduledPublishing>("Does not run on slave servers.");
_logger.Debug<ScheduledPublishing>("Does not run on replica servers.");
return true; // DO repeat, server role can change
case ServerRole.Unknown:
_logger.Debug<ScheduledPublishing>("Does not run on servers with unknown role.");

View File

@@ -17,6 +17,7 @@ namespace Umbraco.Web.Scheduling
internal class ScheduledTasks : RecurringTaskBase
{
private static HttpClient _httpClient;
private readonly IRuntimeState _runtime;
private readonly IUmbracoSettingsSection _settings;
private readonly ILogger _logger;
@@ -65,27 +66,28 @@ namespace Umbraco.Web.Scheduling
private async Task<bool> GetTaskByHttpAync(string url, CancellationToken token)
{
using (var wc = new HttpClient())
if (_httpClient == null)
_httpClient = new HttpClient();
if (Uri.TryCreate(_runtime.ApplicationUrl, UriKind.Absolute, out var baseUri))
_httpClient.BaseAddress = baseUri;
var request = new HttpRequestMessage(HttpMethod.Get, url);
//TODO: pass custom the authorization header, currently these aren't really secured!
//request.Headers.Authorization = AdminTokenAuthorizeAttribute.GetAuthenticationHeaderValue(_appContext);
try
{
// url could be relative, so better set a base url for the http client
wc.BaseAddress = _runtime.ApplicationUrl;
var request = new HttpRequestMessage(HttpMethod.Get, url);
//TODO: pass custom the authorization header, currently these aren't really secured!
//request.Headers.Authorization = AdminTokenAuthorizeAttribute.GetAuthenticationHeaderValue(_appContext);
try
{
var result = await wc.SendAsync(request, token).ConfigureAwait(false); // ConfigureAwait(false) is recommended? http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
return result.StatusCode == HttpStatusCode.OK;
}
catch (Exception ex)
{
_logger.Error<ScheduledTasks>(ex, "An error occurred calling web task for url: {Url}", url);
}
return false;
var result = await _httpClient.SendAsync(request, token).ConfigureAwait(false); // ConfigureAwait(false) is recommended? http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
return result.StatusCode == HttpStatusCode.OK;
}
catch (Exception ex)
{
_logger.Error<ScheduledTasks>(ex, "An error occurred calling web task for url: {Url}", url);
}
return false;
}
public override async Task<bool> PerformRunAsync(CancellationToken token)
@@ -93,7 +95,7 @@ namespace Umbraco.Web.Scheduling
switch (_runtime.ServerRole)
{
case ServerRole.Replica:
_logger.Debug<ScheduledTasks>("Does not run on slave servers.");
_logger.Debug<ScheduledTasks>("Does not run on replica servers.");
return true; // DO repeat, server role can change
case ServerRole.Unknown:
_logger.Debug<ScheduledTasks>("Does not run on servers with unknown role.");

View File

@@ -191,7 +191,10 @@ namespace Umbraco.Web.Security
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<T, int>(dataProtectionProvider.Create("ASP.NET Identity"));
manager.UserTokenProvider = new DataProtectorTokenProvider<T, int>(dataProtectionProvider.Create("ASP.NET Identity"))
{
TokenLifespan = TimeSpan.FromDays(3)
};
}
manager.UserLockoutEnabledByDefault = true;
@@ -703,6 +706,7 @@ namespace Umbraco.Web.Security
var httpContext = HttpContext.Current == null ? (HttpContextBase)null : new HttpContextWrapper(HttpContext.Current);
return httpContext.GetCurrentRequestIpAddress();
}
}
}

View File

@@ -1,4 +1,6 @@
using System;
using HtmlAgilityPack;
using System;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using Umbraco.Core;
using Umbraco.Core.Configuration;
@@ -36,6 +38,11 @@ namespace Umbraco.Web.Templates
{
if (urlProvider == null) throw new ArgumentNullException("urlProvider");
if(string.IsNullOrEmpty(text))
{
return text;
}
// Parse internal links
var tags = LocalLinkPattern.Matches(text);
foreach (Match tag in tags)
@@ -64,6 +71,11 @@ namespace Umbraco.Web.Templates
}
}
if (UmbracoConfig.For.UmbracoSettings().Content.StripUdiAttributes)
{
text = StripUdiDataAttributes(text);
}
return text;
}
@@ -75,6 +87,9 @@ namespace Umbraco.Web.Templates
private static readonly Regex ResolveUrlPattern = new Regex("(=[\"\']?)(\\W?\\~(?:.(?![\"\']?\\s+(?:\\S+)=|[>\"\']))+.)[\"\']?",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
private static readonly Regex UdiDataAttributePattern = new Regex("data-udi=\"[^\\\"]*\"",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
/// <summary>
/// The RegEx matches any HTML attribute values that start with a tilde (~), those that match are passed to ResolveUrl to replace the tilde with the application path.
/// </summary>
@@ -118,5 +133,21 @@ namespace Umbraco.Web.Templates
{
return text.CleanForXss(ignoreFromClean);
}
/// <summary>
/// Strips data-udi attributes from rich text
/// </summary>
/// <param name="input">A html string</param>
/// <returns>A string stripped from the data-uid attributes</returns>
public static string StripUdiDataAttributes(string input)
{
if (string.IsNullOrEmpty(input))
{
return string.Empty;
}
return UdiDataAttributePattern.Replace(input, string.Empty);
}
}
}

View File

@@ -46,8 +46,8 @@ namespace Umbraco.Web.Trees
//if the request is for folders only then just return
if (queryStrings["foldersonly"].IsNullOrWhiteSpace() == false && queryStrings["foldersonly"] == "1") return nodes;
//Normal nodes
var sysIds = GetSystemIds();
//System ListView nodes
var systemListViewDataTypeIds = GetNonDeletableSystemListViewDataTypeIds();
nodes.AddRange(
Services.EntityService.GetChildren(intId.Result, UmbracoObjectTypes.DataType)
@@ -56,7 +56,7 @@ namespace Umbraco.Web.Trees
{
var node = CreateTreeNode(dt.Id.ToInvariantString(), id, queryStrings, dt.Name, "icon-autofill", false);
node.Path = dt.Path;
if (sysIds.Contains(dt.Id))
if (systemListViewDataTypeIds.Contains(dt.Id))
{
node.Icon = "icon-thumbnail-list";
}
@@ -66,15 +66,31 @@ namespace Umbraco.Web.Trees
return nodes;
}
private IEnumerable<int> GetSystemIds()
/// <summary>
/// Get all integer identifiers for the non-deletable system datatypes.
/// </summary>
private static IEnumerable<int> GetNonDeletableSystemDataTypeIds()
{
var systemIds = new[]
{
Constants.System.DefaultLabelDataTypeId
};
return systemIds.Concat(GetNonDeletableSystemListViewDataTypeIds());
}
/// <summary>
/// Get all integer identifiers for the non-deletable system listviews.
/// </summary>
private static IEnumerable<int> GetNonDeletableSystemListViewDataTypeIds()
{
return new[]
{
Constants.DataTypes.DefaultContentListView,
Constants.DataTypes.DefaultMediaListView,
Constants.DataTypes.DefaultMembersListView
};
return systemIds;
}
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
@@ -87,7 +103,7 @@ namespace Umbraco.Web.Trees
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
// root actions
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
menu.Items.Add<ActionNew>(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}"));
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize("actions", ActionRefresh.Instance.Alias), true);
return menu;
}
@@ -98,30 +114,27 @@ namespace Umbraco.Web.Trees
//set the default to create
menu.DefaultMenuAlias = ActionNew.Instance.Alias;
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
menu.Items.Add<ActionNew>(Services.TextService.Localize($"actions/{ActionNew.Instance.Alias}"));
menu.Items.Add(new MenuItem("rename", Services.TextService.Localize(String.Format("actions/{0}", "rename")))
menu.Items.Add(new MenuItem("rename", Services.TextService.Localize("actions/rename"))
{
Icon = "icon icon-edit"
});
if (container.HasChildren == false)
{
//can delete data type
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
menu.Items.Add<ActionDelete>(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}"));
}
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), hasSeparator: true);
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize($"actions/{ActionRefresh.Instance.Alias}"), hasSeparator: true);
}
else
{
var sysIds = GetSystemIds();
var nonDeletableSystemDataTypeIds = GetNonDeletableSystemDataTypeIds();
if (sysIds.Contains(int.Parse(id)) == false)
{
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
}
if (nonDeletableSystemDataTypeIds.Contains(int.Parse(id)) == false)
menu.Items.Add<ActionDelete>(Services.TextService.Localize($"actions/{ActionDelete.Instance.Alias}"));
menu.Items.Add<ActionMove>(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), hasSeparator: true);
menu.Items.Add<ActionMove>(Services.TextService.Localize($"actions/{ActionMove.Instance.Alias}"), hasSeparator: true);
}
return menu;

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@ using Umbraco.Core.Logging;
using System.Diagnostics;
using Umbraco.Core.Models;
using Umbraco.Core.Composing;
using System.Net;
using Umbraco.Core.Events;
using Umbraco.Core.Models.Packaging;
using Umbraco.Core.Services.Implement;
@@ -43,6 +44,7 @@ namespace umbraco.cms.businesslogic.packager
private readonly List<string> _binaryFileErrors = new List<string>();
private int _currentUserId = -1;
private static WebClient _webClient;
public string Name { get; private set; }
@@ -684,9 +686,10 @@ namespace umbraco.cms.businesslogic.packager
if (Directory.Exists(IOHelper.MapPath(SystemDirectories.Packages)) == false)
Directory.CreateDirectory(IOHelper.MapPath(SystemDirectories.Packages));
var wc = new System.Net.WebClient();
if (_webClient == null)
_webClient = new WebClient();
wc.DownloadFile(
_webClient.DownloadFile(
"http://" + PackageServer + "/fetch?package=" + Package.ToString(),
IOHelper.MapPath(SystemDirectories.Packages + "/" + Package + ".umb"));

View File

@@ -1,10 +1,10 @@
using Umbraco.Core;
using System.Net.Http;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Web;
using Umbraco.Web.UI.Pages;
using System;
using System.Linq;
using System.Net;
using System.Net.Mime;
using Umbraco.Core.IO;
using Umbraco.Core.Xml;
@@ -16,42 +16,45 @@ namespace dashboardUtilities
public partial class FeedProxy : UmbracoEnsuredPage
{
private static HttpClient _httpClient;
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (Request.QueryString.AllKeys.Contains("url") && Request.QueryString["url"] != null)
{
var url = Request.QueryString["url"];
if (!string.IsNullOrWhiteSpace(url) && !url.StartsWith("/"))
{
Uri requestUri;
if (Uri.TryCreate(url, UriKind.Absolute, out requestUri))
{
var feedProxyXml = XmlHelper.OpenAsXmlDocument(IOHelper.MapPath(SystemFiles.FeedProxyConfig));
if (feedProxyXml != null
&& feedProxyXml.SelectSingleNode(string.Concat("//allow[@host = '", requestUri.Host, "']")) != null
&& requestUri.Port == 80)
{
using (var client = new WebClient())
{
var response = client.DownloadString(requestUri);
if (Request.QueryString.AllKeys.Contains("url") == false || Request.QueryString["url"] == null)
return;
if (string.IsNullOrEmpty(response) == false)
{
Response.Clear();
Response.ContentType = Request.CleanForXss("type") ?? MediaTypeNames.Text.Xml;
Response.Write(response);
}
}
}
else
{
Current.Logger.Debug<FeedProxy>("Access to unallowed feedproxy attempted: {RequestUrl}", requestUri);
}
}
var url = Request.QueryString["url"];
if (string.IsNullOrWhiteSpace(url) || url.StartsWith("/"))
return;
if (Uri.TryCreate(url, UriKind.Absolute, out var requestUri) == false)
return;
var feedProxyXml = XmlHelper.OpenAsXmlDocument(IOHelper.MapPath(SystemFiles.FeedProxyConfig));
if (feedProxyXml?.SelectSingleNode($"//allow[@host = '{requestUri.Host}']") != null && requestUri.Port == 80)
{
if (_httpClient == null)
_httpClient = new HttpClient();
using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
{
var response = _httpClient.SendAsync(request).Result;
var result = response.Content.ReadAsStringAsync().Result;
if (string.IsNullOrEmpty(result))
return;
Response.Clear();
Response.ContentType = Request.CleanForXss("type") ?? MediaTypeNames.Text.Xml;
Response.Write(result);
}
}
else
{
Current.Logger.Debug<FeedProxy>("Access to unallowed feedproxy attempted: {RequestUrl}", requestUri);
}
}
catch (Exception ex)
{