Refactor Storage Access code
This commit is contained in:
parent
27121c62dc
commit
945e586a2f
6 changed files with 135 additions and 119 deletions
|
@ -50,10 +50,11 @@ import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
|||
import org.shadowice.flocke.andotp.Database.Entry;
|
||||
import org.shadowice.flocke.andotp.Dialogs.PasswordEntryDialog;
|
||||
import org.shadowice.flocke.andotp.R;
|
||||
import org.shadowice.flocke.andotp.Utilities.BackupHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.Constants;
|
||||
import org.shadowice.flocke.andotp.Utilities.DatabaseHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.EncryptionHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.FileHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.StorageAccessHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.Tools;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
@ -238,7 +239,7 @@ public class BackupActivity extends BaseActivity {
|
|||
|
||||
// Get the result from permission requests
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
if (requestCode == Constants.PERMISSIONS_BACKUP_READ_IMPORT_PLAIN) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
showOpenFileSelector(Constants.INTENT_BACKUP_OPEN_DOCUMENT_PLAIN);
|
||||
|
@ -349,16 +350,16 @@ public class BackupActivity extends BaseActivity {
|
|||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType(mimeType);
|
||||
intent.putExtra(Intent.EXTRA_TITLE, FileHelper.backupFilename(this, backupType));
|
||||
intent.putExtra(Intent.EXTRA_TITLE, BackupHelper.backupFilename(this, backupType));
|
||||
startActivityForResult(intent, intentId);
|
||||
} else {
|
||||
if (Tools.mkdir(settings.getBackupDir())) {
|
||||
if (intentId == Constants.INTENT_BACKUP_SAVE_DOCUMENT_PLAIN)
|
||||
doBackupPlain(Tools.buildUri(settings.getBackupDir(), FileHelper.backupFilename(this, Constants.BackupType.PLAIN_TEXT)));
|
||||
doBackupPlain(Tools.buildUri(settings.getBackupDir(), BackupHelper.backupFilename(this, Constants.BackupType.PLAIN_TEXT)));
|
||||
else if (intentId == Constants.INTENT_BACKUP_SAVE_DOCUMENT_CRYPT)
|
||||
doBackupCrypt(Tools.buildUri(settings.getBackupDir(), FileHelper.backupFilename(this, Constants.BackupType.ENCRYPTED)));
|
||||
doBackupCrypt(Tools.buildUri(settings.getBackupDir(), BackupHelper.backupFilename(this, Constants.BackupType.ENCRYPTED)));
|
||||
else if (intentId == Constants.INTENT_BACKUP_SAVE_DOCUMENT_PGP)
|
||||
backupEncryptedWithPGP(Tools.buildUri(settings.getBackupDir(), FileHelper.backupFilename(this, Constants.BackupType.OPEN_PGP)), null);
|
||||
backupEncryptedWithPGP(Tools.buildUri(settings.getBackupDir(), BackupHelper.backupFilename(this, Constants.BackupType.OPEN_PGP)), null);
|
||||
} else {
|
||||
Toast.makeText(this, R.string.backup_toast_mkdir_failed, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
@ -408,7 +409,7 @@ public class BackupActivity extends BaseActivity {
|
|||
|
||||
private void doRestorePlain(Uri uri) {
|
||||
if (Tools.isExternalStorageReadable()) {
|
||||
String content = FileHelper.readFileToString(this, uri);
|
||||
String content = StorageAccessHelper.loadFileString(this, uri);
|
||||
|
||||
restoreEntries(content);
|
||||
} else {
|
||||
|
@ -420,7 +421,7 @@ public class BackupActivity extends BaseActivity {
|
|||
if (Tools.isExternalStorageWritable()) {
|
||||
ArrayList<Entry> entries = DatabaseHelper.loadDatabase(this, encryptionKey);
|
||||
|
||||
if (FileHelper.writeStringToFile(this, uri, DatabaseHelper.entriesToString(entries)))
|
||||
if (StorageAccessHelper.saveFile(this, uri, DatabaseHelper.entriesToString(entries)))
|
||||
Toast.makeText(this, R.string.backup_toast_export_success, Toast.LENGTH_LONG).show();
|
||||
else
|
||||
Toast.makeText(this, R.string.backup_toast_export_failed, Toast.LENGTH_LONG).show();
|
||||
|
@ -475,7 +476,7 @@ public class BackupActivity extends BaseActivity {
|
|||
String decryptedString = "";
|
||||
|
||||
try {
|
||||
byte[] data = FileHelper.readFileToBytes(this, uri);
|
||||
byte[] data = StorageAccessHelper.loadFile(this, uri);
|
||||
|
||||
if (old_format) {
|
||||
SecretKey key = EncryptionHelper.generateSymmetricKeyFromPassword(password);
|
||||
|
@ -546,7 +547,7 @@ public class BackupActivity extends BaseActivity {
|
|||
System.arraycopy(salt, 0, data, Constants.INT_LENGTH, Constants.ENCRYPTION_IV_LENGTH);
|
||||
System.arraycopy(encrypted, 0, data, Constants.INT_LENGTH + Constants.ENCRYPTION_IV_LENGTH, encrypted.length);
|
||||
|
||||
FileHelper.writeBytesToFile(this, uri, data);
|
||||
StorageAccessHelper.saveFile(this, uri, data);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
success = false;
|
||||
|
@ -570,7 +571,7 @@ public class BackupActivity extends BaseActivity {
|
|||
if (decryptIntent == null)
|
||||
decryptIntent = new Intent(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
||||
|
||||
String input = FileHelper.readFileToString(this, uri);
|
||||
String input = StorageAccessHelper.loadFileString(this, uri);
|
||||
|
||||
InputStream is = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8));
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
@ -581,7 +582,7 @@ public class BackupActivity extends BaseActivity {
|
|||
|
||||
private void doBackupEncrypted(Uri uri, String data) {
|
||||
if (Tools.isExternalStorageWritable()) {
|
||||
boolean success = FileHelper.writeStringToFile(this, uri, data);
|
||||
boolean success = StorageAccessHelper.saveFile(this, uri, data);
|
||||
|
||||
if (success)
|
||||
Toast.makeText(this, R.string.backup_toast_export_success, Toast.LENGTH_LONG).show();
|
||||
|
|
|
@ -29,15 +29,17 @@ import android.net.Uri;
|
|||
|
||||
import org.shadowice.flocke.andotp.Database.Entry;
|
||||
import org.shadowice.flocke.andotp.R;
|
||||
import org.shadowice.flocke.andotp.Utilities.BackupHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.Constants;
|
||||
import org.shadowice.flocke.andotp.Utilities.DatabaseHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.EncryptionHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.FileHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.KeyStoreHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.NotificationHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.Settings;
|
||||
import org.shadowice.flocke.andotp.Utilities.StorageAccessHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.Tools;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
@ -54,7 +56,7 @@ public class EncryptedBackupBroadcastReceiver extends BackupBroadcastReceiver {
|
|||
if (!canSaveBackup(context))
|
||||
return;
|
||||
|
||||
Uri savePath = Tools.buildUri(settings.getBackupDir(), FileHelper.backupFilename(context, Constants.BackupType.ENCRYPTED));
|
||||
Uri savePath = Tools.buildUri(settings.getBackupDir(), BackupHelper.backupFilename(context, Constants.BackupType.ENCRYPTED));
|
||||
|
||||
String password = settings.getBackupPasswordEnc();
|
||||
|
||||
|
@ -77,9 +79,21 @@ public class EncryptedBackupBroadcastReceiver extends BackupBroadcastReceiver {
|
|||
String plain = DatabaseHelper.entriesToString(entries);
|
||||
|
||||
try {
|
||||
SecretKey key = EncryptionHelper.generateSymmetricKeyFromPassword(password);
|
||||
int iter = EncryptionHelper.generateRandomIterations();
|
||||
byte[] salt = EncryptionHelper.generateRandom(Constants.ENCRYPTION_IV_LENGTH);
|
||||
|
||||
SecretKey key = EncryptionHelper.generateSymmetricKeyPBKDF2(password, iter, salt);
|
||||
byte[] encrypted = EncryptionHelper.encrypt(key, plain.getBytes(StandardCharsets.UTF_8));
|
||||
FileHelper.writeBytesToFile(context, savePath, encrypted);
|
||||
|
||||
byte[] iterBytes = ByteBuffer.allocate(Constants.INT_LENGTH).putInt(iter).array();
|
||||
byte[] data = new byte[Constants.INT_LENGTH + Constants.ENCRYPTION_IV_LENGTH + encrypted.length];
|
||||
|
||||
System.arraycopy(iterBytes, 0, data, 0, Constants.INT_LENGTH);
|
||||
System.arraycopy(salt, 0, data, Constants.INT_LENGTH, Constants.ENCRYPTION_IV_LENGTH);
|
||||
System.arraycopy(encrypted, 0, data, Constants.INT_LENGTH + Constants.ENCRYPTION_IV_LENGTH, encrypted.length);
|
||||
|
||||
StorageAccessHelper.saveFile(context, savePath, data);
|
||||
|
||||
NotificationHelper.notify(context, Constants.NotificationChannel.BACKUP_SUCCESS, R.string.backup_receiver_title_backup_success, savePath.getPath());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -29,12 +29,13 @@ import android.net.Uri;
|
|||
|
||||
import org.shadowice.flocke.andotp.Database.Entry;
|
||||
import org.shadowice.flocke.andotp.R;
|
||||
import org.shadowice.flocke.andotp.Utilities.BackupHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.Constants;
|
||||
import org.shadowice.flocke.andotp.Utilities.DatabaseHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.FileHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.KeyStoreHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.NotificationHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.Settings;
|
||||
import org.shadowice.flocke.andotp.Utilities.StorageAccessHelper;
|
||||
import org.shadowice.flocke.andotp.Utilities.Tools;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -52,7 +53,7 @@ public class PlainTextBackupBroadcastReceiver extends BackupBroadcastReceiver {
|
|||
if (!canSaveBackup(context))
|
||||
return;
|
||||
|
||||
Uri savePath = Tools.buildUri(settings.getBackupDir(), FileHelper.backupFilename(context, Constants.BackupType.PLAIN_TEXT));
|
||||
Uri savePath = Tools.buildUri(settings.getBackupDir(), BackupHelper.backupFilename(context, Constants.BackupType.PLAIN_TEXT));
|
||||
|
||||
SecretKey encryptionKey = null;
|
||||
|
||||
|
@ -66,7 +67,7 @@ public class PlainTextBackupBroadcastReceiver extends BackupBroadcastReceiver {
|
|||
if (Tools.isExternalStorageWritable()) {
|
||||
ArrayList<Entry> entries = DatabaseHelper.loadDatabase(context, encryptionKey);
|
||||
|
||||
if (FileHelper.writeStringToFile(context, savePath, DatabaseHelper.entriesToString(entries))) {
|
||||
if (StorageAccessHelper.saveFile(context, savePath, DatabaseHelper.entriesToString(entries))) {
|
||||
NotificationHelper.notify(context, Constants.NotificationChannel.BACKUP_SUCCESS, R.string.backup_receiver_title_backup_success, savePath.getPath());
|
||||
} else {
|
||||
NotificationHelper.notify(context, Constants.NotificationChannel.BACKUP_FAILED, R.string.backup_receiver_title_backup_failed, R.string.backup_toast_export_failed);
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package org.shadowice.flocke.andotp.Utilities;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
public class BackupHelper {
|
||||
public static String backupFilename(Context context, Constants.BackupType type) {
|
||||
Settings settings = new Settings(context);
|
||||
switch (type) {
|
||||
case PLAIN_TEXT:
|
||||
if (settings.getIsAppendingDateTimeToBackups()) {
|
||||
return String.format(Constants.BACKUP_FILENAME_PLAIN_FORMAT, Tools.getDateTimeString());
|
||||
} else {
|
||||
return Constants.BACKUP_FILENAME_PLAIN;
|
||||
}
|
||||
case ENCRYPTED:
|
||||
if (settings.getIsAppendingDateTimeToBackups()) {
|
||||
return String.format(Constants.BACKUP_FILENAME_CRYPT_FORMAT, Tools.getDateTimeString());
|
||||
} else {
|
||||
return Constants.BACKUP_FILENAME_CRYPT;
|
||||
}
|
||||
case OPEN_PGP:
|
||||
if (settings.getIsAppendingDateTimeToBackups()) {
|
||||
return String.format(Constants.BACKUP_FILENAME_PGP_FORMAT, Tools.getDateTimeString());
|
||||
} else {
|
||||
return Constants.BACKUP_FILENAME_PGP;
|
||||
}
|
||||
}
|
||||
|
||||
return Constants.BACKUP_FILENAME_PLAIN;
|
||||
}
|
||||
}
|
|
@ -22,59 +22,16 @@
|
|||
|
||||
package org.shadowice.flocke.andotp.Utilities;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
public class FileHelper {
|
||||
public static String readFileToString(Context context, Uri file) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
try {
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(file);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
stringBuilder.append(line).append("\n");
|
||||
}
|
||||
reader.close();
|
||||
inputStream.close();
|
||||
} catch (Exception error) {
|
||||
error.printStackTrace();
|
||||
}
|
||||
|
||||
return(stringBuilder.toString());
|
||||
}
|
||||
|
||||
public static boolean writeStringToFile(Context context, Uri file, String content) {
|
||||
boolean success = true;
|
||||
|
||||
try {
|
||||
OutputStream outputStream = context.getContentResolver().openOutputStream(file);
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
|
||||
writer.write(content);
|
||||
writer.close();
|
||||
outputStream.close();
|
||||
} catch (Exception error) {
|
||||
success = false;
|
||||
error.printStackTrace();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public static byte[] readFileToBytes(File file) throws IOException {
|
||||
class FileHelper {
|
||||
static byte[] readFileToBytes(File file) throws IOException {
|
||||
final InputStream in = new FileInputStream(file);
|
||||
try {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
@ -89,63 +46,10 @@ public class FileHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static void writeBytesToFile(File file, byte[] data) throws IOException {
|
||||
final OutputStream out = new FileOutputStream(file);
|
||||
try {
|
||||
static void writeBytesToFile(File file, byte[] data) throws IOException {
|
||||
try (OutputStream out = new FileOutputStream(file)) {
|
||||
out.write(data);
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] readFileToBytes(Context context, Uri file) throws IOException {
|
||||
final InputStream in = context.getContentResolver().openInputStream(file);
|
||||
try {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int count;
|
||||
while ((count = in.read(buffer)) != -1) {
|
||||
bytes.write(buffer, 0, count);
|
||||
}
|
||||
return bytes.toByteArray();
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeBytesToFile(Context context, Uri file, byte[] data) throws IOException {
|
||||
final OutputStream out = context.getContentResolver().openOutputStream(file);
|
||||
try {
|
||||
out.write(data);
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static String backupFilename(Context context, Constants.BackupType type) {
|
||||
Settings settings = new Settings(context);
|
||||
switch (type) {
|
||||
case PLAIN_TEXT:
|
||||
if (settings.getIsAppendingDateTimeToBackups()) {
|
||||
return String.format(Constants.BACKUP_FILENAME_PLAIN_FORMAT, Tools.getDateTimeString());
|
||||
} else {
|
||||
return Constants.BACKUP_FILENAME_PLAIN;
|
||||
}
|
||||
case ENCRYPTED:
|
||||
if (settings.getIsAppendingDateTimeToBackups()) {
|
||||
return String.format(Constants.BACKUP_FILENAME_CRYPT_FORMAT, Tools.getDateTimeString());
|
||||
} else {
|
||||
return Constants.BACKUP_FILENAME_CRYPT;
|
||||
}
|
||||
case OPEN_PGP:
|
||||
if (settings.getIsAppendingDateTimeToBackups()) {
|
||||
return String.format(Constants.BACKUP_FILENAME_PGP_FORMAT, Tools.getDateTimeString());
|
||||
} else {
|
||||
return Constants.BACKUP_FILENAME_PGP;
|
||||
}
|
||||
}
|
||||
|
||||
return Constants.BACKUP_FILENAME_PLAIN;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package org.shadowice.flocke.andotp.Utilities;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import org.apache.commons.codec.Charsets;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class StorageAccessHelper {
|
||||
public static boolean saveFile(Context context, Uri file, byte[] data) {
|
||||
boolean success = true;
|
||||
|
||||
try {
|
||||
ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(file, "w");
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
|
||||
|
||||
fileOutputStream.write(data);
|
||||
|
||||
fileOutputStream.close();
|
||||
pfd.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public static boolean saveFile(Context context, Uri file, String data) {
|
||||
return saveFile(context, file, data.getBytes(Charsets.UTF_8));
|
||||
}
|
||||
|
||||
public static byte[] loadFile(Context context, Uri file) throws IOException {
|
||||
try (InputStream inputStream = context.getContentResolver().openInputStream(file)) {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int count;
|
||||
|
||||
while ((count = inputStream.read(buffer)) != -1) {
|
||||
bytes.write(buffer, 0, count);
|
||||
}
|
||||
|
||||
return bytes.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static String loadFileString(Context context, Uri file) {
|
||||
String result = "";
|
||||
|
||||
try {
|
||||
byte[] content = loadFile(context, file);
|
||||
result = new String(content, Charsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue