-
Notifications
You must be signed in to change notification settings - Fork 637
-
Hello,
I'm trying to migrate to v3 of the AWS S3 client on my node.js 18.8 app.
Whenever I try to use the PutObjectCommand to upload a file, I get this error : Error: crypto.getRandomValues() not supported
What is it that I am doing wrong here ?
Thank you!
Beta Was this translation helpful? Give feedback.
All reactions
@maxbritto - thanks for your succinct explanation. I was running into the same situation using vite and was able to work around this issue with a combination of rollup settings and a small polyfill borrowing some basic logic from the react-native-get-random-values polyfill.
Changes to vite.config.ts:
import { nodeResolve } from '@rollup/plugin-node-resolve' export default defineConfig({ build: { // ... rollupOptions: { output: { globals: {crypto: 'crypto'}, }, external: ['crypto'], plugins: [nodeResolve({ preferBuiltins: true })], }, }, })
My understanding is that these settings will direct the build/bundle to use the nodejs crypto module i...
Replies: 10 comments 5 replies
-
Can you please share your actual code including import statements?
Hard to say what could go wrong.
Perhaps erase your package.json file and run npm init again?
Beta Was this translation helpful? Give feedback.
All reactions
-
Thank you for your answer, here is the code I'm using :
import { S3Client, PutObjectCommand, PutObjectCommandInput } from "@aws-sdk/client-s3"; import { env } from "process"; export class CdnManager { readonly cdnBaseUrl: string = env.S3_ENDPOINT; readonly cdbBucketName: string = env.S3_BUCKET_NAME; private getS3Client() : S3Client { return new S3Client({region:"auto", endpoint:this.cdnBaseUrl, apiVersion: '2006-03-01', credentials: {accessKeyId:env.S3_ACCESS_KEY_ID, secretAccessKey:env.S3_SECRET_ACCESS_KEY} }); } async upload(destinationFilePath: string, body: string, contentType: string = "text/plain; charset=utf-8") { if (destinationFilePath.startsWith("/")) { destinationFilePath = destinationFilePath.substring(1); } console.log(`cdn upload to`,destinationFilePath); const uploadParams:PutObjectCommandInput = { Bucket: this.cdbBucketName, Key: destinationFilePath, Body: Buffer.from(body), ContentType: contentType }; try { const s3 = this.getS3Client(); const command = new PutObjectCommand(uploadParams); const result = await s3.send(command); console.log("Upload Success", result.$metadata); } catch (error) { console.log("Upload : Error was received for file at ", destinationFilePath, error); } } }
This class is within an internal library with this package.json :
{
"name": "learning-app-data",
"version": "1.0.0",
"description": "Data used in the learning app project",
"main": "src/index.ts",
"scripts": {
"test": "node --inspect-brk node_modules/.bin/jest --runInBand"
},
"author": "Maxime Britto",
"license": "ISC",
"devDependencies": {
"@types/jest": "^27.5.1",
"@types/node": "^18.7.13",
"jest": "^28.1.0",
"ts-jest": "^28.0.2"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.170.0",
"@directus/sdk": "^9.12.1",
"teachable-api": "file:/Users/mbritto/code/node_projects/teachable-api"
}
}This library is the only dependency of a Directus extension with this package :
{
"name": "directus-extension-elements-hooks",
"version": "1.0.0",
"keywords": [
"directus",
"directus-extension",
"directus-custom-hook"
],
"directus:extension": {
"type": "hook",
"path": "dist/index.js",
"source": "src/index.ts",
"host": "^9.12.1"
},
"scripts": {
"build": "directus-extension build",
"dev": "directus-extension build -w --no-minify"
},
"dependencies": {
"learning-app-data": "file:../learning-app-data"
},
"devDependencies": {
"@directus/extensions-sdk": "9.12.1",
"@types/node": "^17.0.41",
"typescript": "^4.7.3"
}
}Which itself is used by the Directus server :
{
"name": "teachable-app-webservice",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "npx nodemon --legacy-watch --exec NODE_OPTIONS=--inspect directus start",
"start": "npx directus start",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@directus/sdk": "^9.0.0",
"directus": "^9.0.1",
"firebase-admin": "^10.0.2",
"mysql": "^2.18.1",
"sharp": "^0.30.4"
}
}I've tried your recommandation and removed the package.json and the package-lock.json then redid the whole npm init and npm install for my library which is using the S3-client library.
The problem remains.
I'm on macOS 12.5 with Node 18.8.0
After 3 hours of research here is the summary of my findings :
@aws-sdk/middleware-retryuses theuuidpackage- the
uuidpackage is relying on a crypto lib setting up a globalWindow.cryptovariable which is done by most recent browsers : (see here: https://github.com/uuidjs/uuid/blob/0f433e5ec444edacd53016de67db021102f36148/src/rng-browser.js) - Node has added this crypto lib since v15.5 but they did the right thing and used a module instead of a global variable
- Many people have had this issue on React Native and their fix was temporarily added to your code base (which was a bad idea : middleware-retry includes react-native #2051 )
- I could not find someone with this issue on a node 18.8 server.
That is why I posted here, I could not find any more information on how to fix this issue.
Thanks for your help!
Beta Was this translation helpful? Give feedback.
All reactions
-
@maxbritto I'm also running into the same issue, also with Directus, and I'm also building a custom hook.
node->16.11.1@aws-sdk/client-cognito-identity-provider->3.180.0directus->9.18.1
Beta Was this translation helpful? Give feedback.
All reactions
-
Well I gave up and went back to the aws sdk v2.
I hope it will be fixed at some point in the future and I will be able to migrate to it at that point
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 2
-
@maxbritto - thanks for your succinct explanation. I was running into the same situation using vite and was able to work around this issue with a combination of rollup settings and a small polyfill borrowing some basic logic from the react-native-get-random-values polyfill.
Changes to vite.config.ts:
import { nodeResolve } from '@rollup/plugin-node-resolve' export default defineConfig({ build: { // ... rollupOptions: { output: { globals: {crypto: 'crypto'}, }, external: ['crypto'], plugins: [nodeResolve({ preferBuiltins: true })], }, }, })
My understanding is that these settings will direct the build/bundle to use the nodejs crypto module instead of some polyfill which likely either shims or does not fully implement crypto.
In my application code, I first import this polyfill so it's run before any transitive deps are imported:
import './polyfills/crypto' // rest of application code
The polyfill:
import crypto from 'crypto' // should have webcrypto.getRandomValues defined if (typeof global.crypto !== 'object') { global.crypto = crypto } if (typeof global.crypto.getRandomValues !== 'function') { global.crypto.getRandomValues = getRandomValues } function getRandomValues(array) { return crypto.webcrypto.getRandomValues(array) }
Hope this helps to diagnose and fix in your own project!
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 13 -
🎉 4 -
❤️ 2
-
@au-z solution worked for me, at directus operator extension. Hope AWS will fix it in a better manner soon.
Beta Was this translation helpful? Give feedback.
All reactions
-
Could you share the code you used? i'm having the same issue, but I'm not using rollup.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
if you are using rollup, this may caused by a resolving issue. update the plugin config in your rollup.config.js to:
{ // ...other configs plugins: [ // ...other plugins nodeResolve({ exportConditions: ['node'] }) ] }
which worked for me. see uuidjs/uuid#544 (comment)
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1 -
❤️ 7
-
Hello! Reopening this discussion to make it searchable.
Beta Was this translation helpful? Give feedback.
All reactions
-
What would you do in the instance where you're not using rollup?
Beta Was this translation helpful? Give feedback.
All reactions
-
I found an answer from a similar problem that another library had: jsdom/jsdom#1612
Basically add this so the dependency can find crypto:
import { Crypto } from "@peculiar/webcrypto"
global.crypto = new Crypto()
Beta Was this translation helpful? Give feedback.
All reactions
-
I was able to get passed this issue by installing 'react-native-get-random-values' and importing and then rebuilding it
to install
npm install react-native-get-random-values --save
adding the import line in the file that's calling the aws
import 'react-native-get-random-values';
Beta Was this translation helpful? Give feedback.
All reactions
-
❤️ 1
-
This fixed the issue for me.
Beta Was this translation helpful? Give feedback.
All reactions
-
this worked for me too
Beta Was this translation helpful? Give feedback.
All reactions
-
I had this error in an AWS lambda function. I was using Node v18.x and when I bumped to Node v22.x everything worked fine.
If you are finding this error in another environment, just make sure that environments node version is high enough to support this (v20 might work too?).
If you can't do that, and are using vite then maybe something like https://www.npmjs.com/package/vite-plugin-node-polyfills would help you.
Beta Was this translation helpful? Give feedback.