From 95eb58587b95b091fa861216842e3cdf9af27c32 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 20 Jan 2025 14:14:28 +0100 Subject: [PATCH 1/9] Merge commit from fork --- .../Controllers/PreviewController.cs | 28 +++++++++++++++++++ .../Views/UmbracoViewPage.cs | 5 +++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs b/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs index 17875c2950..f1531ecb8d 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs @@ -1,3 +1,4 @@ +using System.Globalization; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ViewEngines; @@ -130,6 +131,11 @@ public class PreviewController : Controller [Authorize(Policy = AuthorizationPolicies.BackOfficeAccess)] public ActionResult Frame(int id, string culture) { + if (ValidateProvidedCulture(culture) is false) + { + throw new InvalidOperationException($"Could not recognise the provided culture: {culture}"); + } + EnterPreview(id); // use a numeric URL because content may not be in cache and so .Url would fail @@ -138,6 +144,28 @@ public class PreviewController : Controller return RedirectPermanent($"../../{id}{query}"); } + private static bool ValidateProvidedCulture(string culture) + { + if (string.IsNullOrEmpty(culture)) + { + return true; + } + + // We can be confident the backoffice will have provided a valid culture in linking to the + // preview, so we don't need to check that the culture matches an Umbraco language. + // We are only concerned here with protecting against XSS attacks from a fiddled preview + // URL, so we can just confirm we have a valid culture. + try + { + CultureInfo.GetCultureInfo(culture, true); + return true; + } + catch (CultureNotFoundException) + { + return false; + } + } + public ActionResult? EnterPreview(int id) { IUser? user = _backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser; diff --git a/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs b/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs index 086a0b0c81..403e6324e1 100644 --- a/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs +++ b/src/Umbraco.Web.Common/Views/UmbracoViewPage.cs @@ -141,7 +141,10 @@ public abstract class UmbracoViewPage : RazorPage string.Format( ContentSettings.PreviewBadge, HostingEnvironment.ToAbsolute(GlobalSettings.UmbracoPath), - Context.Request.GetEncodedUrl(), + System.Web.HttpUtility.HtmlEncode(Context.Request.GetEncodedUrl()), // Belt and braces - via a browser at least it doesn't seem possible to have anything other than + // a valid culture code provided in the querystring of this URL. + // But just to be sure of prevention of an XSS vulnterablity we'll HTML encode here too. + // An expected URL is untouched by this encoding. UmbracoContext.PublishedRequest?.PublishedContent?.Id); } else From e934a943b5068913be40a32bfbc5fa92091eb95c Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 20 Jan 2025 17:37:04 +0100 Subject: [PATCH 2/9] build on windows --- build/azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/azure-pipelines.yml b/build/azure-pipelines.yml index c8e370d513..572f93df0a 100644 --- a/build/azure-pipelines.yml +++ b/build/azure-pipelines.yml @@ -71,7 +71,7 @@ stages: - job: A displayName: Build Umbraco CMS pool: - vmImage: 'ubuntu-latest' + vmImage: 'windows-latest' steps: - task: NodeTool@0 displayName: Use Node.js $(nodeVersion) From e77e9c5691685e6a84886d9c6b77888e5debdcaa Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Thu, 24 Oct 2024 14:45:23 +0200 Subject: [PATCH 3/9] Format sql statement (#17354) (cherry picked from commit aa9f194d7611bb830a8fc3b80295c8115fb5b2d6) --- .../SyntaxProvider/SqlServerSyntaxProviderTests.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/SyntaxProvider/SqlServerSyntaxProviderTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/SyntaxProvider/SqlServerSyntaxProviderTests.cs index be90d8695b..7e1d1f163f 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/SyntaxProvider/SqlServerSyntaxProviderTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/SyntaxProvider/SqlServerSyntaxProviderTests.cs @@ -68,12 +68,8 @@ public class SqlServerSyntaxProviderTests : UmbracoIntegrationTest } Assert.AreEqual( - @$"DELETE FROM {t("cmsContentNu")} WHERE {c("nodeId")} IN (SELECT {c("nodeId")} FROM (SELECT DISTINCT cmsContentNu.nodeId -FROM {t("cmsContentNu")} -INNER JOIN {t("umbracoNode")} -ON {t("cmsContentNu")}.{c("nodeId")} = {t("umbracoNode")}.{c("id")} -WHERE (({t("umbracoNode")}.{c("nodeObjectType")} = @0))) x)".Replace(Environment.NewLine, " ").Replace("\n", " ") - .Replace("\r", " "), + @$"DELETE FROM {t("cmsContentNu")} WHERE {c("nodeId")} IN (SELECT {c("nodeId")} FROM (SELECT DISTINCT cmsContentNu.nodeId FROM {t("cmsContentNu")} INNER JOIN {t("umbracoNode")} ON {t("cmsContentNu")}.{c("nodeId")} = {t("umbracoNode")}.{c("id")} WHERE (({t("umbracoNode")}.{c("nodeObjectType")} = @0))) x)".Replace(Environment.NewLine, " ") + .Replace("\n", " ").Replace("\r", " "), sqlOutput.SQL.Replace(Environment.NewLine, " ").Replace("\n", " ").Replace("\r", " ")); Assert.AreEqual(1, sqlOutput.Arguments.Length); From 2161edb871b416faf8f4b14e1634e2f4fcdd4d66 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Tue, 21 Jan 2025 07:41:06 +0100 Subject: [PATCH 4/9] Bump version --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index ba35bbaff3..a88b4d4fd1 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", - "version": "13.5.2", + "version": "13.5.3", "assemblyVersion": { "precision": "build" }, From c7d157bbfd807aff521d65afef8ec815db87dab2 Mon Sep 17 00:00:00 2001 From: Zeegaan Date: Tue, 21 Jan 2025 09:02:00 +0100 Subject: [PATCH 5/9] build on ubuntu --- build/azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/azure-pipelines.yml b/build/azure-pipelines.yml index 572f93df0a..c8e370d513 100644 --- a/build/azure-pipelines.yml +++ b/build/azure-pipelines.yml @@ -71,7 +71,7 @@ stages: - job: A displayName: Build Umbraco CMS pool: - vmImage: 'windows-latest' + vmImage: 'ubuntu-latest' steps: - task: NodeTool@0 displayName: Use Node.js $(nodeVersion) From 3d253f5f06c182255810dbd209774c03c09aec77 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Thu, 23 Jan 2025 11:15:26 +0100 Subject: [PATCH 6/9] bump version --- version.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/version.json b/version.json index 571b476065..54e67d46be 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", - "version": "13.6.0-rc2", + "version": "13.6.0-rc3", "assemblyVersion": { "precision": "build" }, @@ -9,8 +9,7 @@ "semVer": 2.0 }, "publicReleaseRefSpec": [ - "^refs/heads/main$", - "^refs/heads/release/" + "^refs/heads/main$", "^refs/heads/release/" ], "release": { "branchName": "release/{version}", From bf340cd7d4c139f08d6cc0dc669038c3d1ab6022 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Tue, 28 Jan 2025 11:53:00 +0100 Subject: [PATCH 7/9] fix: remove unused parameters and documentation (#18095) this fixes an issue where unused parameters were published as supported, but they were in fact never supported. --- .../src/common/services/assets.service.js | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js index 8149e45ee8..73ac74847b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js @@ -6,7 +6,7 @@ * @requires angularHelper * * @description - * Promise-based utillity service to lazy-load client-side dependencies inside angular controllers. + * Promise-based utility service to lazy-load client-side dependencies inside angular controllers. * * ##usage * To use, simply inject the assetsService into any controller that needs it, and make @@ -20,10 +20,10 @@ * }); * * - * You can also load individual files, which gives you greater control over what attibutes are passed to the file, as well as timeout + * You can also load individual files, which gives you greater control over what attributes are passed to the file: * *
- *      angular.module("umbraco").controller("my.controller". function(assetsService){
+ *      angular.module("umbraco").controller("my.controller". function(assetsService) {
  *          assetsService.loadJs("script.js", $scope, {charset: 'utf-8'}, 10000 }).then(function(){
  *                 //this code executes when the script is done loading
  *          });
@@ -33,7 +33,7 @@
  * For these cases, there are 2 individual methods, one for javascript, and one for stylesheets:
  *
  * 
- *      angular.module("umbraco").controller("my.controller". function(assetsService){
+ *      angular.module("umbraco").controller("my.controller". function(assetsService) {
  *          assetsService.loadCss("stye.css", $scope, {media: 'print'}, 10000 }).then(function(){
  *                 //loadcss cannot determine when the css is done loading, so this will trigger instantly
  *          });
@@ -55,7 +55,7 @@ angular.module('umbraco.services')
             var _op = (url.indexOf("?") > 0) ? "&" : "?";
             url = url + _op + "umb__rnd=" + rnd;
             return url;
-        };
+        }
 
         function convertVirtualPath(path) {
             //make this work for virtual paths
@@ -72,7 +72,7 @@ angular.module('umbraco.services')
         function getFlatpickrLocales(locales, supportedLocales) {
             return getLocales(locales, supportedLocales, 'lib/flatpickr/l10n/');
         }
-        
+
         function getLocales(locales, supportedLocales, path) {
             var localeUrls = [];
             locales = locales.split(',');
@@ -168,17 +168,13 @@ angular.module('umbraco.services')
              *
              * @param {String} path path to the css file to load
              * @param {Scope} scope optional scope to pass into the loader
-             * @param {Object} keyvalue collection of attributes to pass to the stylesheet element
-             * @param {Number} timeout in milliseconds
              * @returns {Promise} Promise object which resolves when the file has loaded
              */
-            loadCss: function (path, scope, attributes, timeout) {
+            loadCss: function (path, scope) {
 
                 path = convertVirtualPath(path);
 
-                var asset = this._getAssetPromise(path); // $q.defer();
-                var t = timeout || 5000;
-                var a = attributes || undefined;
+                const asset = this._getAssetPromise(path);
 
                 if (asset.state === "new") {
                     asset.state = "loading";
@@ -207,17 +203,13 @@ angular.module('umbraco.services')
              *
              * @param {String} path path to the js file to load
              * @param {Scope} scope optional scope to pass into the loader
-             * @param {Object} keyvalue collection of attributes to pass to the script element
-             * @param {Number} timeout in milliseconds
              * @returns {Promise} Promise object which resolves when the file has loaded
              */
-            loadJs: function (path, scope, attributes, timeout) {
+            loadJs: function (path, scope) {
 
                 path = convertVirtualPath(path);
 
-                var asset = this._getAssetPromise(path); // $q.defer();
-                var t = timeout || 5000;
-                var a = attributes || undefined;
+                const asset = this._getAssetPromise(path);
 
                 if (asset.state === "new") {
                     asset.state = "loading";
@@ -250,7 +242,7 @@ angular.module('umbraco.services')
              *
              * @param {Array} pathArray string array of paths to the files to load
              * @param {Scope} scope optional scope to pass into the loader
-             * @param {string} defaultAssetType optional default asset type used to load assets with no extension 
+             * @param {string} defaultAssetType optional default asset type used to load assets with no extension
              * @returns {Promise} Promise object which resolves when all the files has loaded
              */
             load: function (pathArray, scope, defaultAssetType) {

From bb73ec6c68db1ed8de53288c4fd665cff4a8faf2 Mon Sep 17 00:00:00 2001
From: Sven Geusens 
Date: Thu, 30 Jan 2025 09:52:50 +0100
Subject: [PATCH 8/9] Set release version

---
 version.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/version.json b/version.json
index 54e67d46be..0d1b198869 100644
--- a/version.json
+++ b/version.json
@@ -1,6 +1,6 @@
 {
   "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json",
-  "version": "13.6.0-rc3",
+  "version": "13.6.0",
   "assemblyVersion": {
     "precision": "build"
   },

From b9837ac77ccddef66ed37bbf9827167e0b88aad2 Mon Sep 17 00:00:00 2001
From: Bjarke Berg 
Date: Fri, 29 Nov 2024 12:20:19 +0100
Subject: [PATCH 9/9] Optimize Azure pipeline (#17674)

* Only fetch single commit

* Hopefully fixes Nerdbank.GitVersioning.GitException: Shallow clone lacks the objects required to calculate version height. Use full clones or clones with a history at least as deep as the last version height resetting change.

* Do not checkout again

* More test pipeline

* Another attempt

* yet another attempt

* more attempts

* Revert "more attempts"

This reverts commit 5694d97ba620e90fdeea287936f58002f2a5ddba.

* Test without building backoffice and login explicitly

* Fix mem leak in integration tests

* Fixes sqlserver lock test
# Conflicts:
#	build/azure-pipelines.yml
---
 build/azure-pipelines.yml | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/build/azure-pipelines.yml b/build/azure-pipelines.yml
index d5b02db6f2..8d3f9edc0f 100644
--- a/build/azure-pipelines.yml
+++ b/build/azure-pipelines.yml
@@ -73,6 +73,10 @@ stages:
         pool:
           vmImage: 'ubuntu-latest'
         steps:
+          - checkout: self
+            submodules: false
+            lfs: false,
+            fetchDepth: 500
           - task: NodeTool@0
             displayName: Use Node.js $(nodeVersion)
             retryCountOnTaskFailure: 3
@@ -198,6 +202,11 @@ stages:
         pool:
           vmImage: 'ubuntu-latest'
         steps:
+          - checkout: self
+            submodules: false
+            lfs: false,
+            fetchDepth: 1
+            fetchFilter: tree:0
           - task: NodeTool@0
             displayName: Use Node.js 10.15.x
             retryCountOnTaskFailure: 3
@@ -249,6 +258,11 @@ stages:
         pool:
           vmImage: $(vmImage)
         steps:
+          - checkout: self
+            submodules: false
+            lfs: false,
+            fetchDepth: 1
+            fetchFilter: tree:0
           - task: DownloadPipelineArtifact@2
             displayName: Download build artifacts
             inputs:
@@ -288,6 +302,11 @@ stages:
         variables:
           Tests__Database__DatabaseType: 'Sqlite'
         steps:
+          - checkout: self
+            submodules: false
+            lfs: false,
+            fetchDepth: 1
+            fetchFilter: tree:0
           # Setup test environment
           - task: DownloadPipelineArtifact@2
             displayName: Download build artifacts