diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index a417c2e..517e430 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/app/build.gradle b/app/build.gradle index 8979578..d5a242c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,10 +6,15 @@ android { applicationId "com.herbron.moodl" minSdkVersion 19 targetSdkVersion 27 - versionCode 5 - versionName "0.0.5" + versionCode 6 + versionName "0.0.6" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } + + dataBinding { + enabled = true + } + buildTypes { release { minifyEnabled false @@ -32,7 +37,7 @@ dependencies { implementation 'com.android.support:cardview-v7:27.1.1' implementation 'com.mcxiaoke.volley:library:1.0.19' implementation 'com.diogobernardino:williamchart:2.5.0' - implementation 'com.android.support.constraint:constraint-layout:1.1.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.2' implementation 'com.android.support:support-v4:27.1.1' implementation 'com.android.support:palette-v7:27.1.1' implementation 'com.daimajia.swipelayout:library:1.2.0@aar' @@ -47,9 +52,11 @@ dependencies { implementation 'com.mattprecious.swirl:swirl:1.1.0' implementation 'com.wdullaer:materialdatetimepicker:3.5.2' implementation 'com.jmedeisis:draglinearlayout:1.1.0' + implementation 'com.applandeo:material-file-picker:1.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation files('../libs/binance-api.jar') + implementation files('../libs/commons-codec-1.11.jar'); } diff --git a/app/src/main/java/com/herbron/moodl/Activities/SettingsActivity.java b/app/src/main/java/com/herbron/moodl/Activities/SettingsActivity.java index 529b854..d83e2c2 100644 --- a/app/src/main/java/com/herbron/moodl/Activities/SettingsActivity.java +++ b/app/src/main/java/com/herbron/moodl/Activities/SettingsActivity.java @@ -7,6 +7,7 @@ import android.app.Dialog; import android.app.KeyguardManager; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Configuration; @@ -42,7 +43,12 @@ import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; +import com.applandeo.FilePicker; +import com.applandeo.constants.FileType; +import com.applandeo.listeners.OnSelectFileListener; import com.herbron.moodl.BuildConfig; +import com.herbron.moodl.DataManagers.DataCrypter; +import com.herbron.moodl.DataManagers.DatabaseManager; import com.herbron.moodl.FingerprintToolkit.FingerprintDialogFragment; import com.herbron.moodl.FingerprintToolkit.FingerprintHandler; import com.herbron.moodl.MoodlBox; @@ -64,10 +70,10 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.regex.Pattern; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; @@ -169,7 +175,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity { bindPreferenceSummaryToValue(findPreference("default_currency")); bindPreferenceSummaryToValue(findPreference("minimum_value_displayed")); - findPreference("import").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + findPreference("export").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { @@ -178,7 +184,33 @@ public class SettingsActivity extends AppCompatPreferenceActivity { View dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_import_data, null, true); dialogBuilder.setView(dialogView); - CheckBox enterPasswordCheckbox = dialogView.findViewById(R.id.checkboxEnterPassword); + File backupDirectory = new File(Environment.getExternalStorageDirectory(), getString(R.string.app_name)); + + if (!backupDirectory.exists()) { + if (!backupDirectory.mkdirs()) { + Log.d("moodl", "Error while creating directory"); + } + } + + final TextView textViewFilePath = dialogView.findViewById(R.id.textViewFilePath); + textViewFilePath.setText(backupDirectory.getAbsolutePath()); + textViewFilePath.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + new FilePicker.Builder(SettingsActivity.this, new OnSelectFileListener() { + @Override + public void onSelect(File file) { + textViewFilePath.setText(file.getAbsolutePath()); + } + }).fileType("moodl") + .hideFiles(true) + .directory(backupDirectory.getAbsolutePath()) + .mainDirectory(Environment.getExternalStorageDirectory().getAbsolutePath()) + .show(); + } + }); + + final CheckBox enterPasswordCheckbox = dialogView.findViewById(R.id.checkboxEnterPassword); final TextInputLayout textInputLayoutPassword = dialogView.findViewById(R.id.textInputLayoutPassword); enterPasswordCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @@ -196,53 +228,33 @@ public class SettingsActivity extends AppCompatPreferenceActivity { } }); - dialogBuilder.setTitle("Restore backup"); + dialogBuilder.setTitle("Create backup"); dialogBuilder.setPositiveButton("Confirm", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { 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 = "backup.moodl"; + String fileName = getString(R.string.app_name) + "_" + formatter.format(currentDate) + ".backup"; + DatabaseManager databaseManager = new DatabaseManager(SettingsActivity.this); - File dir = new File(Environment.getExternalStorageDirectory(), getString(R.string.app_name)); + File backupFile = new File(textViewFilePath.getText() + "/" + fileName); - if (!dir.exists()) { - if (!dir.mkdirs()) { - Log.d("moodl", "Error while creating directory"); + try (PrintWriter printWriter = new PrintWriter(new FileWriter(backupFile, true))) { + + if(enterPasswordCheckbox.isChecked()) + { + DataCrypter.updateKey(textInputLayoutPassword.getEditText().getText().toString()); + printWriter.write(DataCrypter.encrypt(SettingsActivity.this, databaseManager.getBackupData())); } - } - - File backupFile = new File(dir + "/" + fileName); - - if(backupFile.exists()) - { - try (FileReader fileReader = new FileReader(backupFile)) { - BufferedReader bufferedReader = new BufferedReader(fileReader); - - String line; - - while((line = bufferedReader.readLine()) != null) - { - Log.d("moodl", line); - } - } catch (IOException e) { - Log.d("moodl", "Error > " + e); + else + { + printWriter.write(databaseManager.getBackupData()); } - } - else - { - Log.d("moodl", "Not backup file found"); - try (PrintWriter printWriter = new PrintWriter(new FileWriter(backupFile, true))) { - - printWriter.write("Some data"); - - printWriter.close(); - } catch (IOException e) { - Log.d("moodl", "Error > " + e); - } + printWriter.close(); + } catch (IOException e) { + Log.d("moodl", "Error > " + e); } dialog.dismiss(); diff --git a/app/src/main/java/com/herbron/moodl/DataManagers/DataCrypter.java b/app/src/main/java/com/herbron/moodl/DataManagers/DataCrypter.java new file mode 100644 index 0000000..60de06f --- /dev/null +++ b/app/src/main/java/com/herbron/moodl/DataManagers/DataCrypter.java @@ -0,0 +1,66 @@ +package com.herbron.moodl.DataManagers; + +import android.content.Context; +import android.util.Log; + +import com.herbron.moodl.R; + +import org.apache.commons.codec.binary.Base64; + +import java.io.UnsupportedEncodingException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +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"); + } catch (UnsupportedEncodingException e) { + Log.d("moodl", "Error while creating encryption key " + e.getMessage()); + } + } + + public static String encrypt(Context context, String data) + { + String encryptedData = 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[] encryptedBytes = cipher.doFinal(data.getBytes()); + + encryptedData = Base64.encodeBase64String(encryptedBytes); + } catch (NoSuchPaddingException | NoSuchAlgorithmException + | InvalidKeyException | BadPaddingException + | IllegalBlockSizeException | UnsupportedEncodingException + | InvalidAlgorithmParameterException e) { + + Log.d("moodl", "Error while encrypting data " + e.getMessage()); + + } + + return encryptedData; + } +} diff --git a/app/src/main/java/com/herbron/moodl/DataManagers/DatabaseManager.java b/app/src/main/java/com/herbron/moodl/DataManagers/DatabaseManager.java index 418bbf6..c01d8cb 100644 --- a/app/src/main/java/com/herbron/moodl/DataManagers/DatabaseManager.java +++ b/app/src/main/java/com/herbron/moodl/DataManagers/DatabaseManager.java @@ -144,11 +144,33 @@ public class DatabaseManager extends SQLiteOpenHelper{ return result.getInt(0); } - public int deleteCurrencyFromWatchlist(String symbol) + public void deleteCurrencyFromWatchlist(String symbol) { SQLiteDatabase db = this.getWritableDatabase(); - return db.delete(TABLE_WATCHLIST, KEY_WATCHLIST_SYMBOL + " = '" + symbol + "'", null); + db.delete(TABLE_WATCHLIST, KEY_WATCHLIST_SYMBOL + " = '" + symbol + "'", null); + db.close(); + } + + public String getBackupData() + { + String selectQuerry = "SELECT * FROM " + TABLE_MANUAL_CURRENCIES; + SQLiteDatabase db = this.getWritableDatabase(); + Cursor result = db.rawQuery(selectQuerry, null); + + String backupData = ""; + + while(result.moveToNext()) + { + for(int i = 0; i < result.getColumnCount(); i++) + { + backupData += result.getString(i) + ";@"; + } + + backupData += "\n"; + } + + return backupData; } public List getAllCurrenciesFromWatchlist() diff --git a/app/src/main/res/drawable/background_filepath.xml b/app/src/main/res/drawable/background_filepath.xml new file mode 100644 index 0000000..8cd0f3f --- /dev/null +++ b/app/src/main/res/drawable/background_filepath.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_import_data.xml b/app/src/main/res/layout/dialog_import_data.xml index 203fc43..f835b49 100644 --- a/app/src/main/res/layout/dialog_import_data.xml +++ b/app/src/main/res/layout/dialog_import_data.xml @@ -9,6 +9,13 @@ android:padding="5dp" android:focusableInTouchMode="true"> + + + android:text="@string/enter_password" + android:enabled="false"/> Version + 0123456789MoodlH + Export manual entries Import manual entries diff --git a/app/src/main/res/xml/pref_main.xml b/app/src/main/res/xml/pref_main.xml index 219646c..aba5341 100644 --- a/app/src/main/res/xml/pref_main.xml +++ b/app/src/main/res/xml/pref_main.xml @@ -28,11 +28,11 @@ android:title="@string/pref_title_category_data_backup"> + android:key="export"/> + android:key="import" + android:enabled="false"/> diff --git a/build.gradle b/build.gradle index c46926d..6c02a11 100644 --- a/build.gradle +++ b/build.gradle @@ -19,9 +19,8 @@ allprojects { repositories { google() jcenter() - maven { - url "https://jitpack.io" - } + maven { url "https://jitpack.io" } + maven { url "http://dl.bintray.com/lukaville/maven" } } } diff --git a/libs/commons-codec-1.11.jar b/libs/commons-codec-1.11.jar new file mode 100644 index 0000000..2245120 Binary files /dev/null and b/libs/commons-codec-1.11.jar differ