0

I am working with a javascript library that uses global.crypto, for example, makes a call to global.crypto.getRandomValues(). I want to use the library from the command line (1) for testing my scripts and knowledge, (2) perhaps for back-end code.

How can I make the global.crypto API available to that module from the command line?


Working example:

library.js:

export function getUUID() {
  return crypto.randomUUID();
}

main.js:

import { getUUID } from "./library.js";
console.log(getUUID());

index.html:

<!DOCTYPE html>
<html>
<body>
  <script type="module" src="main.js"></script>
</body>
</html>

Opening index.html from localhost writes a UUID to the console, but running "node main.js" gives

file:/.../library.js:2
  return crypto.randomUUID();
  ^

ReferenceError: crypto is not defined
    at getUUID (file:/.../library.js:2:3)
    at file:/.../main.js:3:13
    at ModuleJob.run (node:internal/modules/esm/module_job:195:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:337:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:61:12)

Edit based on tobiv's answer, here is a solution that works for me, however, may not be best practice? Note that I'm hoping not to edit the library file itself.

main.js (updated)

import * as crypto from 'crypto';
global.crypto = crypto.webcrypto;
import { getUUID } from "./library.js";
console.log(getUUID());

Now running "node main.js" correctly prints a UUID. And if I comment out the first two lines of main.js, I get a version that works in the browser.

Or for CommonJS and the library I'm actually using:

const crypto = require('node:crypto').webcrypto;
global.crypto = crypto;
const library = require("browser-passworder");
console.log(library.generateSalt());

I'm a bit concerned about robustness here if modules load asynchronously, but it's the best solution I've found.

2
  • Where do you import/load that crypto library? Commented Sep 19, 2022 at 17:28
  • 1
    @tobiv by "that crypto library", are you referring to global.crypto? This seems to be available in the browser automatically, i.e. my example above works for me as written: if I serve index.html at localhost and access it in Firefox, it succesfully runs and prints a UUID to the console. If you mean the javascript library I'm referring to that uses global.crypto, I load it at the top of my own javascript file with: import * as passworder from 'browser-passworder' Commented Sep 19, 2022 at 19:43

1 Answer 1

1

Use require('node:crypto').webcrypto to access the module in node:

const crypto = require('node:crypto').webcrypto;

console.log(crypto.randomUUID());

https://nodejs.dev/en/api/v18/webcrypto/

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you! This answers a lot of my question. There is still one piece: can I give the library I'm calling access to this webcrypto? (Without changing the code of the library, otherwise I could fork it and put this at the top.)
One thing that worked for me, but may not be the best approach: in main.js, first import webcrypto as you describe. Then set global.crypto = crypto;. Then import the library. Took this idea from stackoverflow.com/a/4481382/658176
I've used a if (typeof exports === 'object') guard to be able to switch between a native browser and node implementation of a library. github.com/qzind/tray/blob/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.