Skip to content

Commit 99f352a

Browse files
authored
javiercn/check-integrity-validation (#2052)
1 parent b56dc07 commit 99f352a

File tree

2 files changed

+40
-11
lines changed

2 files changed

+40
-11
lines changed

src/UI/Areas/Identity/Pages/V3/_Layout.cshtml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,17 @@
6767
asp-fallback-src="~/Identity/lib/jquery/dist/jquery.min.js"
6868
asp-fallback-test="window.jQuery"
6969
crossorigin="anonymous"
70-
integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT">
70+
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
7171
</script>
7272
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"
7373
asp-fallback-src="~/Identity/lib/bootstrap/dist/js/bootstrap.min.js"
7474
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
7575
crossorigin="anonymous"
76-
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa">
76+
integrity="sha256-U5ZEeKfGNOja007MMD3YBI0A3OSZOQbeG6z2f2Y0hu8=">
7777
</script>
7878
<script src="~/Identity/js/site.js" asp-append-version="true"></script>
7979
</environment>
8080

8181
@RenderSection("Scripts", required: false)
8282
</body>
83-
</html>
83+
</html>

test/Identity.Test/IdentityUIScriptsTest.cs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Linq;
1010
using System.Net.Http;
1111
using System.Security.Cryptography;
12+
using System.Threading;
1213
using System.Threading.Tasks;
1314
using Xunit;
1415
using Xunit.Abstractions;
@@ -23,7 +24,7 @@ public class IdentityUIScriptsTest : IDisposable
2324
public IdentityUIScriptsTest(ITestOutputHelper output)
2425
{
2526
_output = output;
26-
_httpClient = new HttpClient();
27+
_httpClient = new HttpClient(new RetryHandler(new HttpClientHandler() { }));
2728
}
2829

2930
public static IEnumerable<object[]> ScriptWithIntegrityData
@@ -40,15 +41,18 @@ public static IEnumerable<object[]> ScriptWithIntegrityData
4041
[MemberData(nameof(ScriptWithIntegrityData))]
4142
public async Task IdentityUI_ScriptTags_SubresourceIntegrityCheck(ScriptTag scriptTag)
4243
{
43-
string expectedIntegrity;
44+
var sha256Integrity = await GetShaIntegrity(scriptTag, SHA256.Create(), "sha256");
45+
Assert.Equal(scriptTag.Integrity, sha256Integrity);
46+
}
47+
48+
private async Task<string> GetShaIntegrity(ScriptTag scriptTag, HashAlgorithm algorithm, string prefix)
49+
{
4450
using (var respStream = await _httpClient.GetStreamAsync(scriptTag.Src))
4551
using (var alg = SHA256.Create())
4652
{
4753
var hash = alg.ComputeHash(respStream);
48-
expectedIntegrity = "sha256-" + Convert.ToBase64String(hash);
54+
return $"{prefix}-" + Convert.ToBase64String(hash);
4955
}
50-
51-
Assert.Equal(expectedIntegrity, scriptTag.Integrity);
5256
}
5357

5458
public static IEnumerable<object[]> ScriptWithFallbackSrcData
@@ -66,7 +70,7 @@ public static IEnumerable<object[]> ScriptWithFallbackSrcData
6670
public async Task IdentityUI_ScriptTags_FallbackSourceContent_Matches_CDNContent(ScriptTag scriptTag)
6771
{
6872
var slnDir = GetSolutionDir();
69-
var wwwrootDir = Path.Combine(slnDir, "src", "UI", "wwwroot", "V4");
73+
var wwwrootDir = Path.Combine(slnDir, "src", "UI", "wwwroot", scriptTag.Version);
7074

7175
var cdnContent = await _httpClient.GetStringAsync(scriptTag.Src);
7276
var fallbackSrcContent = File.ReadAllText(
@@ -77,6 +81,7 @@ public async Task IdentityUI_ScriptTags_FallbackSourceContent_Matches_CDNContent
7781

7882
public struct ScriptTag
7983
{
84+
public string Version;
8085
public string Src;
8186
public string Integrity;
8287
public string FallbackSrc;
@@ -91,8 +96,9 @@ public override string ToString()
9196
private static List<ScriptTag> GetScriptTags()
9297
{
9398
var slnDir = GetSolutionDir();
94-
var uiDir = Path.Combine(slnDir, "src", "UI", "Areas", "Identity", "Pages", "V4");
95-
var cshtmlFiles = Directory.GetFiles(uiDir, "*.cshtml", SearchOption.AllDirectories);
99+
var uiDirV3 = Path.Combine(slnDir, "src", "UI", "Areas", "Identity", "Pages", "V3");
100+
var uiDirV4 = Path.Combine(slnDir, "src", "UI", "Areas", "Identity", "Pages", "V4");
101+
var cshtmlFiles = GetRazorFiles(uiDirV3).Concat(GetRazorFiles(uiDirV4));
96102

97103
var scriptTags = new List<ScriptTag>();
98104
foreach (var cshtmlFile in cshtmlFiles)
@@ -104,6 +110,8 @@ private static List<ScriptTag> GetScriptTags()
104110
Assert.NotEmpty(scriptTags);
105111

106112
return scriptTags;
113+
114+
IEnumerable<string> GetRazorFiles(string dir) => Directory.GetFiles(dir, "*.cshtml", SearchOption.AllDirectories);
107115
}
108116

109117
private static List<ScriptTag> GetScriptTags(string cshtmlFile)
@@ -123,6 +131,7 @@ private static List<ScriptTag> GetScriptTags(string cshtmlFile)
123131

124132
scriptTags.Add(new ScriptTag
125133
{
134+
Version = cshtmlFile.Contains("V3") ? "V3" : "V4",
126135
Src = scriptElement.Source,
127136
Integrity = scriptElement.Integrity,
128137
FallbackSrc = fallbackSrcAttribute?.Value,
@@ -155,5 +164,25 @@ public void Dispose()
155164
{
156165
_httpClient.Dispose();
157166
}
167+
168+
class RetryHandler : DelegatingHandler
169+
{
170+
public RetryHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }
171+
172+
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
173+
{
174+
HttpResponseMessage result = null;
175+
for (var i = 0; i < 10; i++)
176+
{
177+
result = await base.SendAsync(request, cancellationToken);
178+
if (result.IsSuccessStatusCode)
179+
{
180+
return result;
181+
}
182+
await Task.Delay(1000);
183+
}
184+
return result;
185+
}
186+
}
158187
}
159188
}

0 commit comments

Comments
 (0)