Skip to content

Commit

Permalink
Encrypt current user data when storing into SharedPreferences
Browse files Browse the repository at this point in the history
  • Loading branch information
carmenlau committed Oct 2, 2018
2 parents bf99d29 + 5d35822 commit 1734129
Show file tree
Hide file tree
Showing 12 changed files with 507 additions and 17 deletions.
2 changes: 1 addition & 1 deletion skygear/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ android {
useLibrary 'org.apache.http.legacy'

defaultConfig {
minSdkVersion 16
minSdkVersion 18
targetSdkVersion 26
versionCode 1
versionName skygearVersion
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package io.skygear.skygear;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import org.json.JSONObject;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.HashMap;
import java.util.Map;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;

@RunWith(AndroidJUnit4.class)
@SuppressLint("CommitPrefEdits")
public class SecurePersistentStoreUnitTest {
static Context instrumentationContext;

private static void clearSharedPreferences(Context context) {
SharedPreferences pref = context.getSharedPreferences(
PersistentStore.SKYGEAR_PREF_SPACE,
Context.MODE_PRIVATE
);
SharedPreferences.Editor edit = pref.edit();
edit.clear();
edit.commit();
}

@BeforeClass
public static void setUpClass() throws Exception {
instrumentationContext = InstrumentationRegistry.getContext().getApplicationContext();
clearSharedPreferences(instrumentationContext);
}

@AfterClass
public static void tearDownClass() throws Exception {
clearSharedPreferences(instrumentationContext);
instrumentationContext = null;
}

@Before
public void setUp() throws Exception {
clearSharedPreferences(instrumentationContext);
}

@After
public void tearDown() throws Exception {
clearSharedPreferences(instrumentationContext);
}

@Test
public void testPersistentStoreRestoreUserFromEmptyState() throws Exception {
SecurePersistentStore persistentStore = new SecurePersistentStore(instrumentationContext);
assertNull(persistentStore.currentUser);
}

@Test
public void testPersistentStoreSaveAndRestoreUser() throws Exception {
SecurePersistentStore persistentStore = new SecurePersistentStore(instrumentationContext);

// Save user
Map profile = new HashMap<>();
profile.put("username", "user_12345");
profile.put("email", "user12345@skygear.dev");

persistentStore.currentUser = new Record("user", "12345", profile);
persistentStore.accessToken = "token_12345";
persistentStore.save();

// Restore current user
SecurePersistentStore newPersistentStore = new SecurePersistentStore(instrumentationContext);
Record currentUser = newPersistentStore.currentUser;

assertEquals("user", currentUser.type);
assertEquals("12345", currentUser.id);
assertEquals("user_12345", currentUser.get("username"));
assertEquals("user12345@skygear.dev", currentUser.get("email"));

assertEquals("token_12345", persistentStore.accessToken);

// Current user information should be store in encrypted fields
SharedPreferences pref = instrumentationContext.getSharedPreferences(
SecurePersistentStore.SKYGEAR_PREF_SPACE,
Context.MODE_PRIVATE
);

String currentUserString = pref.getString(PersistentStore.CURRENT_USER_KEY, null);
String currentUserEncryptedString = pref.getString(
SecurePersistentStore.CURRENT_USER_ENCRYPTED_KEY, null);
String currentUserEncryptedKey = pref.getString(
SecurePersistentStore.CURRENT_USER_ENCRYPTED_KEY_KEY, null);
assertNull(currentUserString);
assertNotNull(currentUserEncryptedString);
assertNotNull(currentUserEncryptedKey);

String accessToken = pref.getString(PersistentStore.ACCESS_TOKEN_KEY, null);
String accessTokenEncrypted = pref.getString
(SecurePersistentStore.ACCESS_TOKEN_ENCRYPTED_KEY, null);
String accessTokenEncryptedKey = pref.getString(
SecurePersistentStore.ACCESS_TOKEN_ENCRYPTED_KEY_KEY, null);
assertNull(accessToken);
assertNotNull(accessTokenEncrypted);
assertNotNull(accessTokenEncryptedKey);
}
}
36 changes: 34 additions & 2 deletions skygear/src/main/java/io/skygear/skygear/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,27 @@ public final class Configuration {
*/
final boolean pubsubConnectAutomatically;


/**
* Boolean indicating whether encrypt current user data saved in SharedPreferences.
*/
final boolean encryptCurrentUserData;


private Configuration(
String endpoint,
String apiKey,
String gcmSenderId,
boolean pubsubHandlerExecutionInBackground,
boolean pubsubConnectAutomatically
boolean pubsubConnectAutomatically,
boolean encryptCurrentUserData
) {
this.endpoint = endpoint;
this.apiKey = apiKey;
this.gcmSenderId = gcmSenderId;
this.pubsubHandlerExecutionInBackground = pubsubHandlerExecutionInBackground;
this.pubsubConnectAutomatically = pubsubConnectAutomatically;
this.encryptCurrentUserData = encryptCurrentUserData;
}

/**
Expand Down Expand Up @@ -111,6 +120,15 @@ public boolean isPubsubConnectAutomatically() {
return pubsubConnectAutomatically;
}

/**
* Encrypt current user data boolean.
*
* @return the boolean
*/
public boolean encryptCurrentUserData() {
return encryptCurrentUserData;
}

/**
* Creates an instance of default configuration.
*
Expand Down Expand Up @@ -148,6 +166,7 @@ public static final class Builder {
private String gcmSenderId;
private boolean pubsubHandlerExecutionInBackground;
private boolean pubsubConnectAutomatically;
private boolean encryptCurrentUserData;

/**
* Creates an instance of Builder.
Expand Down Expand Up @@ -212,6 +231,18 @@ public Builder pubsubConnectAutomatically(boolean automatic) {
return this;
}

/**
* Sets whether encrypt current user data saved in SharedPreferences.
*
* @param enabled the boolean indicating whether encryption Enabled
* automatically.
* @return the builder
*/
public Builder encryptCurrentUserData(boolean enabled) {
this.encryptCurrentUserData = enabled;
return this;
}

/**
* Build a configuration.
*
Expand All @@ -231,7 +262,8 @@ public Configuration build() {
this.apiKey,
this.gcmSenderId,
this.pubsubHandlerExecutionInBackground,
this.pubsubConnectAutomatically
this.pubsubConnectAutomatically,
this.encryptCurrentUserData
);
}
}
Expand Down
22 changes: 15 additions & 7 deletions skygear/src/main/java/io/skygear/skygear/Container.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public final class Container {
private static final String TAG = "Skygear SDK";
private static Container sharedInstance;

final PersistentStore persistentStore;
PersistentStore persistentStore;
final Context context;
final RequestManager requestManager;
Configuration config;
Expand Down Expand Up @@ -61,18 +61,13 @@ public Container(Context context, Configuration config) {
this.context = context.getApplicationContext();
this.config = config;
this.requestManager = new RequestManager(this.context, this.config);
this.persistentStore = new PersistentStore(this.context);

this.auth = new AuthContainer(this);
this.pubsub = new PubsubContainer(this);
this.push = new PushContainer(this);
this.publicDatabase = Database.Factory.publicDatabase(this);
this.privateDatabase = Database.Factory.privateDatabase(this);
this.requestManager.accessToken = this.persistentStore.accessToken;

if (this.persistentStore.defaultAccessControl != null) {
AccessControl.defaultAccessControl = this.persistentStore.defaultAccessControl;
}
this.configPersistentStore(config);
}

/**
Expand Down Expand Up @@ -151,6 +146,7 @@ public void configure(Configuration config) {
}

this.config = config;
this.configPersistentStore(config);
this.requestManager.configure(config);
this.pubsub.configure(config);
}
Expand Down Expand Up @@ -263,4 +259,16 @@ public final void onFailure(Error error) {
}
});
}

private void configPersistentStore(Configuration config) {
if (config != null && config.encryptCurrentUserData) {
this.persistentStore = new SecurePersistentStore(this.context);
} else {
this.persistentStore = new PersistentStore(this.context);
}
this.requestManager.accessToken = this.persistentStore.accessToken;
if (this.persistentStore.defaultAccessControl != null) {
AccessControl.defaultAccessControl = this.persistentStore.defaultAccessControl;
}
}
}
10 changes: 5 additions & 5 deletions skygear/src/main/java/io/skygear/skygear/PersistentStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class PersistentStore {
static final String DEVICE_ID_KEY = "device_id";
static final String DEVICE_TOKEN_KEY = "device_token";

private final Context context;
final Context context;
/**
* The Current user.
*/
Expand Down Expand Up @@ -109,7 +109,7 @@ void save() {
prefEditor.apply();
}

private void restoreAuthUser(SharedPreferences pref) {
void restoreAuthUser(SharedPreferences pref) {
String currentUserString = pref.getString(CURRENT_USER_KEY, null);

if (currentUserString == null) {
Expand All @@ -126,7 +126,7 @@ private void restoreAuthUser(SharedPreferences pref) {
}
}

private void saveAuthUser(SharedPreferences.Editor prefEditor) {
void saveAuthUser(SharedPreferences.Editor prefEditor) {
if (this.currentUser != null) {
prefEditor.putString(CURRENT_USER_KEY,
RecordSerializer.serialize(this.currentUser).toString()
Expand All @@ -136,11 +136,11 @@ private void saveAuthUser(SharedPreferences.Editor prefEditor) {
}
}

private void restoreAccessToken(SharedPreferences pref) {
void restoreAccessToken(SharedPreferences pref) {
this.accessToken = pref.getString(ACCESS_TOKEN_KEY, null);
}

private void saveAccessToken(SharedPreferences.Editor prefEditor) {
void saveAccessToken(SharedPreferences.Editor prefEditor) {
if (this.accessToken != null) {
prefEditor.putString(ACCESS_TOKEN_KEY, this.accessToken);
} else {
Expand Down
Loading

0 comments on commit 1734129

Please sign in to comment.