Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use react-native-crypto to support react native environments. #259

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

evanvosberg
Copy link
Member

No description provided.

@evanvosberg
Copy link
Member Author

@alexyangjie this pull request is about to create a React Native compatible version using crypto module.

I do not have a ready to use React Native environment setup. If you like to test it, here are the steps to go:

  • checkout this branch
  • run grunt build
  • replace crypto-js in your React Native project with crypto-js from the build directory
  • add react-native-crypto as dependency to your React Native project
  • test it

@alexyangjie
Copy link

I currently don't have much time to test this. Will probably come back later when I have some time. Thanks.

@Bardiamist
Copy link

Bardiamist commented Feb 12, 2020

  1. I added in package.json:
"crypto-js": "git+https://github.com/brix/crypto-js.git#feature/react-native",
  1. yarn
  2. grunt build
  3. Replace crypto-js folder content by build folder content

Result:

Unable to resolve module `crypto` from `node_modules/crypto-js/core.js`: crypto could not be found within the project.

If you are sure the module exists, try these steps:
 1. Clear watchman watches: watchman watch-del-all
 2. Delete node_modules: rm -rf node_modules and run yarn install
 3. Reset Metro's cache: yarn start --reset-cache
 4. Remove the cache: rm -rf /tmp/metro-*

RCTFatal
__28-[RCTCxxBridge handleError:]_block_invoke
_dispatch_call_block_and_release
_dispatch_client_callout
_dispatch_main_queue_callback_4CF
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
__CFRunLoopRun
CFRunLoopRunSpecific
GSEventRunModal
UIApplicationMain
main
start

@evanvosberg
Copy link
Member Author

@Bardiamist this is indeed weird, as it looks like the try catch block does not catch in this case.

    if (!crypto && typeof require === 'function') {
        try {
            crypto = require('crypto');
         } catch (err) {}
     }

@Bardiamist
Copy link

Bardiamist commented Feb 12, 2020

I don't have crypto dependency

I tried yarn add crypto

Result:

