oblador / react-native-keychain

:key: Keychain Access for React Native
MIT License
3.2k stars 521 forks source link

function getGenericPassword returns invalid data on ios #363

Open fobtracker opened 4 years ago

fobtracker commented 4 years ago

Hi guys. I have a problem.

I created a class in my project.

import Keychain, { SharedWebCredentials } from 'react-native-keychain';

export class Session {
    public static async setGenericPassword(username: string, password: string): Promise<void> {
        await Keychain.setGenericPassword(username, password);
    }

    public static async getGenericPassword(): Promise<SharedWebCredentials | false> {
         return await Keychain.getGenericPassword();
    }

    public static async resetGenericPassword(): Promise<void> {
        await Keychain.resetGenericPassword();
    }
}

Why am I calling the data retrieval function in my code.

useEffect(() => {
    const runEffectAsync = async () => {
        const credentials = await Session.getGenericPassword();

        console.log('credentials', credentials);
    };
    runEffectAsync();
}, []);

I run my application for the first time and the console displays.

credentials false

I close the application and run again, and the console displays.

credentials {"password": "1", "service": "...here app id...", "storage": "keychain", "username": "_pfo"}

I did not use the setGeneris Password function and did not write anything to the storage, I ran my application twice in half of its installation. This behavior is typical only for ios, since the android works fine. What to do with this problem?

I checked this problem on versions 6.1.1 and 6.1.0 there she is present.

React Native: 0.62.2 react-native-keychain: 6.1.1

Vasault commented 4 years ago

getting EXACTLY the same issue, i'm getting _pfo on my username, and 1 on my password, please someone help us both

vikigsv commented 4 years ago

Same issue here..

React Native: 0.59.10 react-native-keychain: 3.1.3

imhuy commented 4 years ago

Same issue here.. "react-native": "0.62.2", "react-native-keychain": "^6.1.1",

fobtracker commented 4 years ago

I solved the problem using password verification, as the password length cannot be less than 7 characters.

useEffect(() => {
    const runEffectAsync = async () => {
        const credentials = await Session.getGenericPassword();
        if (credentials && credentials.username && credentials.password && credentials.password.length > 7) {
            console.log('credentials', credentials)
        } else {
            console.log('no credentials');
        }
    };
    runEffectAsync();
}, []);

But this is a temporary solution, you do not need to apply it. We are waiting for corrections from the authors of this library.

Vasault commented 4 years ago

I solved the problem using password verification, as the password length cannot be less than 7 characters.

useEffect(() => {
    const runEffectAsync = async () => {
        const credentials = await Session.getGenericPassword();
        if (credentials && credentials.username && credentials.password && credentials.password.length > 7) {
            console.log('credentials', credentials)
        } else {
            console.log('no credentials');
        }
    };
    runEffectAsync();
}, []);

But this is a temporary solution, you do not need to apply it. We are waiting for corrections from the authors of this library.

got a similar workaround for the moment

jimjja commented 4 years ago

Any updates on this issue?

jimjja commented 4 years ago

For any future reference, we fixed the issue by defining the service property for the config options. More info here -> https://www.npmjs.com/package/react-native-keychain#options

fedefrei commented 4 years ago

Getting the same error here. Applied a temporary fix waiting for a permanent solution!! Thank!!

JoelOnGithub commented 4 years ago

I am also having this issue. But our users also randomly lose their credentials on iOS. And indeed the username and password returns "_pfo" and "1". Even without signing out.

@jimjja, does your fix still hold up?

jimjja commented 4 years ago

Hey @JoelOnGithub, There were few things we found out that was causing issues with the keychain on ios and android. The main issue we had with ios was that leaving the service prop using the default value of the bundle id didnt work. Because of that we defined the service prop to be a random generated key, GUID for example. We also had some issues with Android where it wasnt able to store the keys.

On the end our config looked something like this:

{
  accessControl:
    Platform.OS === 'ios' ? undefined : ACCESS_CONTROL.APPLICATION_PASSWORD,
  accessible: ACCESSIBLE.WHEN_UNLOCKED, // iOS only
  securityLevel: SECURITY_LEVEL.SECURE_SOFTWARE, // Android only
  rules: 'none', // Android only
  // Keychain doesnt work with BundleId which is why we specify the service manually
  service: 'fba355de-1d7c-40be-b587-ad8805f8c042',
}
JoelOnGithub commented 4 years ago

Okay, thank you very much, ill take a similar approach

SudoPlz commented 4 years ago

@jimjja that config is not a valid json, part of that code is commented out, can you tell us which changes you had luck with?

Besides specifying a service random GUID or did you also have to make other changes too? Also, correct me if I'm wrong, but the way I read this is that the random GUID is generated every time that code runes. Why not use a random string that is always the same (i.e hello_world) or whatever instead of a GUID? Is it necessary for that id to change?

Thanks

jimjja commented 4 years ago

Hi @SudoPlz , I edited the code config in the correct format. Keep in mind that you will need to use it in javascript file as it uses Platform parameter coming from RN. The random GUID is setup instead of the bundle id which is supposed to be the default value. It shouldn't change every time as this is how the encrypted data is being linked per app, so if you start changing it you will loose your encrypted data. As you know the default value is supposed to be the bundleId which is not being regenerate every time. You can use any random string you want it will still be fine. We used GUID as its unique and non human readable.

SudoPlz commented 4 years ago

After some digging I suspect the problem is firebase analytics. I think it's also using that same keychain service and it's saving it's own values. That's probably why changing the service also works. Testing that assumption now.

Vasault commented 4 years ago

After some digging I suspect the problem is firebase analytics. I think it's also using that same keychain service and it's saving it's own values. That's probably why changing the service also works. Testing that assumption now.

you could be right, this also happened to me the moment i implemented crashlytics and analytics from firebase

RishavKumar-3796 commented 4 years ago

Something serious which needs immediate action!

vomchik commented 4 years ago

I have the same issue, on each app start, i get password: "1" until i set a custom service.

vomchik commented 4 years ago

Just deleted Firebase from the project and now all works fine 🤷‍♂️ Currently, I using Firebase 6.18. Is someone able to check it on the newest version?

BTW, _pfo => previous_first_open_count

vomchik commented 4 years ago

Ha, even on the latest Firebase (v6.33) version this issue reproducing.

Workaround: it using the service name 🤷‍♂️

vomchik commented 4 years ago

I have created an issue https://github.com/firebase/firebase-ios-sdk/issues/6582 Waiting ⏲️

JoelOnGithub commented 4 years ago

@vomchik, you can fix it by setting your own key. This way it wont get overwritten.

var settings =  { service: 'com.appname-some-key' };
await Keychain.setGenericPassword(username,password, settings);
await Keychain.getGenericPassword(settings);
await Keychain.resetGenericPassword(settings);
leethree commented 3 years ago

The collision is caused by Firebase but the key and password should still be stored in the keychain. So technically Firebase SDK isn't doing anything wrong. Any 3rd party library could store data in the iOS keychain. The issue is that this library fails to read the correct item out of the keychain items.

Sakshisrivastava413 commented 2 years ago

did anyone figure out the solution for randomly username getting set to _pfo and password to 1 Changing the service property didn't help @fobtracker

ericbsantana commented 2 years ago

@vomchik, you can fix it by setting your own key. This way it wont get overwritten.

var settings =  { service: 'com.appname-some-key' };
await Keychain.setGenericPassword(username,password, settings);
await Keychain.getGenericPassword(settings);
await Keychain.resetGenericPassword(settings);

This works for me. I think it is indeed a conflict with Firebase, as it was said above. Thank you!