Refactor Storage Access code

This commit is contained in:
Jakob Nixdorf 2019-09-17 09:00:32 +02:00
parent 27121c62dc
commit 945e586a2f
No known key found for this signature in database
GPG key ID: BE99BF86574A7DBC
6 changed files with 135 additions and 119 deletions

View file

@ -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();

View file

@ -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();

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}