From 6d2ba3b885587b2ca02e00333eaf1024becad1e0 Mon Sep 17 00:00:00 2001 From: tdavande <113100339+tdavande@users.noreply.github.com> Date: Thu, 24 Oct 2024 09:38:25 +0100 Subject: [PATCH 1/5] GA added --- .../Configuration/ApplicationConfiguration.cs | 2 ++ src/SFA.DAS.ApprenticeApp.Pwa/Program.cs | 9 +++++- .../Views/Shared/_GoogleAnalytics.cshtml | 32 +++++++++++++++++++ .../Views/Shared/_Layout.cshtml | 6 +++- 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_GoogleAnalytics.cshtml diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Configuration/ApplicationConfiguration.cs b/src/SFA.DAS.ApprenticeApp.Pwa/Configuration/ApplicationConfiguration.cs index a2e43688..e1182640 100644 --- a/src/SFA.DAS.ApprenticeApp.Pwa/Configuration/ApplicationConfiguration.cs +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Configuration/ApplicationConfiguration.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using SFA.DAS.ApprenticePortal.SharedUi.GoogleAnalytics; using SFA.DAS.Http.Configuration; namespace SFA.DAS.ApprenticeApp.Pwa.Configuration; @@ -19,6 +20,7 @@ public class ApplicationConfiguration public string? StubAuth { get; set; } public string? PushNotificationPublicKey { get; set; } public bool UseGovSignIn { get; set; } + public GoogleAnalyticsConfiguration GoogleAnalytics { get; set; } } [ExcludeFromCodeCoverage] diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Program.cs b/src/SFA.DAS.ApprenticeApp.Pwa/Program.cs index cf3231da..71325f90 100644 --- a/src/SFA.DAS.ApprenticeApp.Pwa/Program.cs +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Program.cs @@ -1,6 +1,8 @@ -using Microsoft.Extensions.Logging.ApplicationInsights; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging.ApplicationInsights; using SFA.DAS.ApprenticeApp.Pwa.AppStart; using SFA.DAS.ApprenticeApp.Pwa.Configuration; +using SFA.DAS.ApprenticePortal.SharedUi.GoogleAnalytics; using System.Diagnostics.CodeAnalysis; using System.Drawing.Text; using WebEssentials.AspNetCore.Pwa; @@ -43,6 +45,11 @@ ConnectionString = builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"] }); +// configure google analytics +builder.Services.Configure(options => + options.Filters.Add(new EnableGoogleAnalyticsAttribute( + applicationConfiguration.GoogleAnalytics))); + var app = builder.Build(); // Configure the HTTP request pipeline. diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_GoogleAnalytics.cshtml b/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_GoogleAnalytics.cshtml new file mode 100644 index 00000000..96591283 --- /dev/null +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_GoogleAnalytics.cshtml @@ -0,0 +1,32 @@ + +@using SFA.DAS.ApprenticePortal.SharedUi.GoogleAnalytics + +@if (ViewData.GoogleAnalyticsIsEnabled()) +{ +var id = ViewData.GetGoogleTagManagerId(); + +@if (Model == SFA.DAS.ApprenticePortal.SharedUi.GoogleAnalytics.GoogleAnalyticsTag.Head) +{ + + + +} +else if (Model == SFA.DAS.ApprenticePortal.SharedUi.GoogleAnalytics.GoogleAnalyticsTag.Body) +{ + + + +} + +} \ No newline at end of file diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml b/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml index 41931623..8905f77d 100644 --- a/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml @@ -1,7 +1,10 @@ - +@using SFA.DAS.ApprenticePortal.SharedUi.GoogleAnalytics + + + @@ -15,6 +18,7 @@ +
From ae70c6065fc8216780af78a17884ec992697349f Mon Sep 17 00:00:00 2001 From: tdavande <113100339+tdavande@users.noreply.github.com> Date: Thu, 28 Nov 2024 15:00:50 +0000 Subject: [PATCH 2/5] Security Headers configured --- .../Helpers/SecurityHeadersMiddleware.cs.cs | 31 +++++++++++++++++++ src/SFA.DAS.ApprenticeApp.Pwa/Program.cs | 9 ++++-- 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs.cs diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs.cs b/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs.cs new file mode 100644 index 00000000..112b49cf --- /dev/null +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using System.Threading.Tasks; + +namespace SFA.DAS.ApprenticeApp.Pwa.Helpers +{ + public class SecurityHeadersMiddleware + { + private readonly RequestDelegate _next; + + public SecurityHeadersMiddleware(RequestDelegate next) => _next = next; + + public async Task InvokeAsync(HttpContext context) + { + const string dasCdn = "das-at-frnt-end.azureedge.net das-pp-frnt-end.azureedge.net das-mo-frnt-end.azureedge.net das-test-frnt-end.azureedge.net das-test2-frnt-end.azureedge.net das-prd-frnt-end.azureedge.net"; + + if (!context.Response.Headers.ContainsKey("Content-Security-Policy")) + { + context.Response.Headers.Add("Content-Security-Policy", + new StringValues( + $"script-src 'self' 'unsafe-inline' 'unsafe-eval' {dasCdn} https://www.googletagmanager.com https://tagmanager.google.com https://www.google-analytics.com https://ssl.google-analytics.com ; " + + $"style-src 'self' 'unsafe-inline' {dasCdn} https://tagmanager.google.com https://fonts.googleapis.com ; " + + $"img-src {dasCdn} www.googletagmanager.com https://ssl.gstatic.com https://www.gstatic.com https://www.google-analytics.com ; " + + $"font-src {dasCdn} https://fonts.gstatic.com ;" + + "connect-src https://www.google-analytics.com ;" + + "frame-src https://www.googletagmanager.com")); + } + await _next(context); + } + } +} diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Program.cs b/src/SFA.DAS.ApprenticeApp.Pwa/Program.cs index 8cac92c2..6c5bb1dc 100644 --- a/src/SFA.DAS.ApprenticeApp.Pwa/Program.cs +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Program.cs @@ -1,6 +1,8 @@ -using Microsoft.Extensions.Logging.ApplicationInsights; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging.ApplicationInsights; using SFA.DAS.ApprenticeApp.Pwa.AppStart; using SFA.DAS.ApprenticeApp.Pwa.Configuration; +using SFA.DAS.ApprenticeApp.Pwa.Helpers; using SFA.DAS.ApprenticePortal.SharedUi.GoogleAnalytics; using System.Diagnostics.CodeAnalysis; using System.Drawing.Text; @@ -46,7 +48,8 @@ // configure google analytics builder.Services.Configure(options => options.Filters.Add(new EnableGoogleAnalyticsAttribute( - applicationConfiguration.GoogleAnalytics))); + applicationConfiguration.GoogleAnalytics) + )); var app = builder.Build(); @@ -58,6 +61,8 @@ app.UseHsts(); } +// Add Security Headers Middleware +app.UseMiddleware(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseHealthChecks("/ping"); From bdbb15d7b875a97ad6bac000ca8610e63a7c2fa0 Mon Sep 17 00:00:00 2001 From: tdavande <113100339+tdavande@users.noreply.github.com> Date: Fri, 29 Nov 2024 12:48:07 +0000 Subject: [PATCH 3/5] MS clarity added --- .../Configuration/ApplicationConfiguration.cs | 1 + ...rsMiddleware.cs.cs => SecurityHeadersMiddleware.cs} | 5 +---- .../Views/Shared/_Layout.cshtml | 10 ++++++++++ 3 files changed, 12 insertions(+), 4 deletions(-) rename src/SFA.DAS.ApprenticeApp.Pwa/Helpers/{SecurityHeadersMiddleware.cs.cs => SecurityHeadersMiddleware.cs} (93%) diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Configuration/ApplicationConfiguration.cs b/src/SFA.DAS.ApprenticeApp.Pwa/Configuration/ApplicationConfiguration.cs index e1182640..f7dd1b85 100644 --- a/src/SFA.DAS.ApprenticeApp.Pwa/Configuration/ApplicationConfiguration.cs +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Configuration/ApplicationConfiguration.cs @@ -21,6 +21,7 @@ public class ApplicationConfiguration public string? PushNotificationPublicKey { get; set; } public bool UseGovSignIn { get; set; } public GoogleAnalyticsConfiguration GoogleAnalytics { get; set; } + public string? WhiteListEmails { get; set; } } [ExcludeFromCodeCoverage] diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs.cs b/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs similarity index 93% rename from src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs.cs rename to src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs index 112b49cf..a59feaed 100644 --- a/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs.cs +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs @@ -13,9 +13,6 @@ public class SecurityHeadersMiddleware public async Task InvokeAsync(HttpContext context) { const string dasCdn = "das-at-frnt-end.azureedge.net das-pp-frnt-end.azureedge.net das-mo-frnt-end.azureedge.net das-test-frnt-end.azureedge.net das-test2-frnt-end.azureedge.net das-prd-frnt-end.azureedge.net"; - - if (!context.Response.Headers.ContainsKey("Content-Security-Policy")) - { context.Response.Headers.Add("Content-Security-Policy", new StringValues( $"script-src 'self' 'unsafe-inline' 'unsafe-eval' {dasCdn} https://www.googletagmanager.com https://tagmanager.google.com https://www.google-analytics.com https://ssl.google-analytics.com ; " + @@ -24,7 +21,7 @@ public async Task InvokeAsync(HttpContext context) $"font-src {dasCdn} https://fonts.gstatic.com ;" + "connect-src https://www.google-analytics.com ;" + "frame-src https://www.googletagmanager.com")); - } + await _next(context); } } diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml b/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml index da0d92f3..bff4db4a 100644 --- a/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml @@ -9,10 +9,20 @@ + @(ViewData["Title"] == null ? "Apprentice App" : ViewData["Title"]) + @*MS Clarity tag*@ + + From 6b107875a8f7e96bd860653f1563bb0d05599345 Mon Sep 17 00:00:00 2001 From: tdavande <113100339+tdavande@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:22:28 +0000 Subject: [PATCH 4/5] whitespace removed --- .../Helpers/SecurityHeadersMiddleware.cs | 17 ++++++++--------- .../Views/Shared/_GoogleAnalytics.cshtml | 4 +--- .../Views/Shared/_Layout.cshtml | 1 - 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs b/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs index a59feaed..84ab50b7 100644 --- a/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs @@ -13,15 +13,14 @@ public class SecurityHeadersMiddleware public async Task InvokeAsync(HttpContext context) { const string dasCdn = "das-at-frnt-end.azureedge.net das-pp-frnt-end.azureedge.net das-mo-frnt-end.azureedge.net das-test-frnt-end.azureedge.net das-test2-frnt-end.azureedge.net das-prd-frnt-end.azureedge.net"; - context.Response.Headers.Add("Content-Security-Policy", - new StringValues( - $"script-src 'self' 'unsafe-inline' 'unsafe-eval' {dasCdn} https://www.googletagmanager.com https://tagmanager.google.com https://www.google-analytics.com https://ssl.google-analytics.com ; " + - $"style-src 'self' 'unsafe-inline' {dasCdn} https://tagmanager.google.com https://fonts.googleapis.com ; " + - $"img-src {dasCdn} www.googletagmanager.com https://ssl.gstatic.com https://www.gstatic.com https://www.google-analytics.com ; " + - $"font-src {dasCdn} https://fonts.gstatic.com ;" + - "connect-src https://www.google-analytics.com ;" + - "frame-src https://www.googletagmanager.com")); - + context.Response.Headers.Add("Content-Security-Policy", + new StringValues( + $"script-src 'self' 'unsafe-inline' 'unsafe-eval' {dasCdn} https://www.googletagmanager.com https://tagmanager.google.com https://www.google-analytics.com https://ssl.google-analytics.com ; " + + $"style-src 'self' 'unsafe-inline' {dasCdn} https://tagmanager.google.com https://fonts.googleapis.com ; " + + $"img-src {dasCdn} www.googletagmanager.com https://ssl.gstatic.com https://www.gstatic.com https://www.google-analytics.com ; " + + $"font-src {dasCdn} https://fonts.gstatic.com ;" + + "connect-src https://www.google-analytics.com ;" + + "frame-src https://www.googletagmanager.com")); await _next(context); } } diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_GoogleAnalytics.cshtml b/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_GoogleAnalytics.cshtml index 96591283..b87e893c 100644 --- a/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_GoogleAnalytics.cshtml +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_GoogleAnalytics.cshtml @@ -1,5 +1,4 @@ - -@using SFA.DAS.ApprenticePortal.SharedUi.GoogleAnalytics +@using SFA.DAS.ApprenticePortal.SharedUi.GoogleAnalytics @if (ViewData.GoogleAnalyticsIsEnabled()) { @@ -28,5 +27,4 @@ else if (Model == SFA.DAS.ApprenticePortal.SharedUi.GoogleAnalytics.GoogleAnalyt } - } \ No newline at end of file diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml b/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml index bff4db4a..93eca838 100644 --- a/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Views/Shared/_Layout.cshtml @@ -22,7 +22,6 @@ y = l.getElementsByTagName(r)[0]; y.parentNode.insertBefore(t, y); })(window, document, "clarity", "script", "h8wk6eosjr"); - From f9c9ac542eeab9ea5e565e8bb1c89b410b68df45 Mon Sep 17 00:00:00 2001 From: tdavande <113100339+tdavande@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:56:57 +0000 Subject: [PATCH 5/5] missing image fix for local development environment --- .../Helpers/SecurityHeadersMiddleware.cs | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs b/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs index 84ab50b7..b0d11c10 100644 --- a/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs +++ b/src/SFA.DAS.ApprenticeApp.Pwa/Helpers/SecurityHeadersMiddleware.cs @@ -13,14 +13,19 @@ public class SecurityHeadersMiddleware public async Task InvokeAsync(HttpContext context) { const string dasCdn = "das-at-frnt-end.azureedge.net das-pp-frnt-end.azureedge.net das-mo-frnt-end.azureedge.net das-test-frnt-end.azureedge.net das-test2-frnt-end.azureedge.net das-prd-frnt-end.azureedge.net"; - context.Response.Headers.Add("Content-Security-Policy", - new StringValues( - $"script-src 'self' 'unsafe-inline' 'unsafe-eval' {dasCdn} https://www.googletagmanager.com https://tagmanager.google.com https://www.google-analytics.com https://ssl.google-analytics.com ; " + - $"style-src 'self' 'unsafe-inline' {dasCdn} https://tagmanager.google.com https://fonts.googleapis.com ; " + - $"img-src {dasCdn} www.googletagmanager.com https://ssl.gstatic.com https://www.gstatic.com https://www.google-analytics.com ; " + - $"font-src {dasCdn} https://fonts.gstatic.com ;" + - "connect-src https://www.google-analytics.com ;" + - "frame-src https://www.googletagmanager.com")); + + if (!context.Response.Headers.ContainsKey("Content-Security-Policy")) + { + context.Response.Headers.Add("Content-Security-Policy", + new StringValues( + $"script-src 'self' 'unsafe-inline' 'unsafe-eval' {dasCdn} https://www.googletagmanager.com https://tagmanager.google.com https://www.google-analytics.com https://ssl.google-analytics.com ; " + + $"style-src 'self' 'unsafe-inline' {dasCdn} https://tagmanager.google.com https://fonts.googleapis.com ; " + + $"img-src 'self' {dasCdn} www.googletagmanager.com https://ssl.gstatic.com https://www.gstatic.com https://www.google-analytics.com ; " + + $"font-src 'self' {dasCdn} https://fonts.gstatic.com https://localhost:* ; " + + $"connect-src 'self' ws://localhost:* wss://localhost:* http://localhost:* https://localhost:* {dasCdn} https://www.google-analytics.com ; " + + $"frame-src https://www.googletagmanager.com")); + } + await _next(context); } }