-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Description
Looks like the wasm-experimental workload doesn't allow for the successful invocation of Guid.NewGuid, when creating a wasmconsole project and running in NodeJS:
As it turns out, this is because crypto is not present in the global scope, and Math.random is considered unfit for cryptography.
NodeJS does not provide crypto out of the box, as is the case with browsers.
Yet the wasm-tools and wasm-experimental workloads do not guide the user programmer in such a way that they're aware of this conundrum while employing dotnet new wasmconsole and then going ahead and calling Guid.NewGuid.
Given how Guid.NewGuid can be called by any 3rd party lib, far out in the dependency tree, I think a better error message would be in order, if technically possible.
@SteveSandersonMS 's dotnet-wasi-sdk was able to quickly and effectively guide me toward implementing part of WASI_SNAPSHOT_PREVIEW1 (including this very crypto thing).
It even told me what extern InternalCalls lacked bindings (i.e., TaskQueue.SetTimeout) so I quickly backfilled those through c and js.
Reproduction Steps
-
Make sure you have the wasm-tools and wasm-experimental workloads, as described in the Use .NET from any JavaScript app in .NET 7 announcement.
-
Create a new wasmconsole:
dotnet new wasmconsole- In Program.cs call Guid.NewGuid:
Console.WriteLine($"The guide is {Guid.NewGuid()}");
return 0;- Build and run
dotnet build
dotnet runExpected behavior
I would expect Guid.NewGuid to work.
Given the workloads are experimental, I don't expect everything to work, but I think it's essential for you guys to receive feedback.
Also, I would suspect other capabilities to be lacking, such as TimerQueue.SetTimeout and whatnot, but those seem to work.
Actual behavior
You should be able to create a Guid in .NET 7 when targeting wasm and NodeJS by using a provided workload.
Regression?
I don't think this is a regression.
Known Workarounds
A mischievous workaround is falsifying the cryptographical strength of Math.random and adding right at the beginning of main.mjs:
globalThis.crypto = {
getRandomValues(array) {
for (let i = 0; i < array.length; i++) {
const value = Math.floor(Math.random() * 256);
array.set([value], i);
}
}
}A better workaround is to turn the whole thing into a module project and install crypto.
Configuration
- The problem is particular to the configuration, but not to the OS.
- I am not using Blazor, but I am using .NET 7 compiled to wasm and running in NodeJS.
dotnet workload list
Installed Workload Id Manifest Version Installation Source
--------------------------------------------------------------------
wasm-experimental 7.0.1/7.0.100 SDK 7.0.100
wasm-tools 7.0.1/7.0.100 SDK 7.0.100
dotnet --list-sdks
7.0.101 [C:\Program Files\dotnet\sdk]Fwiw:
dotnet --list-runtimes
Microsoft.AspNetCore.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]node --version
v18.12.1systeminfo
...
OS Name: Microsoft Windows 11 Enterprise
OS Version: 10.0.22000 N/A Build 22000
...Other information
The call chain:
- when calling Guid.NewGuid
- it calls Sys.Interop.GetCryptographicallySecureRandom
- which calls libSystem.Native/SystemNative_GetCryptographicallySecureRandomBytes
- which calls the js-implemented extern called dotnet_browser_entropy
- which returns non-zero if crypto is nowhere in sight
