From 88f97261ad1afaa2c2ccb7fb30432eeb9bc91283 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 5 Dec 2024 12:21:33 +0100 Subject: [PATCH] Explicit endpoints returning the Login and BackOffice logos and background (#17696) * Created explicit endpoints returning the login image instead of leaking the configuration. Thereby some hardcoded values have been changed, but the url will now be the same every time. * Remove magic concatenation for action lookup * remove unused backoffice asset (login.jpg) * remove unused umbraco logo assets * add manifest handlers * add mock handlers for the `security/back-office/graphics` endpoints to the backoffice * add mock handlers for the `security/back-office/graphics` endpoints to the login screen * chore: update msw service worker * feat: make static assets available for consumption without copying them from the login project * update consts with new location for static assets * feat: prefix login assets with `login-` * remove unused asset `logo.png` * feat: introduce a `/back-office/graphics/logo` endpoint to serve the logo "mark" used throughout all applications * feat: use the alternative logo for disabled javascript warning * feat: use the umbraco logo on the NoNodes.cshtml page * Do not expose the new readme in the package * feat: add logo.svg * feat: add `umb-app-logo` element to display the backoffice logo including server url and appropriate tags * feat: use the new `umb-app-logo` element relevant places and make sure to add the serverUrl in front of other graphics * feat: move logic to connectedCallback to prevent error from non-existing element * revert usage of HideBackOfficeLogo * feat: add alt text to logos * feat: add obsolete message and a hint to use BackOfficeLogo insted --------- Co-authored-by: Sven Geusens Co-authored-by: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> --- .../Security/BackOfficeGraphicsController.cs | 74 ++++++++++++++++++ .../Umbraco.Cms.StaticAssets.csproj | 4 + .../umbraco/UmbracoBackOffice/Index.cshtml | 8 +- .../umbraco/UmbracoLogin/Index.cshtml | 12 +-- .../umbraco/UmbracoWebsite/NoNodes.cshtml | 4 +- .../wwwroot/umbraco/assets/README.md | 16 ++++ .../wwwroot/umbraco}/assets/login.jpg | Bin .../wwwroot/umbraco/assets/logo.svg} | 0 .../wwwroot/umbraco/assets}/logo_dark.svg | 0 .../wwwroot/umbraco/assets}/logo_light.svg | 0 .../wwwroot/umbraco/website/logo.png | Bin 1746 -> 0 bytes .../Configuration/Models/ContentSettings.cs | 14 +++- .../src/apps/app/app-error.element.ts | 8 +- .../src/apps/app/app-logo.element.ts | 46 +++++++++++ .../src/apps/app/index.ts | 1 + .../backoffice-header-logo.element.ts | 21 +++-- .../shared/layout/installer-layout.element.ts | 11 +-- .../src/assets/umbraco_logo_blue.svg | 1 - .../src/assets/umbraco_logo_white.svg | 1 - .../src/mocks/browser-handlers.ts | 5 +- .../src/mocks/data/document/document.data.ts | 4 +- .../src/mocks/handlers/backoffice.handlers.ts | 50 ++++++++++++ .../auth/modals/umb-app-auth-modal.element.ts | 25 +++++- src/Umbraco.Web.UI.Login/index.html | 10 +-- src/Umbraco.Web.UI.Login/package.json | 49 ++++++------ src/Umbraco.Web.UI.Login/public/login.jpg | Bin 292760 -> 0 bytes .../public/mockServiceWorker.js | 27 +++++-- .../src/mocks/handlers/backoffice.handlers.ts | 53 +++++++++++++ .../src/mocks/handlers/index.ts | 4 +- 29 files changed, 366 insertions(+), 82 deletions(-) create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/Security/BackOfficeGraphicsController.cs create mode 100644 src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/README.md rename src/{Umbraco.Web.UI.Client/src => Umbraco.Cms.StaticAssets/wwwroot/umbraco}/assets/login.jpg (100%) rename src/{Umbraco.Web.UI.Client/src/assets/umbraco_logomark_white.svg => Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/logo.svg} (100%) rename src/{Umbraco.Web.UI.Login/public => Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets}/logo_dark.svg (100%) rename src/{Umbraco.Web.UI.Login/public => Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets}/logo_light.svg (100%) delete mode 100644 src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/website/logo.png create mode 100644 src/Umbraco.Web.UI.Client/src/apps/app/app-logo.element.ts delete mode 100644 src/Umbraco.Web.UI.Client/src/assets/umbraco_logo_blue.svg delete mode 100644 src/Umbraco.Web.UI.Client/src/assets/umbraco_logo_white.svg create mode 100644 src/Umbraco.Web.UI.Client/src/mocks/handlers/backoffice.handlers.ts delete mode 100644 src/Umbraco.Web.UI.Login/public/login.jpg create mode 100644 src/Umbraco.Web.UI.Login/src/mocks/handlers/backoffice.handlers.ts diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Security/BackOfficeGraphicsController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Security/BackOfficeGraphicsController.cs new file mode 100644 index 0000000000..39c71b3c55 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Security/BackOfficeGraphicsController.cs @@ -0,0 +1,74 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Api.Management.Routing; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Configuration.Models; + +namespace Umbraco.Cms.Api.Management.Controllers.Security; + +[ApiVersion("1.0")] +[VersionedApiBackOfficeRoute(Common.Security.Paths.BackOfficeApi.EndpointTemplate + "/graphics")] +[ApiExplorerSettings(IgnoreApi = true)] +public class BackOfficeGraphicsController : Controller +{ + public const string LogoRouteName = nameof(BackOfficeGraphicsController) + "." + nameof(Logo); + public const string LoginBackGroundRouteName = nameof(BackOfficeGraphicsController) + "." + nameof(LoginBackground); + public const string LoginLogoRouteName = nameof(BackOfficeGraphicsController) + "." + nameof(LoginLogo); + public const string LoginLogoAlternativeRouteName = nameof(BackOfficeGraphicsController) + "." + nameof(LoginLogoAlternative); + + private readonly IOptions _contentSettings; + private readonly IContentTypeProvider _contentTypeProvider; + private readonly IWebHostEnvironment _webHostEnvironment; + + public BackOfficeGraphicsController(IOptions contentSettings, IOptions staticFileOptions, IWebHostEnvironment webHostEnvironment) + { + _contentSettings = contentSettings; + _webHostEnvironment = webHostEnvironment; + _contentTypeProvider = staticFileOptions.Value.ContentTypeProvider ?? new FileExtensionContentTypeProvider(); + } + + [HttpGet("login-background", Name = LoginBackGroundRouteName)] + [AllowAnonymous] + [MapToApiVersion("1.0")] + public IActionResult LoginBackground() => HandleFileRequest(_contentSettings.Value.LoginBackgroundImage); + + [HttpGet("logo", Name = LogoRouteName)] + [AllowAnonymous] + [MapToApiVersion("1.0")] + public IActionResult Logo() => HandleFileRequest(_contentSettings.Value.BackOfficeLogo); + + [HttpGet("login-logo", Name = LoginLogoRouteName)] + [AllowAnonymous] + [MapToApiVersion("1.0")] + public IActionResult LoginLogo() => HandleFileRequest(_contentSettings.Value.LoginLogoImage); + + [HttpGet("login-logo-alternative", Name = LoginLogoAlternativeRouteName)] + [AllowAnonymous] + [MapToApiVersion("1.0")] + public IActionResult LoginLogoAlternative() => HandleFileRequest(_contentSettings.Value.LoginLogoImageAlternative); + + private IActionResult HandleFileRequest(string virtualPath) + { + var filePath = Path.Combine(Constants.SystemDirectories.Umbraco, virtualPath).TrimStart(Constants.CharArrays.Tilde); + var fileInfo = _webHostEnvironment.WebRootFileProvider.GetFileInfo(filePath); + + if (fileInfo.PhysicalPath is null) + { + return NotFound(); + } + + if (_contentTypeProvider.TryGetContentType(fileInfo.PhysicalPath, out var contentType)) + { + Stream fileStream = fileInfo.CreateReadStream(); + return File(fileStream, contentType); + } + + return StatusCode(StatusCodes.Status412PreconditionFailed); + } +} diff --git a/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj b/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj index c3842bd167..d6fbf7ab37 100644 --- a/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj +++ b/src/Umbraco.Cms.StaticAssets/Umbraco.Cms.StaticAssets.csproj @@ -72,6 +72,10 @@ + + + + diff --git a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoBackOffice/Index.cshtml b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoBackOffice/Index.cshtml index 16fb9c48e6..a838386653 100644 --- a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoBackOffice/Index.cshtml +++ b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoBackOffice/Index.cshtml @@ -1,4 +1,5 @@ @using Microsoft.Extensions.Options +@using Umbraco.Cms.Api.Management.Controllers.Security @using Umbraco.Cms.Api.Management.Extensions @using Umbraco.Cms.Core.Configuration.Models @using Umbraco.Cms.Core.Logging @@ -11,13 +12,12 @@ @inject IJsonSerializer JsonSerializer @inject IProfilerHtml ProfilerHtml @inject IOptions GlobalSettings -@inject IOptions ContentSettings @{ bool.TryParse(Context.Request.Query["umbDebug"], out var isDebug); var backOfficePath = BackOfficePathGenerator.BackOfficePath; var backOfficeAssetsPath = BackOfficePathGenerator.BackOfficeAssetsPath; - var loginLogoImage = ContentSettings.Value.LoginLogoImage; + var loginLogoImageAlternative = Url.RouteUrl(BackOfficeGraphicsController.LoginLogoAlternativeRouteName, new {Version= "1"}); } @@ -54,8 +54,8 @@ }
-

- +

+ logo

For full functionality of Umbraco CMS it is necessary to enable JavaScript.

Here are the instructions how to enable JavaScript in your web browser.

diff --git a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoLogin/Index.cshtml b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoLogin/Index.cshtml index 856796cd25..0cc86a50be 100644 --- a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoLogin/Index.cshtml +++ b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoLogin/Index.cshtml @@ -1,5 +1,6 @@ @using Microsoft.AspNetCore.Mvc.TagHelpers @using Microsoft.Extensions.Options; +@using Umbraco.Cms.Api.Management.Controllers.Security @using Umbraco.Cms.Api.Management.Extensions @using Umbraco.Cms.Api.Management.Security @using Umbraco.Cms.Core.Configuration.Models @@ -10,7 +11,6 @@ @using Umbraco.Cms.Core.Serialization @using Umbraco.Cms.Web.Common.Hosting @using Umbraco.Extensions -@inject IOptions ContentSettings @inject IOptions SecuritySettings @inject IEmailSender EmailSender @inject IHostingEnvironment HostingEnvironment @@ -23,9 +23,9 @@ @{ bool.TryParse(Context.Request.Query["umbDebug"], out var isDebug); var backOfficePath = GlobalSettings.Value.GetBackOfficePath(HostingEnvironment); - var loginLogoImage = ContentSettings.Value.LoginLogoImage; - var loginLogoImageAlternative = ContentSettings.Value.LoginLogoImageAlternative; - var loginBackgroundImage = ContentSettings.Value.LoginBackgroundImage; + var loginLogoImage = Url.RouteUrl(BackOfficeGraphicsController.LoginLogoRouteName, new {Version= "1"}); + var loginLogoImageAlternative = Url.RouteUrl(BackOfficeGraphicsController.LoginLogoAlternativeRouteName, new {Version= "1"}); + var loginBackgroundImage = Url.RouteUrl(BackOfficeGraphicsController.LoginBackGroundRouteName, new {Version= "1"}); var usernameIsEmail = SecuritySettings.Value.UsernameIsEmail; var allowUserInvite = EmailSender.CanSendRequiredEmail(); var allowPasswordReset = SecuritySettings.Value.AllowPasswordReset && EmailSender.CanSendRequiredEmail(); @@ -73,8 +73,8 @@ }
-

- +

+ logo

For full functionality of Umbraco CMS it is necessary to enable JavaScript.

Here are the instructions how to enable JavaScript in your web browser.

diff --git a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoWebsite/NoNodes.cshtml b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoWebsite/NoNodes.cshtml index 622cce9f0c..b6bbef0e3a 100644 --- a/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoWebsite/NoNodes.cshtml +++ b/src/Umbraco.Cms.StaticAssets/umbraco/UmbracoWebsite/NoNodes.cshtml @@ -1,4 +1,5 @@ @using Microsoft.Extensions.Options +@using Umbraco.Cms.Api.Management.Controllers.Security @using Umbraco.Cms.Core.Configuration.Models @using Umbraco.Cms.Core.Hosting @using Umbraco.Cms.Core.Routing @@ -8,6 +9,7 @@ @inject IOptions globalSettings @{ var backOfficePath = globalSettings.Value.GetBackOfficePath(hostingEnvironment); + var logoImage = Url.RouteUrl(BackOfficeGraphicsController.LogoRouteName, new {Version= "1"}); } @@ -26,7 +28,7 @@

Welcome to your Umbraco installation

diff --git a/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/README.md b/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/README.md new file mode 100644 index 0000000000..ec89c77566 --- /dev/null +++ b/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/README.md @@ -0,0 +1,16 @@ +# Umbraco static assets + +The files in this directory are static assets that are used by the Umbraco backoffice, installer, public-facing sites, and login screen. These files are served by the Umbraco backend and are not intended to be used by the front-end of your website. + +## Structure + +The assets are structured in the following way: + +| Name | Description | Usage | +| ---- |--------------------------------------------------------------------|---------------------------------------------------------------------------------| +| `login.jpg` | The background image for the login screen. | /umbraco/management/api/v1/security/back-office/graphics/login-background | +| `logo.svg` | The Umbraco logo for the Backoffice and other public facing sites. | /umbraco/management/api/v1/security/back-office/graphics/logo | +| `logo_dark.svg` | The Umbraco logo in dark mode for the login screen. | /umbraco/management/api/v1/security/back-office/graphics/login-logo-alternative | +| `logo_light.svg` | The Umbraco logo in light mode for the login screen. | /umbraco/management/api/v1/security/back-office/graphics/login-logo | + +All assets are linked up through the BackOfficeGraphicsController which uses the constants defined in [ContentSettings](../../../../Umbraco.Core/Configuration/Models/ContentSettings.cs). diff --git a/src/Umbraco.Web.UI.Client/src/assets/login.jpg b/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/login.jpg similarity index 100% rename from src/Umbraco.Web.UI.Client/src/assets/login.jpg rename to src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/login.jpg diff --git a/src/Umbraco.Web.UI.Client/src/assets/umbraco_logomark_white.svg b/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/logo.svg similarity index 100% rename from src/Umbraco.Web.UI.Client/src/assets/umbraco_logomark_white.svg rename to src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/logo.svg diff --git a/src/Umbraco.Web.UI.Login/public/logo_dark.svg b/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/logo_dark.svg similarity index 100% rename from src/Umbraco.Web.UI.Login/public/logo_dark.svg rename to src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/logo_dark.svg diff --git a/src/Umbraco.Web.UI.Login/public/logo_light.svg b/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/logo_light.svg similarity index 100% rename from src/Umbraco.Web.UI.Login/public/logo_light.svg rename to src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets/logo_light.svg diff --git a/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/website/logo.png b/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/website/logo.png deleted file mode 100644 index ec59683c50e1e54d09c2edd1523ab72f9f1e0ff8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1746 zcmeHH`#Tc~0Nt)K&$4;Udm-=0J0*#{`DQlq7z-7WVwx+KD_I`pev*aidX$SAVfK+n z3~icZ#2q#+(uCb%tY}8A{*HUk_nmXT^Xoa^ck&Q$4|y4N82|tv@8#)=+;{X(N=fXi z>5_CE007)T_y)M`$G!jYUuvMQs`dQ->eVDuo=KqU| zLw_PV2XR(<2SU9u8{_MGnNnXctdolT*gN$e- z8CZ|WJf)4p%hgr|cj|_$(U#x8Eb)LI{`A#0;8>2iaNd_|R^;sW>4OcO0L5c#Hmqvg zoCwwv3cH!7$SO(53EOdZVloCcmaA1~8087LT75Py9viX3^^_)I<=N|jIwuCRT8M_J zlvp~4lzgxZI$o;9L`S2^C=-ne^?W(;I59sJw6+(yRD(3Q73UK4su`YHS z^T3FVg*;6S$jq%IT6P$hUM4MmqObj{{4^sWigwrCOZX8{ie8V%;LGXRi_x7Zb?^mJ^i~n;37~!4&OHj77%tHzmZIQ4y=C(sVtl(K-PF z+RE%IkXVsO0Gb_oGTDfg1x?X0O$MQeHQ-){+vUwGg7T^r2jVW0bKiIhN9yL@ZpmrA zfCLDUkWflbXU9kTYZbNnv!gZH4MvqPA2UXa&tE%)he3abGPjSrEsUg8t2sye`q>TK z5=?pfW0rT`0**T-guaZ!SgF*8N2`NfL^%yxROuaG6UgG*&jlTRM1xeL$RQ?!y6y`M zAwnP3pHP)k*4HOqpOft;B6yPduot`lOpOgHUPht^Ckv + /// Gets or sets a value for the path to the backoffice logo. + /// + [DefaultValue(StaticBackOfficeLogo)] + public string BackOfficeLogo { get; set; } = StaticBackOfficeLogo; + /// /// Gets or sets a value indicating whether to hide the backoffice umbraco logo or not. /// [DefaultValue(StaticHideBackOfficeLogo)] + [Obsolete("This setting is no longer used and will be removed in future versions. An alternative BackOffice logo can be set using the BackOfficeLogo setting.")] public bool HideBackOfficeLogo { get; set; } = StaticHideBackOfficeLogo; /// diff --git a/src/Umbraco.Web.UI.Client/src/apps/app/app-error.element.ts b/src/Umbraco.Web.UI.Client/src/apps/app/app-error.element.ts index da1a03ffbe..fc34f7156b 100644 --- a/src/Umbraco.Web.UI.Client/src/apps/app/app-error.element.ts +++ b/src/Umbraco.Web.UI.Client/src/apps/app/app-error.element.ts @@ -167,8 +167,8 @@ export class UmbAppErrorElement extends UmbLitElement { return html`
-