esm-dev / esm.sh

A fast, smart, & global CDN for modern(es2015+) web development.
https://esm.sh
MIT License
3.05k stars 147 forks source link

Use Web Cryptography API for wbn-sign-webcrypto, crypto-browserify throws for subtle, doesn't implement Ed25519 #786

Open guest271314 opened 8 months ago

guest271314 commented 8 months ago

I'm using Web Cryptography API (with algorithm Ed25519) for the ability to run the same source code using node, deno, and bun and other JavaScript runtimes, including the browser.

I am not using Node.js node:crypto implementation, which apparently cannot be polyfilled.

From the source code of crypto-browesrify https://esm.sh/v135/crypto-browserify@3.12.0/esnext/crypto-browserify.mjs it doesn't look like Ed25519 algorithm is implemented in that module.

import { WebBundleId } from "https://esm.sh/gh/guest271314/wbn-sign-webcrypto/lib/wbn-sign.js";
TypeError: Cannot read properties of undefined (reading 'subtle')
    at l (https://esm.sh/v135/gh/guest271314/wbn-sign-webcrypto@44185e29b6/esnext/lib/wbn-sign.js:3:3508)
    at b.serialize (https://esm.sh/v135/gh/guest271314/wbn-sign-webcrypto@44185e29b6/esnext/lib/wbn-sign.js:3:5957)
    at b.serializeWithIsolatedWebAppOrigin (https://esm.sh/v135/gh/guest271314/wbn-sign-webcrypto@44185e29b6/esnext/lib/wbn-sign.js:3:6105)
    at file:///home/user/webbundle/rollup.wbn.js:52:5

Node.js v22.0.0-nightly202312315fb6305971

from

  async serialize() {
    return base32Encode(
      new Uint8Array([
        ...(await getRawPublicKey(this.key)),
        ...this.appIdSuffix,
      ]),
      "RFC4648",
      { padding: false },
    ).toLowerCase();
  }

and

https://github.com/guest271314/wbn-sign-webcrypto/blob/main/lib/utils/utils.js

export async function getRawPublicKey(publicKey) {
  // Currently this is the only way for us to get the raw 32 bytes of the public key.
  return new Uint8Array(await webcrypto.subtle.exportKey("spki", publicKey))
    .slice(-32);
}
ije commented 8 months ago

seems crypto-browesrify doesn't implement the webcrypto object, you can use the global crypto.subtle object in browser

guest271314 commented 8 months ago

Yes. Unfortunately esm.sh is importing crypto-browserify. I don't have any references to crypto-browserify in my source code.

ije commented 8 months ago

esm.sh will replace "node:crypto" to crypto-browserify for browsers

guest271314 commented 8 months ago

I didn't make the request from the browser. I made the request from Deno.

I'm using webcrypto object defined on node:crypto. crypto-browserfy doesn't implement webcrypto or Ed26619 algorithm. As far as I understand node:crypto can't be polyfilled.

esm.sh importing crypto-browserify is throwing errors, can't be used. The code should identify webcrypto is being used. Not import crypto-browserify. The point of https://github.com/guest271314/wbn-sign-webcrypto is to use standardized Web Cryptography API, and to not use Node.js crypto implementation.

guest271314 commented 8 months ago

In other word esm.sh importing crypto-browserify is breaking my code. See https://github.com/paulmillr/noble-ed25519/discussions/98#top

For interop with node or webcrypto, it’s simple: just use their export and import methods.

the problem lies deeper than node api: the package in question wants to consume some specific key format.

...

All node parts have to be replaced for browser - that’s correct

So I did that. The same webscrypto code runs in deno, node, and bun. Deno has some peculiarities with regard to dynamic imports, and when building with bun I have to import Buffer module from std and define globally; when building with esbuild I don't have to define Buffer globally. Other than that I implemented npm:wbn-sign to work using Web Cryptography API instead of node:crypto, so the same code can run in multiple JavaScript runtimes, and next the browser.

I was rather surprised when I saw esm.sh was depending on crypto-browserify. I looked at the repository while researching how to go about replacing a Node.js implementation with a standardized Web Platform API implementation. I think the last update was 6 years ago? SO I couldn't use that. The browser, Node.js, Deno, and Bun implement Web Cryptograpphy API.

Nowhere in my code do I intend to use crypto-browserify.

guest271314 commented 8 months ago

You can repoduce the error by running this code https://github.com/guest271314/webbundle/blob/main/index.js and substituting

import { WebBundleId } from "https://esm.sh/gh/guest271314/wbn-sign-webcrypto/lib/wbn-sign.js";

for

import { WebBundleId } from "wbn-sign-webcrypto";

for

ije commented 8 months ago

I didn't make the request from the browser. I made the request from Deno.

weird, Deno should work fine:

Screenshot 2024-01-06 at 16 27 51
ije commented 8 months ago

i got a different error:

Screenshot 2024-01-06 at 16 29 11
guest271314 commented 8 months ago

I don't think you followed all of the steps here https://github.com/guest271314/webbundle before substituting import from esm.sh for wbn-sign.js.

crypto-browserify is never going to work for Ed25519 algorithm as-is. Just read the source code and observe complete absence of that algorithm.

Again, nowhere in my code do I import crypto-browserify.

guest271314 commented 8 months ago

weird, Deno should work fine: Works for Deno. Doesn't work for Node.js.

TypeError: Cannot read properties of undefined (reading 'subtle')
    at l (https://esm.sh/v135/gh/guest271314/wbn-sign-webcrypto@44185e29b6/esnext/lib/wbn-sign.js:3:3508)
    at b.serialize (https://esm.sh/v135/gh/guest271314/wbn-sign-webcrypto@44185e29b6/esnext/lib/wbn-sign.js:3:5957)
    at b.serializeWithIsolatedWebAppOrigin (https://esm.sh/v135/gh/guest271314/wbn-sign-webcrypto@44185e29b6/esnext/lib/wbn-sign.js:3:6105)
    at file:///home/user/webbundle/index.js:24:5

Node.js v22.0.0-nightly2024010657c22e4a22