Skip to content

Commit 5403ec4

Browse files
committed
Fixed sha-integrity content of script tags in IdentityUI's cshtml files
Related to aspnet/Templating#520
1 parent e306b86 commit 5403ec4

File tree

3 files changed

+114
-3
lines changed

3 files changed

+114
-3
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
asp-fallback-src="~/Identity/lib/jquery/dist/jquery.min.js"
6868
asp-fallback-test="window.jQuery"
6969
crossorigin="anonymous"
70-
integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk">
70+
integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT">
7171
</script>
7272
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
7373
asp-fallback-src="~/Identity/lib/bootstrap/dist/js/bootstrap.min.js"

src/UI/Areas/Identity/Pages/_ValidationScriptsPartial.cshtml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
asp-fallback-src="~/Identity/lib/jquery-validation/dist/jquery.validate.min.js"
88
asp-fallback-test="window.jQuery && window.jQuery.validator"
99
crossorigin="anonymous"
10-
integrity="sha384-Fnqn3nxp3506LP/7Y3j/25BlWeA3PXTyT1l78LjECcPaKCV12TsZP7yyMxOe/G/k">
10+
integrity="sha384-rZfj/ogBloos6wzLGpPkkOr/gpkBNLZ6b6yLy4o+ok+t/SAKlL5mvXLr0OXNi1Hp">
1111
</script>
1212
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.9/jquery.validate.unobtrusive.min.js"
1313
asp-fallback-src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
1414
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
1515
crossorigin="anonymous"
16-
integrity="sha384-JrXK+k53HACyavUKOsL+NkmSesD2P+73eDMrbTtTk0h4RmOF8hF8apPlkp26JlyH">
16+
integrity="sha384-ifv0TYDWxBHzvAk2Z0n8R434FL1Rlv/Av18DXE43N/1rvHyOG4izKst0f2iSLdds">
1717
</script>
1818
</environment>
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Net.Http;
8+
using System.Security.Cryptography;
9+
using System.Text.RegularExpressions;
10+
using System.Threading.Tasks;
11+
using Xunit;
12+
using Xunit.Abstractions;
13+
14+
namespace Microsoft.AspNetCore.Identity.Test
15+
{
16+
public class CdnScriptTagTests
17+
{
18+
private readonly ITestOutputHelper _output;
19+
20+
public CdnScriptTagTests(ITestOutputHelper output)
21+
{
22+
_output = output;
23+
}
24+
25+
[Fact]
26+
public async Task IdentityUI_ScriptTags_SubresourceIntegrityCheck()
27+
{
28+
var slnDir = GetSolutionDir();
29+
var sourceDir = Path.Combine(slnDir, "src", "UI");
30+
var cshtmlFiles = Directory.GetFiles(sourceDir, "*.cshtml", SearchOption.AllDirectories);
31+
32+
var scriptTags = new List<ScriptTag>();
33+
foreach (var cshtmlFile in cshtmlFiles)
34+
{
35+
scriptTags.AddRange(GetScriptTags(cshtmlFile));
36+
}
37+
38+
Assert.NotEmpty(scriptTags);
39+
40+
var shasum = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
41+
using (var client = new HttpClient())
42+
{
43+
foreach (var script in scriptTags)
44+
{
45+
if (shasum.ContainsKey(script.Src))
46+
{
47+
continue;
48+
}
49+
50+
using (var resp = await client.GetStreamAsync(script.Src))
51+
using (var alg = SHA384.Create())
52+
{
53+
var hash = alg.ComputeHash(resp);
54+
shasum.Add(script.Src, "sha384-" + Convert.ToBase64String(hash));
55+
}
56+
}
57+
}
58+
59+
Assert.All(scriptTags, t =>
60+
{
61+
Assert.True(shasum[t.Src] == t.Integrity, userMessage: $"Expected integrity on script tag to be {shasum[t.Src]} but it was {t.Integrity}. {t.FileName}");
62+
});
63+
}
64+
65+
private struct ScriptTag
66+
{
67+
public string Src;
68+
public string Integrity;
69+
public string FileName;
70+
}
71+
72+
private static readonly Regex _scriptRegex = new Regex(@"<script[^>]*src=""(?'src'http[^""]+)""[^>]*integrity=""(?'integrity'[^""]+)""([^>]*)>", RegexOptions.Multiline);
73+
74+
private IEnumerable<ScriptTag> GetScriptTags(string cshtmlFile)
75+
{
76+
string contents;
77+
using (var reader = new StreamReader(File.OpenRead(cshtmlFile)))
78+
{
79+
contents = reader.ReadToEnd();
80+
}
81+
82+
var match = _scriptRegex.Match(contents);
83+
while (match != null && match != Match.Empty)
84+
{
85+
var tag = new ScriptTag
86+
{
87+
Src = match.Groups["src"].Value,
88+
Integrity = match.Groups["integrity"].Value,
89+
FileName = Path.GetFileName(cshtmlFile)
90+
};
91+
yield return tag;
92+
_output.WriteLine($"Found script tag in '{tag.FileName}', src='{tag.Src}' integrity='{tag.Integrity}'");
93+
match = match.NextMatch();
94+
}
95+
}
96+
97+
private static string GetSolutionDir()
98+
{
99+
var dir = new DirectoryInfo(AppContext.BaseDirectory);
100+
while (dir != null)
101+
{
102+
if (File.Exists(Path.Combine(dir.FullName, "Identity.sln")))
103+
{
104+
break;
105+
}
106+
dir = dir.Parent;
107+
}
108+
return dir.FullName;
109+
}
110+
}
111+
}

0 commit comments

Comments
 (0)