use of eu.siacs.conversations.utils.BackupFileHeader in project Conversations by siacs.
the class BackupFileAdapter method onBindViewHolder.
@Override
public void onBindViewHolder(@NonNull BackupFileViewHolder backupFileViewHolder, int position) {
final ImportBackupService.BackupFile backupFile = files.get(position);
final BackupFileHeader header = backupFile.getHeader();
backupFileViewHolder.binding.accountJid.setText(header.getJid().asBareJid().toString());
backupFileViewHolder.binding.accountStatus.setText(String.format("%s ยท %s", header.getApp(), DateUtils.formatDateTime(backupFileViewHolder.binding.getRoot().getContext(), header.getTimestamp(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR)));
backupFileViewHolder.binding.tglAccountStatus.setVisibility(View.GONE);
backupFileViewHolder.binding.getRoot().setOnClickListener(v -> {
if (listener != null) {
listener.onClick(backupFile);
}
});
loadAvatar(header.getJid(), backupFileViewHolder.binding.accountImage);
}
use of eu.siacs.conversations.utils.BackupFileHeader in project Conversations by siacs.
the class ImportBackupService method importBackup.
private boolean importBackup(final Uri uri, final String password) {
Log.d(Config.LOGTAG, "importing backup from " + uri);
final Stopwatch stopwatch = Stopwatch.createStarted();
try {
final SQLiteDatabase db = mDatabaseBackend.getWritableDatabase();
final InputStream inputStream;
final String path = uri.getPath();
final long fileSize;
if ("file".equals(uri.getScheme()) && path != null) {
final File file = new File(path);
inputStream = new FileInputStream(file);
fileSize = file.length();
} else {
final Cursor returnCursor = getContentResolver().query(uri, null, null, null, null);
if (returnCursor == null) {
fileSize = 0;
} else {
returnCursor.moveToFirst();
fileSize = returnCursor.getLong(returnCursor.getColumnIndex(OpenableColumns.SIZE));
returnCursor.close();
}
inputStream = getContentResolver().openInputStream(uri);
}
if (inputStream == null) {
synchronized (mOnBackupProcessedListeners) {
for (final OnBackupProcessed l : mOnBackupProcessedListeners) {
l.onBackupRestoreFailed();
}
}
return false;
}
final CountingInputStream countingInputStream = new CountingInputStream(inputStream);
final DataInputStream dataInputStream = new DataInputStream(countingInputStream);
final BackupFileHeader backupFileHeader = BackupFileHeader.read(dataInputStream);
Log.d(Config.LOGTAG, backupFileHeader.toString());
if (mDatabaseBackend.getAccountJids(false).contains(backupFileHeader.getJid())) {
synchronized (mOnBackupProcessedListeners) {
for (OnBackupProcessed l : mOnBackupProcessedListeners) {
l.onAccountAlreadySetup();
}
}
return false;
}
final byte[] key = ExportBackupService.getKey(password, backupFileHeader.getSalt());
final AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine());
cipher.init(false, new AEADParameters(new KeyParameter(key), 128, backupFileHeader.getIv()));
final CipherInputStream cipherInputStream = new CipherInputStream(countingInputStream, cipher);
final GZIPInputStream gzipInputStream = new GZIPInputStream(cipherInputStream);
final BufferedReader reader = new BufferedReader(new InputStreamReader(gzipInputStream, Charsets.UTF_8));
db.beginTransaction();
String line;
StringBuilder multiLineQuery = null;
while ((line = reader.readLine()) != null) {
int count = count(line, '\'');
if (multiLineQuery != null) {
multiLineQuery.append('\n');
multiLineQuery.append(line);
if (count % 2 == 1) {
db.execSQL(multiLineQuery.toString());
multiLineQuery = null;
updateImportBackupNotification(fileSize, countingInputStream.getCount());
}
} else {
if (count % 2 == 0) {
db.execSQL(line);
updateImportBackupNotification(fileSize, countingInputStream.getCount());
} else {
multiLineQuery = new StringBuilder(line);
}
}
}
db.setTransactionSuccessful();
db.endTransaction();
final Jid jid = backupFileHeader.getJid();
final Cursor countCursor = db.rawQuery("select count(messages.uuid) from messages join conversations on conversations.uuid=messages.conversationUuid join accounts on conversations.accountUuid=accounts.uuid where accounts.username=? and accounts.server=?", new String[] { jid.getEscapedLocal(), jid.getDomain().toEscapedString() });
countCursor.moveToFirst();
final int count = countCursor.getInt(0);
Log.d(Config.LOGTAG, String.format("restored %d messages in %s", count, stopwatch.stop().toString()));
countCursor.close();
stopBackgroundService();
synchronized (mOnBackupProcessedListeners) {
for (OnBackupProcessed l : mOnBackupProcessedListeners) {
l.onBackupRestored();
}
}
return true;
} catch (final Exception e) {
final Throwable throwable = e.getCause();
final boolean reasonWasCrypto = throwable instanceof BadPaddingException || e instanceof ZipException;
synchronized (mOnBackupProcessedListeners) {
for (OnBackupProcessed l : mOnBackupProcessedListeners) {
if (reasonWasCrypto) {
l.onBackupDecryptionFailed();
} else {
l.onBackupRestoreFailed();
}
}
}
Log.d(Config.LOGTAG, "error restoring backup " + uri, e);
return false;
}
}
use of eu.siacs.conversations.utils.BackupFileHeader in project Conversations by siacs.
the class ExportBackupService method export.
private List<File> export() throws Exception {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "backup");
mBuilder.setContentTitle(getString(R.string.notification_create_backup_title)).setSmallIcon(R.drawable.ic_archive_white_24dp).setProgress(1, 0, false);
startForeground(NOTIFICATION_ID, mBuilder.build());
int count = 0;
final int max = this.mAccounts.size();
final SecureRandom secureRandom = new SecureRandom();
final List<File> files = new ArrayList<>();
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);
secureRandom.nextBytes(salt);
final BackupFileHeader backupFileHeader = new BackupFileHeader(getString(R.string.app_name), account.getJid(), System.currentTimeMillis(), IV, salt);
final Progress progress = new Progress(mBuilder, max, count);
final File file = new File(FileBackend.getBackupDirectory(this) + account.getJid().asBareJid().toEscapedString() + ".ceb");
files.add(file);
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);
backupFileHeader.write(dataOutputStream);
dataOutputStream.flush();
final Cipher cipher = Compatibility.twentyEight() ? Cipher.getInstance(CIPHERMODE) : Cipher.getInstance(CIPHERMODE, PROVIDER);
final byte[] key = getKey(password, salt);
SecretKeySpec keySpec = new SecretKeySpec(key, KEYTYPE);
IvParameterSpec ivSpec = new IvParameterSpec(IV);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
CipherOutputStream cipherOutputStream = new CipherOutputStream(fileOutputStream, cipher);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(cipherOutputStream);
PrintWriter writer = new PrintWriter(gzipOutputStream);
SQLiteDatabase db = this.mDatabaseBackend.getReadableDatabase();
final String uuid = account.getUuid();
accountExport(db, uuid, writer);
simpleExport(db, Conversation.TABLENAME, Conversation.ACCOUNT, uuid, writer);
messageExport(db, uuid, writer, progress);
for (String table : Arrays.asList(SQLiteAxolotlStore.PREKEY_TABLENAME, SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME, SQLiteAxolotlStore.SESSION_TABLENAME, SQLiteAxolotlStore.IDENTITIES_TABLENAME)) {
simpleExport(db, table, SQLiteAxolotlStore.ACCOUNT, uuid, writer);
}
writer.flush();
writer.close();
mediaScannerScanFile(file);
Log.d(Config.LOGTAG, "written backup to " + file.getAbsoluteFile());
count++;
}
return files;
}
Aggregations