diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cbb75d73..a0ba521a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ + + + 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // permission was granted doScanQRCode(); } else { - Snackbar.make(fab, R.string.msg_camera_permission, Snackbar.LENGTH_LONG).setCallback(new Snackbar.Callback() { - @Override - public void onDismissed(Snackbar snackbar, int event) { - super.onDismissed(snackbar, event); - - if (entries.isEmpty()) { - showNoAccount(); - } - } - }).show(); + showSimpleSnackbar(R.string.msg_camera_permission); } - } - else { + } else if (requestCode == PERMISSIONS_REQUEST_WRITE_EXPORT) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + doExportJSON(); + } else { + showSimpleSnackbar(R.string.msg_storage_permissions); + } + } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } - private Entry nextSelection = null; + private void showSimpleSnackbar(int string_res) { + Snackbar.make(fab, string_res, Snackbar.LENGTH_LONG).setCallback(new Snackbar.Callback() { + @Override + public void onDismissed(Snackbar snackbar, int event) { + super.onDismissed(snackbar, event); + + if (entries.isEmpty()) { + showNoAccount(); + } + } + }).show(); + } + private void showNoAccount(){ Snackbar noAccountSnackbar = Snackbar.make(fab, R.string.no_accounts, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.button_add, new View.OnClickListener() { @@ -286,7 +326,15 @@ public class MainActivity extends AppCompatActivity { public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); - if(id == R.id.action_about){ + if (id == R.id.action_export) { + exportJSONWithWarning(); + + return true; + } else if (id == R.id.action_import) { + SettingsHelper.importFromJSON(this); + + return true; + } else if (id == R.id.action_about){ showAbout(); return true; diff --git a/app/src/main/java/org/shadowice/flocke/andotp/SettingsHelper.java b/app/src/main/java/org/shadowice/flocke/andotp/SettingsHelper.java index c12e15d2..0f58a6a0 100644 --- a/app/src/main/java/org/shadowice/flocke/andotp/SettingsHelper.java +++ b/app/src/main/java/org/shadowice/flocke/andotp/SettingsHelper.java @@ -27,11 +27,15 @@ import android.content.Context; import org.json.JSONArray; import org.json.JSONException; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileWriter; +import java.io.Writer; import java.util.ArrayList; import javax.crypto.SecretKey; +import static android.os.Environment.getExternalStorageDirectory; import static org.shadowice.flocke.andotp.Utils.readFully; import static org.shadowice.flocke.andotp.Utils.writeFully; @@ -39,6 +43,8 @@ public class SettingsHelper { public static final String KEY_FILE = "otp.key"; public static final String SETTINGS_FILE = "secrets.dat"; + public static final String EXPORT_FILE = "otp_accounts.json"; + public static void store(Context context, ArrayList entries){ JSONArray a = new JSONArray(); @@ -81,4 +87,44 @@ public class SettingsHelper { } return entries; } + + public static JSONArray readJSON(Context context) { + JSONArray json = new JSONArray(); + + try { + byte[] data = readFully(new File(context.getFilesDir() + "/" + SETTINGS_FILE)); + + SecretKey key = EncryptionHelper.loadOrGenerateKeys(context, new File(context.getFilesDir() + "/" + KEY_FILE)); + data = EncryptionHelper.decrypt(key, data); + + json = new JSONArray(new String(data)); + } + catch (Exception e) { + } + + return json; + } + + public static boolean exportAsJSON(Context context) { + File outputFile = new File(getExternalStorageDirectory() + "/" + EXPORT_FILE); + + JSONArray data = readJSON(context); + + boolean success = true; + + try { + Writer output = new BufferedWriter(new FileWriter(outputFile)); + output.write(data.toString()); + output.close(); + } catch (Exception e) { + success = false; + e.printStackTrace(); + } + + return success; + } + + public static void importFromJSON(Context context) { + + } } \ No newline at end of file diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 7f252914..5ec5f721 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -1,6 +1,25 @@ + + + + + + + + + Edit Scan QR Code About + Import / Export + Export as JSON + Import from JSON Invalid QR Code Account added Cancel @@ -17,6 +20,13 @@ Rename "Remove " Camera permission not granted + Storage permissions not granted + Security warning + + Do you really want to export the database as plain-text JSON file? + This file contains all your secret keys, please keep it safe! + + Export to external storage successful An open-source two-factor authentication App for Android 4.3+