Skip to content
This repository has been archived by the owner on Sep 4, 2024. It is now read-only.

crypto and localstorage error in react native #96

Open
destimon opened this issue Sep 13, 2020 · 4 comments
Open

crypto and localstorage error in react native #96

destimon opened this issue Sep 13, 2020 · 4 comments

Comments

@destimon
Copy link

Currently trying to use mtproto-core in react-native project.

Have next issues:

During call method from the instance - getting undefined localStorage

[03:34:24] [Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'this.localStorage.getItem')]
- node_modules\@mtproto\core\src\storage\index.js:49:35 in Storage#get
- node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
- node_modules\regenerator-runtime\runtime.js:293:29 in invoke
- node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
- node_modules\regenerator-runtime\runtime.js:154:27 in invoke
- node_modules\regenerator-runtime\runtime.js:189:16 in PromiseImpl$argument_0
- node_modules\promise\setimmediate\core.js:45:6 in tryCallTwo
- node_modules\promise\setimmediate\core.js:200:22 in doResolve
- node_modules\promise\setimmediate\core.js:66:11 in Promise
- node_modules\regenerator-runtime\runtime.js:188:15 in callInvokeWithMethodAndArg
- node_modules\regenerator-runtime\runtime.js:211:38 in enqueue
- node_modules\regenerator-runtime\runtime.js:238:8 in exports.async
* http://192.168.0.105:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&minify=false&hot=false:171436:41 in get
- node_modules\@mtproto\core\src\index.js:75:40 in MTProto#call
- node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
- node_modules\regenerator-runtime\runtime.js:293:29 in invoke
- node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
- node_modules\regenerator-runtime\runtime.js:154:27 in invoke
- node_modules\regenerator-runtime\runtime.js:189:16 in PromiseImpl$argument_0
- node_modules\promise\setimmediate\core.js:45:6 in tryCallTwo
- node_modules\promise\setimmediate\core.js:200:22 in doResolve
- node_modules\promise\setimmediate\core.js:66:11 in Promise
- node_modules\regenerator-runtime\runtime.js:188:15 in callInvokeWithMethodAndArg
- node_modules\regenerator-runtime\runtime.js:211:38 in enqueue
- node_modules\regenerator-runtime\runtime.js:238:8 in exports.async
* http://192.168.0.105:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&minify=false&hot=false:141073:41 in call
- node_modules\react-native\Libraries\Components\Touchable\TouchableNativeFeedback.js:169:10 in Pressability$argument_0.onPress
- node_modules\react-native\Libraries\Pressability\Pressability.js:655:17 in _performTransitionSideEffects
- node_modules\react-native\Libraries\Pressability\Pressability.js:589:6 in _receiveSignal
- node_modules\react-native\Libraries\Pressability\Pressability.js:499:8 in responderEventHandlers.onResponderRelease
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:286:4 in invokeGuardedCallbackImpl
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:497:2 in invokeGuardedCallback
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:521:2 in invokeGuardedCallbackAndCatchFirstError
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:683:41 in executeDispatch
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:707:19 in executeDispatchesInOrder
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:872:28 in executeDispatchesAndRelease
* [native code]:null in forEach
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:851:4 in forEachAccumulated
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:897:20 in runEventsInBatch
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:1069:18 in runExtractedPluginEventsInBatch
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2835:35 in batchedUpdates$argument_0
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:20569:13 in batchedUpdates$1
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2731:29 in batchedUpdates
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2834:16 in _receiveRootNodeIDEvent
- node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2911:27 in receiveTouches
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:425:19 in __callFunction
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:112:6 in __guard$argument_0
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:373:10 in __guard
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:111:4 in callFunctionReturnFlushedQueue
* [native code]:null in callFunctionReturnFlushedQueue

Any call method causes that error. Obviously, localStorage property, as i checked, is undefined in mtproto instance after initializating.

const confirmPhone = useCallback(() => {
  const api_id = [API_ID];
  const api_hash = [API_HASH];

  const mtproto = new MTProto({
    api_id,
    api_hash,
  });

  mtproto.call("auth.sendCode", {
    phone_number: "9996621234",
    settings: {
      _: "codeSettings",
    },
  });
}, []);

I've tried to replace default storage with custom storage:

const confirmPhone = useCallback(() => {
  const api_id = [API_ID];
  const api_hash = [API_HASH];

  const mtproto = new MTProto({
    api_id,
    api_hash,
    customLocalStorage: tempLocalStorage, // Custom storage from @mtproto/core/src/storage/temp
  });

  mtproto.call("auth.sendCode", {
    phone_number: "9996621234",
    settings: {
      _: "codeSettings",
    },
  });
}, []);

