Merge branch 'dev-v8' into temp8-U4-11219

This commit is contained in:
Shannon
2018-04-19 23:49:06 +10:00
45 changed files with 562 additions and 394 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ This project and everyone participating in it is governed by the [our Code of Co
### Reporting Bugs
This section guides you through submitting a bug report for Umbraco CMS. Following these guidelines helps maintainers and the community understand your report 📝, reproduce the behavior 💻 💻, and find related reports 🔎.
Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](ISSUE_TEMPLATE.md), the information it asks for helps us resolve issues faster.
Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](http://issues.umbraco.org/issues#newissue=61-30118), the information it asks for helps us resolve issues faster.
> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
+1 -1
View File
@@ -355,7 +355,7 @@ namespace Umbraco.Core.Scoping
}
var parent = ParentScope;
_scopeProvider.AmbientScope = parent;
_scopeProvider.AmbientScope = parent; // might be null = this is how scopes are removed from context objects
#if DEBUG_SCOPES
_scopeProvider.Disposed(this);
+4 -4
View File
@@ -43,17 +43,17 @@ namespace Umbraco.Core.Services
/// Creates a new content item from a blueprint.
/// </summary>
IContent CreateContentFromBlueprint(IContent blueprint, string name, int userId = 0);
/// <summary>
/// Deletes blueprints for a content type.
/// </summary>
void DeleteBlueprintsOfType(int contentTypeId, int userId = 0);
/// <summary>
/// Deletes blueprints for content types.
/// </summary>
void DeleteBlueprintsOfTypes(IEnumerable<int> contentTypeIds, int userId = 0);
#endregion
#region Get, Count Documents
@@ -340,7 +340,7 @@ namespace Umbraco.Core.Services
/// Sorts documents.
/// </summary>
bool Sort(IEnumerable<int> ids, int userId = 0, bool raiseEvents = true);
#endregion
#region Publish Document
+3 -2
View File
@@ -59,8 +59,9 @@ namespace Umbraco.Core.Services
_locker.EnterWriteLock();
foreach (var pair in pairs)
{
_id2Key.Add(pair.id, new TypedId<Guid>(pair.key, umbracoObjectType));
_key2Id.Add(pair.key, new TypedId<int>(pair.id, umbracoObjectType));
_id2Key[pair.id] = new TypedId<Guid>(pair.key, umbracoObjectType);
_key2Id[pair.key] = new TypedId<int>(pair.id, umbracoObjectType);
}
}
finally
@@ -25,6 +25,7 @@ The tour object consist of two parts - The overall tour configuration and a list
"group": "My Custom Group" // Used to group tours in the help drawer
"groupOrder": 200 // Control the order of tour groups
"allowDisable": // Adds a "Don't" show this tour again"-button to the intro step
"culture" : // From v7.11+. Specifies the culture of the tour (eg. en-US), if set the tour will only be shown to users with this culture set on their profile. If omitted or left empty the tour will be visible to all users
"requiredSections":["content", "media", "mySection"] // Sections that the tour will access while running, if the user does not have access to the required tour sections, the tour will not load.
"steps": [] // tour steps - see next example
}
@@ -286,6 +286,7 @@
$scope.page.buttonGroupState = "success";
}, function (err) {
formHelper.showNotifications(err.data);
$scope.page.buttonGroupState = 'error';
});
}
@@ -54,8 +54,6 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
controller: function ($scope, $element) {
var vm = this;
var isInitialized = false;
var registeredCallbacks = {
treeNodeExpanded: [],
@@ -163,9 +161,7 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
if (!args.path) {
throw "args.path cannot be null";
}
var treeNode = loadActiveTree(args.tree);
if (angular.isString(args.path)) {
args.path = args.path.replace('"', '').split(',');
}
@@ -200,6 +196,8 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
deleteAnimations = false;
var treeNode = loadActiveTree(args.tree);
return treeService.syncTree({
node: treeNode,
path: args.path,
@@ -275,13 +273,6 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
//set the data once we have it
$scope.tree = data;
//call the callback, this allows for hosting controllers to bind to events and use the exposed API
if (!isInitialized) {
isInitialized = true;
$scope.onInit();
}
enableDeleteAnimations();
$scope.loading = false;
@@ -433,6 +424,8 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
});
loadTree();
$scope.onInit();
}
};
}
@@ -57,7 +57,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
saveModel),
'Failed to save permissions');
},
getRecycleBin: function () {
return umbRequestHelper.resourcePromise(
@@ -425,7 +425,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetEmpty",
"GetEmpty",
[{ blueprintId: blueprintId }, { parentId: parentId}])),
'Failed to retrieve blueprint for id ' + blueprintId);
},
@@ -489,6 +489,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
getChildren: function (parentId, options) {
var defaults = {
includeProperties: [],
pageSize: 0,
pageNumber: 0,
filter: '',
@@ -532,6 +533,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
"GetChildren",
{
id: parentId,
includeProperties: _.pluck(options.includeProperties, 'alias').join(","),
pageNumber: options.pageNumber,
pageSize: options.pageSize,
orderBy: options.orderBy,
@@ -581,7 +583,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
"contentApiBaseUrl",
"GetDetailedPermissions", { contentId: contentId })),
'Failed to retrieve permissions for content item ' + contentId);
},
},
getPermissions: function (nodeIds) {
return umbRequestHelper.resourcePromise(
@@ -742,11 +744,11 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
createBlueprintFromContent: function (contentId, name) {
return umbRequestHelper.resourcePromise(
$http.post(
$http.post(
umbRequestHelper.getApiUrl("contentApiBaseUrl", "CreateBlueprintFromContent", {
contentId: contentId, name: name
})
),
})
),
"Failed to create blueprint from content with id " + contentId
);
}
@@ -122,6 +122,18 @@ function mediaTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
'Failed to delete content type contaier');
},
/**
* @ngdoc method
* @name umbraco.resources.mediaTypeResource#save
* @methodOf umbraco.resources.mediaTypeResource
*
* @description
* Saves or update a media type
*
* @param {Object} content data type object to create/update
* @returns {Promise} resourcePromise object.
*
*/
save: function (contentType) {
var saveModel = umbDataFormatter.formatContentTypePostData(contentType);
@@ -86,8 +86,8 @@ function memberTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
/**
* @ngdoc method
* @name umbraco.resources.contentTypeResource#save
* @methodOf umbraco.resources.contentTypeResource
* @name umbraco.resources.memberTypeResource#save
* @methodOf umbraco.resources.memberTypeResource
*
* @description
* Saves or update a member type
@@ -237,10 +237,11 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
}
//if we are not creating, then we should add unpublish too,
// if we are not creating, then we should add unpublish too,
// so long as it's already published and if the user has access to publish
// and the user has access to unpublish (may have been removed via Event)
if (!args.create) {
if (args.content.publishDate && _.contains(args.content.allowedActions, "U")) {
if (args.content.publishDate && _.contains(args.content.allowedActions, "U") && _.contains(args.content.allowedActions, "Z")) {
buttons.subButtons.push(createButtonDefinition("Z"));
}
}
@@ -8,7 +8,7 @@
// Sortabel
// Sortable
// -------------------------
// sortable-helper
@@ -127,6 +127,16 @@
position: relative;
margin-bottom: 40px;
padding-top: 10px;
&:hover {
background-color: @grayLighter;
}
&[ng-click],
&[data-ng-click],
&[x-ng-click] {
cursor: pointer;
}
}
.umb-grid .row-tools a {
@@ -431,7 +441,7 @@
background-color: @gray-10;
.umb-row-title-bar {
cursor: default;
cursor: inherit;
}
.umb-row-title {
@@ -16,24 +16,23 @@
<i class="large {{docType.icon}}"></i>
<span class="menu-label">
{{docType.name}}
<small>
{{docType.description}}
</small>
<small>{{docType.description}}</small>
</span>
</a>
</li>
<!--
<li class="add">
<a href="#settings/documenttype/create/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="nav.hideNavigation()">
<i class="icon-large icon-plus"></i>
<span class="menu-label">
Create a new media type
<small>
Design and configure a new media type
</small>
</span>
</a>
</li> -->
<!--
<li class="add">
<a href="#settings/documenttype/create/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="nav.hideNavigation()">
<i class="icon-large icon-plus"></i>
<span class="menu-label">
Create a new media type
<small>
Design and configure a new media type
</small>
</span>
</a>
</li>
-->
</ul>
</li>
</ul>
@@ -6,10 +6,9 @@
<li ng-repeat="docType in allowedTypes">
<a href="#member/member/edit/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="nav.hideNavigation()">
<i class="large icon-users"></i>
<span class="menu-label">{{docType.name}}
<i class="large {{docType.icon}}"></i>
<span class="menu-label">
{{docType.name}}
<small>{{docType.description}}</small>
</span>
</a>
@@ -24,4 +23,3 @@
<localize key="buttons_somethingElse">Do something else</localize>
</button>
</div>
@@ -1,6 +1,6 @@
/**
* The controller that is used for a couple different Property Editors: Multi Node Tree Picker, Content Picker,
* The controller that is used for a couple different Property Editors: Multi Node Tree Picker, Content Picker,
* since this is used by MNTP and it supports content, media and members, there is code to deal with all 3 of those types
* @param {any} $scope
* @param {any} entityResource
@@ -70,7 +70,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
$scope.renderModel = [];
$scope.dialogEditor = editorState && editorState.current && editorState.current.isDialogEditor === true;
$scope.dialogEditor = editorState && editorState.current && editorState.current.isDialogEditor === true;
//the default pre-values
var defaultConfig = {
@@ -105,7 +105,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
$scope.model.config.showOpenButton = Object.toBoolean($scope.model.config.showOpenButton);
$scope.model.config.showEditButton = Object.toBoolean($scope.model.config.showEditButton);
$scope.model.config.showPathOnHover = Object.toBoolean($scope.model.config.showPathOnHover);
var entityType = $scope.model.config.startNode.type === "member"
? "Member"
: $scope.model.config.startNode.type === "media"
@@ -135,8 +135,8 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
},
treeAlias: $scope.model.config.startNode.type,
section: $scope.model.config.startNode.type,
idType: "int",
//only show the lang selector for content
idType: "int",
//only show the lang selector for content
showLanguageSelector: $scope.model.config.startNode.type === "content"
};
@@ -267,11 +267,6 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
}
var notSupported = [
"Umbraco.CheckBoxList",
"Umbraco.DropDownMultiple",
"Umbraco.MacroContainer",
"Umbraco.RadioButtonList",
"Umbraco.MultipleTextstring",
"Umbraco.Tags",
"Umbraco.UploadField",
"Umbraco.ImageCropper"
@@ -266,7 +266,7 @@ angular.module("umbraco")
editor.on('ObjectResized', function (e) {
var qs = "?width=" + e.width + "&height=" + e.height;
var qs = "?width=" + e.width + "&height=" + e.height + "&mode=max";
var srcAttr = $(e.target).attr("src");
var path = srcAttr.split("?")[0];
$(e.target).attr("data-mce-src", path + qs);
@@ -384,7 +384,7 @@ angular.module("umbraco")
// element might still be there even after the modal has been hidden.
$scope.$on('$destroy', function () {
unsubscribe();
if (tinyMceEditor !== undefined && tinyMceEditor != null) {
if (tinyMceEditor !== undefined && tinyMceEditor != null) {
tinyMceEditor.destroy()
}
});
+1
View File
@@ -368,6 +368,7 @@
</Content>
<None Include="Umbraco\Config\Create\UI.Release.xml">
<DependentUpon>UI.xml</DependentUpon>
<SubType>Designer</SubType>
</None>
<Content Include="Global.asax" />
<Content Include="Umbraco\Config\Lang\en_us.xml">
@@ -1283,7 +1283,7 @@
<key alias="xmlDataIntegrityCheckMedia">媒體 - 所有XML:%0%,總共發佈:%1%,不合格:%2%</key>
<key alias="xmlDataIntegrityCheckContent">內容 - 所有XML:%0%,總共發佈:%1%,不合格:%2%</key>
<key alias="httpsCheckInvalidCertificate">憑證驗證錯誤:%0%</key>
<key alias="httpsCheckInvalidUrl">網址探查錯誤:%0% - '%1%'</key>
<key alias="healthCheckInvalidUrl">網址探查錯誤:%0% - '%1%'</key>
<key alias="httpsCheckIsCurrentSchemeHttps">您目前使用HTTPS瀏覽本站:%0%</key>
<key alias="httpsCheckConfigurationRectifyNotPossible">在您的web.config檔案中,appSetting的umbracoUseSSL是設為false。當您開始使用HTTPS時,應將其改為 true。</key>
<key alias="httpsCheckConfigurationCheckResult">在您的web.config檔案中,appSetting的umbracoUseSSL是設為 %0%,您的cookies %0% 標成安全。</key>
@@ -1316,10 +1316,10 @@
<key alias="optionalFilePermissionFailed"><![CDATA[以下檔案必須擁有寫入權限好讓系統可以正常運作,但無法連接:<strong>%0%</strong>。如果無須寫入,不需採取行動。]]></key>
<key alias="clickJackingCheckHeaderFound"><![CDATA[標頭或meta-tag的 <strong>X-Frame-Options</strong> 設定能控制網站是否可以被其他人IFRAMEd已找到。]]></key>
<key alias="clickJackingCheckHeaderNotFound"><![CDATA[標頭或meta-tag的 <strong>X-Frame-Options</strong> 設定能控制網站是否可以被其他人IFRAMEd沒有找到。]]></key>
<key alias="clickJackingSetHeaderInConfig">調整設定的標頭</key>
<key alias="setHeaderInConfig">調整設定的標頭</key>
<key alias="clickJackingSetHeaderInConfigDescription">在 web.config 的 httpProtocol/customHeaders 區域增加設定來防止本站被別的網站IFRAMEd。</key>
<key alias="clickJackingSetHeaderInConfigSuccess">在 web.config 的 httpProtocol/customHeaders 區域已經增加設定來防止本站被別的網站IFRAMEd。</key>
<key alias="clickJackingSetHeaderInConfigError">無法更新web.config檔案,錯誤:%0%</key>
<key alias="setHeaderInConfigError">無法更新web.config檔案,錯誤:%0%</key>
<!-- The following key get these tokens passed in:
0: Comma delimitted list of headers found
-->
@@ -30,20 +30,6 @@
<delete assembly="umbraco" type="macroTasks" />
</tasks>
</nodeType>
<nodeType alias="xslt">
<header>Macro</header>
<usercontrol>/create/xslt.ascx</usercontrol>
<tasks>
<delete assembly="umbraco" type="XsltTasks" />
</tasks>
</nodeType>
<nodeType alias="xsltFolder">
<header>Xslt</header>
<usercontrol>/create/xslt.ascx</usercontrol>
<tasks>
<delete assembly="umbraco" type="XsltTasks" />
</tasks>
</nodeType>
<nodeType alias="users">
<header>User</header>
<usercontrol>/create/user.ascx</usercontrol>
@@ -30,21 +30,7 @@
<delete assembly="Umbraco.Web" type="macroTasks" />
</tasks>
</nodeType>
<nodeType alias="xslt">
<header>Macro</header>
<usercontrol>/create/xslt.ascx</usercontrol>
<tasks>
<delete assembly="Umbraco.Web" type="XsltTasks" />
</tasks>
</nodeType>
<nodeType alias="xsltFolder">
<header>Xslt</header>
<usercontrol>/create/xslt.ascx</usercontrol>
<tasks>
<create assembly="Umbraco.Web" type="XsltTasks" />
<delete assembly="Umbraco.Web" type="XsltTasks" />
</tasks>
</nodeType>
<nodeType alias="users">
<header>User</header>
<usercontrol>/create/user.ascx</usercontrol>
+18 -3
View File
@@ -1938,7 +1938,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="httpsCheckInvalidCertificate">Certificate validation error: '%0%'</key>
<key alias="httpsCheckExpiredCertificate">Your website's SSL certificate has expired.</key>
<key alias="httpsCheckExpiringCertificate">Your website's SSL certificate is expiring in %0% days.</key>
<key alias="httpsCheckInvalidUrl">Error pinging the URL %0% - '%1%'</key>
<key alias="healthCheckInvalidUrl">Error pinging the URL %0% - '%1%'</key>
<key alias="httpsCheckIsCurrentSchemeHttps">You are currently %0% viewing the site using the HTTPS scheme.</key>
<key alias="httpsCheckConfigurationRectifyNotPossible">The appSetting 'umbracoUseSSL' is set to 'false' in your web.config file. Once you access this site using the HTTPS scheme, that should be set to 'true'.</key>
<key alias="httpsCheckConfigurationCheckResult">The appSetting 'umbracoUseSSL' is set to '%0%' in your web.config file, your cookies are %1% marked as secure.</key>
@@ -1978,10 +1978,25 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="clickJackingCheckHeaderFound"><![CDATA[The header or meta-tag <strong>X-Frame-Options</strong> used to control whether a site can be IFRAMEd by another was found.]]></key>
<key alias="clickJackingCheckHeaderNotFound"><![CDATA[The header or meta-tag <strong>X-Frame-Options</strong> used to control whether a site can be IFRAMEd by another was not found.]]></key>
<key alias="clickJackingSetHeaderInConfig">Set Header in Config</key>
<key alias="setHeaderInConfig">Set Header in Config</key>
<key alias="clickJackingSetHeaderInConfigDescription">Adds a value to the httpProtocol/customHeaders section of web.config to prevent the site being IFRAMEd by other websites.</key>
<key alias="clickJackingSetHeaderInConfigSuccess">A setting to create a header preventing IFRAMEing of the site by other websites has been added to your web.config file.</key>
<key alias="clickJackingSetHeaderInConfigError">Could not update web.config file. Error: %0%</key>
<key alias="setHeaderInConfigError">Could not update web.config file. Error: %0%</key>
<key alias="noSniffCheckHeaderFound"><![CDATA[The header or meta-tag <strong>X-Content-Type-Options</strong> used to protect against MIME sniffing vulnerabilities was found.]]></key>
<key alias="noSniffCheckHeaderNotFound"><![CDATA[The header or meta-tag <strong>X-Content-Type-Options</strong> used to protect against MIME sniffing vulnerabilities was not found.]]></key>
<key alias="noSniffSetHeaderInConfigDescription">Adds a value to the httpProtocol/customHeaders section of web.config to protect against MIME sniffing vulnerabilities.</key>
<key alias="noSniffSetHeaderInConfigSuccess">A setting to create a header protecting against MIME sniffing vulnerabilities has been added to your web.config file.</key>
<key alias="hSTSCheckHeaderFound"><![CDATA[The header <strong>Strict-Transport-Security</strong>, also known as the HSTS-header, was found.]]></key>
<key alias="hSTSCheckHeaderNotFound"><![CDATA[The header <strong>Strict-Transport-Security</strong> was not found.]]></key>
<key alias="hSTSSetHeaderInConfigDescription">Adds the header 'Strict-Transport-Security' with the value 'max-age=10886400; preload' to the httpProtocol/customHeaders section of web.config. Use this fix only if you will have your domains running with https for the next 18 weeks (minimum).</key>
<key alias="hSTSSetHeaderInConfigSuccess">The HSTS header has been added to your web.config file.</key>
<key alias="xssProtectionCheckHeaderFound"><![CDATA[The header <strong>X-XSS-Protection</strong> was found.]]></key>
<key alias="xssProtectionCheckHeaderNotFound"><![CDATA[The header <strong>X-XSS-Protection</strong> was not found.]]></key>
<key alias="xssProtectionSetHeaderInConfigDescription">Adds the header 'X-XSS-Protection' with the value '1; mode=block' to the httpProtocol/customHeaders section of web.config. </key>
<key alias="xssProtectionSetHeaderInConfigSuccess">The X-XSS-Protection header has been added to your web.config file.</key>
<!-- The following key get these tokens passed in:
0: Comma delimitted list of headers found
@@ -2065,7 +2065,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="httpsCheckInvalidCertificate">Certificate validation error: '%0%'</key>
<key alias="httpsCheckExpiredCertificate">Your website's SSL certificate has expired.</key>
<key alias="httpsCheckExpiringCertificate">Your website's SSL certificate is expiring in %0% days.</key>
<key alias="httpsCheckInvalidUrl">Error pinging the URL %0% - '%1%'</key>
<key alias="healthCheckInvalidUrl">Error pinging the URL %0% - '%1%'</key>
<key alias="httpsCheckIsCurrentSchemeHttps">You are currently %0% viewing the site using the HTTPS scheme.</key>
<key alias="httpsCheckConfigurationRectifyNotPossible">The appSetting 'umbracoUseSSL' is set to 'false' in your web.config file. Once you access this site using the HTTPS scheme, that should be set to 'true'.</key>
<key alias="httpsCheckConfigurationCheckResult">The appSetting 'umbracoUseSSL' is set to '%0%' in your web.config file, your cookies are %1% marked as secure.</key>
@@ -2105,10 +2105,25 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="clickJackingCheckHeaderFound"><![CDATA[The header or meta-tag <strong>X-Frame-Options</strong> used to control whether a site can be IFRAMEd by another was found.]]></key>
<key alias="clickJackingCheckHeaderNotFound"><![CDATA[The header or meta-tag <strong>X-Frame-Options</strong> used to control whether a site can be IFRAMEd by another was not found.]]></key>
<key alias="clickJackingSetHeaderInConfig">Set Header in Config</key>
<key alias="setHeaderInConfig">Set Header in Config</key>
<key alias="clickJackingSetHeaderInConfigDescription">Adds a value to the httpProtocol/customHeaders section of web.config to prevent the site being IFRAMEd by other websites.</key>
<key alias="clickJackingSetHeaderInConfigSuccess">A setting to create a header preventing IFRAMEing of the site by other websites has been added to your web.config file.</key>
<key alias="clickJackingSetHeaderInConfigError">Could not update web.config file. Error: %0%</key>
<key alias="setHeaderInConfigError">Could not update web.config file. Error: %0%</key>
<key alias="noSniffCheckHeaderFound"><![CDATA[The header or meta-tag <strong>X-Content-Type-Options</strong> used to protect against MIME sniffing vulnerabilities was found.]]></key>
<key alias="noSniffCheckHeaderNotFound"><![CDATA[The header or meta-tag <strong>X-Content-Type-Options</strong> used to protect against MIME sniffing vulnerabilities was not found.]]></key>
<key alias="noSniffSetHeaderInConfigDescription">Adds a value to the httpProtocol/customHeaders section of web.config to protect against MIME sniffing vulnerabilities.</key>
<key alias="noSniffSetHeaderInConfigSuccess">A setting to create a header protecting against MIME sniffing vulnerabilities has been added to your web.config file.</key>
<key alias="hSTSCheckHeaderFound"><![CDATA[The header <strong>Strict-Transport-Security</strong>, also known as the HSTS-header, was found.]]></key>
<key alias="hSTSCheckHeaderNotFound"><![CDATA[The header <strong>Strict-Transport-Security</strong> was not found.]]></key>
<key alias="hSTSSetHeaderInConfigDescription">Adds the header 'Strict-Transport-Security' with the value 'max-age=10886400; preload' to the httpProtocol/customHeaders section of web.config. Use this fix only if you will have your domains running with https for the next 18 weeks (minimum).</key>
<key alias="hSTSSetHeaderInConfigSuccess">The HSTS header has been added to your web.config file.</key>
<key alias="xssProtectionCheckHeaderFound"><![CDATA[The header <strong>X-XSS-Protection</strong> was found.]]></key>
<key alias="xssProtectionCheckHeaderNotFound"><![CDATA[The header <strong>X-XSS-Protection</strong> was not found.]]></key>
<key alias="xssProtectionSetHeaderInConfigDescription">Adds the header 'X-XSS-Protection' with the value '1; mode=block' to the httpProtocol/customHeaders section of web.config. </key>
<key alias="xssProtectionSetHeaderInConfigSuccess">The X-XSS-Protection header has been added to your web.config file.</key>
<!-- The following key get these tokens passed in:
0: Comma delimitted list of headers found
@@ -1798,7 +1798,7 @@
<key alias="httpsCheckInvalidCertificate">Error validando certificado: '%0%'</key>
<key alias="httpsCheckExpiredCertificate">El ceriticado SSL de tu sitio ha caducado.</key>
<key alias="httpsCheckExpiringCertificate">El ceriticado SSL de tu sitio caducará en %0% días.</key>
<key alias="httpsCheckInvalidUrl">Error pinging la URL %0% - '%1%'</key>
<key alias="healthCheckInvalidUrl">Error pinging la URL %0% - '%1%'</key>
<key alias="httpsCheckIsCurrentSchemeHttps">Actualmente estás %0% viendo el sitio usando el esquema HTTPS.</key>
<key alias="httpsCheckConfigurationRectifyNotPossible">El appSetting 'umbracoUseSSL' está configurado como 'false' en tu archivo web.config. Una vez que accedes al sitio usando HTTPS, debería ser configuraio como 'true'.</key>
<key alias="httpsCheckConfigurationCheckResult">Ele appSetting 'umbracoUseSSL' está configurado como '%0%' en tu archivo your web.config, tus cookies son %1% marcadas como seguras.</key>
@@ -1838,10 +1838,10 @@
<key alias="clickJackingCheckHeaderFound"><![CDATA[El header or meta-tag <strong>X-Frame-Options</strong> usado para controlar si un sitio puede ser IFRAMEd por otra fue encontrado.]]></key>
<key alias="clickJackingCheckHeaderNotFound"><![CDATA[El header or meta-tag <strong>X-Frame-Options</strong> usado para controlar si un sitio puede ser IFRAMEd por otra no se ha encontrado.]]></key>
<key alias="clickJackingSetHeaderInConfig">Establecer Header en Config</key>
<key alias="setHeaderInConfig">Establecer Header en Config</key>
<key alias="clickJackingSetHeaderInConfigDescription">Adds a value to the httpProtocol/customHeaders section of web.config to prevent the site being IFRAMEd by other websites.</key>
<key alias="clickJackingSetHeaderInConfigSuccess">A setting to create a header preventing IFRAMEing of the site by other websites has been added to your web.config file.</key>
<key alias="clickJackingSetHeaderInConfigError">Could not update web.config file. Error: %0%</key>
<key alias="setHeaderInConfigError">Could not update web.config file. Error: %0%</key>
<!-- The following key get these tokens passed in:
0: Comma delimitted list of headers found
@@ -1359,7 +1359,7 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à
<key alias="xmlDataIntegrityCheckContent">Total XML : %0%, Total publié : %1%</key>
<key alias="httpsCheckInvalidCertificate">Erreur de validation du certificat : '%0%'</key>
<key alias="httpsCheckInvalidUrl">Erreur en essayant de contacter l'URL %0% - '%1%'</key>
<key alias="healthCheckInvalidUrl">Erreur en essayant de contacter l'URL %0% - '%1%'</key>
<key alias="httpsCheckIsCurrentSchemeHttps">Vous êtes actuellement %0% à voir le site via le schéma HTTPS.</key>
<key alias="httpsCheckConfigurationRectifyNotPossible">La valeur appSetting 'umbracoUseSSL' est fixée à 'false' dans votre fichier web.config. Une fois que vous donnerez accès à ce site en utilisant le schéma HTTPS, cette valeur devra être mise à 'true'.</key>
<key alias="httpsCheckConfigurationCheckResult">La valeur appSetting 'umbracoUseSSL' est fixée à '%0%' dans votre fichier web.config, vos cookies sont %1% marqués comme étant sécurisés.</key>
@@ -1399,10 +1399,10 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à
<key alias="clickJackingCheckHeaderFound"><![CDATA[Le header ou meta-tag <strong>X-Frame-Options</strong>, utilisé pour contrôler si un site peut être intégré dans un autre via IFRAME, a été trouvé.]]></key>
<key alias="clickJackingCheckHeaderNotFound"><![CDATA[Le header ou meta-tag <strong>X-Frame-Options</strong> , utilisé pour contrôler si un site peut être intégré dans un autre via IFRAME, n'a pas été trouvé.]]></key>
<key alias="clickJackingSetHeaderInConfig">Configurez le Header dans le fichier Config</key>
<key alias="setHeaderInConfig">Configurez le Header dans le fichier Config</key>
<key alias="clickJackingSetHeaderInConfigDescription">Ajoute une valeur dans la section httpProtocol/customHeaders du fichier web.config afin d'éviter que le site ne soit intégré dans d'autres sites via IFRAME.</key>
<key alias="clickJackingSetHeaderInConfigSuccess">Une configuration générant un header qui empêche l'intégration du site par d'autres sites via IFRAME a été ajoutée à votre fichier web.config.</key>
<key alias="clickJackingSetHeaderInConfigError">Impossible de modifier le fichier web.config. Erreur : %0%</key>
<key alias="setHeaderInConfigError">Impossible de modifier le fichier web.config. Erreur : %0%</key>
<!-- The following key get these tokens passed in:
0: Comma delimitted list of headers found
@@ -1368,7 +1368,7 @@ Om een vertalingstaak te sluiten, ga aub naar het detailoverzicht en klik op de
<key alias="httpsCheckValidCertificate">Het cerficaat van de website is ongeldig.</key>
<key alias="httpsCheckInvalidCertificate">Cerficaat validatie foutmelding: '%0%'</key>
<key alias="httpsCheckInvalidUrl">Fout bij pingen van URL %0% - '%1%'</key>
<key alias="healthCheckInvalidUrl">Fout bij pingen van URL %0% - '%1%'</key>
<key alias="httpsCheckIsCurrentSchemeHttps">De site wordt momenteel %0% bekeken via HTTPS.</key>
<key alias="httpsCheckConfigurationRectifyNotPossible">De appSetting 'umbracoUseSSL' in web.config staat op 'false'. Indien HTTPS gebruikt wordt moet deze op 'true' staan.</key>
<key alias="httpsCheckConfigurationCheckResult">De appSetting 'umbracoUseSSL' in web.config is ingesteld op '%0%'. Cookies zijn %1% ingesteld als secure.</key>
@@ -1408,10 +1408,10 @@ Om een vertalingstaak te sluiten, ga aub naar het detailoverzicht en klik op de
<key alias="clickJackingCheckHeaderFound"><![CDATA[De <strong>X-Frame-Options</strong> header of meta-tag om IFRAMEing door andere websites te voorkomen is aanwezig!]]></key>
<key alias="clickJackingCheckHeaderNotFound"><![CDATA[De <strong>X-Frame-Options</strong> header of meta-tag om IFRAMEing door andere websites te voorkomen is NIET aanwezig.]]></key>
<key alias="clickJackingSetHeaderInConfig">Voorkom IFRAMEing via web.config</key>
<key alias="setHeaderInConfig">Voorkom IFRAMEing via web.config</key>
<key alias="clickJackingSetHeaderInConfigDescription">Voegt de instelling toe aan de httpProtocol/customHeaders section in web.config om IFRAMEing door andere websites te voorkomen.</key>
<key alias="clickJackingSetHeaderInConfigSuccess">De instelling om IFRAMEing door andere websites te voorkomen is toegevoegd aan de web.config!</key>
<key alias="clickJackingSetHeaderInConfigError">Web.config kon niet aangepast worden door error: %0%</key>
<key alias="setHeaderInConfigError">Web.config kon niet aangepast worden door error: %0%</key>
<!-- The following key get these tokens passed in:
0: Comma delimitted list of headers found
@@ -1618,7 +1618,7 @@ Naciśnij przycisk <strong>instaluj</strong>, aby zainstalować bazę danych Umb
<key alias="httpsCheckInvalidCertificate">Błąd walidacji certyfikatu: '%0%'</key>
<key alias="httpsCheckExpiredCertificate">Certyfikat SSL Twojej strony wygasł.</key>
<key alias="httpsCheckExpiringCertificate">Certyfikat SSL Twojej strony wygaśnie za %0% dni.</key>
<key alias="httpsCheckInvalidUrl">Błąd pingowania adresu URL %0% - '%1%'</key>
<key alias="healthCheckInvalidUrl">Błąd pingowania adresu URL %0% - '%1%'</key>
<key alias="httpsCheckIsCurrentSchemeHttps">Oglądasz %0% stronę używając HTTPS.</key>
<key alias="httpsCheckConfigurationRectifyNotPossible">appSetting 'umbracoUseSSL' został ustawiony na 'false' w Twoim pliku web.config. Po uzyskaniu dostępu do strony, używając HTTPS, powinieneś go ustawić na 'true'.</key>
<key alias="httpsCheckConfigurationCheckResult">appSetting 'umbracoUseSSL' został ustawiony na '%0%' w Twoim pliku web.config, Twoje ciasteczka są %1% ustawione jako bezpieczne.</key>
@@ -1658,10 +1658,10 @@ Naciśnij przycisk <strong>instaluj</strong>, aby zainstalować bazę danych Umb
<key alias="clickJackingCheckHeaderFound"><![CDATA[Nagłówek lub meta-tag <strong>X-Frame-Options</strong> używany do kontrolowania czy strona może być IFRAME'owana przez inną został znaleziony.]]></key>
<key alias="clickJackingCheckHeaderNotFound"><![CDATA[Nagłówek lub meta-tag <strong>X-Frame-Options</strong> używany do kontrolowania czy strona może być IFRAME'owana przez inną nie został znaleziony.]]></key>
<key alias="clickJackingSetHeaderInConfig">Ustaw nagłówek w Config</key>
<key alias="setHeaderInConfig">Ustaw nagłówek w Config</key>
<key alias="clickJackingSetHeaderInConfigDescription">Dodaje wartość do sekcji httpProtocol/customHeaders pliku web.config, aby zapobiec IFRAME'owania strony przez inne witryny.</key>
<key alias="clickJackingSetHeaderInConfigSuccess">Ustawienie do tworzenia nagłówka, zapobiegającego IFRAME'owania strony przez inne witryny zostało dodane do Twojego pliku web.config.</key>
<key alias="clickJackingSetHeaderInConfigError">Nie można zaktualizować pliku web.config. Błąd: %0%</key>
<key alias="setHeaderInConfigError">Nie można zaktualizować pliku web.config. Błąd: %0%</key>
<!-- Następujące klucze spowodują, że tokeny zostaną przekazane:
0: Lista znalezionych nagłówków, oddzielonych przecinkami
@@ -756,7 +756,7 @@
<key alias="httpsCheckValidCertificate">Сертификат Вашего веб-сайта отмечен как проверенный.</key>
<key alias="httpsCheckInvalidCertificate">Ошибка проверки сертификата: '%0%'</key>
<key alias="httpsCheckInvalidUrl">Ошибка проверки адреса URL %0% - '%1%'</key>
<key alias="healthCheckInvalidUrl">Ошибка проверки адреса URL %0% - '%1%'</key>
<key alias="httpsCheckIsCurrentSchemeHttps">Сейчас Вы %0% просматриваете сайт, используя протокол HTTPS.</key>
<key alias="httpsCheckConfigurationRectifyNotPossible">Параметр 'umbracoUseSSL' в секции 'appSetting' установлен в 'false' в файле web.config. Если Вам необходим доступ к сайту по протоколу HTTPS, нужно установить данный параметр в 'true'.</key>
<key alias="httpsCheckConfigurationCheckResult">Параметр 'umbracoUseSSL' в секции 'appSetting' в файле установлен в '%0%', значения cookies %1% маркированы как безопасные.</key>
@@ -796,10 +796,10 @@
<key alias="clickJackingCheckHeaderFound"><![CDATA[Был обнаружен заголовок или мета-тэг <strong>X-Frame-Options</strong>, использующийся для управления возможностью помещать сайт в IFRAME на другом сайте.]]></key>
<key alias="clickJackingCheckHeaderNotFound"><![CDATA[Заголовок или мета-тэг <strong>X-Frame-Options</strong>, использующийся для управления возможностью помещать сайт в IFRAME на другом сайте, не обнаружен.]]></key>
<key alias="clickJackingSetHeaderInConfig">Установить заголовок в файле конфигурации</key>
<key alias="setHeaderInConfig">Установить заголовок в файле конфигурации</key>
<key alias="clickJackingSetHeaderInConfigDescription">Добавляет значение в секцию 'httpProtocol/customHeaders' файла web.config, препятствующее возможному использованию этого сайта внутри IFRAME на другом сайте.</key>
<key alias="clickJackingSetHeaderInConfigSuccess">Значение, добавляющее заголовок, препятствующий использованию этого сайта внутри IFRAME другого сайта, успешно добавлено в файл web.config.</key>
<key alias="clickJackingSetHeaderInConfigError">Невозможно обновить файл web.config. Ошибка: %0%</key>
<key alias="setHeaderInConfigError">Невозможно обновить файл web.config. Ошибка: %0%</key>
<!-- The following key get these tokens passed in:
0: Comma delimitted list of headers found
@@ -1396,10 +1396,10 @@
<key alias="clickJackingCheckHeaderFound"><![CDATA[The header or meta-tag <strong>X-Frame-Options</strong> used to control whether a site can be IFRAMEd by another was found.]]></key>
<key alias="clickJackingCheckHeaderNotFound"><![CDATA[The header or meta-tag <strong>X-Frame-Options</strong> used to control whether a site can be IFRAMEd by another was not found.]]></key>
<key alias="clickJackingSetHeaderInConfig">Set Header in Config</key>
<key alias="setHeaderInConfig">Set Header in Config</key>
<key alias="clickJackingSetHeaderInConfigDescription">Adds a value to the httpProtocol/customHeaders section of web.config to prevent the site being IFRAMEd by other websites.</key>
<key alias="clickJackingSetHeaderInConfigSuccess">A setting to create a header preventing IFRAMEing of the site by other websites has been added to your web.config file.</key>
<key alias="clickJackingSetHeaderInConfigError">Could not update web.config file. Error: %0%</key>
<key alias="setHeaderInConfigError">Could not update web.config file. Error: %0%</key>
<!-- The following key get these tokens passed in:
0: Comma delimitted list of headers found
@@ -77,14 +77,18 @@ namespace Umbraco.Web
batch.Clear();
//Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount
foreach (var instructionsBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
using (var scope = ScopeProvider.CreateScope())
{
WriteInstructions(instructionsBatch);
foreach (var instructionsBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
{
WriteInstructions(scope, instructionsBatch);
}
scope.Complete();
}
}
private void WriteInstructions(IEnumerable<RefreshInstruction> instructions)
private void WriteInstructions(IScope scope, IEnumerable<RefreshInstruction> instructions)
{
var dto = new CacheInstructionDto
{
@@ -93,12 +97,7 @@ namespace Umbraco.Web
OriginIdentity = LocalIdentity,
InstructionCount = instructions.Sum(x => x.JsonIdCount)
};
using (var scope = ScopeProvider.CreateScope())
{
scope.Database.Insert(dto);
scope.Complete();
}
scope.Database.Insert(dto);
}
protected ICollection<RefreshInstructionEnvelope> GetBatch(bool create)
@@ -139,9 +138,13 @@ namespace Umbraco.Web
if (batch == null)
{
//only write the json blob with a maximum count of the MaxProcessingInstructionCount
foreach (var maxBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
using (var scope = ScopeProvider.CreateScope())
{
WriteInstructions(maxBatch);
foreach (var maxBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
{
WriteInstructions(scope, maxBatch);
}
scope.Complete();
}
}
else
+40 -14
View File
@@ -306,11 +306,11 @@ namespace Umbraco.Web.Editors
//remove this tab if it exists: umbContainerView
var containerTab = mapped.Tabs.FirstOrDefault(x => x.Alias == Constants.Conventions.PropertyGroups.ListViewGroupName);
mapped.Tabs = mapped.Tabs.Except(new[] { containerTab });
//Remove all variants except for the default since currently the default must be saved before other variants can be edited
mapped.Tabs = mapped.Tabs.Except(new[] { containerTab });
//Remove all variants except for the default since currently the default must be saved before other variants can be edited
//TODO: Allow for editing all variants at once ... this will be a future task
mapped.Variants = new[] {mapped.Variants.First(x => x.IsCurrent)};
mapped.Variants = new[] {mapped.Variants.First(x => x.IsCurrent)};
return mapped;
}
@@ -390,6 +390,24 @@ namespace Umbraco.Web.Editors
Direction orderDirection = Direction.Ascending,
bool orderBySystemField = true,
string filter = "")
{
return GetChildren(id, null, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
}
/// <summary>
/// Gets the children for the content id passed in
/// </summary>
/// <returns></returns>
[FilterAllowedOutgoingContent(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic, IContent>>), "Items")]
public PagedResult<ContentItemBasic<ContentPropertyBasic, IContent>> GetChildren(
int id,
string includeProperties,
int pageNumber = 0, //TODO: This should be '1' as it's not the index
int pageSize = 0,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
bool orderBySystemField = true,
string filter = "")
{
long totalChildren;
IContent[] children;
@@ -422,8 +440,16 @@ namespace Umbraco.Web.Editors
}
var pagedResult = new PagedResult<ContentItemBasic<ContentPropertyBasic, IContent>>(totalChildren, pageNumber, pageSize);
pagedResult.Items = children
.Select(Mapper.Map<IContent, ContentItemBasic<ContentPropertyBasic, IContent>>);
pagedResult.Items = children.Select(content =>
Mapper.Map<IContent, ContentItemBasic<ContentPropertyBasic, IContent>>(content,
opts =>
{
// if there's a list of property aliases to map - we will make sure to store this in the mapping context.
if (String.IsNullOrWhiteSpace(includeProperties) == false)
{
opts.Items["IncludeProperties"] = includeProperties.Split(new[] { ", ", "," }, StringSplitOptions.RemoveEmptyEntries);
}
}));
return pagedResult;
}
@@ -618,7 +644,7 @@ namespace Umbraco.Web.Editors
{
//publish the item and check if it worked, if not we will show a diff msg below
contentItem.PersistedContent.PublishValues(contentItem.LanguageId); //we are not checking for a return value here because we've alraedy pre-validated the property values
//check if we are publishing other variants and validate them
var allLangs = Services.LocalizationService.GetAllLanguages().ToList();
var variantsToValidate = contentItem.PublishVariations.Where(x => x.LanguageId != contentItem.LanguageId).ToList();
@@ -629,8 +655,8 @@ namespace Umbraco.Web.Editors
var errMsg = Services.TextService.Localize("speechBubbles/contentLangValidationError", new[]{allLangs.First(x => x.Id == publishVariation.LanguageId).CultureName});
ModelState.AddModelError("publish_variant_" + publishVariation.LanguageId + "_", errMsg);
}
}
}
//validate any mandatory variants that are not in the list
var mandatoryLangs = Mapper.Map<IEnumerable<ILanguage>, IEnumerable<Language>>(allLangs)
.Where(x => variantsToValidate.All(v => v.LanguageId != x.Id)) //don't include variants above
@@ -643,7 +669,7 @@ namespace Umbraco.Web.Editors
var errMsg = Services.TextService.Localize("speechBubbles/contentReqLangValidationError", new[]{allLangs.First(x => x.Id == lang.Id).CultureName});
ModelState.AddModelError("publish_variant_" + lang.Id + "_", errMsg);
}
}
}
publishStatus = Services.ContentService.SaveAndPublish(contentItem.PersistedContent, Security.CurrentUser.Id);
wasCancelled = publishStatus.Result == PublishResultType.FailedCancelledByEvent;
@@ -949,9 +975,9 @@ namespace Umbraco.Web.Editors
}
}
base.MapPropertyValues<IContent, ContentItemSave>(
contentItem,
(save, property) => property.GetValue(save.LanguageId), //get prop val
base.MapPropertyValues<IContent, ContentItemSave>(
contentItem,
(save, property) => property.GetValue(save.LanguageId), //get prop val
(save, property, v) => property.SetValue(v, save.LanguageId)); //set prop val
}
@@ -1138,7 +1164,7 @@ namespace Umbraco.Web.Editors
}
return allowed;
}
/// <summary>
/// Used to map an <see cref="IContent"/> instance to a <see cref="ContentItemDisplay"/> and ensuring a language is present if required
/// </summary>
@@ -63,7 +63,7 @@ namespace Umbraco.Web.Editors
}
/// <summary>
/// Deletes a document type wth a given ID
/// Deletes a media type with a given ID
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
@@ -120,17 +120,16 @@ namespace Umbraco.Web.Editors
/// <summary>
/// Returns all member types
/// Returns all media types
/// </summary>
public IEnumerable<ContentTypeBasic> GetAll()
{
return Services.MediaTypeService.GetAll()
.Select(Mapper.Map<IMediaType, ContentTypeBasic>);
}
/// <summary>
/// Deletes a document type container wth a given ID
/// Deletes a media type container wth a given ID
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
+8 -3
View File
@@ -121,13 +121,18 @@ namespace Umbraco.Web.Editors
var contents = File.ReadAllText(tourFile);
var tours = JsonConvert.DeserializeObject<BackOfficeTour[]>(contents);
var backOfficeTours = tours.Where(x =>
aliasFilters.Count == 0 || aliasFilters.All(filter => filter.IsMatch(x.Alias)) == false);
var localizedTours = backOfficeTours.Where(x =>
string.IsNullOrWhiteSpace(x.Culture) || x.Culture.Equals(Security.CurrentUser.Language,
StringComparison.InvariantCultureIgnoreCase)).ToList();
var tour = new BackOfficeTourFile
{
FileName = Path.GetFileNameWithoutExtension(tourFile),
PluginName = pluginName,
Tours = tours
.Where(x => aliasFilters.Count == 0 || aliasFilters.All(filter => filter.IsMatch(x.Alias)) == false)
.ToArray()
Tours = localizedTours
};
//don't add if all of the tours are filtered
@@ -0,0 +1,221 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Xml.XPath;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Security
{
public abstract class BaseHttpHeaderCheck : HealthCheck
{
protected IRuntimeState Runtime { get; }
protected ILocalizedTextService TextService { get; }
private const string SetHeaderInConfigAction = "setHeaderInConfig";
private readonly string _header;
private readonly string _value;
private readonly string _localizedTextPrefix;
private readonly bool _metaTagOptionAvailable;
protected BaseHttpHeaderCheck(
IRuntimeState runtime,
ILocalizedTextService textService,
string header, string value, string localizedTextPrefix, bool metaTagOptionAvailable)
{
Runtime = runtime;
TextService = textService ?? throw new ArgumentNullException(nameof(textService));
_header = header;
_value = value;
_localizedTextPrefix = localizedTextPrefix;
_metaTagOptionAvailable = metaTagOptionAvailable;
}
/// <summary>
/// Get the status for this health check
/// </summary>
/// <returns></returns>
public override IEnumerable<HealthCheckStatus> GetStatus()
{
//return the statuses
return new[] { CheckForHeader() };
}
/// <summary>
/// Executes the action and returns it's status
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public override HealthCheckStatus ExecuteAction(HealthCheckAction action)
{
switch (action.Alias)
{
case SetHeaderInConfigAction:
return SetHeaderInConfig();
default:
throw new InvalidOperationException("HTTP Header action requested is either not executable or does not exist");
}
}
protected HealthCheckStatus CheckForHeader()
{
var message = string.Empty;
var success = false;
// Access the site home page and check for the click-jack protection header or meta tag
var url = Runtime.ApplicationUrl;
var request = WebRequest.Create(url);
request.Method = "GET";
try
{
var response = request.GetResponse();
// Check first for header
success = DoHttpHeadersContainHeader(response);
// If not found, and available, check for meta-tag
if (success == false && _metaTagOptionAvailable)
{
success = DoMetaTagsContainKeyForHeader(response);
}
message = success
? TextService.Localize($"healthcheck/{_localizedTextPrefix}CheckHeaderFound")
: TextService.Localize($"healthcheck/{_localizedTextPrefix}CheckHeaderNotFound");
}
catch (Exception ex)
{
message = TextService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url.ToString(), ex.Message });
}
var actions = new List<HealthCheckAction>();
if (success == false)
{
actions.Add(new HealthCheckAction(SetHeaderInConfigAction, Id)
{
Name = TextService.Localize("healthcheck/setHeaderInConfig"),
Description = TextService.Localize($"healthcheck/{_localizedTextPrefix}SetHeaderInConfigDescription")
});
}
return
new HealthCheckStatus(message)
{
ResultType = success ? StatusResultType.Success : StatusResultType.Error,
Actions = actions
};
}
private bool DoHttpHeadersContainHeader(WebResponse response)
{
return response.Headers.AllKeys.Contains(_header);
}
private bool DoMetaTagsContainKeyForHeader(WebResponse response)
{
using (var stream = response.GetResponseStream())
{
if (stream == null) return false;
using (var reader = new StreamReader(stream))
{
var html = reader.ReadToEnd();
var metaTags = ParseMetaTags(html);
return metaTags.ContainsKey(_header);
}
}
}
private static Dictionary<string, string> ParseMetaTags(string html)
{
var regex = new Regex("<meta http-equiv=\"(.+?)\" content=\"(.+?)\"", RegexOptions.IgnoreCase);
return regex.Matches(html)
.Cast<Match>()
.ToDictionary(m => m.Groups[1].Value, m => m.Groups[2].Value);
}
private HealthCheckStatus SetHeaderInConfig()
{
var errorMessage = string.Empty;
var success = SaveHeaderToConfigFile(out errorMessage);
if (success)
{
return
new HealthCheckStatus(TextService.Localize(string.Format("healthcheck/{0}SetHeaderInConfigSuccess", _localizedTextPrefix)))
{
ResultType = StatusResultType.Success
};
}
return
new HealthCheckStatus(TextService.Localize("healthcheck/setHeaderInConfigError", new [] { errorMessage }))
{
ResultType = StatusResultType.Error
};
}
private bool SaveHeaderToConfigFile(out string errorMessage)
{
try
{
// There don't look to be any useful classes defined in https://msdn.microsoft.com/en-us/library/system.web.configuration(v=vs.110).aspx
// for working with the customHeaders section, so working with the XML directly.
var configFile = IOHelper.MapPath("~/Web.config");
var doc = XDocument.Load(configFile);
var systemWebServerElement = doc.XPathSelectElement("/configuration/system.webServer");
var httpProtocolElement = systemWebServerElement.Element("httpProtocol");
if (httpProtocolElement == null)
{
httpProtocolElement = new XElement("httpProtocol");
systemWebServerElement.Add(httpProtocolElement);
}
var customHeadersElement = httpProtocolElement.Element("customHeaders");
if (customHeadersElement == null)
{
customHeadersElement = new XElement("customHeaders");
httpProtocolElement.Add(customHeadersElement);
}
var removeHeaderElement = customHeadersElement.Elements("remove")
.SingleOrDefault(x => x.Attribute("name") != null &&
x.Attribute("name")?.Value == _value);
if (removeHeaderElement == null)
{
removeHeaderElement = new XElement("remove");
removeHeaderElement.Add(new XAttribute("name", _header));
customHeadersElement.Add(removeHeaderElement);
}
var addHeaderElement = customHeadersElement.Elements("add")
.SingleOrDefault(x => x.Attribute("name") != null &&
x.Attribute("name").Value == _header);
if (addHeaderElement == null)
{
addHeaderElement = new XElement("add");
addHeaderElement.Add(new XAttribute("name", _header));
addHeaderElement.Add(new XAttribute("value", _value));
customHeadersElement.Add(addHeaderElement);
}
doc.Save(configFile);
errorMessage = string.Empty;
return true;
}
catch (Exception ex)
{
errorMessage = ex.Message;
return false;
}
}
}
}
@@ -1,14 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Xml.XPath;
using Umbraco.Core.Configuration;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Security
@@ -18,202 +8,11 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
"Click-Jacking Protection",
Description = "Checks if your site is allowed to be IFRAMEd by another site and thus would be susceptible to click-jacking.",
Group = "Security")]
public class ClickJackingCheck : HealthCheck
public class ClickJackingCheck : BaseHttpHeaderCheck
{
private readonly ILocalizedTextService _textService;
private readonly IRuntimeState _runtime;
private readonly IHttpContextAccessor _httpContextAccessor;
private const string SetFrameOptionsHeaderInConfigActiobn = "setFrameOptionsHeaderInConfig";
private const string XFrameOptionsHeader = "X-Frame-Options";
private const string XFrameOptionsValue = "sameorigin"; // Note can't use "deny" as that would prevent Umbraco itself using IFRAMEs
public ClickJackingCheck(ILocalizedTextService textService, IRuntimeState runtime, IHttpContextAccessor httpContextAccessor)
public ClickJackingCheck(IRuntimeState runtime, ILocalizedTextService textService)
: base(runtime, textService, "X-Frame-Options", "sameorigin", "clickJacking", true)
{
_textService = textService;
_runtime = runtime;
_httpContextAccessor = httpContextAccessor;
}
/// <summary>
/// Get the status for this health check
/// </summary>
/// <returns></returns>
public override IEnumerable<HealthCheckStatus> GetStatus()
{
//return the statuses
return new[] { CheckForFrameOptionsHeader() };
}
/// <summary>
/// Executes the action and returns it's status
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public override HealthCheckStatus ExecuteAction(HealthCheckAction action)
{
switch (action.Alias)
{
case SetFrameOptionsHeaderInConfigActiobn:
return SetFrameOptionsHeaderInConfig();
default:
throw new InvalidOperationException("HttpsCheck action requested is either not executable or does not exist");
}
}
private HealthCheckStatus CheckForFrameOptionsHeader()
{
var message = string.Empty;
var success = false;
// Access the site home page and check for the click-jack protection header or meta tag
var url = _runtime.ApplicationUrl;
var request = WebRequest.Create(url);
request.Method = "GET";
try
{
var response = request.GetResponse();
// Check first for header
success = DoHeadersContainFrameOptions(response);
// If not found, check for meta-tag
if (success == false)
{
success = DoMetaTagsContainFrameOptions(response);
}
message = success
? _textService.Localize("healthcheck/clickJackingCheckHeaderFound")
: _textService.Localize("healthcheck/clickJackingCheckHeaderNotFound");
}
catch (Exception ex)
{
message = _textService.Localize("healthcheck/httpsCheckInvalidUrl", new[] { url.ToString(), ex.Message });
}
var actions = new List<HealthCheckAction>();
if (success == false)
{
actions.Add(new HealthCheckAction(SetFrameOptionsHeaderInConfigActiobn, Id)
{
Name = _textService.Localize("healthcheck/clickJackingSetHeaderInConfig"),
Description = _textService.Localize("healthcheck/clickJackingSetHeaderInConfigDescription")
});
}
return
new HealthCheckStatus(message)
{
ResultType = success ? StatusResultType.Success : StatusResultType.Error,
Actions = actions
};
}
private static bool DoHeadersContainFrameOptions(WebResponse response)
{
return response.Headers.AllKeys.Contains(XFrameOptionsHeader);
}
private static bool DoMetaTagsContainFrameOptions(WebResponse response)
{
using (var stream = response.GetResponseStream())
{
if (stream == null) return false;
using (var reader = new StreamReader(stream))
{
var html = reader.ReadToEnd();
var metaTags = ParseMetaTags(html);
return metaTags.ContainsKey(XFrameOptionsHeader);
}
}
}
private static Dictionary<string, string> ParseMetaTags(string html)
{
var regex = new Regex("<meta http-equiv=\"(.+?)\" content=\"(.+?)\"", RegexOptions.IgnoreCase);
return regex.Matches(html)
.Cast<Match>()
.ToDictionary(m => m.Groups[1].Value, m => m.Groups[2].Value);
}
private HealthCheckStatus SetFrameOptionsHeaderInConfig()
{
var errorMessage = string.Empty;
var success = SaveHeaderToConfigFile(out errorMessage);
if (success)
{
return
new HealthCheckStatus(_textService.Localize("healthcheck/clickJackingSetHeaderInConfigSuccess"))
{
ResultType = StatusResultType.Success
};
}
return
new HealthCheckStatus(_textService.Localize("healthcheck/clickJackingSetHeaderInConfigError", new [] { errorMessage }))
{
ResultType = StatusResultType.Error
};
}
private static bool SaveHeaderToConfigFile(out string errorMessage)
{
try
{
// There don't look to be any useful classes defined in https://msdn.microsoft.com/en-us/library/system.web.configuration(v=vs.110).aspx
// for working with the customHeaders section, so working with the XML directly.
var configFile = IOHelper.MapPath("~/Web.config");
var doc = XDocument.Load(configFile);
var systemWebServerElement = doc.XPathSelectElement("/configuration/system.webServer");
var httpProtocolElement = systemWebServerElement.Element("httpProtocol");
if (httpProtocolElement == null)
{
httpProtocolElement = new XElement("httpProtocol");
systemWebServerElement.Add(httpProtocolElement);
}
var customHeadersElement = httpProtocolElement.Element("customHeaders");
if (customHeadersElement == null)
{
customHeadersElement = new XElement("customHeaders");
httpProtocolElement.Add(customHeadersElement);
}
var removeHeaderElement = customHeadersElement.Elements("remove")
.SingleOrDefault(x => x.Attribute("name") != null &&
x.Attribute("name").Value == XFrameOptionsHeader);
if (removeHeaderElement == null)
{
removeHeaderElement = new XElement("remove");
removeHeaderElement.Add(new XAttribute("name", XFrameOptionsHeader));
customHeadersElement.Add(removeHeaderElement);
}
var addHeaderElement = customHeadersElement.Elements("add")
.SingleOrDefault(x => x.Attribute("name") != null &&
x.Attribute("name").Value == XFrameOptionsHeader);
if (addHeaderElement == null)
{
addHeaderElement = new XElement("add");
addHeaderElement.Add(new XAttribute("name", XFrameOptionsHeader));
addHeaderElement.Add(new XAttribute("value", XFrameOptionsValue));
customHeadersElement.Add(addHeaderElement);
}
doc.Save(configFile);
errorMessage = string.Empty;
return true;
}
catch (Exception ex)
{
errorMessage = ex.Message;
return false;
}
}
}
}
@@ -2,8 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using Umbraco.Core.Configuration;
using Umbraco.Core;
using Umbraco.Core.Services;
@@ -0,0 +1,23 @@
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Security
{
[HealthCheck(
"E2048C48-21C5-4BE1-A80B-8062162DF124",
"Cookie hijacking and protocol downgrade attacks Protection (Strict-Transport-Security Header (HSTS))",
Description = "Checks if your site, when running with HTTPS, contains the Strict-Transport-Security Header (HSTS). If not, it adds with a default of 100 days.",
Group = "Security")]
public class HstsCheck : BaseHttpHeaderCheck
{
// The check is mostly based on the instructions in the OWASP CheatSheet
// (https://www.owasp.org/index.php/HTTP_Strict_Transport_Security_Cheat_Sheet)
// and the blogpost of Troy Hunt (https://www.troyhunt.com/understanding-http-strict-transport/)
// If you want do to it perfectly, you have to submit it https://hstspreload.appspot.com/,
// but then you should include subdomains and I wouldn't suggest to do that for Umbraco-sites.
public HstsCheck(IRuntimeState runtime, ILocalizedTextService textService)
: base(runtime, textService, "Strict-Transport-Security", "max-age=10886400; preload", "hSTS", true)
{
}
}
}
@@ -100,7 +100,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
else
{
result = StatusResultType.Error;
message = _textService.Localize("healthcheck/httpsCheckInvalidUrl", new[] { url, response.StatusDescription });
message = _textService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url, response.StatusDescription });
}
}
catch (Exception ex)
@@ -110,11 +110,11 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
{
message = exception.Status == WebExceptionStatus.TrustFailure
? _textService.Localize("healthcheck/httpsCheckInvalidCertificate", new [] { exception.Message })
: _textService.Localize("healthcheck/httpsCheckInvalidUrl", new [] { url, exception.Message });
: _textService.Localize("healthcheck/healthCheckInvalidUrl", new [] { url, exception.Message });
}
else
{
message = _textService.Localize("healthcheck/httpsCheckInvalidUrl", new[] { url, ex.Message });
message = _textService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url, ex.Message });
}
result = StatusResultType.Error;
@@ -0,0 +1,18 @@
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Security
{
[HealthCheck(
"1CF27DB3-EFC0-41D7-A1BB-EA912064E071",
"Content/MIME Sniffing Protection",
Description = "Checks that your site contains a header used to protect against MIME sniffing vulnerabilities.",
Group = "Security")]
public class NoSniffCheck : BaseHttpHeaderCheck
{
public NoSniffCheck(IRuntimeState runtime, ILocalizedTextService textService)
: base(runtime, textService, "X-Content-Type-Options", "nosniff", "noSniff", false)
{
}
}
}
@@ -0,0 +1,23 @@
using Umbraco.Core;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Security
{
[HealthCheck(
"F4D2B02E-28C5-4999-8463-05759FA15C3A",
"Cross-site scripting Protection (X-XSS-Protection header)",
Description = "This header enables the Cross-site scripting (XSS) filter in your browser. It checks for the presence of the X-XSS-Protection-header.",
Group = "Security")]
public class XssProtectionCheck : BaseHttpHeaderCheck
{
// The check is mostly based on the instructions in the OWASP CheatSheet
// (https://www.owasp.org/index.php/HTTP_Strict_Transport_Security_Cheat_Sheet)
// and the blogpost of Troy Hunt (https://www.troyhunt.com/understanding-http-strict-transport/)
// If you want do to it perfectly, you have to submit it https://hstspreload.appspot.com/,
// but then you should include subdomains and I wouldn't suggest to do that for Umbraco-sites.
public XssProtectionCheck(IRuntimeState runtime, ILocalizedTextService textService)
: base(runtime, textService, "X-XSS-Protection", "1; mode=block", "xssProtection", true)
{
}
}
}
+4 -1
View File
@@ -11,7 +11,7 @@ namespace Umbraco.Web.Models
{
public BackOfficeTour()
{
RequiredSections = new List<string>();
RequiredSections = new List<string>();
}
[DataMember(Name = "name")]
@@ -28,5 +28,8 @@ namespace Umbraco.Web.Models
public List<string> RequiredSections { get; set; }
[DataMember(Name = "steps")]
public BackOfficeTourStep[] Steps { get; set; }
[DataMember(Name = "culture")]
public string Culture { get; set; }
}
}
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Logging;
@@ -50,17 +52,29 @@ namespace Umbraco.Web.Models.Mapping
{
//a language Id needs to be set for a property type that can be varried by language
throw new InvalidOperationException($"No languageId found in mapping operation when one is required for the culture neutral property type {property.PropertyType.Alias}");
}
}
var result = new TDestination
{
Id = property.Id,
Value = editor.GetValueEditor().ToEditor(property, DataTypeService, languageId),
Alias = property.Alias,
PropertyEditor = editor,
Editor = editor.Alias
};
// if there's a set of property aliases specified, we will check if the current property's value should be mapped.
// if it isn't one of the ones specified in 'includeProperties', we will just return the result without mapping the Value.
if (context.Options.Items.ContainsKey("IncludeProperties"))
{
var includeProperties = context.Options.Items["IncludeProperties"] as IEnumerable<string>;
if (includeProperties != null && includeProperties.Contains(property.Alias) == false)
{
return result;
}
}
// if no 'IncludeProperties' were specified or this property is set to be included - we will map the value and return.
result.Value = editor.GetValueEditor().ToEditor(property, DataTypeService, languageId);
return result;
}
}
@@ -0,0 +1,16 @@
using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors.ParameterEditors
{
[ParameterEditor(Constants.PropertyEditors.MultiNodeTreePickerAlias, "Multiple Content Picker", "contentpicker")]
public class MultipleContentPickerParameterEditor : ParameterEditor
{
public MultipleContentPickerParameterEditor()
{
Configuration.Add("multiPicker", "1");
Configuration.Add("minNumber",0 );
Configuration.Add("maxNumber", 0);
}
}
}
@@ -14,7 +14,7 @@ using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi.Filters;
using System.Globalization;
using Umbraco.Core.Models.Entities;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web._Legacy.Actions;
namespace Umbraco.Web.Trees
{
@@ -148,7 +148,7 @@ namespace Umbraco.Web.Trees
}
// get child entities - if id is root, but user's start nodes do not contain the
// root node, this returns the start nodes instead of root's children
// root node, this returns the start nodes instead of root's children
var langId = queryStrings["languageId"].TryConvertTo<int?>();
var entities = GetChildEntities(id, langId.Success ? langId.Result : null).ToList();
nodes.AddRange(entities.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings)).Where(x => x != null));
@@ -194,8 +194,8 @@ namespace Umbraco.Web.Trees
entityId = entity.Id;
}
IEntitySlim[] result;
IEntitySlim[] result;
// if a request is made for the root node but user has no access to
// root node, return start nodes instead
@@ -204,31 +204,31 @@ namespace Umbraco.Web.Trees
result = UserStartNodes.Length > 0
? Services.EntityService.GetAll(UmbracoObjectType, UserStartNodes).ToArray()
: Array.Empty<IEntitySlim>();
}
else
{
result = Services.EntityService.GetChildren(entityId, UmbracoObjectType).ToArray();
}
if (langId.HasValue)
{
//need to update all node names
//TODO: This is not currently stored, we need to wait until U4-11128 is complete for this to work, in the meantime
// we'll mock using this and it will just be some mock data
foreach(var e in result)
{
if (e.AdditionalData.TryGetValue("VariantNames", out var variantNames))
{
var casted = (IDictionary<int, string>)variantNames;
e.Name = casted[langId.Value];
}
else
{
e.Name = e.Name + " (lang: " + langId.Value + ")";
}
}
}
}
else
{
result = Services.EntityService.GetChildren(entityId, UmbracoObjectType).ToArray();
}
if (langId.HasValue)
{
//need to update all node names
//TODO: This is not currently stored, we need to wait until U4-11128 is complete for this to work, in the meantime
// we'll mock using this and it will just be some mock data
foreach(var e in result)
{
if (e.AdditionalData.TryGetValue("VariantNames", out var variantNames))
{
var casted = (IDictionary<int, string>)variantNames;
e.Name = casted[langId.Value];
}
else
{
e.Name = e.Name + " (lang: " + langId.Value + ")";
}
}
}
return result;
}
@@ -389,7 +389,7 @@ namespace Umbraco.Web.Trees
/// <remarks>By default the user must have Browse permissions to see the node in the Content tree</remarks>
/// <returns></returns>
internal bool CanUserAccessNode(IUmbracoEntity doc, IEnumerable<MenuItem> allowedUserOptions, int? langId)
{
{
//TODO: At some stage when we implement permissions on languages we'll need to take care of langId
return allowedUserOptions.Select(x => x.Action).OfType<ActionBrowse>().Any();
}
+4
View File
@@ -140,6 +140,8 @@
<Compile Include="Editors\PreviewController.cs" />
<Compile Include="Editors\TemplateController.cs" />
<Compile Include="Editors\TourController.cs" />
<Compile Include="HealthCheck\Checks\Security\XssProtectionCheck.cs" />
<Compile Include="HealthCheck\Checks\Security\HstsCheck.cs" />
<Compile Include="Editors\UserEditorAuthorizationHelper.cs" />
<Compile Include="Editors\UserGroupAuthorizationAttribute.cs" />
<Compile Include="Editors\UserGroupEditorAuthorizationHelper.cs" />
@@ -186,6 +188,8 @@
<Compile Include="HealthCheck\Checks\Config\TraceCheck.cs" />
<Compile Include="HealthCheck\Checks\Config\ValueComparisonType.cs" />
<Compile Include="HealthCheck\Checks\Config\CompilationDebugCheck.cs" />
<Compile Include="HealthCheck\Checks\Security\BaseHttpHeaderCheck.cs" />
<Compile Include="HealthCheck\Checks\Security\NoSniffCheck.cs" />
<Compile Include="HealthCheck\Checks\Services\SmtpCheck.cs" />
<Compile Include="HealthCheck\Checks\Permissions\FolderAndFilePermissionsCheck.cs" />
<Compile Include="HealthCheck\Checks\Security\ExcessiveHeadersCheck.cs" />