Merge branch 'AndyButland-u4-9558' into dev-v7

This commit is contained in:
Sebastiaan Janssen
2017-05-20 12:13:47 +02:00
15 changed files with 259 additions and 169 deletions

View File

@@ -139,6 +139,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
internal CommaDelimitedConfigurationElement DisallowedUploadFiles
{
get { return GetOptionalDelimitedElement("disallowedUploadFiles", new[] {"ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd"}); }
}
[ConfigurationProperty("allowedUploadFiles")]
internal CommaDelimitedConfigurationElement AllowedUploadFiles
{
get { return GetOptionalDelimitedElement("allowedUploadFiles", new string[0]); }
}
[ConfigurationProperty("cloneXmlContent")]
@@ -307,6 +313,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
IEnumerable<string> IContentSection.DisallowedUploadFiles
{
get { return DisallowedUploadFiles; }
}
IEnumerable<string> IContentSection.AllowedUploadFiles
{
get { return AllowedUploadFiles; }
}
bool IContentSection.CloneXmlContent

View File

@@ -0,0 +1,19 @@
using System.Linq;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public static class ContentSectionExtensions
{
/// <summary>
/// Determines if file extension is allowed for upload based on (optional) white list and black list
/// held in settings.
/// Allow upload if extension is whitelisted OR if there is no whitelist and extension is NOT blacklisted.
/// </summary>
public static bool IsFileAllowedForUpload(this IContentSection contentSection, string extension)
{
return contentSection.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)) ||
(contentSection.AllowedUploadFiles.Any() == false &&
contentSection.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)) == false);
}
}
}

View File

@@ -52,7 +52,9 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
MacroErrorBehaviour MacroErrorBehaviour { get; }
IEnumerable<string> DisallowedUploadFiles { get; }
IEnumerable<string> DisallowedUploadFiles { get; }
IEnumerable<string> AllowedUploadFiles { get; }
bool CloneXmlContent { get; }

View File

@@ -237,6 +237,7 @@
<Compile Include="Configuration\UmbracoSettings\ContentError404Collection.cs" />
<Compile Include="Configuration\UmbracoSettings\ContentErrorPageElement.cs" />
<Compile Include="Configuration\UmbracoSettings\ContentErrorsElement.cs" />
<Compile Include="Configuration\UmbracoSettings\ContentSectionExtensions.cs" />
<Compile Include="Configuration\UmbracoSettings\ImagingAutoFillPropertiesCollection.cs" />
<Compile Include="Configuration\UmbracoSettings\ImagingAutoFillUploadFieldElement.cs" />
<Compile Include="Configuration\UmbracoSettings\ContentImagingElement.cs" />

View File

@@ -177,6 +177,20 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
public void DisallowedUploadFiles()
{
Assert.IsTrue(SettingsSection.Content.DisallowedUploadFiles.All(x => "ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd".Split(',').Contains(x)));
}
[Test]
public void AllowedUploadFiles()
{
Assert.IsTrue(SettingsSection.Content.AllowedUploadFiles.All(x => "jpg,gif,png".Split(',').Contains(x)));
}
[Test]
public void IsFileAllowedForUpload_WithWhitelist()
{
Assert.IsTrue(SettingsSection.Content.IsFileAllowedForUpload("png"));
Assert.IsFalse(SettingsSection.Content.IsFileAllowedForUpload("bmp"));
Assert.IsFalse(SettingsSection.Content.IsFileAllowedForUpload("php"));
}
}
}

View File

