Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support new Fingerprint and Integrity metadata required in .NET 9 SDK Preview 4 #855

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 59 additions & 15 deletions src/Uno.Wasm.Bootstrap/StaticWebAssetsResolverTask.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// ******************************************************************

// ******************************************************************
// Copyright � 2015-2022 Uno Platform inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -22,6 +23,8 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Uno.Wasm.Bootstrap.Extensions;
Expand Down Expand Up @@ -70,20 +73,7 @@ public override bool Execute()
Log.LogMessage(MessageImportance.Low, $"Found {filteredAssets.Length} filtered assets");

StaticWebAsset =
filteredAssets.Select(asset =>
new TaskItem(asset, new Dictionary<string, string>
{
["SourceType"] = "Discovered",
["SourceId"] = AssemblyName,
["ContentRoot"] = fixedDistPath,
["RelativePath"] = asset.Replace(fixedDistPath, ""),
["BasePath"] = WebAppBasePath is { Length: > 0 } ? WebAppBasePath : "/",
["AssetKind"] = "All",
["AssetMode"] = "All",
["AssetRole"] = "Primary",
["OriginalItemSpec"] = asset,
}
))
filteredAssets.Select(asset => new TaskItem(asset, GetMetadata(asset, fixedDistPath)))
.ToArray();
}
else
Expand All @@ -93,4 +83,58 @@ public override bool Execute()

return true;
}

private Dictionary<string, string> GetMetadata(string asset, string fixedDistPath)
{
var dict = new Dictionary<string, string>
{
["SourceType"] = "Discovered",
["SourceId"] = AssemblyName,
["ContentRoot"] = fixedDistPath,
["RelativePath"] = asset.Replace(fixedDistPath, ""),
["BasePath"] = WebAppBasePath is { Length: > 0 } ? WebAppBasePath : "/",
["AssetKind"] = "All",
["AssetMode"] = "All",
["AssetRole"] = "Primary",
["OriginalItemSpec"] = asset,
};

var (fingerprint, integrity) = ComputeFingerprintAndIntegrity(asset, asset);
dict.Add("Fingerprint", fingerprint);
dict.Add("Integrity", integrity);
return dict;
}

// https://github.com/dotnet/sdk/blob/cc17704acfbee4b2ef49a82aa6f65aaa9cafffef/src/StaticWebAssetsSdk/Tasks/Data/StaticWebAsset.cs#L233-L248
private static (string fingerprint, string integrity) ComputeFingerprintAndIntegrity(string identity, string originalItemSpec)
{
using var file = File.Exists(identity) ?
File.OpenRead(identity) :
(File.Exists(originalItemSpec) ?
File.OpenRead(originalItemSpec) :
throw new InvalidOperationException($"No file exists for the asset at either location '{identity}' or '{originalItemSpec}'."));

#if NET6_0_OR_GREATER
var hash = SHA256.HashData(file);
#else
using var sha = SHA256.Create();
var hash = sha.ComputeHash(file);
#endif
return (ToBase36(hash), Convert.ToBase64String(hash));
}

private static string ToBase36(byte[] hash)
{
const string chars = "0123456789abcdefghijklmnopqrstuvwxyz";

var result = new char[10];
var dividend = BigInteger.Abs(new BigInteger(hash.AsSpan().Slice(0, 9).ToArray()));
for (var i = 0; i < 10; i++)
{
dividend = BigInteger.DivRem(dividend, 36, out var remainder);
result[i] = chars[(int)remainder];
}

return new string(result);
}
}
Loading