From dd96df7b4f674b45d412d3519e8d646feb8d0a11 Mon Sep 17 00:00:00 2001 From: Lanaparezanin Date: Fri, 19 Dec 2025 13:41:11 -0800 Subject: [PATCH 1/5] Cookie fix --- .../Infrastructure/CookieTempDataProvider.cs | 39 +++++++++++++++---- .../CookieTempDataProviderFacts.cs | 1 + 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs b/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs index 4444c0d33d..4389b68fd3 100644 --- a/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs +++ b/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs @@ -94,14 +94,18 @@ protected virtual IDictionary LoadTempData(ControllerContext con //silently ignore incorrect cookie values } - if (_httpContext.Response != null && _httpContext.Response.Cookies != null) + // Only clear the cookie if it was present in the request + if (cookie != null && _httpContext.Response != null && _httpContext.Response.Cookies != null) { - var responseCookie = _httpContext.Response.Cookies.Get(TempDataCookieKey); - if (responseCookie != null) + var responseCookie = new HttpCookie(TempDataCookieKey) { - responseCookie.Expires = DateTime.MinValue; - responseCookie.Value = String.Empty; - } + Expires = DateTime.UtcNow.AddDays(-1), + Value = String.Empty, + HttpOnly = true, + Secure = true, + SameSite = SameSiteMode.Lax + }; + _httpContext.Response.Cookies.Add(responseCookie); } return dictionary; @@ -109,7 +113,12 @@ protected virtual IDictionary LoadTempData(ControllerContext con protected virtual void SaveTempData(ControllerContext controllerContext, IDictionary values) { - if (values.Count > 0) + // Only save TempData as a cookie if the user has consented or if there was already a TempData cookie + // This prevents setting non-essential cookies without user consent + var hasExistingCookie = _httpContext.Request?.Cookies[TempDataCookieKey] != null; + var canWriteCookies = CanWriteNonEssentialCookies(); + + if (values.Count > 0 && (hasExistingCookie || canWriteCookies)) { // Serialize dictionary to JSON string json = JsonConvert.SerializeObject(values); @@ -121,10 +130,24 @@ protected virtual void SaveTempData(ControllerContext controllerContext, IDictio var cookie = new HttpCookie(TempDataCookieKey, protectedJson) { HttpOnly = true, - Secure = true + Secure = true, + SameSite = SameSiteMode.Lax }; _httpContext.Response.Cookies.Add(cookie); } } + + private bool CanWriteNonEssentialCookies() + { + // Check if cookie consent has been granted + // This uses the same mechanism as the CookieComplianceHttpModule + if (_httpContext?.Items?[ServicesConstants.CookieComplianceCanWriteAnalyticsCookies] is bool canWrite) + { + return canWrite; + } + + // If consent information is not available, default to false for safety + return false; + } } } diff --git a/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs b/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs index 5d46322d96..dfc31f4d9b 100644 --- a/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs +++ b/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs @@ -140,6 +140,7 @@ public void StoresValuesInCookieInEncodedFormat() var cookie = cookies["__Controller::TempData"]; Assert.True(cookie.HttpOnly); Assert.True(cookie.Secure); + Assert.Equal(SameSiteMode.Lax, cookie.SameSite); // Decrypt and deserialize the cookie value var unprotectedBytes = MachineKey.Unprotect(Convert.FromBase64String(cookie.Value), "__Controller::TempData"); From d193aa9d76771bc6eae066d209403c47c49ec2a2 Mon Sep 17 00:00:00 2001 From: Lanaparezanin Date: Fri, 30 Jan 2026 11:28:31 -0800 Subject: [PATCH 2/5] Removed unnecessary code --- .../Infrastructure/CookieTempDataProvider.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs b/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs index 4389b68fd3..9d05dbe0e5 100644 --- a/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs +++ b/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs @@ -95,17 +95,14 @@ protected virtual IDictionary LoadTempData(ControllerContext con } // Only clear the cookie if it was present in the request - if (cookie != null && _httpContext.Response != null && _httpContext.Response.Cookies != null) + if (_httpContext.Response != null && _httpContext.Response.Cookies != null) { - var responseCookie = new HttpCookie(TempDataCookieKey) + var responseCookie = _httpContext.Response.Cookies.Get(TempDataCookieKey); + if (responseCookie != null) { - Expires = DateTime.UtcNow.AddDays(-1), - Value = String.Empty, - HttpOnly = true, - Secure = true, - SameSite = SameSiteMode.Lax - }; - _httpContext.Response.Cookies.Add(responseCookie); + responseCookie.Expires = DateTime.MinValue; + responseCookie.Value = String.Empty; + } } return dictionary; From 5bd914f16f863ed3959b0620a06b0f208f397ee5 Mon Sep 17 00:00:00 2001 From: Lanaparezanin Date: Fri, 30 Jan 2026 11:32:09 -0800 Subject: [PATCH 3/5] Removed unnecessary comment --- src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs b/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs index 9d05dbe0e5..92bf59f9d5 100644 --- a/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs +++ b/src/NuGetGallery/Infrastructure/CookieTempDataProvider.cs @@ -94,7 +94,6 @@ protected virtual IDictionary LoadTempData(ControllerContext con //silently ignore incorrect cookie values } - // Only clear the cookie if it was present in the request if (_httpContext.Response != null && _httpContext.Response.Cookies != null) { var responseCookie = _httpContext.Response.Cookies.Get(TempDataCookieKey); From 301c0ab9456d538e4aed27d0ee2f0d67deedebfb Mon Sep 17 00:00:00 2001 From: Lanaparezanin Date: Fri, 30 Jan 2026 11:51:52 -0800 Subject: [PATCH 4/5] Testfix --- .../Infrastructure/CookieTempDataProviderFacts.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs b/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs index dfc31f4d9b..ccbcb0c904 100644 --- a/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs +++ b/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs @@ -124,7 +124,16 @@ public void StoresValuesInCookieInEncodedFormat() { var cookies = new HttpCookieCollection(); var httpContext = new Mock(); + + // Mock the Items collection and set the consent flag + var items = new System.Collections.Generic.Dictionary + { + [ServicesConstants.CookieComplianceCanWriteAnalyticsCookies] = true + }; + httpContext.Setup(c => c.Items).Returns(items); + httpContext.Setup(c => c.Request.Cookies).Returns(new HttpCookieCollection()); httpContext.Setup(c => c.Response.Cookies).Returns(cookies); + ITempDataProvider provider = new CookieTempDataProvider(httpContext.Object); var controllerContext = new ControllerContext(); From a8c287ce2b73cf2bd815f0383bc655a7590337cc Mon Sep 17 00:00:00 2001 From: Lanaparezanin Date: Fri, 30 Jan 2026 11:53:05 -0800 Subject: [PATCH 5/5] Nits --- .../Infrastructure/CookieTempDataProviderFacts.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs b/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs index ccbcb0c904..aea13f3356 100644 --- a/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs +++ b/tests/NuGetGallery.Facts/Infrastructure/CookieTempDataProviderFacts.cs @@ -124,8 +124,6 @@ public void StoresValuesInCookieInEncodedFormat() { var cookies = new HttpCookieCollection(); var httpContext = new Mock(); - - // Mock the Items collection and set the consent flag var items = new System.Collections.Generic.Dictionary { [ServicesConstants.CookieComplianceCanWriteAnalyticsCookies] = true @@ -133,7 +131,6 @@ public void StoresValuesInCookieInEncodedFormat() httpContext.Setup(c => c.Items).Returns(items); httpContext.Setup(c => c.Request.Cookies).Returns(new HttpCookieCollection()); httpContext.Setup(c => c.Response.Cookies).Returns(cookies); - ITempDataProvider provider = new CookieTempDataProvider(httpContext.Object); var controllerContext = new ControllerContext();