Metro Bundler has encountered an error: While trying to resolve module `crypto` from file `/Users/bardiamist/Documents/proj/node_modules/crypto-js/core.js`, the package `/Users/bardiamist/Documents/proj/node_modules/crypto/package.json` was successfully found. However, this package itself specifies a `main` module field that could not be resolved (`/Users/bardiamist/Documents/proj/node_modules/crypto/index.js`. Indeed, none of these files exist:

  * /Users/bardiamist/Documents/proj/node_modules/crypto/index.js(.native|.ios.js|.native.js|.js|.ios.json|.native.json|.json|.ios.ts|.native.ts|.ts|.ios.tsx|.native.tsx|.tsx)
  * /Users/bardiamist/Documents/proj/node_modules/crypto/index.js/index(.native|.ios.js|.native.js|.js|.ios.json|.native.json|.json|.ios.ts|.native.ts|.ts|.ios.tsx|.native.tsx|.tsx)

RCTFatal
__28-[RCTCxxBridge handleError:]_block_invoke
_dispatch_call_block_and_release
_dispatch_client_callout
_dispatch_main_queue_callback_4CF
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
__CFRunLoopRun
CFRunLoopRunSpecific
GSEventRunModal
UIApplicationMain
main
start

@evanvosberg
Copy link
Member Author

The crypto module is native in NodeJS and does not exists in React Native environment.

Therefor require('crypto') is wrapped in a try catch.

In case it fails the is another require('react-native-crypto') wrapped in a try catch as well.

Well the problem seems to be the usage of a bundler, as the bundler is doing static analysis and is trying to add crypto to the bundle. The try catch doesn't matter in this case.

Right now I'm not sure how to handle is on bundler level.

@mtt87
Copy link

mtt87 commented Feb 13, 2020

Just a note

Installing react-native-crypto just for the random numbers means that you are going to bloat your project with a lot of crap / unnecessary packages and hacky things.
Look at the installation process for example:

npm i --save react-native-crypto
# install peer deps 
npm i --save react-native-randombytes
react-native link react-native-randombytes
# install latest rn-nodeify 
npm i --save-dev tradle/rn-nodeify
# install node core shims and recursively hack package.json files 
# in ./node_modules to add/update the "browser"/"react-native" field with relevant mappings 
./node_modules/.bin/rn-nodeify --hack --install

In my case I decided to go with crypto-js for simplicity and no need to install loads of unused crap, aware that it can't generate random numbers safely.

I would consider if this library might work out without the need to install the entire react-native-crypto bloat
https://www.npmjs.com/package/react-native-randombytes

@vincicat
Copy link

The crypto module is native in NodeJS and does not exists in React Native environment.

Therefor require('crypto') is wrapped in a try catch.

In case it fails the is another require('react-native-crypto') wrapped in a try catch as well.

Well the problem seems to be the usage of a bundler, as the bundler is doing static analysis and is trying to add crypto to the bundle. The try catch doesn't matter in this case.

Right now I'm not sure how to handle is on bundler level.

straightforward solution:

delete core.js:25-37(=all the require statement)
example

that will fix the issues on RN 0.60+. (tested in RN 0.61)

If a fallback is needed,
solution 1: allow user to provide their own 'crypto' object after import into the core
solution 2: ask user to provide a global crypto instance(via require() or polyfill), as modern node.js/browser/RN webworker has the global crypto object for crypto.getRandomValues() or crypto.randomBytes(), and some library has already doing this

@aeirola
Copy link

aeirola commented Feb 19, 2020

Another solution which doesn't require any changes to crypto-js is to use the metro bundler config (https://facebook.github.io/metro/docs/en/configuration#extranodemodules) to point the crypto import to a polyfill package of your choosing. In metro.config.js add:

module.exports = {
  resolver: {
    extraNodeModules: {
      crypto: './node_modules/react-native-crypto,
    },
  },
};

A lighter polyfill could be https://github.com/LinusU/react-native-get-random-values, but it doesn't seem to be very up to date.

For more info how this works, see https://github.com/parshap/node-libs-react-native#usage-with-react-native-packager

@sunnylqm
Copy link

react native(metro) does not support conditional require(no runtime require)

@Bardiamist
Copy link

Bardiamist commented Mar 28, 2020

react native(metro) does not support conditional require(no runtime require)

Should be possible

Update: seems you are right

@sunnylqm
Copy link

@Bardiamist That's different. Metro will force every require exists.

@micheleberetta98
Copy link

Hey, is there any news about this?

@Bardiamist
Copy link

I can confirm that problem in require('crypto').

Can we remove it? And find another solution for NodeJS developers.
Maybe they can do something like global.crypto = require('crypto') before import crypto-js.

@aeirola Thanks for the solution. I'll just import react-native-get-random-values before crypto-js:

import 'react-native-get-random-values';
import hmacSHA512 from 'crypto-js/hmac-sha512';

I want fork crypto-js without next code block and use it

  // Native crypto import via require (NodeJS)
  if (!crypto && typeof require === 'function') {
    try {
      crypto = require('crypto');
    } catch (err) {}
}

@FMaz008
Copy link

FMaz008 commented Dec 20, 2020

Another solution which doesn't require any changes to crypto-js is to use the metro bundler config (https://facebook.github.io/metro/docs/en/configuration#extranodemodules) to point the crypto import to a polyfill package of your choosing. In metro.config.js add:

module.exports = {
  resolver: {
    extraNodeModules: {
      crypto: './node_modules/react-native-crypto',
    },
  },
};

A lighter polyfill could be https://github.com/LinusU/react-native-get-random-values, but it doesn't seem to be very up to date.

For more info how this works, see https://github.com/parshap/node-libs-react-native#usage-with-react-native-packager

Althought I'm not a fan of adding a whole librairie just to get rid of an error, doing a npm i --save react-native-crypto, and then adding this code to the metro.config.js file did get rid of the error. Thanks.

@DurandSacha
Copy link

a package.json config "crypto-js": "3.3.0", worked for me

@LucasHang
Copy link

I made this by using crypto-es lib instead.
I´m not sure if it fills all the necessities of crypto-js, but worked for me.

@ankitpatel7225
Copy link

i have same issue like

Error: Unable to resolve module crypto from node_modules\request\lib\helpers.js: crypto could not be found within the project.

If you are sure the module exists, try these steps:

  1. Clear watchman watches: watchman watch-del-all
  2. Delete node_modules: rm -rf node_modules and run yarn install
  3. Reset Metro's cache: yarn start --reset-cache
  4. Remove the cache: rm -rf /tmp/metro-*
    at ModuleResolver.resolveDependency (D:\ReactNative\ECommerce\node_modules\metro\src\node-haste\DependencyGraph\ModuleResolution.js:186:15)
    at ResolutionRequest.resolveDependency (D:\ReactNative\ECommerce\node_modules\metro\src\node-haste\DependencyGraph\ResolutionRequest.js:52:18)
    at DependencyGraph.resolveDependency (D:\ReactNative\ECommerce\node_modules\metro\src\node-haste\DependencyGraph.js:287:16)
    at Object.resolve (D:\ReactNative\ECommerce\node_modules\metro\src\lib\transformHelpers.js:267:42)
    at D:\ReactNative\ECommerce\node_modules\metro\src\DeltaBundler\traverseDependencies.js:434:31
    at Array.map ()
    at resolveDependencies (D:\ReactNative\ECommerce\node_modules\metro\src\DeltaBundler\traverseDependencies.js:431:18) at D:\ReactNative\ECommerce\node_modules\metro\src\DeltaBundler\traverseDependencies.js:275:33
    at Generator.next ()
    at asyncGeneratorStep (D:\ReactNative\ECommerce\node_modules\metro\src\DeltaBundler\traverseDependencies.js:87:24)

in react native if some one have any answer then please tell me i learning react native and at morning my project was running perfectly but from last 3 hour i face this issue so please help me on this

thanks in advance :)

