2019-05-27 16:06:07 +02:00
|
|
|
package lu.circl.mispbump.auxiliary;
|
|
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.SharedPreferences;
|
|
|
|
|
2019-07-23 14:58:07 +02:00
|
|
|
import androidx.core.util.Pair;
|
|
|
|
|
2019-05-27 16:06:07 +02:00
|
|
|
import com.google.gson.Gson;
|
2019-06-04 20:48:24 +02:00
|
|
|
import com.google.gson.reflect.TypeToken;
|
2019-05-27 16:06:07 +02:00
|
|
|
|
2019-06-04 20:48:24 +02:00
|
|
|
import java.lang.reflect.Type;
|
2019-05-27 16:06:07 +02:00
|
|
|
import java.security.InvalidAlgorithmParameterException;
|
|
|
|
import java.security.InvalidKeyException;
|
|
|
|
import java.security.NoSuchAlgorithmException;
|
2019-06-04 20:48:24 +02:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
2019-06-17 09:49:09 +02:00
|
|
|
import java.util.UUID;
|
2019-05-27 16:06:07 +02:00
|
|
|
|
|
|
|
import javax.crypto.BadPaddingException;
|
|
|
|
import javax.crypto.IllegalBlockSizeException;
|
|
|
|
import javax.crypto.NoSuchPaddingException;
|
|
|
|
|
2019-06-04 20:48:24 +02:00
|
|
|
import lu.circl.mispbump.models.UploadInformation;
|
2019-06-19 20:01:49 +02:00
|
|
|
import lu.circl.mispbump.models.restModels.Organisation;
|
2019-07-16 15:25:28 +02:00
|
|
|
import lu.circl.mispbump.models.restModels.Role;
|
2019-06-19 20:01:49 +02:00
|
|
|
import lu.circl.mispbump.models.restModels.User;
|
2019-05-27 16:06:07 +02:00
|
|
|
import lu.circl.mispbump.security.KeyStoreWrapper;
|
|
|
|
|
|
|
|
public class PreferenceManager {
|
|
|
|
|
|
|
|
private static final String PREFERENCES_FILE = "user_settings";
|
|
|
|
|
2019-07-23 14:58:07 +02:00
|
|
|
private static final String USER_CREDENTIALS = "user_credentials";
|
2019-05-27 16:06:07 +02:00
|
|
|
private static final String USER_INFOS = "user_infos";
|
|
|
|
private static final String USER_ORG_INFOS = "user_org_infos";
|
|
|
|
|
2019-06-04 20:48:24 +02:00
|
|
|
private static final String UPLOAD_INFO = "upload_info";
|
|
|
|
|
2019-07-16 15:25:28 +02:00
|
|
|
private static final String MISP_ROLES = "misp_roles";
|
|
|
|
|
2019-05-27 16:06:07 +02:00
|
|
|
private SharedPreferences preferences;
|
|
|
|
private static PreferenceManager instance;
|
|
|
|
|
|
|
|
private PreferenceManager(Context context) {
|
|
|
|
preferences = context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper class to save and retrieve (sensitive) information to and from SharedPreferences.
|
2019-05-27 20:03:27 +02:00
|
|
|
*
|
2019-05-27 16:06:07 +02:00
|
|
|
* @param context for accessing the SharedPreferences file.
|
|
|
|
* @return singleton instance
|
|
|
|
*/
|
|
|
|
public static PreferenceManager getInstance(Context context) {
|
2019-05-27 20:03:27 +02:00
|
|
|
if (instance == null) {
|
2019-05-27 16:06:07 +02:00
|
|
|
instance = new PreferenceManager(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-16 15:25:28 +02:00
|
|
|
/**
|
|
|
|
* Save downloaded MISP roles on device.
|
2019-07-23 14:58:07 +02:00
|
|
|
*
|
2019-07-16 15:25:28 +02:00
|
|
|
* @param roles {@link Role}
|
|
|
|
*/
|
|
|
|
public void setRoles(Role[] roles) {
|
|
|
|
SharedPreferences.Editor editor = preferences.edit();
|
|
|
|
editor.putString(MISP_ROLES, new Gson().toJson(roles));
|
|
|
|
editor.apply();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets downloaded and saved MISP roles if available.
|
|
|
|
* <p/>
|
|
|
|
* Roles are downloaded on login and updated with each profile update.
|
|
|
|
*
|
|
|
|
* @return {@link Role}[] or null
|
|
|
|
*/
|
|
|
|
public Role[] getRoles() {
|
2019-07-23 14:58:07 +02:00
|
|
|
Type type = new TypeToken<Role[]>() {
|
|
|
|
}.getType();
|
2019-07-16 15:25:28 +02:00
|
|
|
String rolesString = preferences.getString(MISP_ROLES, "");
|
|
|
|
|
|
|
|
assert rolesString != null;
|
|
|
|
if (rolesString.isEmpty()) {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
return new Gson().fromJson(rolesString, type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-27 16:06:07 +02:00
|
|
|
/**
|
|
|
|
* Saves user infos from "users/view/me" (encrypted)
|
2019-05-27 20:03:27 +02:00
|
|
|
*
|
2019-06-04 20:48:24 +02:00
|
|
|
* @param user {@link User}
|
2019-05-27 16:06:07 +02:00
|
|
|
*/
|
|
|
|
public void setUserInfo(User user) {
|
|
|
|
try {
|
|
|
|
String userStr = new Gson().toJson(user);
|
|
|
|
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
|
|
|
|
String encryptedUserInfo = keyStoreWrapper.encrypt(userStr);
|
|
|
|
SharedPreferences.Editor editor = preferences.edit();
|
|
|
|
editor.putString(USER_INFOS, encryptedUserInfo);
|
|
|
|
editor.apply();
|
|
|
|
} catch (NoSuchPaddingException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (NoSuchAlgorithmException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (InvalidKeyException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (BadPaddingException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (IllegalBlockSizeException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-05-27 20:03:27 +02:00
|
|
|
* Returns the user information if already stored and decrypts it.
|
2019-05-27 16:06:07 +02:00
|
|
|
*
|
|
|
|
* @return decrypted user info if any, else null
|
|
|
|
*/
|
|
|
|
public User getUserInfo() {
|
|
|
|
|
|
|
|
if (!preferences.contains(USER_INFOS)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
|
|
|
|
String decrypted = keyStoreWrapper.decrypt(preferences.getString(USER_INFOS, ""));
|
|
|
|
return new Gson().fromJson(decrypted, User.class);
|
|
|
|
} catch (NoSuchPaddingException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (NoSuchAlgorithmException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (InvalidAlgorithmParameterException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (InvalidKeyException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (BadPaddingException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (IllegalBlockSizeException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Save user org infos from "organisations/view/{orgId}" (encrypted)
|
2019-05-27 20:03:27 +02:00
|
|
|
*
|
2019-05-27 16:06:07 +02:00
|
|
|
* @param organisation Object representation of json organisation information
|
|
|
|
*/
|
|
|
|
public void setUserOrgInfo(Organisation organisation) {
|
|
|
|
try {
|
|
|
|
String orgStr = new Gson().toJson(organisation);
|
|
|
|
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_ORGANISATION_INFO_ALIAS);
|
|
|
|
String encrypted = keyStoreWrapper.encrypt(orgStr);
|
|
|
|
SharedPreferences.Editor editor = preferences.edit();
|
|
|
|
editor.putString(USER_ORG_INFOS, encrypted);
|
|
|
|
editor.apply();
|
|
|
|
} catch (NoSuchPaddingException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (NoSuchAlgorithmException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (InvalidKeyException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (BadPaddingException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (IllegalBlockSizeException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-05-27 20:03:27 +02:00
|
|
|
* Returns the user organisation information if already stored and decrypts it.
|
2019-05-27 16:06:07 +02:00
|
|
|
*
|
|
|
|
* @return decrypted user org info if any, else null
|
|
|
|
*/
|
|
|
|
public Organisation getUserOrganisation() {
|
|
|
|
|
2019-05-27 20:03:27 +02:00
|
|
|
if (!preferences.contains(USER_ORG_INFOS)) {
|
2019-05-27 16:06:07 +02:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_ORGANISATION_INFO_ALIAS);
|
|
|
|
String decrypted = keyStoreWrapper.decrypt(preferences.getString(USER_ORG_INFOS, ""));
|
|
|
|
return new Gson().fromJson(decrypted, Organisation.class);
|
|
|
|
} catch (NoSuchPaddingException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (NoSuchAlgorithmException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (InvalidAlgorithmParameterException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (InvalidKeyException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (BadPaddingException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (IllegalBlockSizeException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-23 14:58:07 +02:00
|
|
|
public void setUserCredentials(String url, String authkey) {
|
2019-05-27 16:06:07 +02:00
|
|
|
try {
|
2019-07-23 14:58:07 +02:00
|
|
|
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_CREDENTIALS_ALIAS);
|
2019-05-27 16:06:07 +02:00
|
|
|
SharedPreferences.Editor editor = preferences.edit();
|
2019-07-23 14:58:07 +02:00
|
|
|
editor.putString(USER_CREDENTIALS, keyStoreWrapper.encrypt(new Gson().toJson(new Pair<>(url, authkey))));
|
2019-05-27 16:06:07 +02:00
|
|
|
editor.apply();
|
2019-07-23 14:58:07 +02:00
|
|
|
} catch (NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException e) {
|
2019-05-27 16:06:07 +02:00
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-23 14:58:07 +02:00
|
|
|
public Pair<String, String> getUserCredentials() {
|
|
|
|
if (!preferences.contains(USER_CREDENTIALS)) {
|
2019-07-14 18:18:54 +02:00
|
|
|
return null;
|
2019-05-27 16:06:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2019-07-23 14:58:07 +02:00
|
|
|
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_CREDENTIALS_ALIAS);
|
|
|
|
Type type = new TypeToken<Pair<String, String>>() {}.getType();
|
|
|
|
String serializedCreds = keyStoreWrapper.decrypt(preferences.getString(USER_CREDENTIALS, ""));
|
|
|
|
return new Gson().fromJson(serializedCreds, type);
|
|
|
|
} catch (InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
|
2019-05-27 16:06:07 +02:00
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
|
2019-07-14 18:18:54 +02:00
|
|
|
return null;
|
2019-05-27 16:06:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
private List<UploadInformation> cachedUploadInformationList;
|
2019-06-17 09:49:09 +02:00
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
private void loadUploadInformationList() {
|
2019-06-17 09:49:09 +02:00
|
|
|
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
|
|
|
|
String storedUploadInfoString = preferences.getString(UPLOAD_INFO, null);
|
2019-06-04 20:48:24 +02:00
|
|
|
|
2019-07-23 14:58:07 +02:00
|
|
|
Type type = new TypeToken<List<UploadInformation>>() {
|
|
|
|
}.getType();
|
2019-06-04 20:48:24 +02:00
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
if (storedUploadInfoString == null || storedUploadInfoString.isEmpty()) {
|
|
|
|
cachedUploadInformationList = new ArrayList<>();
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
storedUploadInfoString = ksw.decrypt(storedUploadInfoString);
|
|
|
|
cachedUploadInformationList = new Gson().fromJson(storedUploadInfoString, type);
|
|
|
|
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | NoSuchAlgorithmException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2019-06-17 09:49:09 +02:00
|
|
|
}
|
2019-07-02 13:34:36 +02:00
|
|
|
}
|
2019-06-17 09:49:09 +02:00
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
private void saveUploadInformationList() {
|
2019-06-17 09:49:09 +02:00
|
|
|
try {
|
2019-07-02 13:34:36 +02:00
|
|
|
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
|
|
|
|
String cipherText = ksw.encrypt(new Gson().toJson(cachedUploadInformationList));
|
|
|
|
SharedPreferences.Editor editor = preferences.edit();
|
|
|
|
editor.putString(UPLOAD_INFO, cipherText);
|
|
|
|
editor.apply();
|
|
|
|
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException e) {
|
2019-06-17 09:49:09 +02:00
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
public List<UploadInformation> getUploadInformationList() {
|
|
|
|
if (cachedUploadInformationList == null) {
|
|
|
|
loadUploadInformationList();
|
2019-06-04 20:48:24 +02:00
|
|
|
}
|
2019-07-02 13:34:36 +02:00
|
|
|
|
|
|
|
return cachedUploadInformationList;
|
2019-06-17 09:49:09 +02:00
|
|
|
}
|
2019-06-04 20:48:24 +02:00
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
public void setUploadInformationList(List<UploadInformation> uploadInformationList) {
|
|
|
|
cachedUploadInformationList = uploadInformationList;
|
|
|
|
saveUploadInformationList();
|
|
|
|
}
|
2019-06-04 20:48:24 +02:00
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
public UploadInformation getUploadInformation(UUID uuid) {
|
|
|
|
if (cachedUploadInformationList == null) {
|
|
|
|
loadUploadInformationList();
|
2019-06-17 09:49:09 +02:00
|
|
|
}
|
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
for (UploadInformation ui : cachedUploadInformationList) {
|
|
|
|
if (ui.getUuid().compareTo(uuid) == 0) {
|
|
|
|
return ui;
|
2019-06-17 09:49:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
return null;
|
2019-06-04 20:48:24 +02:00
|
|
|
}
|
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
public void addUploadInformation(UploadInformation uploadInformation) {
|
|
|
|
if (cachedUploadInformationList == null) {
|
|
|
|
loadUploadInformationList();
|
|
|
|
}
|
2019-06-04 20:48:24 +02:00
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
// update if exists
|
|
|
|
for (int i = 0; i < cachedUploadInformationList.size(); i++) {
|
|
|
|
if (cachedUploadInformationList.get(i).getUuid().compareTo(uploadInformation.getUuid()) == 0) {
|
|
|
|
cachedUploadInformationList.set(i, uploadInformation);
|
|
|
|
saveUploadInformationList();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2019-06-17 09:49:09 +02:00
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
// else: add
|
|
|
|
cachedUploadInformationList.add(uploadInformation);
|
|
|
|
saveUploadInformationList();
|
|
|
|
}
|
2019-06-17 09:49:09 +02:00
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
public void removeUploadInformation(UUID uuid) {
|
|
|
|
if (cachedUploadInformationList == null) {
|
|
|
|
loadUploadInformationList();
|
|
|
|
}
|
2019-06-17 09:49:09 +02:00
|
|
|
|
2019-07-02 13:34:36 +02:00
|
|
|
for (UploadInformation ui : cachedUploadInformationList) {
|
|
|
|
if (ui.getUuid().compareTo(uuid) == 0) {
|
2019-07-02 23:40:42 +02:00
|
|
|
// if is last element, then clear everything including IV and key in KeyStore
|
2019-07-02 13:34:36 +02:00
|
|
|
if (cachedUploadInformationList.size() == 1) {
|
2019-06-17 09:49:09 +02:00
|
|
|
clearUploadInformation();
|
|
|
|
} else {
|
2019-07-02 13:34:36 +02:00
|
|
|
cachedUploadInformationList.remove(ui);
|
|
|
|
saveUploadInformationList();
|
2019-06-17 09:49:09 +02:00
|
|
|
}
|
|
|
|
}
|
2019-06-04 20:48:24 +02:00
|
|
|
}
|
2019-06-17 09:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void clearUploadInformation() {
|
2019-07-02 13:34:36 +02:00
|
|
|
cachedUploadInformationList.clear();
|
|
|
|
|
2019-06-17 09:49:09 +02:00
|
|
|
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
|
|
|
|
keyStoreWrapper.deleteStoredKey();
|
|
|
|
|
|
|
|
SharedPreferences.Editor editor = preferences.edit();
|
|
|
|
editor.remove(UPLOAD_INFO);
|
|
|
|
editor.apply();
|
2019-06-04 20:48:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-16 15:25:28 +02:00
|
|
|
public void clearAllData() {
|
2019-05-27 16:06:07 +02:00
|
|
|
SharedPreferences.Editor editor = preferences.edit();
|
|
|
|
|
2019-07-23 14:58:07 +02:00
|
|
|
// clearServerUrl();
|
|
|
|
// clearAutomationKey();
|
2019-07-16 15:25:28 +02:00
|
|
|
clearUploadInformation();
|
2019-05-27 16:06:07 +02:00
|
|
|
|
|
|
|
editor.clear();
|
|
|
|
editor.apply();
|
|
|
|
}
|
2019-05-27 20:03:27 +02:00
|
|
|
}
|