Backup encryption feature
- Add encryption option when exporting and importing backup - Add wipe data option when importing backup
This commit is contained in:
parent
f8bb7b0487
commit
47c4fb0daf
@ -28,6 +28,7 @@ import com.herbron.moodl.Activities.HomeActivityFragments.Summary;
|
||||
import com.herbron.moodl.Activities.HomeActivityFragments.Watchlist;
|
||||
import com.herbron.moodl.BalanceSwitchManagerInterface;
|
||||
import com.herbron.moodl.BalanceUpdateInterface;
|
||||
import com.herbron.moodl.DataManagers.DatabaseManager;
|
||||
import com.herbron.moodl.DataManagers.PreferencesManager;
|
||||
import com.herbron.moodl.PlaceholderManager;
|
||||
import com.herbron.moodl.R;
|
||||
@ -59,7 +60,6 @@ public class HomeActivity extends AppCompatActivity implements BalanceUpdateInte
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
/**Interface setup**/
|
||||
Window w = getWindow();
|
||||
|
||||
setContentView(R.layout.activity_currency_summary);
|
||||
|
||||
|
@ -70,7 +70,7 @@ public class Summary extends Fragment implements BalanceSwitchManagerInterface,
|
||||
|
||||
private LinearLayout currencyLayout;
|
||||
private PreferencesManager preferencesManager;
|
||||
private com.herbron.moodl.DataManagers.BalanceManager balanceManager;
|
||||
private BalanceManager balanceManager;
|
||||
private SwipeRefreshLayout refreshLayout;
|
||||
private Dialog loadingDialog;
|
||||
private String defaultCurrency;
|
||||
|
@ -46,6 +46,10 @@ import com.herbron.moodl.FingerprintToolkit.FingerprintHandler;
|
||||
import com.herbron.moodl.MoodlBox;
|
||||
import com.herbron.moodl.R;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
@ -468,21 +472,34 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
||||
checkPermissions();
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.getDefault());
|
||||
Date currentDate = new Date();
|
||||
String fileName = getString(R.string.app_name) + "_" + formatter.format(currentDate) + ".backup";
|
||||
String fileName = "Bakup_" + formatter.format(currentDate) + ".moodl";
|
||||
DatabaseManager databaseManager = new DatabaseManager(getContext());
|
||||
|
||||
if(enterPasswordCheckbox.isChecked())
|
||||
{
|
||||
DataCrypter.updateKey(textInputLayoutPassword.getEditText().getText().toString());
|
||||
}
|
||||
|
||||
File backupFile = new File(textViewFilePath.getText() + "/" + fileName);
|
||||
|
||||
try (PrintWriter printWriter = new PrintWriter(new FileWriter(backupFile, true))) {
|
||||
|
||||
if(enterPasswordCheckbox.isChecked())
|
||||
{
|
||||
DataCrypter.updateKey(textInputLayoutPassword.getEditText().getText().toString());
|
||||
printWriter.write(DataCrypter.encrypt(getActivity(), databaseManager.getBackupData()));
|
||||
}
|
||||
else
|
||||
{
|
||||
printWriter.write(databaseManager.getBackupData());
|
||||
try {
|
||||
JSONObject backupJson = new JSONObject();
|
||||
|
||||
if(enterPasswordCheckbox.isChecked())
|
||||
{
|
||||
backupJson.put("encodeChecker", DataCrypter.encrypt(getContext(), "NaukVerification"));
|
||||
}
|
||||
else
|
||||
{
|
||||
backupJson.put("encodeChecker", "NaukVerification");
|
||||
}
|
||||
backupJson.put("transactions", databaseManager.getBackupData(getContext(),enterPasswordCheckbox.isChecked()));
|
||||
|
||||
printWriter.write(backupJson.toString());
|
||||
} catch (JSONException e) {
|
||||
Log.d("moodl", "Error while creating backup json " + e.getMessage());
|
||||
}
|
||||
|
||||
printWriter.close();
|
||||
@ -542,6 +559,10 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
||||
}
|
||||
});
|
||||
|
||||
final CheckBox enterPasswordCheckbox = dialogView.findViewById(R.id.checkboxEnterPassword);
|
||||
final CheckBox wipeCheckbox = dialogView.findViewById(R.id.checkboxWipeData);
|
||||
final TextInputLayout textInputLayoutPassword = dialogView.findViewById(R.id.textInputLayoutPassword);
|
||||
|
||||
dialogBuilder.setTitle(getString(R.string.restoreBackup));
|
||||
dialogBuilder.setPositiveButton(getString(R.string.confirm), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
@ -551,6 +572,16 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
||||
|
||||
DatabaseManager databaseManager = new DatabaseManager(context);
|
||||
|
||||
if(enterPasswordCheckbox.isChecked())
|
||||
{
|
||||
DataCrypter.updateKey(textInputLayoutPassword.getEditText().getText().toString());
|
||||
}
|
||||
|
||||
if(wipeCheckbox.isChecked())
|
||||
{
|
||||
databaseManager.wipeTransactions();
|
||||
}
|
||||
|
||||
File backupFile = new File(textViewFilePath.getText().toString());
|
||||
|
||||
try {
|
||||
@ -564,13 +595,37 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
||||
completeFile += str;
|
||||
}
|
||||
|
||||
String[] results = completeFile.split(Pattern.quote("]"));
|
||||
try {
|
||||
JSONObject backupJson = new JSONObject(completeFile);
|
||||
String checker;
|
||||
|
||||
for(int i = 0; i < results.length; i++)
|
||||
{
|
||||
String[] columnValues = results[i].split(Pattern.quote(";@"));
|
||||
if(enterPasswordCheckbox.isChecked())
|
||||
{
|
||||
checker = DataCrypter.decrypt(getContext(), backupJson.getString("encodeChecker"));
|
||||
}
|
||||
else
|
||||
{
|
||||
checker = backupJson.getString("encodeChecker");
|
||||
}
|
||||
|
||||
databaseManager.addRowTransaction(columnValues);
|
||||
if(checker.equals("NaukVerification"))
|
||||
{
|
||||
JSONArray transactionsArray = backupJson.getJSONArray("transactions");
|
||||
|
||||
for(int i = 0; i < transactionsArray.length(); i++)
|
||||
{
|
||||
JSONObject transactionObject = transactionsArray.getJSONObject(i);
|
||||
|
||||
databaseManager.addRowTransaction(transactionObject, getContext(), enterPasswordCheckbox.isChecked());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
textInputLayoutPassword.setError("Wrong password");
|
||||
}
|
||||
|
||||
} catch (JSONException e) {
|
||||
Log.d("moodl", "Error while creating backup json " + e);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
|
@ -56,7 +56,6 @@ public class CurrencyDetailsList {
|
||||
|
||||
if (response.length() > 0) {
|
||||
processDetailResult(response, callBack);
|
||||
upToDate = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -109,6 +108,8 @@ public class CurrencyDetailsList {
|
||||
|
||||
sortDetails();
|
||||
|
||||
upToDate = true;
|
||||
|
||||
callBack.onSuccess();
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,10 @@ import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.herbron.moodl.R;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import android.util.Base64;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
@ -20,19 +20,19 @@ import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
|
||||
public class DataCrypter {
|
||||
|
||||
private static Key aesKey;
|
||||
|
||||
public static void updateKey(String key)
|
||||
{
|
||||
for(int i = 0; key.getBytes().length < 32; i++)
|
||||
{
|
||||
key += "0";
|
||||
}
|
||||
|
||||
try {
|
||||
aesKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
|
||||
byte[] keyByte = key.getBytes("UTF-8");
|
||||
byte[] finalKey = new byte[32];
|
||||
System.arraycopy(keyByte, 0, finalKey, 0, keyByte.length);
|
||||
|
||||
aesKey = new SecretKeySpec(finalKey, "AES");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.d("moodl", "Error while creating encryption key " + e.getMessage());
|
||||
}
|
||||
@ -49,9 +49,10 @@ public class DataCrypter {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivParameterSpec);
|
||||
|
||||
byte[] encryptedBytes = cipher.doFinal(data.getBytes());
|
||||
byte[] encryptedBytes = cipher.doFinal(data.getBytes("UTF-8"));
|
||||
|
||||
encryptedData = Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
|
||||
|
||||
encryptedData = Base64.encodeBase64String(encryptedBytes);
|
||||
} catch (NoSuchPaddingException | NoSuchAlgorithmException
|
||||
| InvalidKeyException | BadPaddingException
|
||||
| IllegalBlockSizeException | UnsupportedEncodingException
|
||||
@ -63,4 +64,26 @@ public class DataCrypter {
|
||||
|
||||
return encryptedData;
|
||||
}
|
||||
|
||||
public static String decrypt(Context context, String data)
|
||||
{
|
||||
String decryptedData = null;
|
||||
|
||||
try {
|
||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(context.getString(R.string.ivKey).getBytes("UTF-8"));
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivParameterSpec);
|
||||
|
||||
byte[] dataBytes = Base64.decode(data, Base64.DEFAULT);
|
||||
decryptedData = new String(dataBytes, StandardCharsets.UTF_8);
|
||||
|
||||
} catch(NoSuchPaddingException | NoSuchAlgorithmException
|
||||
| InvalidKeyException | UnsupportedEncodingException
|
||||
| InvalidAlgorithmParameterException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return decryptedData;
|
||||
}
|
||||
}
|
||||
|
@ -5,10 +5,15 @@ import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.herbron.moodl.DataManagers.CurrencyData.Currency;
|
||||
import com.herbron.moodl.DataManagers.CurrencyData.Transaction;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@ -152,36 +157,82 @@ public class DatabaseManager extends SQLiteOpenHelper{
|
||||
db.close();
|
||||
}
|
||||
|
||||
public String getBackupData()
|
||||
public JSONArray getBackupData(Context context, boolean encryptData)
|
||||
{
|
||||
String selectQuerry = "SELECT * FROM " + TABLE_MANUAL_CURRENCIES;
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
Cursor result = db.rawQuery(selectQuerry, null);
|
||||
|
||||
String backupData = "";
|
||||
JSONArray transactionsArray = new JSONArray();
|
||||
|
||||
while(result.moveToNext())
|
||||
{
|
||||
JSONObject transactionJson = new JSONObject();
|
||||
|
||||
for(int i = 0; i < result.getColumnCount(); i++)
|
||||
{
|
||||
backupData += result.getString(i) + ";@";
|
||||
try {
|
||||
if(result.getString(i) != null)
|
||||
{
|
||||
if(encryptData)
|
||||
{
|
||||
transactionJson.put(result.getColumnName(i), DataCrypter.encrypt(context, result.getString(i)));
|
||||
}
|
||||
else
|
||||
{
|
||||
transactionJson.put(result.getColumnName(i), result.getString(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
transactionJson.put(result.getColumnName(i), "");
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.d("moodl", "Error while creating a json transaction");
|
||||
}
|
||||
}
|
||||
|
||||
backupData += "\n";
|
||||
transactionsArray.put(transactionJson);
|
||||
}
|
||||
|
||||
return backupData;
|
||||
return transactionsArray;
|
||||
}
|
||||
|
||||
public void addRowTransaction(String[] rowValues)
|
||||
public void wipeTransactions()
|
||||
{
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
db.execSQL("DELETE FROM "+ TABLE_MANUAL_CURRENCIES);
|
||||
}
|
||||
|
||||
public void addRowTransaction(JSONObject rawValues, Context context, boolean decrypt)
|
||||
{
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
|
||||
values.put(KEY_CURRENCY_SYMBOL, rowValues[1]);
|
||||
values.put(KEY_CURRENCY_BALANCE, rowValues[3]);
|
||||
values.put(KEY_CURRENCY_DATE, rowValues[4]);
|
||||
values.put(KEY_CURRENCY_PURCHASED_PRICE, rowValues[5]);
|
||||
try {
|
||||
if(decrypt)
|
||||
{
|
||||
values.put(KEY_CURRENCY_SYMBOL, DataCrypter.decrypt(context, rawValues.getString(KEY_CURRENCY_SYMBOL)));
|
||||
values.put(KEY_CURRENCY_NAME, DataCrypter.decrypt(context, rawValues.getString(KEY_CURRENCY_NAME)));
|
||||
values.put(KEY_CURRENCY_BALANCE, DataCrypter.decrypt(context, rawValues.getString(KEY_CURRENCY_BALANCE)));
|
||||
values.put(KEY_CURRENCY_DATE, DataCrypter.decrypt(context, rawValues.getString(KEY_CURRENCY_DATE)));
|
||||
values.put(KEY_CURRENCY_PURCHASED_PRICE, DataCrypter.decrypt(context, rawValues.getString(KEY_CURRENCY_PURCHASED_PRICE)));
|
||||
values.put(KEY_CURRENCY_IS_MINED, DataCrypter.decrypt(context, rawValues.getString(KEY_CURRENCY_IS_MINED)));
|
||||
values.put(KEY_CURRENCY_FEES, DataCrypter.decrypt(context, rawValues.getString(KEY_CURRENCY_FEES)));
|
||||
}
|
||||
else
|
||||
{
|
||||
values.put(KEY_CURRENCY_SYMBOL, rawValues.getString(KEY_CURRENCY_SYMBOL));
|
||||
values.put(KEY_CURRENCY_NAME, rawValues.getString(KEY_CURRENCY_NAME));
|
||||
values.put(KEY_CURRENCY_BALANCE, rawValues.getString(KEY_CURRENCY_BALANCE));
|
||||
values.put(KEY_CURRENCY_DATE, rawValues.getString(KEY_CURRENCY_DATE));
|
||||
values.put(KEY_CURRENCY_PURCHASED_PRICE, rawValues.getString(KEY_CURRENCY_PURCHASED_PRICE));
|
||||
values.put(KEY_CURRENCY_IS_MINED, rawValues.getString(KEY_CURRENCY_IS_MINED));
|
||||
values.put(KEY_CURRENCY_FEES, rawValues.getString(KEY_CURRENCY_FEES));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.d("moodl", "Error while inserting transaction");
|
||||
}
|
||||
|
||||
db.insert(TABLE_MANUAL_CURRENCIES, null, values);
|
||||
db.close();
|
||||
|
@ -17,10 +17,10 @@
|
||||
android:background="@drawable/background_filepath"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkboxConserveData"
|
||||
android:id="@+id/checkboxWipeData"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/conserve_data"
|
||||
android:text="@string/wipe_data"
|
||||
android:enabled="false" />
|
||||
|
||||
<CheckBox
|
||||
@ -41,8 +41,7 @@
|
||||
android:id="@+id/checkboxEnterPassword"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enter_password"
|
||||
android:enabled="false"/>
|
||||
android:text="@string/enter_password"/>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/textInputLayoutPassword"
|
||||
|
@ -17,11 +17,10 @@
|
||||
android:background="@drawable/background_filepath"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkboxConserveData"
|
||||
android:id="@+id/checkboxWipeData"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/conserve_data"
|
||||
android:enabled="false"/>
|
||||
android:text="@string/wipe_data"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkboxRestoreEntries"
|
||||
@ -41,8 +40,7 @@
|
||||
android:id="@+id/checkboxEnterPassword"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enter_password"
|
||||
android:enabled="false"/>
|
||||
android:text="@string/enter_password"/>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/textInputLayoutPassword"
|
||||
|
@ -87,10 +87,10 @@
|
||||
<string name="pref_title_export">Exporter les entrées manuelles</string>
|
||||
<string name="pref_title_import">Importer de nouvelles entrées</string>
|
||||
<string name="pref_title_category_synchronization">Synchronisation</string>
|
||||
<string name="conserve_data">Conserver les données</string>
|
||||
<string name="wipe_data">Supprimer les données actuelles</string>
|
||||
<string name="restore_manual_entries">Restaurer les transactions manuelles</string>
|
||||
<string name="restore_keys">Restaurer les clefs d\'API</string>
|
||||
<string name="enter_password">Entrerr un mot de passe</string>
|
||||
<string name="enter_password">Entrer un mot de passe</string>
|
||||
<string name="password">Mot de passe</string>
|
||||
<string name="title_activity_exchange_settings">Réglages</string>
|
||||
<string name="save">Sauvegarder</string>
|
||||
|
@ -203,7 +203,7 @@
|
||||
<string name="field_empty">This field cannot be blank</string>
|
||||
<string name="field_nan">This field must be a number</string>
|
||||
<string name="field_negative">This field must be positive</string>
|
||||
<string name="conserve_data">Conserve current data</string>
|
||||
<string name="wipe_data">Wipe current data</string>
|
||||
<string name="restore_manual_entries">Restore manual entries</string>
|
||||
<string name="restore_keys">Restore API keys</string>
|
||||
<string name="enter_password">Enter password</string>
|
||||
|
Loading…
Reference in New Issue
Block a user