@@ -100,6 +100,9 @@
<!-- These file types will not be allowed to be uploaded via the upload control for media and content -->
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd</disallowedUploadFiles>
<!-- If completed, only the file extensions listed below will be allowed to be uploaded. If empty, disallowedUploadFiles will apply to prevent upload of specific file extensions. -->
<allowedUploadFiles>jpg,png,gif</allowedUploadFiles>
<!-- Defines the default document type property used when adding properties in the back-office (if missing or empty, defaults to Textstring -->
<defaultDocumentTypeProperty>Textstring</defaultDocumentTypeProperty>
</content>

View File

@@ -15,15 +15,23 @@ angular.module("umbraco")
$scope.multiPicker = (dialogOptions.multiPicker && dialogOptions.multiPicker !== "0") ? true : false;
$scope.startNodeId = dialogOptions.startNodeId ? dialogOptions.startNodeId : -1;
$scope.cropSize = dialogOptions.cropSize;
$scope.lastOpenedNode = localStorageService.get("umbLastOpenedMediaNodeId");
if ($scope.onlyImages) {
$scope.acceptedFileTypes = mediaHelper
.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes);
} else {
$scope.acceptedFileTypes = !mediaHelper
.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.disallowedUploadFiles);
}
$scope.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB";
$scope.lastOpenedNode = localStorageService.get("umbLastOpenedMediaNodeId");
var umbracoSettings = Umbraco.Sys.ServerVariables.umbracoSettings;
var allowedUploadFiles = mediaHelper.formatFileTypes(umbracoSettings.allowedUploadFiles);
if ($scope.onlyImages) {
$scope.acceptedFileTypes = mediaHelper.formatFileTypes(umbracoSettings.imageFileTypes);
} else {
// Use whitelist of allowed file types if provided
if (allowedUploadFiles !== '') {
$scope.acceptedFileTypes = allowedUploadFiles;
} else {
// If no whitelist, we pass in a blacklist by adding ! to the file extensions, allowing everything EXCEPT for disallowedUploadFiles
$scope.acceptedFileTypes = !mediaHelper.formatFileTypes(umbracoSettings.disallowedUploadFiles);
}
}
$scope.maxFileSize = umbracoSettings.maxFileSize + "KB";
$scope.model.selectedImages = [];

View File

