Skip to content

Commit

Permalink
Fixed issue with cookies not being removed if users reject them. Upda…
Browse files Browse the repository at this point in the history
…ted tests
  • Loading branch information
sam-c-dfe committed Jan 16, 2025
1 parent 96c65f5 commit 7bb5507
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,12 @@ public static class CookieKeyNames
public const string UserJourneyKey = "user_journey";

public const string CookiesPreferenceKey = "cookies_preferences_set";

public const string ClarityUserIdKey = "_clck";

public const string ClaritySessionKey = "_clsk";

public const string GoogleAnalyticsKey = "_ga";

public const string GoogleAnalyticsSessionStateKey = "_ga_";
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,20 @@ public class CookiesPreferenceService(ICookieManager cookieManager) : ICookiesPr
public void SetVisibility(bool visibility)
{
var currentCookie = GetCookie();
DeleteCookie();
DeleteCookie(CookieKeyNames.CookiesPreferenceKey);
CreateCookie(CookieKeyNames.CookiesPreferenceKey, currentCookie.HasApproved, visibility,
currentCookie.IsRejected);
}

public void RejectCookies()
{
DeleteCookie();
DeleteCookie(CookieKeyNames.CookiesPreferenceKey);
// Delete any remaining GA or Clarity cookies too
DeleteCookie(CookieKeyNames.ClarityUserIdKey);
DeleteCookie(CookieKeyNames.ClaritySessionKey);
DeleteCookie(CookieKeyNames.GoogleAnalyticsKey);
DeleteGoogleAnalyticSessionStateCookie();

CreateCookie(CookieKeyNames.CookiesPreferenceKey, false, true, true);
}

Expand Down Expand Up @@ -50,9 +56,9 @@ public DfeCookie GetCookie()
}
}

private void DeleteCookie()
private void DeleteCookie(string key)
{
cookieManager.DeleteOutboundCookie(CookieKeyNames.CookiesPreferenceKey);
cookieManager.DeleteOutboundCookie(key);
}

private void CreateCookie(string key, bool value, bool visibility = true, bool rejected = false)
Expand All @@ -69,4 +75,15 @@ private void CreateCookie(string key, bool value, bool visibility = true, bool r

cookieManager.SetOutboundCookie(key, serializedCookie, cookieOptions);
}

private void DeleteGoogleAnalyticSessionStateCookie()
{
var allCookies = cookieManager.ReadInboundCookies();
var gaSessionStateCookie =
allCookies?.Keys.FirstOrDefault(x => x.StartsWith(CookieKeyNames.GoogleAnalyticsSessionStateKey));
if (gaSessionStateCookie != null)
{
DeleteCookie(gaSessionStateCookie);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("A spec that checks for security headers in the response", () => {
);
expect(response.headers).to.have.property(
"content-security-policy",
"script-src 'self' 'sha256-2eCA8tPChvVMeSRvRNqlmBco1wRmAKXWVzJ8Vpb9S6Y=' 'sha256-VAoCuOmBv4C4V/WthoGzlhYyYpWir44ETG7WKh+3kG8=' 'sha256-Om9RNNoMrdmIZzT4Oo7KaozVNUg6zYxVQuq3CPld2Ms=' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' 'sha256-lD2YLKoqlgPJ6bMRB0gZKeUdZqwszfrRSmAnzX0TSls=' 'sha256-1f+6vEGZewP7dkvrYIBD4bqMLOhumfg10mwfKd2jU7I=' 'sha256-LBWtLNxa0f5+6KBUNLCp8JXVP7YuPtJtEt1Ku3cCKdY=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js https://www.clarity.ms/ https://c.bing.com;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com https://*.clarity.ms/collect;block-all-mixed-content;upgrade-insecure-requests;"
"script-src 'self' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js https://www.clarity.ms/ https://c.bing.com;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com https://*.clarity.ms/collect;block-all-mixed-content;upgrade-insecure-requests;"
);
expect(response.headers).to.have.property(
"cross-origin-resource-policy",
Expand Down Expand Up @@ -62,7 +62,7 @@ describe("A spec that checks for security headers in the response", () => {
);
expect(response.headers).to.have.property(
"content-security-policy",
"script-src 'self' 'sha256-2eCA8tPChvVMeSRvRNqlmBco1wRmAKXWVzJ8Vpb9S6Y=' 'sha256-VAoCuOmBv4C4V/WthoGzlhYyYpWir44ETG7WKh+3kG8=' 'sha256-Om9RNNoMrdmIZzT4Oo7KaozVNUg6zYxVQuq3CPld2Ms=' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' 'sha256-lD2YLKoqlgPJ6bMRB0gZKeUdZqwszfrRSmAnzX0TSls=' 'sha256-1f+6vEGZewP7dkvrYIBD4bqMLOhumfg10mwfKd2jU7I=' 'sha256-LBWtLNxa0f5+6KBUNLCp8JXVP7YuPtJtEt1Ku3cCKdY=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js https://www.clarity.ms/ https://c.bing.com;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com https://*.clarity.ms/collect;block-all-mixed-content;upgrade-insecure-requests;"
"script-src 'self' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js https://www.clarity.ms/ https://c.bing.com;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com https://*.clarity.ms/collect;block-all-mixed-content;upgrade-insecure-requests;"
);
expect(response.headers).to.have.property(
"cross-origin-resource-policy",
Expand Down Expand Up @@ -96,7 +96,7 @@ describe("A spec that checks for security headers in the response", () => {
);
expect(response.headers).to.have.property(
"content-security-policy",
"script-src 'self' 'sha256-2eCA8tPChvVMeSRvRNqlmBco1wRmAKXWVzJ8Vpb9S6Y=' 'sha256-VAoCuOmBv4C4V/WthoGzlhYyYpWir44ETG7WKh+3kG8=' 'sha256-Om9RNNoMrdmIZzT4Oo7KaozVNUg6zYxVQuq3CPld2Ms=' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' 'sha256-lD2YLKoqlgPJ6bMRB0gZKeUdZqwszfrRSmAnzX0TSls=' 'sha256-1f+6vEGZewP7dkvrYIBD4bqMLOhumfg10mwfKd2jU7I=' 'sha256-LBWtLNxa0f5+6KBUNLCp8JXVP7YuPtJtEt1Ku3cCKdY=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js https://www.clarity.ms/ https://c.bing.com;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com https://*.clarity.ms/collect;block-all-mixed-content;upgrade-insecure-requests;"
"script-src 'self' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js https://www.clarity.ms/ https://c.bing.com;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com https://*.clarity.ms/collect;block-all-mixed-content;upgrade-insecure-requests;"
);
expect(response.headers).to.have.property(
"cross-origin-resource-policy",
Expand Down Expand Up @@ -139,7 +139,7 @@ describe("A spec that checks for security headers in the response", () => {
);
expect(response.headers).to.have.property(
"content-security-policy",
"script-src 'self' 'sha256-2eCA8tPChvVMeSRvRNqlmBco1wRmAKXWVzJ8Vpb9S6Y=' 'sha256-VAoCuOmBv4C4V/WthoGzlhYyYpWir44ETG7WKh+3kG8=' 'sha256-Om9RNNoMrdmIZzT4Oo7KaozVNUg6zYxVQuq3CPld2Ms=' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' 'sha256-lD2YLKoqlgPJ6bMRB0gZKeUdZqwszfrRSmAnzX0TSls=' 'sha256-1f+6vEGZewP7dkvrYIBD4bqMLOhumfg10mwfKd2jU7I=' 'sha256-LBWtLNxa0f5+6KBUNLCp8JXVP7YuPtJtEt1Ku3cCKdY=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js https://www.clarity.ms/ https://c.bing.com;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com https://*.clarity.ms/collect;block-all-mixed-content;upgrade-insecure-requests;"
"script-src 'self' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js https://www.clarity.ms/ https://c.bing.com;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com https://*.clarity.ms/collect;block-all-mixed-content;upgrade-insecure-requests;"
);
expect(response.headers).to.have.property(
"cross-origin-resource-policy",
Expand Down Expand Up @@ -176,7 +176,7 @@ describe("A spec that checks for security headers in the response", () => {
);
expect(response.headers).to.have.property(
"content-security-policy",
"script-src 'self' 'sha256-2eCA8tPChvVMeSRvRNqlmBco1wRmAKXWVzJ8Vpb9S6Y=' 'sha256-VAoCuOmBv4C4V/WthoGzlhYyYpWir44ETG7WKh+3kG8=' 'sha256-Om9RNNoMrdmIZzT4Oo7KaozVNUg6zYxVQuq3CPld2Ms=' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' 'sha256-lD2YLKoqlgPJ6bMRB0gZKeUdZqwszfrRSmAnzX0TSls=' 'sha256-1f+6vEGZewP7dkvrYIBD4bqMLOhumfg10mwfKd2jU7I=' 'sha256-LBWtLNxa0f5+6KBUNLCp8JXVP7YuPtJtEt1Ku3cCKdY=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js https://www.clarity.ms/ https://c.bing.com;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com https://*.clarity.ms/collect;block-all-mixed-content;upgrade-insecure-requests;"
"script-src 'self' 'unsafe-hashes' 'sha256-GUQ5ad8JK5KmEWmROf3LZd9ge94daqNvd8xy9YS1iDw=' 'sha256-l5MP+9OapFXGxjKMNj/89ExAW2TvAFFoADrbsmtSJXo=' https://www.googletagmanager.com/gtm.js https://www.googletagmanager.com/gtag/js https://www.clarity.ms/ https://c.bing.com;object-src 'self';frame-ancestors https://app.contentful.com;connect-src *.google-analytics.com https://*.clarity.ms/collect;block-all-mixed-content;upgrade-insecure-requests;"
);
expect(response.headers).to.have.property(
"cross-origin-resource-policy",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
using Dfe.EarlyYearsQualification.Web.Constants;
using Dfe.EarlyYearsQualification.Web.Services.Cookies;
using Dfe.EarlyYearsQualification.Web.Services.CookiesPreferenceService;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Moq;

namespace Dfe.EarlyYearsQualification.UnitTests.Services;

[TestClass]
public class CookieServiceTests
{
private const string FakeGoogleAnalyticsSessionCookie = "_ga_TEST";

[TestMethod]
[DataRow(true)]
[DataRow(false)]
Expand Down Expand Up @@ -45,7 +45,11 @@ public void RejectCookies_MethodCalled_SetsCorrectCookie()

cookieService.RejectCookies();

mockContext.Verify(x => x.DeleteOutboundCookie("cookies_preferences_set"), Times.Once);
mockContext.Verify(x => x.DeleteOutboundCookie(CookieKeyNames.ClaritySessionKey), Times.Once);
mockContext.Verify(x => x.DeleteOutboundCookie(CookieKeyNames.ClarityUserIdKey), Times.Once);
mockContext.Verify(x => x.DeleteOutboundCookie(CookieKeyNames.GoogleAnalyticsKey), Times.Once);
mockContext.Verify(x => x.DeleteOutboundCookie(FakeGoogleAnalyticsSessionCookie), Times.Once);
mockContext.Verify(x => x.DeleteOutboundCookie(CookieKeyNames.CookiesPreferenceKey), Times.Once);

var serializedCookieToCheck = JsonSerializer.Serialize(new DfeCookie
{
Expand Down Expand Up @@ -159,7 +163,7 @@ private static Mock<ICookieManager> SetContextWithPreferenceCookie(DfeCookie mod

var mockManager = new Mock<ICookieManager>();

var cookies = new Dictionary<string, string> { { CookieKeyNames.CookiesPreferenceKey, serializedModel } };
var cookies = new Dictionary<string, string> { { CookieKeyNames.CookiesPreferenceKey, serializedModel }, { FakeGoogleAnalyticsSessionCookie, "test" } };

mockManager.Setup(m => m.ReadInboundCookies())
.Returns(cookies);
Expand Down

0 comments on commit 7bb5507

Please sign in to comment.