@Bardiamist
Copy link

Bardiamist commented Mar 16, 2021

In React native 0.64.0 inlineRequires is enabled by default. So now it working good for me with react-native-get-random-values.

Instruction:

  1. Check inlineRequires: true in metro.config.js
  2. yarn add react-native-get-random-values
  3. cd ios/ && pod install
  4. Rebuild app
  5. Add import 'react-native-get-random-values'; before crypto-js import. For example at the top of App.js.

@vincicat
Copy link

vincicat commented Apr 12, 2021

In React native 0.64.0 inlineRequires is enabled by default. So now it working good for me with react-native-get-random-values.

Instruction:

  1. Check inlineRequires: true in metro.config.js
  2. yarn add react-native-get-random-values
  3. cd ios/ && pod install
  4. Rebuild app
  5. Add import 'react-native-get-random-values'; before crypto-js import. For example at the top of App.js.

inlineRequires seems enabled by default in RN 0.64, doing a basic npm installation should work for the part of crypto-js imports without crypto.getRandomValues() (e.g. sha256())

So the RN issue for 4.x is gone and this PR is subject to close, the final task is adding RN-related instructions back to the README...

@1Jesper1
Copy link

1Jesper1 commented Mar 3, 2022

@vincicat Could you add it to the README?

@weizixuanDavid
Copy link

