scottyab / secure-preferences

Android Shared preference wrapper than encrypts the values of Shared Preferences. It's not bullet proof security but rather a quick win for incrementally making your android app more secure.
1.53k stars 235 forks source link

Use secure-preferences with Robolectric #16

Closed ntarocco closed 9 years ago

ntarocco commented 9 years ago

I am using secure-preferences to encrypt my local preferences. However, when using Robolectric to run unit tests, the preferences are not correctly filled in, and when trying to check if the key is contained in the file, it is always empty.

My app code for the shared prefs:

public class AppSharedPrefs {
    private ApplicationSharedPreferences(Context context) {
        sSharedPreferences = new SecurePreferences(context, context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE));
        sEditor = sSharedPreferences.edit();
        mContext = context;

        clearSharedPreferences();

    }

    public static ApplicationSharedPreferences getInstance(Context context) {
        if (instance == null) {
            instance = new ApplicationSharedPreferences(context);
        }
        return instance;
    }

    ... then all getter and setter ...
}

Then, my test code:

@RunWith(TestRunner.class)
public class CustomerAPITest extends GlobalTestCase {

    @Test
    public void handleActionTest() throws JSONException {
        final String VALUE = "1";

        AppSharedPreferences asp = AppSharedPreferences.getInstance(getTestContext());
        asp.setMyValue(VALUE);

        new CustomerAPI().handleAction();
        ....
    }
}

and my function in "handleAction()" will read VALUE, with:

AppSharedPreferences asp = AppSharedPreferences.getInstance(context);
asp.getMyValue(VALUE); // always null

but is always null, shared preferences always empty. If I remove SecurePreferences and use standard Android prefs, everything works.

Any clue how to solve this and if it is a problem of the library?

scottyab commented 9 years ago

Not tried with Robolectric (will add to my todo), which version of shared prefs? 0.1.0 or the older 0.4.0?

ntarocco commented 9 years ago

0.0.4, I can try to see if with the version 0.1.0 the problem is not reproducible...

scottyab commented 9 years ago

Are you sure you're tests are being correctly cleared down afterwards? I found with the unit tests I wrote in the lib, i had to manually delete the created pref xml files between tests otherwise it would reuse.

pivotal-csaa-dev commented 9 years ago

We saw the same issue. We worked around it by manually setting the private static SharedPreferences field to null before each test. So, the root issue is because the SecurePreferences class uses the static field, so suppling a different filename will get ignored if SecurePreferences was instantiated with a different file name in a test that ran before this one. We suspect that the sFile variable being static may be a mistake due the comment above it: //default for testing

Here's our subclass that allows us to reset the static field before instantiating SecurePreferences again:

public class TestSafeSecurePreferences extends SecurePreferences {

    public TestSafeSecurePreferences(Context context) {
        super(context);
    }

    public TestSafeSecurePreferences(Context context, String password, String sharedPrefFilename) {
        super(context, password, sharedPrefFilename);
    }

    public static void clearStaticState() {
        try {
            Field staticField = SecurePreferences.class.getDeclaredField("sFile");
            staticField.setAccessible(true);
            staticField.set(null, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
scottyab commented 9 years ago

Thanks for this see #22, a fix will be in version 0.1.2

pivotal-csaa-dev commented 9 years ago

Cool!. Do you have a target release date for version 0.1.2?

scottyab commented 9 years ago

@pivotal-csaa-dev 0.1.2 has been pushed to maven central, awaiting replication.