Closed emclab closed 4 years ago
I think this should be all you need to get started:
https://docs.ethers.io/v5/cookbook/react-native/
If you have any problems, or suggestions to improve the docs, please let me know. :)
ricmoo, the doc is a good starting point for me. Many thanks.
In the doc, it specifically mentions module react native crypto. I used [react-native-crypto](https://www.npmjs.com/package/react-native-crypto)
before. Is it good to fit in here? What kind of shim
do I need for react-native-crypto
if it is? Or it can go without shim in react native.
I’m not terribly familiar with RN other than what I tried out to get the RN test harness and docs together, but the main thing that a package like that is required for is the window.crypto.randomBytes
. If that package exposes that, you’re golden. :)
Otherwise, if does mean Wallet.createRandom()
is using an insecure random number source. If you are not creating random numbers in your dApp though (i.e. you only import existing mnemonics for wallets or use reliable random sources to create random wallets) you should be a-ok too.
(I just checked that package on npm, and I did try it out. It does expose a randomBytes
, but when I dove into the iOS source code a bit deeper it does so in a way that may be vulnerable to local scripts sniffing the internal workings; just something to keep in mind)
I see. I need investigate further about that. I used [rn-nodeify](https://www.npmjs.com/package/rn-nodeify)
to provide shim for some node core, including crypto.
ricmoo
, is there article about the local scripts sniffing the internal workings on IOS? I did some online search and did not find much about it. I may not use the right key words. Thanks.
I don’t think so. It's more or less just a term I made up to describe the case where another script (or library installed via npm) running on the same host (i.e. phone) can sniff/access the initial seed they use for the synchronous random values and replace reading random numbers to generate the same sequence.
To get an idea of what I mean, just check out how it works here. Anything running in the same RN process has access to this and so it can “sniff” the seed...
I don’t really understand why they do this since iOS support synchronous random bytes in a way that is compatible with the native RN hooks, but I could not find any library the correctly implemented this and don’t really want to maintain a react native native module myself. :)
I just came across this module [react-native-securerandom](https://www.npmjs.com/package/react-native-securerandom)
which is more actively maintained and gaining popularity. This module does not require shim
of rn-nodeify
but just a few changes in setup file for both IOS and Android. Is it a good fit for ethers
?
Yes, that library looks perfect! You will have to shim the crypto.getRandomValues though, and the import order of the root RN seems to be deferred, so you will likely need to create the shim as an import. But you could do something like:
import { generateSecureRandom } from 'react-native-securerandom';
window.crypto.getRandomValues = function(array) {
console.log("Remove this later; just checking to make sure this is used");
const random = generateSecureRandom(array.length);
for (let i = 0; i < array.length; i++) { array[i] = random[i]; }
};
So,put that in some file and import it before the shims, and then try ethers.Wallet.createRandom()
and make sure that console.log shows up in the output. If it does, you are golden.
If it works let me know (along with any other tweaks) and I'll add it to the RN docs for ethers. :)
(actually, it might make sense to ping the author of that library to offer a built-in shim)
ricmoo
, thank you for the details. I just installed the ethers
and is in the process of getting it started. Will update.
A shim.js
was created under root of app for the code above and import "./shim"
before import "@ethersproject/shims"
in App.js
. Here is an error about window.crypto
:
[Wed Sep 30 2020 15:09:32.565] BUNDLE ./index.js
[Wed Sep 30 2020 15:10:00.313] ERROR TypeError: undefined is not an object (evaluating 'window.crypto')
[Wed Sep 30 2020 15:10:00.316] ERROR Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication)
[Wed Sep 30 2020 15:10:00.317] ERROR Invariant Violation: Module AppRegistry is not a registered callable module (calling runApplication)
Oh, try adding:
if (window.crypto == null) { window.crypto = {}; }
before setting the function.
Bingo & well done! Here is the output:
info Reloading app...
[Wed Sep 30 2020 15:24:51.568] BUNDLE ./index.js
[Wed Sep 30 2020 15:25:28.701] LOG Shims Injected:
[Wed Sep 30 2020 15:25:28.705] LOG - atob
[Wed Sep 30 2020 15:25:28.729] LOG - btoa
[Wed Sep 30 2020 15:25:28.731] LOG - nextTick
[Wed Sep 30 2020 15:25:28.732] LOG - FileReader.prototype.readAsArrayBuffer
[Wed Sep 30 2020 15:25:28.734] LOG Running "aniPinch" with {"rootTag":81}
[Wed Sep 30 2020 15:25:28.749] LOG Remove this later; just checking to make sure this is used
Here is the shim.js
for output above:
import { generateSecureRandom } from 'react-native-securerandom';
if (window.crypto == null) window.crypto = {};
window.crypto.getRandomValues = function(array) {
console.log("Remove this later; just checking to make sure this is used");
const random = generateSecureRandom(array.length);
for (let i = 0; i < array.length; i++) { array[i] = random[i]; }
};
That’s awesome. I can open an issue upstream to see if the author of that library would like to incorporate it. Unless you want to.
I will update the docs with this lib too. Good find. :)
Great! go ahead with pull request. If you need me to followup with it, please let me know. I would be happy to help. Many thanks.
Actually, can you double check it works?
What happens if you use ethers.utils.getRandomBytes(32)
after setting the shim. It looks like it may only return a promise and not the actual random data synchronously... :s
Got some error [20:38:20] E | ReactNativeJS ▶︎ TypeError: _ethers.ethers.utils.getRandomBytes is not a function. (In '_ethers.ethers.utils.getRandomBytes(32)', '_ethers.ethers.utils.getRandomBytes' is undefined) │ │ This error is located at: │ in App (at renderApplication.js:45) │ in RCTView (at View.js:34) │ in View (at AppContainer.js:106) │ in RCTView (at View.js:34) │ in View (at AppContainer.js:132) └ in AppContainer (at renderApplication.js:39)
Tried callback ethers.utils.getRandomBytes(32).then() and the error seems to be the same.
ethers.utils.randomBytes(32) return output (a is the returned):
[21:10:50] I | ReactNativeJS ▶︎ 'a : ', { '0': 0, │ '1': 0, │ '2': 0, │ '3': 0, │ '4': 0, │ '5': 0, │ '6': 0, │ '7': 0, │ '8': 0, │ '9': 0, │ '10': 0, │ '11': 0, │ '12': 0, │ '13': 0, │ '14': 0, │ '15': 0, │ '16': 0, │ '17': 0, │ '18': 0, │ '19': 0, │ '20': 0, │ '21': 0, │ '22': 0, │ '23': 0, │ '24': 0, │ '25': 0, │ '26': 0, │ '27': 0, │ '28': 0, │ '29': 0, │ '30': 0, │ '31': 0 } └ Remove this later; just checking to make sure this is used
So, yes, it isn't working... The library returns a Promise, so it cannot be used this way (synchronously)...
I do recall trying that library now, and encountering the same problem... :(
added await and still output 0s:
const random = await generateSecureRandom(array.length);
But this requires the async call out of your lib I guess. It seems to be really big issue to get a secure random string!
Yeah... :(
Shall I use react-native-crypto
instead? Or whenever the app require a random string, the app calls the backend server and requires one. I am thinking to require a longer length random string from server and "randomly" pick out of it on app and form a string to its designated length to avoid being sniffed over the internet transportation. But I am not sure if the string generated will be random enough.
Never call a server for random numbers. That is a significant security vulnerability! Never ever. Ever! :p
Choosing a longer string and all that jazz does not improve the quality of the random string and puts a crazy serious attack vector in your app.
Also, that would be async anyways, at which point you might as well use the securerandom library.
The react-native-crypto is your best bet (least worst option), and while I got it working their build instructions were a bit convoluted.
react-native-crypto
!
But I don't quite understand why requiring a random string base from server would be a significant security risk. The frontend app only uses the random string base returned ( over https
certainly) to form the random string needed locally. Let's say someone get hold of the random string returned by the server, he/she only knows that the random string on app will be created out of the string he/she has but still does not know exactly what the random string the app is going to have. On the other hand the sniffer only knows the char set to be used to form random string on app, just like we know any random string will be out of char set of 10digit + 26 char (up/low case).
But that random string will be used in some deterministic fashion by the app, which is logic an attacker that sniffed that data can also replay. Keep in mind even having a little bit of knowledge greatly impacts the security profile. There is no way to add entropy without a truly random source, so if you send that string to the device, entropy can only be lost, reducing the security.
"but still does not know exactly what the random string the app is going to have"
i.e. If they get that string, they will have a VERY good idea of what the string will be be, even if you stir it up a bit, they can stir it in similar ways.
There are other issues as well to keep in mind:
a) I, the app user, must trust the entropy coming from your server. If you decide to be malicious or if someone hijacks (hacks into your server) they can select the data feed me
b) Many school networks use authenticated certificates for their WiFi and coffee shops MitM traffic for authentication purposes; in either of these cases it may be possible for the in-flight entropy to be discovered. On many OSes I may get a simple dialog box indicating "Do you wish to trust this entity: Starbucks", in which case selecting "OK" (which most users just tap aimlessly) now renders all my content viewable by middle parties.
c) Replay; even if the data is encrypted, it could have been logged somewhere, which means some day the decryption keys may come to light, exposing historic data used
HTTPS is a must but is not a magic bullet, and why not let the device use a true random source, which is has available locally.
The big advantage of blockchain is we have a truly trestles system. There is no need to add the need to trust other parties. If you use a compromised source for entropy to generate private keys, they will be stolen from. This has happened many times before (e.g. brain wallets, faulty use of JavaScript RNG and there was a case where someone was querying on-line sources for random numbers) and all ended up stolen; luckily in a few cases, by white hats.
Long story short, do not use random data from a server. :)
Great comments. Security is always a big concern but a lot of time a user ( me for ex) just can not think of all the possible consequences an action may comes with.
It seems to me that there is no truly random
ever existing. Any random is deterministic algorithmatically. This may be the cause of related security issue.
Oh yes. Security is quite hard to get right, which is why there is such a (justified) stigma against “rolling your own crypto”. :)
There are true random sources. Your phone uses low bits in the noise in the EM spectrum on their BlueTooth, Wifi and GSM antennae, which is basically chunks of static left over from the Big Bang, so pretty hard to guess. :)
Computers will use similar sources, as well as stirring in network traffic, keystroke timestamps, hard drive jitter and whatnot. Even this stirring though is very crucial to be done in ways that do not damage the underlying entropy they are trying to mix.
But these are things hardware designers and OS architects figure out for us, which is why it’s best to use what they give us. :)
Is there way I can test the installation of react-native-crypto
? The installation went without error.
After removing react-native-securerandom
from the app, the same test code
let a = await ethers.utils.randomBytes(32);
console.log("a : ", a);
generated the following random output:
[Wed Oct 07 2020 21:34:55.711] WARN Setting a timer for a long period of time, i.e. multiple minutes, is a performance and correctness issue on Android as it keeps the timer module awake, and timers can only be called when the app is in the foreground. See https://github.com/facebook/react-native/issues/12981 for more info.
(Saw setTimeout with duration 120000ms)
[Wed Oct 07 2020 21:34:55.713] LOG a : [203, 209, 49, 68, 230, 96, 32, 87, 254, 210, 13, 132, 134, 53, 46, 17, 200, 226, 74, 84, 214, 121, 226, 12, 173, 246, 242, 52, 77, 155, 137, 68]
Is it random enough to be used with ethers.js
? react-native-crypto
was not installed. Not sure what is the warning about the timer.
Came across [react-native-get-random-values](https://github.com/LinusU/react-native-get-random-values)
claiming strong random in RN for module calling crypto.getRandomValues
. The module is actively maintained and has currently ~140K weekly download. Also it does not return promise and is sync op.
Awesome! That looks perfect!! I checked the source and it looks good.
I’ll update the docs with package.
Thanks! :)
Sounds great! No shim needed, isn't it?
react-native-crypto
is pain to use with rn-nodeify
which introduces modification and quite a few modules. Some of modules may not be used at all and may also be out of date.
Just installed react-native-get-random-values
and import it at top of App.js
. Here is the console output:
[Thu Oct 08 2020 12:27:12.456] LOG a : [155, 34, 116, 184, 69, 174, 29, 185, 193, 169, 81, 237, 231, 76, 132, 96, 202, 21, 198, 216, 96, 182, 130, 69, 9, 27, 3, 141, 151, 56, 91, 162]
crypto.randomBytes shim is not working in RN.
how get erc20 balanceOf
const mainProvider = new ethers.providers.JsonRpcProvider(url);
let content= new ethers.Contract(erc20_token,erc20_abi,mainProvider);
content.balanceOf(address).then(res=>{
console.log(res);
})
@Lloyd1229 Can you double check if the erc20 token address and provider is correct? If contract does not exist at that address then, you'd get such error.
I tested solution given on this website https://docs.ethers.io/v5/cookbook/react-native/ but I am still getting this error when trying to get the token balance Error: could not detect network (event="noNetwork", code=NETWORK_ERROR, version=providers/5.0.23). Anyone knows solution to this please?
I am getting the error warning of no secure random source available with expo sdk 42.0.1 even with react-native-get-random-values
imported at the top of my App.js
The error:
[Unhandled promise rejection: Error: no secure random source avaialble (operation="crypto.getRandomValues", code=UNSUPPORTED_OPERATION, version=random/5.4.0)]
@nikita-zot-1408 the reason why your getting an error is that ios only access HTTPS. so use ngrok to create a tunnel to your localhost then you will be able to get the balance.
@loekTheDreamer Any change I could bug you for a quick walk-through or a link that I could add to the cookbook? :)
@loekTheDreamer Any change I could bug you for a quick walk-through or a link that I could add to the cookbook? :)
sure, just not sure what you mean? @ricmoo
I’ve never set up ngrok, if you have any info on setting it up for iOS, I’d include it in the cookbook in the React Native section. :)
Oh, it's super simple @ricmoo just follow these steps:
unzip /path/to/ngrok.zip
./ngrok authtoken yourSecretToken
./ngrok http 7545
I am new to
ethers.js
and just read a online post about it. I am looking for a lib (such asweb3.js
) which can be integrated with React Native 0.63 app and providing features of ethereum wallet, performing transaction, such as invoking smart contract methods , transferring fund and viewing transactions on chain. The post I just read claims thatethers.js
supportsReact Native
by default. I am excited about it as I have tried to usern-nodeify
foripfs
module on RN app and could not solve a few bundle issue. What is the procedure of addingethers.js
to a React Native 0.63 app? Any documents or online posts would help. Thanks.