my react-native is ^0.69.4, import 'react-native-get-random-values' before using 'crypto-js', but it does not work :(

@cl3i550n
Copy link

In React native 0.64.0 inlineRequires is enabled by default. So now it working good for me with react-native-get-random-values.

Instruction:

  1. Check inlineRequires: true in metro.config.js
  2. yarn add react-native-get-random-values
  3. cd ios/ && pod install
  4. Rebuild app
  5. Add import 'react-native-get-random-values'; before crypto-js import. For example at the top of App.js.

Works for me RN 0.70.6

@kathrynowy
Copy link

In React native 0.64.0 inlineRequires is enabled by default. So now it working good for me with react-native-get-random-values.

Instruction:

  1. Check inlineRequires: true in metro.config.js
  2. yarn add react-native-get-random-values
  3. cd ios/ && pod install
  4. Rebuild app
  5. Add import 'react-native-get-random-values'; before crypto-js import. For example at the top of App.js.

Thanks! Works for me! RN 0.71.6

@nkqdev
Copy link

nkqdev commented May 18, 2023

In React native 0.64.0 inlineRequires is enabled by default. So now it working good for me with react-native-get-random-values.

Instruction:

  1. Check inlineRequires: true in metro.config.js
  2. yarn add react-native-get-random-values
  3. cd ios/ && pod install
  4. Rebuild app
  5. Add import 'react-native-get-random-values'; before crypto-js import. For example at the top of App.js.

Thank you! It's works for me RN 0.71.8

@th3f0r3ign3r
Copy link

In React native 0.64.0 inlineRequires is enabled by default. So now it working good for me with react-native-get-random-values.
Instruction:

  1. Check inlineRequires: true in metro.config.js
  2. yarn add react-native-get-random-values
  3. cd ios/ && pod install
  4. Rebuild app
  5. Add import 'react-native-get-random-values'; before crypto-js import. For example at the top of App.js.

Thank you! It's works for me RN 0.71.8

What to do if in my RN 0.71.8 project I don't have the metro.config.js by default

@Bardiamist
Copy link

Bardiamist commented Jun 15, 2023

In React native 0.64.0 inlineRequires is enabled by default. So now it working good for me with react-native-get-random-values.
Instruction:

  1. Check inlineRequires: true in metro.config.js
  2. yarn add react-native-get-random-values
  3. cd ios/ && pod install
  4. Rebuild app
  5. Add import 'react-native-get-random-values'; before crypto-js import. For example at the top of App.js.

Thank you! It's works for me RN 0.71.8

What to do if in my RN 0.71.8 project I don't have the metro.config.js by default

React native 0.71.8 have it by default https://github.com/facebook/react-native/blob/0.71-stable/template/metro.config.js

@th3f0r3ign3r
Copy link

5. import 'react-native-get-random-values';

Big Thanks @Bardiamist 🙏🏾🙏🏾

@A-Kasaaian
Copy link

I spent 2 days to solve the issue, I have inlineRequires: false, in metro config and changing it breaks the app.

I installed yarn add react-native-get-random-values.

Then imported react-native-get-random-values before crypto-js but it didn't work.

After hours of debugging, I found it's Babel's compiling order issue. crypto-js is always compiled earlier than react-native-get-random-values. In another word crypto-js looks for global.crypto before react-native-get-random-values assigns it. imports compile with higher priority than the rest of codes.

My file was:

import 'react-native-get-random-values'
import crypto from 'crypto-js`

The fix was lowering the compile order of crypto-js to make sure it compiles after global.crypto is assigned:

import 'react-native-get-random-values'
const crypto = require('crypto-js')

@Shiv-Softtech
Copy link

Shiv-Softtech commented Aug 1, 2023

I Got This Error Any one Help for this Removing Error
crypto could not be found within the project or in these directories:
node_modules\tedious\node_modules
node_modules
....\node_modules
5 | });
6 | exports.default = void 0;

7 | var _crypto = _interopRequireDefault(require("crypto"));
| ^
8 | var _os = _interopRequireDefault(require("os"));
9 | var tls = _interopRequireWildcard(require("tls"));
10 | var net = _interopRequireWildcard(require("net"));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.