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

v4 Not working with react-native #67

Closed
LucasBerger opened this issue Jul 31, 2022 · 7 comments
Closed

v4 Not working with react-native #67

LucasBerger opened this issue Jul 31, 2022 · 7 comments

Comments

@LucasBerger
Copy link

When using version 4.0.0 of this library there are errors when starting the app:

Error: redux-persist-transform-encrypt: Expected outbound state to be a string.
and
Error: Native crypto module could not be used to get secure random number.

Downgrading to 3.x solves these issues

@maxdeviant
Copy link
Owner

I was worried this would happen.

This is the same issue reported in #49. The "solution" at the time was to downgrade crypto-js to a version that did not depend on Node's built-in crypto.

However, in v4 we upgraded crypto-js to fix some security issues in the previous version (requested in #57).

I anticipated that upgrading crypto-js would break React Native usage, which is why I opted for the major version bump.

Could you see if this workaround listed on the crypto-js repo solves the issue? brix/crypto-js#259 (comment)

@langarus
Copy link

I've encountered the same issue. Downgrading is not an options as I was looking to encrypt only partially the redux store, and this is available only on v4.0.0.

What I have done on the other hand is reimplemented the encrypt logic in another file. The only thing I've changed is removed the onError from interface of EncryptTransformConfig.

These are the packages

"react-native": "0.68.0",
"crypto-js": "^4.1.1",
"json-stringify-safe": "^5.0.1",
"redux-persist": "^6.0.0",

This is the implementation - which is pretty much copy paste.

import * as Aes from "crypto-js/aes";
import * as CryptoJsCore from "crypto-js/core";
import stringify from "json-stringify-safe";
import { createTransform } from "redux-persist";
import type { TransformConfig } from "redux-persist/lib/createTransform";

export interface EncryptTransformConfig {
    secretKey: string;
}

const makeError = (message: string) => new Error(`redux-encryption-err: ${message}`);

export const encryptStore = <HSS, S = any, RS = any>(
    config: EncryptTransformConfig,
    transformConfig?: TransformConfig
) => {
    if (typeof config === "undefined") {
        throw makeError("No configuration provided.");
    }

    const { secretKey } = config;
    if (!secretKey) {
        throw makeError("No secret key provided.");
    }

    const onError = console.warn;

    return createTransform<HSS, string, S, RS>(
        (inboundState, _key) => Aes.encrypt(stringify(inboundState), secretKey).toString(),
        (outboundState, _key) => {
            if (typeof outboundState !== "string") {
                return onError(makeError("Expected outbound state to be a string."));
            }

            try {
                const decryptedString = Aes.decrypt(outboundState, secretKey).toString(CryptoJsCore.enc.Utf8);
                if (!decryptedString) {
                    throw new Error("Decrypted string is empty.");
                }

                try {
                    return JSON.parse(decryptedString);
                } catch {
                    return onError(makeError("Failed to parse state as JSON."));
                }
            } catch {
                return onError(
                    makeError("Could not decrypt state. Please verify that you are using the correct secret key.")
                );
            }
        },
        transformConfig
    );
};

@maxdeviant
Copy link
Owner

Apologies, I'm not sure I'm following how removing the onError from the EncryptTransformConfig resolved the issue.

The error Error: Native crypto module could not be used to get secure random number. seems to stem from React Native not supporting the native crypto package.

@langarus
Copy link

@maxdeviant maybe it's not clear. That is just a customisation I've done. It has nothing to do fixing the issue.

I've replicated the logic locally so I have more control over it. Removing the onError was just for me.

Also I've done this as well
brix/crypto-js#259 (comment)

Basically you have to install react-native-get-random-values run pod install and add this import before the crypto-js import (I put in the root index.tsx file), and it seems to work. Now if I comment that import it throws the error, but leaving it uncommented fixes it.

@maxdeviant
Copy link
Owner

Ah, that makes more sense. Thanks for the clarification!

@jackkrone
Copy link

Downgrading is not an options as I was looking to encrypt only partially the redux store, and this is available only on v4.0.0.

Why do you say this @langarus ? I'm using 3.0.1 and am able to encrypt only part of the store. Maybe I'm missing something. I'm using a nested persist like this:

const rootPersistConfig = {
  key: 'root',
  storage: AsyncStorage,
  blacklist: ['encryptedFields'],
};

const encryptedPersistConfig = {
  key: 'encryptedFields',
  storage: AsyncStorage,
  transforms: [
    encryptTransform({
      secretKey: 'my-super-secret-key',
      onError(error) {},
    }),
  ],
};

const rootReducer = combineReducers({
  offices: officesReducer,
  user: userReducer,
  encryptedFields: persistReducer(
    encryptedPersistConfig,
    encryptedFieldsReducer,
  ),
});

const persistedReducer = persistReducer(rootPersistConfig, rootReducer);

@dipanshujindaladt
Copy link

Hi Team

I am also facing the same issue.

I installed the library react-native-get-random-values and import in store.js and sync.js file but still facing the same issue.

simulator_screenshot_E48E912A-77E0-4E04-9ACA-821E73EE047A

@maxdeviant maxdeviant closed this as not planned Won't fix, can't repro, duplicate, stale Feb 2, 2024
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

5 participants