Fix attachment sizes during backup exports.

This commit is contained in:
Greyson Parrelli 2019-11-15 18:21:49 -05:00
parent e241589c92
commit a8309b6b2b
2 changed files with 38 additions and 7 deletions

View File

@ -32,7 +32,7 @@ public class AttachmentId {
} }
public @NonNull String toString() { public @NonNull String toString() {
return "(row id: " + rowId + ", unique ID: " + uniqueId + ")"; return "AttachmentId::(" + rowId + ", " + uniqueId + ")";
} }
public boolean isValid() { public boolean isValid() {

View File

@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream; import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream;
import org.thoughtcrime.securesms.database.AttachmentDatabase; import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupReceiptDatabase; import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.MmsSmsColumns; import org.thoughtcrime.securesms.database.MmsSmsColumns;
@ -31,6 +32,7 @@ import org.thoughtcrime.securesms.database.StickerDatabase;
import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.profiles.AvatarHelper; import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.util.Conversions; import org.thoughtcrime.securesms.util.Conversions;
import org.thoughtcrime.securesms.util.Stopwatch;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.kdf.HKDFv3; import org.whispersystems.libsignal.kdf.HKDFv3;
import org.whispersystems.libsignal.util.ByteUtil; import org.whispersystems.libsignal.util.ByteUtil;
@ -73,6 +75,8 @@ public class FullBackupExporter extends FullBackupBase {
List<String> tables = exportSchema(input, outputStream); List<String> tables = exportSchema(input, outputStream);
int count = 0; int count = 0;
Stopwatch stopwatch = new Stopwatch("Backup");
for (String table : tables) { for (String table : tables) {
if (table.equals(MmsDatabase.TABLE_NAME)) { if (table.equals(MmsDatabase.TABLE_NAME)) {
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringMessage, null, count); count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringMessage, null, count);
@ -91,6 +95,7 @@ public class FullBackupExporter extends FullBackupBase {
{ {
count = exportTable(table, input, outputStream, null, null, count); count = exportTable(table, input, outputStream, null, null, count);
} }
stopwatch.split("table::" + table);
} }
for (BackupProtos.SharedPreference preference : IdentityKeyUtil.getBackupRecord(context)) { for (BackupProtos.SharedPreference preference : IdentityKeyUtil.getBackupRecord(context)) {
@ -98,11 +103,16 @@ public class FullBackupExporter extends FullBackupBase {
outputStream.write(preference); outputStream.write(preference);
} }
stopwatch.split("prefs");
for (File avatar : AvatarHelper.getAvatarFiles(context)) { for (File avatar : AvatarHelper.getAvatarFiles(context)) {
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count)); EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
outputStream.write(avatar.getName(), new FileInputStream(avatar), avatar.length()); outputStream.write(avatar.getName(), new FileInputStream(avatar), avatar.length());
} }
stopwatch.split("avatars");
stopwatch.stop(TAG);
outputStream.writeEnd(); outputStream.writeEnd();
outputStream.close(); outputStream.close();
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, ++count)); EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, ++count));
@ -201,8 +211,14 @@ public class FullBackupExporter extends FullBackupBase {
String data = cursor.getString(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA)); String data = cursor.getString(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA));
byte[] random = cursor.getBlob(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA_RANDOM)); byte[] random = cursor.getBlob(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA_RANDOM));
if (!TextUtils.isEmpty(data) && size <= 0) { if (!TextUtils.isEmpty(data)) {
size = calculateVeryOldStreamLength(attachmentSecret, random, data); long fileLength = new File(data).length();
long dbLength = size;
if (size <= 0 || fileLength != dbLength) {
size = calculateVeryOldStreamLength(attachmentSecret, random, data);
Log.w(TAG, "Needed size calculation! Manual: " + size + " File: " + fileLength + " DB: " + dbLength + " ID: " + new AttachmentId(rowId, uniqueId));
}
} }
if (!TextUtils.isEmpty(data) && size > 0) { if (!TextUtils.isEmpty(data) && size > 0) {
@ -331,7 +347,9 @@ public class FullBackupExporter extends FullBackupBase {
.build()) .build())
.build()); .build());
writeStream(in); if (writeStream(in) != size) {
throw new IOException("Size mismatch!");
}
} }
public void write(@NonNull AttachmentId attachmentId, @NonNull InputStream in, long size) throws IOException { public void write(@NonNull AttachmentId attachmentId, @NonNull InputStream in, long size) throws IOException {
@ -343,7 +361,9 @@ public class FullBackupExporter extends FullBackupBase {
.build()) .build())
.build()); .build());
writeStream(in); if (writeStream(in) != size) {
throw new IOException("Size mismatch!");
}
} }
public void writeSticker(long rowId, @NonNull InputStream in, long size) throws IOException { public void writeSticker(long rowId, @NonNull InputStream in, long size) throws IOException {
@ -354,7 +374,9 @@ public class FullBackupExporter extends FullBackupBase {
.build()) .build())
.build()); .build());
writeStream(in); if (writeStream(in) != size) {
throw new IOException("Size mismatch!");
}
} }
void writeDatabaseVersion(int version) throws IOException { void writeDatabaseVersion(int version) throws IOException {
@ -367,13 +389,18 @@ public class FullBackupExporter extends FullBackupBase {
write(outputStream, BackupProtos.BackupFrame.newBuilder().setEnd(true).build()); write(outputStream, BackupProtos.BackupFrame.newBuilder().setEnd(true).build());
} }
private void writeStream(@NonNull InputStream inputStream) throws IOException { /**
* @return The amount of data written from the provided InputStream.
*/
private long writeStream(@NonNull InputStream inputStream) throws IOException {
try { try {
Conversions.intToByteArray(iv, 0, counter++); Conversions.intToByteArray(iv, 0, counter++);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(cipherKey, "AES"), new IvParameterSpec(iv)); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(cipherKey, "AES"), new IvParameterSpec(iv));
mac.update(iv); mac.update(iv);
byte[] buffer = new byte[8192]; byte[] buffer = new byte[8192];
long total = 0;
int read; int read;
while ((read = inputStream.read(buffer)) != -1) { while ((read = inputStream.read(buffer)) != -1) {
@ -383,6 +410,8 @@ public class FullBackupExporter extends FullBackupBase {
outputStream.write(ciphertext); outputStream.write(ciphertext);
mac.update(ciphertext); mac.update(ciphertext);
} }
total += read;
} }
byte[] remainder = cipher.doFinal(); byte[] remainder = cipher.doFinal();
@ -391,6 +420,8 @@ public class FullBackupExporter extends FullBackupBase {
byte[] attachmentDigest = mac.doFinal(); byte[] attachmentDigest = mac.doFinal();
outputStream.write(attachmentDigest, 0, 10); outputStream.write(attachmentDigest, 0, 10);
return total;
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { } catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }