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.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<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[] 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<File> files) {
private void notifySuccess(final List<File> 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<Uri> 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;