Fixed sha-integrity content of script tags in IdentityUI's cshtml files
Related to https://github.com/aspnet/templating/issues/520
This commit is contained in:
parent
e306b8680e
commit
5403ec47ec
|
|
@ -67,7 +67,7 @@
|
||||||
asp-fallback-src="~/Identity/lib/jquery/dist/jquery.min.js"
|
asp-fallback-src="~/Identity/lib/jquery/dist/jquery.min.js"
|
||||||
asp-fallback-test="window.jQuery"
|
asp-fallback-test="window.jQuery"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk">
|
integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT">
|
||||||
</script>
|
</script>
|
||||||
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
|
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
|
||||||
asp-fallback-src="~/Identity/lib/bootstrap/dist/js/bootstrap.min.js"
|
asp-fallback-src="~/Identity/lib/bootstrap/dist/js/bootstrap.min.js"
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,12 @@
|
||||||
asp-fallback-src="~/Identity/lib/jquery-validation/dist/jquery.validate.min.js"
|
asp-fallback-src="~/Identity/lib/jquery-validation/dist/jquery.validate.min.js"
|
||||||
asp-fallback-test="window.jQuery && window.jQuery.validator"
|
asp-fallback-test="window.jQuery && window.jQuery.validator"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
integrity="sha384-Fnqn3nxp3506LP/7Y3j/25BlWeA3PXTyT1l78LjECcPaKCV12TsZP7yyMxOe/G/k">
|
integrity="sha384-rZfj/ogBloos6wzLGpPkkOr/gpkBNLZ6b6yLy4o+ok+t/SAKlL5mvXLr0OXNi1Hp">
|
||||||
</script>
|
</script>
|
||||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.9/jquery.validate.unobtrusive.min.js"
|
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.9/jquery.validate.unobtrusive.min.js"
|
||||||
asp-fallback-src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
|
asp-fallback-src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
|
||||||
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
|
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
integrity="sha384-JrXK+k53HACyavUKOsL+NkmSesD2P+73eDMrbTtTk0h4RmOF8hF8apPlkp26JlyH">
|
integrity="sha384-ifv0TYDWxBHzvAk2Z0n8R434FL1Rlv/Av18DXE43N/1rvHyOG4izKst0f2iSLdds">
|
||||||
</script>
|
</script>
|
||||||
</environment>
|
</environment>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Identity.Test
|
||||||
|
{
|
||||||
|
public class CdnScriptTagTests
|
||||||
|
{
|
||||||
|
private readonly ITestOutputHelper _output;
|
||||||
|
|
||||||
|
public CdnScriptTagTests(ITestOutputHelper output)
|
||||||
|
{
|
||||||
|
_output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task IdentityUI_ScriptTags_SubresourceIntegrityCheck()
|
||||||
|
{
|
||||||
|
var slnDir = GetSolutionDir();
|
||||||
|
var sourceDir = Path.Combine(slnDir, "src", "UI");
|
||||||
|
var cshtmlFiles = Directory.GetFiles(sourceDir, "*.cshtml", SearchOption.AllDirectories);
|
||||||
|
|
||||||
|
var scriptTags = new List<ScriptTag>();
|
||||||
|
foreach (var cshtmlFile in cshtmlFiles)
|
||||||
|
{
|
||||||
|
scriptTags.AddRange(GetScriptTags(cshtmlFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.NotEmpty(scriptTags);
|
||||||
|
|
||||||
|
var shasum = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
using (var client = new HttpClient())
|
||||||
|
{
|
||||||
|
foreach (var script in scriptTags)
|
||||||
|
{
|
||||||
|
if (shasum.ContainsKey(script.Src))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var resp = await client.GetStreamAsync(script.Src))
|
||||||
|
using (var alg = SHA384.Create())
|
||||||
|
{
|
||||||
|
var hash = alg.ComputeHash(resp);
|
||||||
|
shasum.Add(script.Src, "sha384-" + Convert.ToBase64String(hash));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.All(scriptTags, t =>
|
||||||
|
{
|
||||||
|
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}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct ScriptTag
|
||||||
|
{
|
||||||
|
public string Src;
|
||||||
|
public string Integrity;
|
||||||
|
public string FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Regex _scriptRegex = new Regex(@"<script[^>]*src=""(?'src'http[^""]+)""[^>]*integrity=""(?'integrity'[^""]+)""([^>]*)>", RegexOptions.Multiline);
|
||||||
|
|
||||||
|
private IEnumerable<ScriptTag> GetScriptTags(string cshtmlFile)
|
||||||
|
{
|
||||||
|
string contents;
|
||||||
|
using (var reader = new StreamReader(File.OpenRead(cshtmlFile)))
|
||||||
|
{
|
||||||
|
contents = reader.ReadToEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
var match = _scriptRegex.Match(contents);
|
||||||
|
while (match != null && match != Match.Empty)
|
||||||
|
{
|
||||||
|
var tag = new ScriptTag
|
||||||
|
{
|
||||||
|
Src = match.Groups["src"].Value,
|
||||||
|
Integrity = match.Groups["integrity"].Value,
|
||||||
|
FileName = Path.GetFileName(cshtmlFile)
|
||||||
|
};
|
||||||
|
yield return tag;
|
||||||
|
_output.WriteLine($"Found script tag in '{tag.FileName}', src='{tag.Src}' integrity='{tag.Integrity}'");
|
||||||
|
match = match.NextMatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetSolutionDir()
|
||||||
|
{
|
||||||
|
var dir = new DirectoryInfo(AppContext.BaseDirectory);
|
||||||
|
while (dir != null)
|
||||||
|
{
|
||||||
|
if (File.Exists(Path.Combine(dir.FullName, "Identity.sln")))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dir = dir.Parent;
|
||||||
|
}
|
||||||
|
return dir.FullName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue