From 4bc43af690203267303c65a55c4b2f905c3679e8 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 2 Jun 2020 07:59:16 +0200 Subject: [PATCH] improve logging in export backup service. closes #3672 --- .../services/ExportBackupService.java | 59 +++++++++++-------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/ExportBackupService.java b/src/main/java/eu/siacs/conversations/services/ExportBackupService.java index 7b034a255..7c98db35d 100644 --- a/src/main/java/eu/siacs/conversations/services/ExportBackupService.java +++ b/src/main/java/eu/siacs/conversations/services/ExportBackupService.java @@ -14,6 +14,8 @@ import android.os.IBinder; import android.support.v4.app.NotificationCompat; import android.util.Log; +import com.google.common.base.Strings; + import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -70,7 +72,7 @@ public class ExportBackupService extends Service { if (Compatibility.runsAndTargetsTwentyFour(context)) { openIntent.setType("resource/folder"); } 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); @@ -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 Cursor accountCursor = db.query(Account.TABLENAME, null, Account.UUID + "=?", new String[]{uuid}, null, null, null); 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 { - SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); - return factory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, 1024, 128)).getEncoded(); - } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { - throw new AssertionError(e); + factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException(e); } + return factory.generateSecret(new PBEKeySpec(password.toCharArray(), salt, 1024, 128)).getEncoded(); } - private static String cursorToString(String tablename, Cursor cursor, int max) { - return cursorToString(tablename, cursor, max, false); + private static String cursorToString(final String table, final Cursor cursor, final int max) { + return cursorToString(table, cursor, max, false); } - private static String cursorToString(final String tablename, final Cursor cursor, int max, boolean ignore) { - final boolean identities = SQLiteAxolotlStore.IDENTITIES_TABLENAME.equals(tablename); + private static String cursorToString(final String table, final Cursor cursor, int max, boolean ignore) { + final boolean identities = SQLiteAxolotlStore.IDENTITIES_TABLENAME.equals(table); StringBuilder builder = new StringBuilder(); builder.append("INSERT "); if (ignore) { builder.append("OR IGNORE "); } - builder.append("INTO ").append(tablename).append("("); + builder.append("INTO ").append(table).append("("); int skipColumn = -1; for (int i = 0; i < cursor.getColumnCount(); ++i) { final String name = cursor.getColumnName(i); @@ -222,7 +225,8 @@ public class ExportBackupService extends Service { try { files = export(); success = true; - } catch (Exception e) { + } catch (final Exception e) { + Log.d(Config.LOGTAG, "unable to create backup", e); success = false; files = Collections.emptyList(); } @@ -234,6 +238,8 @@ public class ExportBackupService extends Service { stopSelf(); }).start(); return START_STICKY; + } else { + Log.d(Config.LOGTAG, "ExportBackupService. ignoring start command because already running"); } return START_NOT_STICKY; } @@ -241,7 +247,7 @@ public class ExportBackupService extends Service { 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}); 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 p = 0; while (cursor != null && cursor.moveToNext()) { @@ -272,7 +278,14 @@ public class ExportBackupService extends Service { final int max = this.mAccounts.size(); final SecureRandom secureRandom = new SecureRandom(); final List 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[] salt = new byte[16]; secureRandom.nextBytes(IV); @@ -281,8 +294,9 @@ public class ExportBackupService extends Service { final Progress progress = new Progress(mBuilder, max, count); final File file = new File(FileBackend.getBackupDirectory(this) + account.getJid().asBareJid().toEscapedString() + ".ceb"); files.add(file); - if (file.getParentFile().mkdirs()) { - Log.d(Config.LOGTAG, "created backup directory " + file.getParentFile().getAbsolutePath()); + final File directory = file.getParentFile(); + if (directory != null && directory.mkdirs()) { + Log.d(Config.LOGTAG, "created backup directory " + directory.getAbsolutePath()); } final FileOutputStream fileOutputStream = new FileOutputStream(file); final DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream); @@ -290,8 +304,7 @@ public class ExportBackupService extends Service { dataOutputStream.flush(); final Cipher cipher = Compatibility.twentyEight() ? Cipher.getInstance(CIPHERMODE) : Cipher.getInstance(CIPHERMODE, PROVIDER); - byte[] key = getKey(account.getPassword(), salt); - Log.d(Config.LOGTAG, backupFileHeader.toString()); + final byte[] key = getKey(password, salt); SecretKeySpec keySpec = new SecretKeySpec(key, KEYTYPE); IvParameterSpec ivSpec = new IvParameterSpec(IV); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); @@ -315,7 +328,7 @@ public class ExportBackupService extends Service { return files; } - private void notifySuccess(List files) { + private void notifySuccess(final List files) { final String path = FileBackend.getBackupDirectory(this); PendingIntent openFolderIntent = null; @@ -331,14 +344,14 @@ public class ExportBackupService extends Service { if (files.size() > 0) { final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); ArrayList uris = new ArrayList<>(); - for(File file : files) { + for (File file : files) { uris.add(FileBackend.getUriForFile(this, file)); } intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setType(MIME_TYPE); 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"); @@ -361,7 +374,7 @@ public class ExportBackupService extends Service { return null; } - private class Progress { + private static class Progress { private final NotificationCompat.Builder builder; private final int max; private final int count;