and now getting the next error:

[03:44:27] [Unhandled promise rejection: ReferenceError: Can't find variable: crypto]
- node_modules\@mtproto\core\src\utils\common\random\index.browser.js:1:0 in getRandomBytes
- node_modules\@mtproto\core\src\rpc\index.js:723:18 in RPC#updateSession
- node_modules\@mtproto\core\src\rpc\index.js:34:19 in RPC#constructor
- node_modules\@mtproto\core\src\index.js:129:18 in MTProto#createRPC
* http://192.168.0.105:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&minify=false&hot=false:141104:30 in call$
- node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
- node_modules\regenerator-runtime\runtime.js:293:29 in invoke
- node_modules\regenerator-runtime\runtime.js:63:36 in tryCatch
- node_modules\regenerator-runtime\runtime.js:154:27 in invoke
- node_modules\regenerator-runtime\runtime.js:164:18 in PromiseImpl.resolve.then$argument_0
- node_modules\promise\setimmediate\core.js:37:13 in tryCallOne
- node_modules\promise\setimmediate\core.js:123:24 in setImmediate$argument_0
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:135:14 in _callTimer
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:183:16 in _callImmediatesPass
- node_modules\react-native\Libraries\Core\Timers\JSTimers.js:446:30 in callImmediates
* [native code]:null in callImmediates
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:396:6 in __callImmediates
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:144:6 in __guard$argument_0
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:373:10 in __guard
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:143:4 in flushedQueue
* [native code]:null in flushedQueue
* [native code]:null in callFunctionReturnFlushedQueue

Seems like it can't support Node.js, but in simple Node.js project(w/o any frameworks) everything works fine.

$ node -v
v14.10.1

Will be grateful for any help 🙏🏻.

@destimon destimon changed the title crypto crypto and localstorage error in react native Sep 13, 2020
@alik0211
Copy link
Owner

  1. By storage: you need to write your own customLocalStorage.
  2. And probably, now cryptographic functions are not compatible with react-native. I will try to fix this in the next release

You can follow future releases in the official telegram channel - https://t.me/mtproto_core

@happymaskterriblefate
Copy link

I've spent a bunch of time attempting to get the correct crypto APIs to be available in react-native, without success.

From what I can tell, the APIs required are:

  • crypto.getRandomBytes
  • crypto.rsa
  • crypto.SHA1
  • crypto.SHA256
  • crypto.getRandomBytes
  • crypto.subtle.deriveBits, crypto.subtle.importKey, and crypto.subtle.digest

I've found alternatives to these APIs in various packages, but ultimately run into either compatibility problems or an API that is async when MTProto expects it to be sync (getRandomBytes for example).

Do you have a suggestion for an alternative library that would work in react-native? If not, is there anything I can do to help get react-native support? Thanks!

@happymaskterriblefate
Copy link

happymaskterriblefate commented May 3, 2021

I had just about given up, but then tried the react-native-webview-crypto package.

Here's what worked for me:

App.js

import React, { useEffect } from "react";
import WebviewCrypto from "react-native-webview-crypto";
import { TextEncoder, TextDecoder } from "web-encoding";
import "react-native-get-random-values";
import { View } from "react-native";
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import MTProto from "@mtproto/core/envs/browser";

polyfillGlobal("TextEncoder", () => TextEncoder);
polyfillGlobal("TextDecoder", () => TextDecoder);

// Dummy storage to get things working
class CustomStorage {
  constructor() {
    this.data = {};
  }

  set(key, value) {
    this.data[key] = value;
    return Promise.resolve();
  }

  get(key) {
    return Promise.resolve(this.data[key]);
  }
}

const App = () => {
  useEffect(() => {
    // REPLACE WITH YOUR VALUES
    const api_id = "xxxxxxx";
    const api_hash = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    const mtproto = new MTProto({
      api_id,
      api_hash,

      storageOptions: {
        instance: new CustomStorage(),
      },
    });

    // 2. Print the user country code
    mtproto.call("help.getNearestDc").then(result => {
      console.log("Nearest DC:", result.country);
    });
  }, []);

  return (
    <View>
      <WebviewCrypto />
    </View>
  );
};

export default App;

You'll need react-native-webview-crypto, web-encoding, react-native-get-random-values, as well as the polyfillGlobal helper built into react-native. Then load the browser version of MTProto located at @mtproto/core/envs/browser.

image

I hope this saves someone time in the future. If I run into any other issues, I'll followup in this thread.

@happymaskterriblefate
Copy link

Added a PR here: #187

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

No branches or pull requests

3 participants