From 5c1c864bb3016e60e8bf61bd1e28d1d60d57c7e3 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 2 Mar 2023 14:31:20 +0100 Subject: [PATCH 1/5] hash assets and IL check --- src/mono/wasm/runtime/assets.ts | 10 +- src/mono/wasm/runtime/dotnet.d.ts | 4 + src/mono/wasm/runtime/types.ts | 4 + src/tasks/WasmAppBuilder/WasmAppBuilder.cs | 137 ++++++++++++++---- .../WasmAppBuilder/WasmAppBuilder.csproj | 1 + 5 files changed, 124 insertions(+), 32 deletions(-) diff --git a/src/mono/wasm/runtime/assets.ts b/src/mono/wasm/runtime/assets.ts index 38544d0d94894c..30b43d61c84124 100644 --- a/src/mono/wasm/runtime/assets.ts +++ b/src/mono/wasm/runtime/assets.ts @@ -74,7 +74,7 @@ export function get_preferred_icu_asset(): string | null { return OTHERS; } -export function shouldLoadIcuAsset(asset : AssetEntryInternal, preferredIcuAsset: string | null) : boolean{ +export function shouldLoadIcuAsset(asset: AssetEntryInternal, preferredIcuAsset: string | null): boolean { return !(asset.behavior == "icu" && asset.name != preferredIcuAsset); } @@ -293,6 +293,14 @@ async function start_asset_download_sources(asset: AssetEntryInternal): Promise< return response; } catch (err) { + if (!response) { + response = { + ok: false, + url: attemptUrl, + status: 0, + statusText: "" + err, + } as any; + } continue; //next source } } diff --git a/src/mono/wasm/runtime/dotnet.d.ts b/src/mono/wasm/runtime/dotnet.d.ts index bcfce611388fee..d6e84c710f1c41 100644 --- a/src/mono/wasm/runtime/dotnet.d.ts +++ b/src/mono/wasm/runtime/dotnet.d.ts @@ -132,6 +132,10 @@ type MonoConfig = { * initial number of workers to add to the emscripten pthread pool */ pthreadPoolSize?: number; + /** + * hash of assets + */ + assetsHash?: string; }; interface ResourceRequest { name: string; diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts index 1de2fc6998912b..5896e9736f9242 100644 --- a/src/mono/wasm/runtime/types.ts +++ b/src/mono/wasm/runtime/types.ts @@ -119,6 +119,10 @@ export type MonoConfig = { * initial number of workers to add to the emscripten pthread pool */ pthreadPoolSize?: number, + /** + * hash of assets + */ + assetsHash?: string, }; export type MonoConfigInternal = MonoConfig & { diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs index 95a065dbdf177f..1423c1b074f0a2 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs @@ -4,14 +4,20 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; +using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Serialization; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; +using System.Numerics; +using System.Security.Cryptography; +using System.Reflection.PortableExecutable; +using System.Reflection.Metadata; namespace Microsoft.WebAssembly.Build.Tasks; @@ -37,6 +43,8 @@ public class WasmAppBuilder : WasmAppBuilderBaseTask // public ITaskItem[]? ExtraConfig { get; set; } + private static SHA256 HashAlgorithm = SHA256.Create(); + private sealed class WasmAppConfig { [JsonPropertyName("mainAssemblyName")] @@ -51,46 +59,49 @@ private sealed class WasmAppConfig public List RemoteSources { get; set; } = new List(); [JsonExtensionData] public Dictionary Extra { get; set; } = new(); + [JsonPropertyName("assetsHash")] + public string AssetsHash { get; set; } = "none"; } private class AssetEntry { - protected AssetEntry (string name, string behavior) + protected AssetEntry (string name, string hash, string behavior) { Name = name; Behavior = behavior; + Hash = hash; } [JsonPropertyName("behavior")] public string Behavior { get; init; } [JsonPropertyName("name")] public string Name { get; init; } - // TODO [JsonPropertyName("hash")] - // TODO public string? Hash { get; set; } + [JsonPropertyName("hash")] + public string? Hash { get; set; } } private sealed class WasmEntry : AssetEntry { - public WasmEntry(string name) : base(name, "dotnetwasm") { } + public WasmEntry(string name, string hash) : base(name, hash, "dotnetwasm") { } } private sealed class ThreadsWorkerEntry : AssetEntry { - public ThreadsWorkerEntry(string name) : base(name, "js-module-threads") { } + public ThreadsWorkerEntry(string name, string hash) : base(name, hash, "js-module-threads") { } } private sealed class AssemblyEntry : AssetEntry { - public AssemblyEntry(string name) : base(name, "assembly") {} + public AssemblyEntry(string name, string hash) : base(name, hash, "assembly") {} } private sealed class PdbEntry : AssetEntry { - public PdbEntry(string name) : base(name, "pdb") {} + public PdbEntry(string name, string hash) : base(name, hash, "pdb") {} } private sealed class SatelliteAssemblyEntry : AssetEntry { - public SatelliteAssemblyEntry(string name, string culture) : base(name, "resource") + public SatelliteAssemblyEntry(string name, string hash, string culture) : base(name, hash, "resource") { CultureName = culture; } @@ -101,14 +112,14 @@ public SatelliteAssemblyEntry(string name, string culture) : base(name, "resourc private sealed class VfsEntry : AssetEntry { - public VfsEntry(string name) : base(name, "vfs") {} + public VfsEntry(string name, string hash) : base(name, hash, "vfs") {} [JsonPropertyName("virtualPath")] public string? VirtualPath { get; set; } } private sealed class IcuData : AssetEntry { - public IcuData(string name) : base(name, "icu") {} + public IcuData(string name, string hash) : base(name, hash, "icu") {} [JsonPropertyName("loadRemote")] public bool LoadRemote { get; set; } } @@ -183,12 +194,20 @@ protected override bool ExecuteInternal() foreach (ITaskItem item in NativeAssets) { - string dest = Path.Combine(AppDir!, Path.GetFileName(item.ItemSpec)); + var name = Path.GetFileName(item.ItemSpec); + var dest = Path.Combine(AppDir!, name); if (!FileCopyChecked(item.ItemSpec, dest, "NativeAssets")) return false; + if (name == "dotnet.wasm") + { + config.Assets.Add(new WasmEntry (name, GetFileHash(item.ItemSpec)) ); + } + else if (IncludeThreadsWorker && name == "dotnet.worker.js") + { + config.Assets.Add(new ThreadsWorkerEntry (name, GetFileHash(item.ItemSpec))); + } } - string packageJsonPath = Path.Combine(AppDir, "package.json"); if (!File.Exists(packageJsonPath)) { @@ -199,14 +218,24 @@ protected override bool ExecuteInternal() foreach (var assembly in _assemblies) { string assemblyPath = assembly; - if (UseWebcil) - assemblyPath = Path.ChangeExtension(assemblyPath, ".webcil"); - config.Assets.Add(new AssemblyEntry(Path.GetFileName(assemblyPath))); - if (DebugLevel != 0) { - var pdb = assembly; - pdb = Path.ChangeExtension(pdb, ".pdb"); - if (File.Exists(pdb)) - config.Assets.Add(new PdbEntry(Path.GetFileName(pdb))); + var bytes = File.ReadAllBytes(assemblyPath); + if (!IsAssembly(bytes)) + { + Log.LogWarning("Skipping non-assembly file: " + assemblyPath); + } + else + { + if (UseWebcil) + assemblyPath = Path.ChangeExtension(assemblyPath, ".webcil"); + + config.Assets.Add(new AssemblyEntry(Path.GetFileName(assemblyPath), GetFileHash(bytes))); + if (DebugLevel != 0) + { + var pdb = assembly; + pdb = Path.ChangeExtension(pdb, ".pdb"); + if (File.Exists(pdb)) + config.Assets.Add(new PdbEntry(Path.GetFileName(pdb), GetFileHash(pdb))); + } } } @@ -228,12 +257,13 @@ protected override bool ExecuteInternal() else Log.LogMessage(MessageImportance.Low, $"Skipped generating {finalWebcil} as the contents are unchanged."); _fileWrites.Add(finalWebcil); - config.Assets.Add(new SatelliteAssemblyEntry(Path.GetFileName(finalWebcil), args.culture)); + config.Assets.Add(new SatelliteAssemblyEntry(Path.GetFileName(finalWebcil), GetFileHash(finalWebcil), args.culture)); } else { - FileCopyChecked(args.fullPath, Path.Combine(directory, name), "SatelliteAssemblies"); - config.Assets.Add(new SatelliteAssemblyEntry(name, args.culture)); + var satellitePath = Path.Combine(directory, name); + FileCopyChecked(args.fullPath, satellitePath, "SatelliteAssemblies"); + config.Assets.Add(new SatelliteAssemblyEntry(name, GetFileHash(satellitePath), args.culture)); } }); @@ -271,10 +301,10 @@ protected override bool ExecuteInternal() targetPathTable[targetPath] = item.ItemSpec; var generatedFileName = $"{i++}_{Path.GetFileName(item.ItemSpec)}"; + var vfsPath = Path.Combine(supportFilesDir, generatedFileName); + FileCopyChecked(item.ItemSpec, vfsPath, "FilesToIncludeInFileSystem"); - FileCopyChecked(item.ItemSpec, Path.Combine(supportFilesDir, generatedFileName), "FilesToIncludeInFileSystem"); - - var asset = new VfsEntry ($"supportFiles/{generatedFileName}") { + var asset = new VfsEntry ($"supportFiles/{generatedFileName}", GetFileHash(vfsPath)) { VirtualPath = targetPath }; config.Assets.Add(asset); @@ -291,15 +321,11 @@ protected override bool ExecuteInternal() Log.LogError($"Expected the file defined as ICU resource: {idfn} to exist but it does not."); return false; } - config.Assets.Add(new IcuData(Path.GetFileName(idfn)) { LoadRemote = loadRemote }); + config.Assets.Add(new IcuData(Path.GetFileName(idfn), GetFileHash(idfn)) { LoadRemote = loadRemote }); } } - config.Assets.Add(new WasmEntry ("dotnet.wasm") ); - if (IncludeThreadsWorker) - config.Assets.Add(new ThreadsWorkerEntry ("dotnet.worker.js") ); - if (RemoteSources?.Length > 0) { foreach (var source in RemoteSources) @@ -328,6 +354,16 @@ protected override bool ExecuteInternal() string tmpMonoConfigPath = Path.GetTempFileName(); using (var sw = File.CreateText(tmpMonoConfigPath)) { + HashAlgorithm.Initialize(); + var sb = new StringBuilder(); + foreach(AssetEntry asset in config.Assets) + { + sb.Append(asset.Hash); + } + var bytesToHash = Encoding.UTF8.GetBytes(sb.ToString()); + var hashBytes = HashAlgorithm.ComputeHash(bytesToHash); + config.AssetsHash = "sha256-" + Convert.ToBase64String(hashBytes); + var json = JsonSerializer.Serialize (config, new JsonSerializerOptions { WriteIndented = true }); sw.Write(json); } @@ -408,4 +444,43 @@ private static bool TryConvert(string str, Type type, out object? value) return false; } } + + public static bool IsAssembly(byte[] bytes) + { + try + { + // Try to read CLI metadata from the PE file. + using var peReader = new PEReader(ImmutableArray.Create(bytes)); + + if (!peReader.HasMetadata) + { + return false; // File does not have CLI metadata. + } + + // Check that file has an assembly manifest. + MetadataReader reader = peReader.GetMetadataReader(); + return reader.IsAssembly; + } + catch (BadImageFormatException) + { + return false; + } + catch (FileNotFoundException) + { + return false; + } + } + + public static string GetFileHash(string filePath) + { + return GetFileHash(File.ReadAllBytes(filePath)); + } + + public static string GetFileHash(byte[] bytes) + { + HashAlgorithm.Initialize(); + var hashBytes = HashAlgorithm.ComputeHash(bytes); + return "sha256-" + Convert.ToBase64String(hashBytes); + } + } diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj index 3fd2f17c30a253..320586d8693944 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj @@ -5,6 +5,7 @@ $(NoWarn),CA1050 $(NoWarn),CS8604,CS8602 + $(NoWarn),CA1850 false true true From 237e1eabaf74214d2a16fccb16e477d46cef47de Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 2 Mar 2023 14:55:41 +0100 Subject: [PATCH 2/5] @thaystg feedback about webcil hash --- .../wasm/browser-advanced/Wasm.Advanced.Sample.csproj | 1 + src/tasks/WasmAppBuilder/WasmAppBuilder.cs | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj b/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj index c7a311e87358ff..11eac88f6dca6b 100644 --- a/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj +++ b/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj @@ -3,6 +3,7 @@ true true + true -s USE_CLOSURE_COMPILER=1 -s LEGACY_GL_EMULATION=1 -lGL -lSDL -lidbfs.js diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs index 1423c1b074f0a2..2dcbb44e8d6c38 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs @@ -219,6 +219,7 @@ protected override bool ExecuteInternal() { string assemblyPath = assembly; var bytes = File.ReadAllBytes(assemblyPath); + // for the is IL IsAssembly check we need to read the bytes from the original DLL if (!IsAssembly(bytes)) { Log.LogWarning("Skipping non-assembly file: " + assemblyPath); @@ -226,7 +227,11 @@ protected override bool ExecuteInternal() else { if (UseWebcil) - assemblyPath = Path.ChangeExtension(assemblyPath, ".webcil"); + { + assemblyPath = Path.Combine(asmRootPath, Path.ChangeExtension(Path.GetFileName(assembly), ".webcil")); + // For the hash, read the bytes from the webcil file, not the dll file. + bytes = File.ReadAllBytes(assemblyPath); + } config.Assets.Add(new AssemblyEntry(Path.GetFileName(assemblyPath), GetFileHash(bytes))); if (DebugLevel != 0) From 168facd2d7dcc8e016e7506846b706f5ec3b8dd8 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 2 Mar 2023 15:00:01 +0100 Subject: [PATCH 3/5] fix prefetch --- src/mono/sample/wasm/browser-advanced/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/sample/wasm/browser-advanced/index.html b/src/mono/sample/wasm/browser-advanced/index.html index b5c8649a6d7e45..b4cefe75f40724 100644 --- a/src/mono/sample/wasm/browser-advanced/index.html +++ b/src/mono/sample/wasm/browser-advanced/index.html @@ -12,7 +12,7 @@ - + From b9678faa9e4fdba381fc6044e49e3bac434bb8da Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 2 Mar 2023 19:30:50 +0100 Subject: [PATCH 4/5] feedback --- .../AndroidAppBuilder.csproj | 2 +- .../AotCompilerTask/MonoAOTCompiler.csproj | 2 +- .../AppleAppBuilder/AppleAppBuilder.csproj | 2 +- src/tasks/Common/Utils.cs | 69 +++++++++++++++++++ .../MonoTargetsTasks/MonoTargetsTasks.csproj | 2 +- .../TestExclusionListTasks.csproj | 2 +- .../ManagedToNativeGenerator.cs | 14 +--- src/tasks/WasmAppBuilder/WasmAppBuilder.cs | 69 +++---------------- .../WorkloadBuildTasks.csproj | 2 +- 9 files changed, 86 insertions(+), 78 deletions(-) diff --git a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.csproj b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.csproj index 3dd38caa3c8809..69c1877a575cfc 100644 --- a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.csproj +++ b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.csproj @@ -5,7 +5,7 @@ true false enable - $(NoWarn),CA1050 + $(NoWarn),CA1050,CA1850 diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj b/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj index 28e5cc265c80aa..e76730b5aeca07 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj @@ -5,7 +5,7 @@ true false enable - $(NoWarn),CA1050 + $(NoWarn),CA1050,CA1850 $(NoWarn),CS8604,CS8602 diff --git a/src/tasks/AppleAppBuilder/AppleAppBuilder.csproj b/src/tasks/AppleAppBuilder/AppleAppBuilder.csproj index 75c898c560c0e3..61f3cc89e3c61b 100644 --- a/src/tasks/AppleAppBuilder/AppleAppBuilder.csproj +++ b/src/tasks/AppleAppBuilder/AppleAppBuilder.csproj @@ -5,7 +5,7 @@ true false enable - $(NoWarn),CA1050 + $(NoWarn),CA1050,CA1850 diff --git a/src/tasks/Common/Utils.cs b/src/tasks/Common/Utils.cs index 91e5b77c1e198e..17b915f330bae5 100644 --- a/src/tasks/Common/Utils.cs +++ b/src/tasks/Common/Utils.cs @@ -3,9 +3,12 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; +using System.Reflection.PortableExecutable; +using System.Reflection.Metadata; using System.Security.Cryptography; using System.Text; using Microsoft.Build.Framework; @@ -237,6 +240,32 @@ public static string ComputeHash(string filepath) return Convert.ToBase64String(hash); } + public static string ComputeIntegrity(string filepath) + { + using var stream = File.OpenRead(filepath); + using HashAlgorithm hashAlgorithm = SHA256.Create(); + + byte[] hash = hashAlgorithm.ComputeHash(stream); + return "sha256-" + Convert.ToBase64String(hash); + } + + public static string ComputeIntegrity(byte[] bytes) + { + using HashAlgorithm hashAlgorithm = SHA256.Create(); + + byte[] hash = hashAlgorithm.ComputeHash(bytes); + return "sha256-" + Convert.ToBase64String(hash); + } + + public static string ComputeTextIntegrity(string str) + { + using HashAlgorithm hashAlgorithm = SHA256.Create(); + + var bytes = Encoding.UTF8.GetBytes(str); + byte[] hash = hashAlgorithm.ComputeHash(bytes); + return "sha256-" + Convert.ToBase64String(hash); + } + #if NETCOREAPP public static void DirectoryCopy(string sourceDir, string destDir, Func? predicate=null) { @@ -258,4 +287,44 @@ public static void DirectoryCopy(string sourceDir, string destDir, Func$(TargetFrameworkForNETCoreTasks);$(TargetFrameworkForNETFrameworkTasks) false enable - $(NoWarn),CA1050 + $(NoWarn),CA1050,CA1850 diff --git a/src/tasks/TestExclusionListTasks/TestExclusionListTasks.csproj b/src/tasks/TestExclusionListTasks/TestExclusionListTasks.csproj index d17dc95c41af62..a717c45f42c5ae 100644 --- a/src/tasks/TestExclusionListTasks/TestExclusionListTasks.csproj +++ b/src/tasks/TestExclusionListTasks/TestExclusionListTasks.csproj @@ -5,7 +5,7 @@ true false enable - $(NoWarn),CA1050 + $(NoWarn),CA1050,CA1850 diff --git a/src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs b/src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs index 081803b4b3c994..74855a41daf85d 100644 --- a/src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs +++ b/src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs @@ -6,7 +6,6 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using System.Reflection.PortableExecutable; using System.Text; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -128,7 +127,7 @@ private List FilterOutUnmanagedBinaries(string[] assemblies) try { - if (!IsManagedAssembly(asmPath)) + if (!Utils.IsManagedAssembly(asmPath)) { Log.LogMessage(MessageImportance.Low, $"Skipping unmanaged {asmPath}."); continue; @@ -145,15 +144,4 @@ private List FilterOutUnmanagedBinaries(string[] assemblies) return managedAssemblies; } - - private static bool IsManagedAssembly(string filePath) - { - if (!File.Exists(filePath)) - return false; - - using FileStream fileStream = File.OpenRead(filePath); - using PEReader reader = new(fileStream, PEStreamOptions.Default); - return reader.HasMetadata; - } - } diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs index 2dcbb44e8d6c38..a893c5ddcb5156 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; -using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -14,10 +13,6 @@ using System.Text.Json.Serialization; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -using System.Numerics; -using System.Security.Cryptography; -using System.Reflection.PortableExecutable; -using System.Reflection.Metadata; namespace Microsoft.WebAssembly.Build.Tasks; @@ -43,8 +38,6 @@ public class WasmAppBuilder : WasmAppBuilderBaseTask // public ITaskItem[]? ExtraConfig { get; set; } - private static SHA256 HashAlgorithm = SHA256.Create(); - private sealed class WasmAppConfig { [JsonPropertyName("mainAssemblyName")] @@ -200,11 +193,11 @@ protected override bool ExecuteInternal() return false; if (name == "dotnet.wasm") { - config.Assets.Add(new WasmEntry (name, GetFileHash(item.ItemSpec)) ); + config.Assets.Add(new WasmEntry (name, Utils.ComputeIntegrity(item.ItemSpec)) ); } else if (IncludeThreadsWorker && name == "dotnet.worker.js") { - config.Assets.Add(new ThreadsWorkerEntry (name, GetFileHash(item.ItemSpec))); + config.Assets.Add(new ThreadsWorkerEntry (name, Utils.ComputeIntegrity(item.ItemSpec))); } } @@ -220,7 +213,7 @@ protected override bool ExecuteInternal() string assemblyPath = assembly; var bytes = File.ReadAllBytes(assemblyPath); // for the is IL IsAssembly check we need to read the bytes from the original DLL - if (!IsAssembly(bytes)) + if (!Utils.IsManagedAssembly(bytes)) { Log.LogWarning("Skipping non-assembly file: " + assemblyPath); } @@ -233,13 +226,13 @@ protected override bool ExecuteInternal() bytes = File.ReadAllBytes(assemblyPath); } - config.Assets.Add(new AssemblyEntry(Path.GetFileName(assemblyPath), GetFileHash(bytes))); + config.Assets.Add(new AssemblyEntry(Path.GetFileName(assemblyPath), Utils.ComputeIntegrity(bytes))); if (DebugLevel != 0) { var pdb = assembly; pdb = Path.ChangeExtension(pdb, ".pdb"); if (File.Exists(pdb)) - config.Assets.Add(new PdbEntry(Path.GetFileName(pdb), GetFileHash(pdb))); + config.Assets.Add(new PdbEntry(Path.GetFileName(pdb), Utils.ComputeIntegrity(pdb))); } } } @@ -262,13 +255,13 @@ protected override bool ExecuteInternal() else Log.LogMessage(MessageImportance.Low, $"Skipped generating {finalWebcil} as the contents are unchanged."); _fileWrites.Add(finalWebcil); - config.Assets.Add(new SatelliteAssemblyEntry(Path.GetFileName(finalWebcil), GetFileHash(finalWebcil), args.culture)); + config.Assets.Add(new SatelliteAssemblyEntry(Path.GetFileName(finalWebcil), Utils.ComputeIntegrity(finalWebcil), args.culture)); } else { var satellitePath = Path.Combine(directory, name); FileCopyChecked(args.fullPath, satellitePath, "SatelliteAssemblies"); - config.Assets.Add(new SatelliteAssemblyEntry(name, GetFileHash(satellitePath), args.culture)); + config.Assets.Add(new SatelliteAssemblyEntry(name, Utils.ComputeIntegrity(satellitePath), args.culture)); } }); @@ -309,7 +302,7 @@ protected override bool ExecuteInternal() var vfsPath = Path.Combine(supportFilesDir, generatedFileName); FileCopyChecked(item.ItemSpec, vfsPath, "FilesToIncludeInFileSystem"); - var asset = new VfsEntry ($"supportFiles/{generatedFileName}", GetFileHash(vfsPath)) { + var asset = new VfsEntry ($"supportFiles/{generatedFileName}", Utils.ComputeIntegrity(vfsPath)) { VirtualPath = targetPath }; config.Assets.Add(asset); @@ -326,7 +319,7 @@ protected override bool ExecuteInternal() Log.LogError($"Expected the file defined as ICU resource: {idfn} to exist but it does not."); return false; } - config.Assets.Add(new IcuData(Path.GetFileName(idfn), GetFileHash(idfn)) { LoadRemote = loadRemote }); + config.Assets.Add(new IcuData(Path.GetFileName(idfn), Utils.ComputeIntegrity(idfn)) { LoadRemote = loadRemote }); } } @@ -359,15 +352,12 @@ protected override bool ExecuteInternal() string tmpMonoConfigPath = Path.GetTempFileName(); using (var sw = File.CreateText(tmpMonoConfigPath)) { - HashAlgorithm.Initialize(); var sb = new StringBuilder(); foreach(AssetEntry asset in config.Assets) { sb.Append(asset.Hash); } - var bytesToHash = Encoding.UTF8.GetBytes(sb.ToString()); - var hashBytes = HashAlgorithm.ComputeHash(bytesToHash); - config.AssetsHash = "sha256-" + Convert.ToBase64String(hashBytes); + config.AssetsHash = Utils.ComputeTextIntegrity(sb.ToString()); var json = JsonSerializer.Serialize (config, new JsonSerializerOptions { WriteIndented = true }); sw.Write(json); @@ -449,43 +439,4 @@ private static bool TryConvert(string str, Type type, out object? value) return false; } } - - public static bool IsAssembly(byte[] bytes) - { - try - { - // Try to read CLI metadata from the PE file. - using var peReader = new PEReader(ImmutableArray.Create(bytes)); - - if (!peReader.HasMetadata) - { - return false; // File does not have CLI metadata. - } - - // Check that file has an assembly manifest. - MetadataReader reader = peReader.GetMetadataReader(); - return reader.IsAssembly; - } - catch (BadImageFormatException) - { - return false; - } - catch (FileNotFoundException) - { - return false; - } - } - - public static string GetFileHash(string filePath) - { - return GetFileHash(File.ReadAllBytes(filePath)); - } - - public static string GetFileHash(byte[] bytes) - { - HashAlgorithm.Initialize(); - var hashBytes = HashAlgorithm.ComputeHash(bytes); - return "sha256-" + Convert.ToBase64String(hashBytes); - } - } diff --git a/src/tasks/WorkloadBuildTasks/WorkloadBuildTasks.csproj b/src/tasks/WorkloadBuildTasks/WorkloadBuildTasks.csproj index 0153d9a31ae4d1..fbb13d8d9c4ecf 100644 --- a/src/tasks/WorkloadBuildTasks/WorkloadBuildTasks.csproj +++ b/src/tasks/WorkloadBuildTasks/WorkloadBuildTasks.csproj @@ -2,7 +2,7 @@ $(TargetFrameworkForNETCoreTasks) enable - $(NoWarn),CA1050 + $(NoWarn),CA1050,CA1850 From e717e0e13613e62563620ae74cffe0b0ecf4a331 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 2 Mar 2023 19:33:44 +0100 Subject: [PATCH 5/5] feedback --- src/tasks/WasmAppBuilder/WasmAppBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs index a893c5ddcb5156..b7441396754fe1 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs @@ -215,7 +215,7 @@ protected override bool ExecuteInternal() // for the is IL IsAssembly check we need to read the bytes from the original DLL if (!Utils.IsManagedAssembly(bytes)) { - Log.LogWarning("Skipping non-assembly file: " + assemblyPath); + Log.LogMessage(MessageImportance.Low, "Skipping non-assembly file: " + assemblyPath); } else {