@@ -6,118 +6,124 @@
* @description
* The controller for the content type editor
*/
(function() {
"use strict";
(function () {
"use strict";
function ListViewGridLayoutController($scope, $routeParams, mediaHelper, mediaResource, $location, listViewHelper, mediaTypeHelper) {
function ListViewGridLayoutController($scope, $routeParams, mediaHelper, mediaResource, $location, listViewHelper, mediaTypeHelper) {
var vm = this;
var vm = this;
var umbracoSettings = Umbraco.Sys.ServerVariables.umbracoSettings;
vm.nodeId = $scope.contentId;
//we pass in a blacklist by adding ! to the file extensions, allowing everything EXCEPT for disallowedUploadFiles
vm.acceptedFileTypes = !mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.disallowedUploadFiles);
vm.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB";
vm.activeDrag = false;
vm.mediaDetailsTooltip = {};
vm.itemsWithoutFolders = [];
vm.isRecycleBin = $scope.contentId === '-21' || $scope.contentId === '-20';
vm.acceptedMediatypes = [];
vm.nodeId = $scope.contentId;
// Use whitelist of allowed file types if provided
vm.acceptedFileTypes = mediaHelper.formatFileTypes(umbracoSettings.allowedUploadFiles);
if (vm.acceptedFileTypes === '') {
// If not provided, we pass in a blacklist by adding ! to the file extensions, allowing everything EXCEPT for disallowedUploadFiles
vm.acceptedFileTypes = !mediaHelper.formatFileTypes(umbracoSettings.disallowedUploadFiles);
}
vm.dragEnter = dragEnter;
vm.dragLeave = dragLeave;
vm.onFilesQueue = onFilesQueue;
vm.onUploadComplete = onUploadComplete;
vm.maxFileSize = umbracoSettings.maxFileSize + "KB";
vm.activeDrag = false;
vm.mediaDetailsTooltip = {};
vm.itemsWithoutFolders = [];
vm.isRecycleBin = $scope.contentId === '-21' || $scope.contentId === '-20';
vm.acceptedMediatypes = [];
vm.hoverMediaItemDetails = hoverMediaItemDetails;
vm.selectContentItem = selectContentItem;
vm.selectItem = selectItem;
vm.selectFolder = selectFolder;
vm.goToItem = goToItem;
vm.dragEnter = dragEnter;
vm.dragLeave = dragLeave;
vm.onFilesQueue = onFilesQueue;
vm.onUploadComplete = onUploadComplete;
function activate() {
vm.itemsWithoutFolders = filterOutFolders($scope.items);
vm.hoverMediaItemDetails = hoverMediaItemDetails;
vm.selectContentItem = selectContentItem;
vm.selectItem = selectItem;
vm.selectFolder = selectFolder;
vm.goToItem = goToItem;
//no need to make another REST/DB call if this data is not used when we are browsing the bin
if ($scope.entityType === 'media' && !vm.isRecycleBin) {
mediaTypeHelper.getAllowedImagetypes(vm.nodeId).then(function (types) {
vm.acceptedMediatypes = types;
});
}
function activate() {
vm.itemsWithoutFolders = filterOutFolders($scope.items);
}
//no need to make another REST/DB call if this data is not used when we are browsing the bin
if ($scope.entityType === 'media' && !vm.isRecycleBin) {
mediaTypeHelper.getAllowedImagetypes(vm.nodeId).then(function (types) {
vm.acceptedMediatypes = types;
});
}
function filterOutFolders(items) {
}
var newArray = [];
function filterOutFolders(items) {
if(items && items.length ) {
var newArray = [];
for (var i = 0; items.length > i; i++) {
var item = items[i];
var isFolder = !mediaHelper.hasFilePropertyType(item);
if (items && items.length) {
if (!isFolder) {
newArray.push(item);
}
}
for (var i = 0; items.length > i; i++) {
var item = items[i];
var isFolder = !mediaHelper.hasFilePropertyType(item);
}
if (!isFolder) {
newArray.push(item);
}
}
return newArray;
}
}
function dragEnter(el, event) {
vm.activeDrag = true;
}
return newArray;
}
function dragLeave(el, event) {
vm.activeDrag = false;
}
function dragEnter(el, event) {
vm.activeDrag = true;
}
function onFilesQueue() {
vm.activeDrag = false;
}
function dragLeave(el, event) {
vm.activeDrag = false;
}
function onUploadComplete() {
$scope.getContent($scope.contentId);
}
function onFilesQueue() {
vm.activeDrag = false;
}
function hoverMediaItemDetails(item, event, hover) {
function onUploadComplete() {
$scope.getContent($scope.contentId);
}
if (hover && !vm.mediaDetailsTooltip.show) {
function hoverMediaItemDetails(item, event, hover) {
vm.mediaDetailsTooltip.event = event;
vm.mediaDetailsTooltip.item = item;
vm.mediaDetailsTooltip.show = true;
if (hover && !vm.mediaDetailsTooltip.show) {
} else if (!hover && vm.mediaDetailsTooltip.show) {
vm.mediaDetailsTooltip.event = event;
vm.mediaDetailsTooltip.item = item;
vm.mediaDetailsTooltip.show = true;
vm.mediaDetailsTooltip.show = false;
} else if (!hover && vm.mediaDetailsTooltip.show) {
}
vm.mediaDetailsTooltip.show = false;
}
}
function selectContentItem(item, $event, $index) {
listViewHelper.selectHandler(item, $index, $scope.items, $scope.selection, $event);
}
}
function selectItem(item, $event, $index) {
listViewHelper.selectHandler(item, $index, vm.itemsWithoutFolders, $scope.selection, $event);
}
function selectContentItem(item, $event, $index) {
listViewHelper.selectHandler(item, $index, $scope.items, $scope.selection, $event);
}
function selectFolder(folder, $event, $index) {
listViewHelper.selectHandler(folder, $index, $scope.folders, $scope.selection, $event);
}
function selectItem(item, $event, $index) {
listViewHelper.selectHandler(item, $index, vm.itemsWithoutFolders, $scope.selection, $event);
}
function goToItem(item, $event, $index) {
$location.path($scope.entityType + '/' + $scope.entityType + '/edit/' + item.id);
}
function selectFolder(folder, $event, $index) {
listViewHelper.selectHandler(folder, $index, $scope.folders, $scope.selection, $event);
}
activate();
function goToItem(item, $event, $index) {
$location.path($scope.entityType + '/' + $scope.entityType + '/edit/' + item.id);
}
}
activate();
angular.module("umbraco").controller("Umbraco.PropertyEditors.ListView.GridLayoutController", ListViewGridLayoutController);
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.ListView.GridLayoutController", ListViewGridLayoutController);
})();

View File

@@ -1,89 +1,96 @@
(function () {
"use strict";
"use strict";
function ListViewListLayoutController($scope, listViewHelper, $location, mediaHelper, mediaTypeHelper) {
function ListViewListLayoutController($scope, listViewHelper, $location, mediaHelper, mediaTypeHelper) {
var vm = this;
var vm = this;
var umbracoSettings = Umbraco.Sys.ServerVariables.umbracoSettings;
vm.nodeId = $scope.contentId;
//we pass in a blacklist by adding ! to the file extensions, allowing everything EXCEPT for disallowedUploadFiles
vm.acceptedFileTypes = !mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.disallowedUploadFiles);
vm.maxFileSize = Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB";
vm.activeDrag = false;
vm.isRecycleBin = $scope.contentId === '-21' || $scope.contentId === '-20';
vm.acceptedMediatypes = [];
vm.nodeId = $scope.contentId;
vm.selectItem = selectItem;
vm.clickItem = clickItem;
vm.selectAll = selectAll;
vm.isSelectedAll = isSelectedAll;
vm.isSortDirection = isSortDirection;
vm.sort = sort;
vm.dragEnter = dragEnter;
vm.dragLeave = dragLeave;
vm.onFilesQueue = onFilesQueue;
vm.onUploadComplete = onUploadComplete;
function activate() {
if ($scope.entityType === 'media') {
mediaTypeHelper.getAllowedImagetypes(vm.nodeId).then(function (types) {
vm.acceptedMediatypes = types;
});
// Use whitelist of allowed file types if provided
vm.acceptedFileTypes = mediaHelper.formatFileTypes(umbracoSettings.allowedUploadFiles);
if (vm.acceptedFileTypes === '') {
// If not provided, we pass in a blacklist by adding ! to the file extensions, allowing everything EXCEPT for disallowedUploadFiles
vm.acceptedFileTypes = !mediaHelper.formatFileTypes(umbracoSettings.disallowedUploadFiles);
}
}
vm.maxFileSize = umbracoSettings.maxFileSize + "KB";
vm.activeDrag = false;
vm.isRecycleBin = $scope.contentId === '-21' || $scope.contentId === '-20';
vm.acceptedMediatypes = [];
function selectAll($event) {
listViewHelper.selectAllItems($scope.items, $scope.selection, $event);
}
vm.selectItem = selectItem;
vm.clickItem = clickItem;
vm.selectAll = selectAll;
vm.isSelectedAll = isSelectedAll;
vm.isSortDirection = isSortDirection;
vm.sort = sort;
vm.dragEnter = dragEnter;
vm.dragLeave = dragLeave;
vm.onFilesQueue = onFilesQueue;
vm.onUploadComplete = onUploadComplete;
function isSelectedAll() {
return listViewHelper.isSelectedAll($scope.items, $scope.selection);
}
function activate() {
function selectItem(selectedItem, $index, $event) {
listViewHelper.selectHandler(selectedItem, $index, $scope.items, $scope.selection, $event);
}
if ($scope.entityType === 'media') {
mediaTypeHelper.getAllowedImagetypes(vm.nodeId).then(function (types) {
vm.acceptedMediatypes = types;
});
}
function clickItem(item) {
// if item.id is 2147483647 (int.MaxValue) use item.key
$location.path($scope.entityType + '/' +$scope.entityType + '/edit/' + (item.id === 2147483647 ? item.key : item.id));
}
}
function isSortDirection(col, direction) {
return listViewHelper.setSortingDirection(col, direction, $scope.options);
}
function selectAll($event) {
listViewHelper.selectAllItems($scope.items, $scope.selection, $event);
}
function sort(field, allow, isSystem) {
if (allow) {
$scope.options.orderBySystemField = isSystem;
listViewHelper.setSorting(field, allow, $scope.options);
function isSelectedAll() {
return listViewHelper.isSelectedAll($scope.items, $scope.selection);
}
function selectItem(selectedItem, $index, $event) {
listViewHelper.selectHandler(selectedItem, $index, $scope.items, $scope.selection, $event);
}
function clickItem(item) {
// if item.id is 2147483647 (int.MaxValue) use item.key
$location.path($scope.entityType + '/' + $scope.entityType + '/edit/' + (item.id === 2147483647 ? item.key : item.id));
}
function isSortDirection(col, direction) {
return listViewHelper.setSortingDirection(col, direction, $scope.options);
}
function sort(field, allow, isSystem) {
if (allow) {
$scope.options.orderBySystemField = isSystem;
listViewHelper.setSorting(field, allow, $scope.options);
$scope.getContent($scope.contentId);
}
}
// Dropzone upload functions
function dragEnter(el, event) {
vm.activeDrag = true;
}
function dragLeave(el, event) {
vm.activeDrag = false;
}
function onFilesQueue() {
vm.activeDrag = false;
}
function onUploadComplete() {
$scope.getContent($scope.contentId);
}
}
}
// Dropzone upload functions
function dragEnter(el, event) {
vm.activeDrag = true;
}
activate();
function dragLeave(el, event) {
vm.activeDrag = false;
}
}
function onFilesQueue() {
vm.activeDrag = false;
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.ListView.ListLayoutController", ListViewListLayoutController);
function onUploadComplete() {
$scope.getContent($scope.contentId);
}
activate();
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.ListView.ListLayoutController", ListViewListLayoutController);
}) ();
})();

View File

@@ -102,6 +102,9 @@
<!-- These file types will not be allowed to be uploaded via the upload control for media and content -->
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,xhtml,html,htm,svg,php,htaccess</disallowedUploadFiles>
<!-- If completed, only the file extensions listed below will be allowed to be uploaded. If empty, disallowedUploadFiles will apply to prevent upload of specific file extensions. -->
<allowedUploadFiles></allowedUploadFiles>
<!-- Defines the default document type property used when adding properties in the back-office (if missing or empty, defaults to Textstring -->
<defaultDocumentTypeProperty>Textstring</defaultDocumentTypeProperty>

View File

@@ -391,6 +391,10 @@ namespace Umbraco.Web.Editors
{
"disallowedUploadFiles",
string.Join(",", UmbracoConfig.For.UmbracoSettings().Content.DisallowedUploadFiles)
},
{
"allowedUploadFiles",
string.Join(",", UmbracoConfig.For.UmbracoSettings().Content.AllowedUploadFiles)
},
{
"maxFileSize",

View File

@@ -33,7 +33,8 @@ using Umbraco.Core.Configuration;
using Umbraco.Web.UI;
using Notification = Umbraco.Web.Models.ContentEditing.Notification;
using Umbraco.Core.Persistence;
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Web.Editors
{
/// <remarks>
@@ -723,7 +724,7 @@ namespace Umbraco.Web.Editors
var safeFileName = fileName.ToSafeFileName();
var ext = safeFileName.Substring(safeFileName.LastIndexOf('.') + 1).ToLower();
if (UmbracoConfig.For.UmbracoSettings().Content.DisallowedUploadFiles.Contains(ext) == false)
if (UmbracoConfig.For.UmbracoSettings().Content.IsFileAllowedForUpload(ext))
{
var mediaType = Constants.Conventions.MediaTypes.File;

View File

@@ -9,7 +9,8 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using umbraco;
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Web.PropertyEditors
{
internal class UploadFileTypeValidator : IPropertyValidator
@@ -41,8 +42,9 @@ namespace Umbraco.Web.PropertyEditors
internal static bool ValidateFileExtension(string fileName)
{
if (fileName.IndexOf('.') <= 0) return false;
var extension = Path.GetExtension(fileName).TrimStart(".");
return UmbracoConfig.For.UmbracoSettings().Content.DisallowedUploadFiles.Any(x => StringExtensions.InvariantEquals(x, extension)) == false;
var extension = Path.GetExtension(fileName).TrimStart(".");
return UmbracoConfig.For.UmbracoSettings().Content.IsFileAllowedForUpload(extension);
}
}

View File

@@ -270,6 +270,14 @@ namespace umbraco
public static IEnumerable<string> DisallowedUploadFiles
{
get { return UmbracoConfig.For.UmbracoSettings().Content.DisallowedUploadFiles; }
}
/// <summary>
/// File types that will be allowed to be uploaded via the content/media upload control
/// </summary>
public static IEnumerable<string> AllowedUploadFiles
{
get { return UmbracoConfig.For.UmbracoSettings().Content.AllowedUploadFiles; }
}
/// <summary>

View File

@@ -9,7 +9,8 @@ using System.Web.UI.WebControls;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using umbraco.interfaces;
using Umbraco.Core;
using Umbraco.Core;
using Umbraco.Core.Configuration.UmbracoSettings;
using Content = umbraco.cms.businesslogic.Content;
using Umbraco.Core;
@@ -90,8 +91,8 @@ namespace umbraco.editorControls
//now check the file type
var extension = Path.GetExtension(postedFile.FileName).TrimStart(".");
return UmbracoConfig.For.UmbracoSettings().Content.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)) == false;
return UmbracoConfig.For.UmbracoSettings().Content.IsFileAllowedForUpload(extension);
}
public string Text