improve logging in export backup service. closes #3672

This commit is contained in:
Daniel Gultsch 2020-06-02 07:59:16 +02:00
parent 0391e78832
commit 4bc43af690

View file

@ -14,6 +14,8 @@ import android.os.IBinder;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.util.Log; import android.util.Log;
import com.google.common.base.Strings;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -70,7 +72,7 @@ public class ExportBackupService extends Service {
if (Compatibility.runsAndTargetsTwentyFour(context)) { if (Compatibility.runsAndTargetsTwentyFour(context)) {
openIntent.setType("resource/folder"); openIntent.setType("resource/folder");
} else { } else {
openIntent.setDataAndType(Uri.parse("file://"+path),"resource/folder"); openIntent.setDataAndType(Uri.parse("file://" + path), "resource/folder");
} }
openIntent.putExtra("org.openintents.extra.ABSOLUTE_PATH", path); openIntent.putExtra("org.openintents.extra.ABSOLUTE_PATH", path);
@ -87,7 +89,7 @@ public class ExportBackupService extends Service {
} }
private static void accountExport(SQLiteDatabase db, String uuid, PrintWriter writer) { private static void accountExport(final SQLiteDatabase db, final String uuid, final PrintWriter writer) {
final StringBuilder builder = new StringBuilder(); final StringBuilder builder = new StringBuilder();
final Cursor accountCursor = db.query(Account.TABLENAME, null, Account.UUID + "=?", new String[]{uuid}, null, null, null); final Cursor accountCursor = db.query(Account.TABLENAME, null, Account.UUID + "=?", new String[]{uuid}, null, null, null);
while (accountCursor != null && accountCursor.moveToNext()) { while (accountCursor != null && accountCursor.moveToNext()) {
@ -136,27 +138,28 @@ public class ExportBackupService extends Service {
} }
} }
public static byte[] getKey(String password, byte[] salt) { public static byte[] getKey(final String password, final byte[] salt) throws InvalidKeySpecException {
final SecretKeyFactory factory;
try { try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
return factory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, 1024, 128)).getEncoded(); } catch (NoSuchAlgorithmException e) {
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) { throw new IllegalStateException(e);
throw new AssertionError(e);
} }
return factory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, 1024, 128)).getEncoded();
} }
private static String cursorToString(String tablename, Cursor cursor, int max) { private static String cursorToString(final String table, final Cursor cursor, final int max) {
return cursorToString(tablename, cursor, max, false); return cursorToString(table, cursor, max, false);
} }
private static String cursorToString(final String tablename, final Cursor cursor, int max, boolean ignore) { private static String cursorToString(final String table, final Cursor cursor, int max, boolean ignore) {
final boolean identities = SQLiteAxolotlStore.IDENTITIES_TABLENAME.equals(tablename); final boolean identities = SQLiteAxolotlStore.IDENTITIES_TABLENAME.equals(table);
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("INSERT "); builder.append("INSERT ");
if (ignore) { if (ignore) {
builder.append("OR IGNORE "); builder.append("OR IGNORE ");
} }
builder.append("INTO ").append(tablename).append("("); builder.append("INTO ").append(table).append("(");
int skipColumn = -1; int skipColumn = -1;
for (int i = 0; i < cursor.getColumnCount(); ++i) { for (int i = 0; i < cursor.getColumnCount(); ++i) {
final String name = cursor.getColumnName(i); final String name = cursor.getColumnName(i);
@ -222,7 +225,8 @@ public class ExportBackupService extends Service {
try { try {
files = export(); files = export();
success = true; success = true;
} catch (Exception e) { } catch (final Exception e) {
Log.d(Config.LOGTAG, "unable to create backup", e);
success = false; success = false;
files = Collections.emptyList(); files = Collections.emptyList();
} }
@ -234,6 +238,8 @@ public class ExportBackupService extends Service {
stopSelf(); stopSelf();
}).start(); }).start();
return START_STICKY; return START_STICKY;
} else {
Log.d(Config.LOGTAG, "ExportBackupService. ignoring start command because already running");
} }
return START_NOT_STICKY; return START_NOT_STICKY;
} }
@ -241,7 +247,7 @@ public class ExportBackupService extends Service {
private void messageExport(SQLiteDatabase db, String uuid, PrintWriter writer, Progress progress) { private void messageExport(SQLiteDatabase db, String uuid, PrintWriter writer, Progress progress) {
Cursor cursor = db.rawQuery("select messages.* from messages join conversations on conversations.uuid=messages.conversationUuid where conversations.accountUuid=?", new String[]{uuid}); Cursor cursor = db.rawQuery("select messages.* from messages join conversations on conversations.uuid=messages.conversationUuid where conversations.accountUuid=?", new String[]{uuid});
int size = cursor != null ? cursor.getCount() : 0; int size = cursor != null ? cursor.getCount() : 0;
Log.d(Config.LOGTAG, "exporting " + size + " messages"); Log.d(Config.LOGTAG, "exporting " + size + " messages for account " + uuid);
int i = 0; int i = 0;
int p = 0; int p = 0;
while (cursor != null && cursor.moveToNext()) { while (cursor != null && cursor.moveToNext()) {
@ -272,7 +278,14 @@ public class ExportBackupService extends Service {
final int max = this.mAccounts.size(); final int max = this.mAccounts.size();
final SecureRandom secureRandom = new SecureRandom(); final SecureRandom secureRandom = new SecureRandom();
final List<File> files = new ArrayList<>(); final List<File> files = new ArrayList<>();
for (Account account : this.mAccounts) { Log.d(Config.LOGTAG, "starting backup for " + max + " accounts");
for (final Account account : this.mAccounts) {
final String password = account.getPassword();
if (Strings.nullToEmpty(password).trim().isEmpty()) {
Log.d(Config.LOGTAG, String.format("skipping backup for %s because password is empty. unable to encrypt", account.getJid().asBareJid()));
continue;
}
Log.d(Config.LOGTAG, String.format("exporting data for account %s (%s)", account.getJid().asBareJid(), account.getUuid()));
final byte[] IV = new byte[12]; final byte[] IV = new byte[12];
final byte[] salt = new byte[16]; final byte[] salt = new byte[16];
secureRandom.nextBytes(IV); secureRandom.nextBytes(IV);
@ -281,8 +294,9 @@ public class ExportBackupService extends Service {
final Progress progress = new Progress(mBuilder, max, count); final Progress progress = new Progress(mBuilder, max, count);
final File file = new File(FileBackend.getBackupDirectory(this) + account.getJid().asBareJid().toEscapedString() + ".ceb"); final File file = new File(FileBackend.getBackupDirectory(this) + account.getJid().asBareJid().toEscapedString() + ".ceb");
files.add(file); files.add(file);
if (file.getParentFile().mkdirs()) { final File directory = file.getParentFile();
Log.d(Config.LOGTAG, "created backup directory " + file.getParentFile().getAbsolutePath()); if (directory != null && directory.mkdirs()) {
Log.d(Config.LOGTAG, "created backup directory " + directory.getAbsolutePath());
} }
final FileOutputStream fileOutputStream = new FileOutputStream(file); final FileOutputStream fileOutputStream = new FileOutputStream(file);
final DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream); final DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
@ -290,8 +304,7 @@ public class ExportBackupService extends Service {
dataOutputStream.flush(); dataOutputStream.flush();
final Cipher cipher = Compatibility.twentyEight() ? Cipher.getInstance(CIPHERMODE) : Cipher.getInstance(CIPHERMODE, PROVIDER); final Cipher cipher = Compatibility.twentyEight() ? Cipher.getInstance(CIPHERMODE) : Cipher.getInstance(CIPHERMODE, PROVIDER);
byte[] key = getKey(account.getPassword(), salt); final byte[] key = getKey(password, salt);
Log.d(Config.LOGTAG, backupFileHeader.toString());
SecretKeySpec keySpec = new SecretKeySpec(key, KEYTYPE); SecretKeySpec keySpec = new SecretKeySpec(key, KEYTYPE);
IvParameterSpec ivSpec = new IvParameterSpec(IV); IvParameterSpec ivSpec = new IvParameterSpec(IV);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
@ -315,7 +328,7 @@ public class ExportBackupService extends Service {
return files; return files;
} }
private void notifySuccess(List<File> files) { private void notifySuccess(final List<File> files) {
final String path = FileBackend.getBackupDirectory(this); final String path = FileBackend.getBackupDirectory(this);
PendingIntent openFolderIntent = null; PendingIntent openFolderIntent = null;
@ -331,14 +344,14 @@ public class ExportBackupService extends Service {
if (files.size() > 0) { if (files.size() > 0) {
final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
ArrayList<Uri> uris = new ArrayList<>(); ArrayList<Uri> uris = new ArrayList<>();
for(File file : files) { for (File file : files) {
uris.add(FileBackend.getUriForFile(this, file)); uris.add(FileBackend.getUriForFile(this, file));
} }
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setType(MIME_TYPE); intent.setType(MIME_TYPE);
final Intent chooser = Intent.createChooser(intent, getString(R.string.share_backup_files)); final Intent chooser = Intent.createChooser(intent, getString(R.string.share_backup_files));
shareFilesIntent = PendingIntent.getActivity(this,190, chooser, PendingIntent.FLAG_UPDATE_CURRENT); shareFilesIntent = PendingIntent.getActivity(this, 190, chooser, PendingIntent.FLAG_UPDATE_CURRENT);
} }
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup"); NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup");
@ -361,7 +374,7 @@ public class ExportBackupService extends Service {
return null; return null;
} }
private class Progress { private static class Progress {
private final NotificationCompat.Builder builder; private final NotificationCompat.Builder builder;
private final int max; private final int max;
private final int count; private final int count;