aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Schneppe <christian@pix-art.de>2016-08-08 22:04:57 +0200
committerChristian Schneppe <christian@pix-art.de>2016-08-09 22:34:03 +0200
commitbb4c255314e0beb1713050cc231f317894997f53 (patch)
tree97a413d8b0db8759d8876ac2ee0ce9b56dff5f3e
parent7dd493bff1ddfb0f12d95a6ed466f42973e09051 (diff)
reworked backup service
* automatically save database encrypted to local storage at 4 am each day * run backup import in new thread
-rw-r--r--src/main/AndroidManifest.xml7
-rw-r--r--src/main/java/de/pixart/messenger/Config.java6
-rw-r--r--src/main/java/de/pixart/messenger/services/AlarmReceiver.java21
-rw-r--r--src/main/java/de/pixart/messenger/services/ExportLogsService.java66
-rw-r--r--src/main/java/de/pixart/messenger/services/XmppConnectionService.java32
-rw-r--r--src/main/java/de/pixart/messenger/ui/UpdaterActivity.java45
-rw-r--r--src/main/java/de/pixart/messenger/ui/WelcomeActivity.java184
-rw-r--r--src/main/java/de/pixart/messenger/utils/EncryptDecryptFile.java73
-rw-r--r--src/main/res/layout/password.xml12
-rw-r--r--src/main/res/values-de/strings.xml6
-rw-r--r--src/main/res/values/strings.xml6
11 files changed, 347 insertions, 111 deletions
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 44742fa38..e3007ddef 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -18,7 +18,7 @@
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-
+ <uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission
android:name="android.permission.READ_PHONE_STATE"
tools:node="remove"/>
@@ -48,6 +48,11 @@
</intent-filter>
</receiver>
+ <receiver
+ android:name="de.pixart.messenger.services.AlarmReceiver">
+ </receiver>
+
+
<activity
android:name="de.pixart.messenger.ui.StartUI"
android:configChanges="orientation|screenSize"
diff --git a/src/main/java/de/pixart/messenger/Config.java b/src/main/java/de/pixart/messenger/Config.java
index 822da1000..262123784 100644
--- a/src/main/java/de/pixart/messenger/Config.java
+++ b/src/main/java/de/pixart/messenger/Config.java
@@ -42,7 +42,7 @@ public final class Config {
public static final String BUG_REPORTS = "bugs@pix-art.de";
- public static String inviteUserURL = "https://jabber.pix-art.de/i/";
+ public static final String inviteUserURL = "https://jabber.pix-art.de/i/";
public static final String DOMAIN_LOCK = "pix-art.de"; //only allow account creation for this domain
public static final String MAGIC_CREATE_DOMAIN = "pix-art.de";
@@ -92,6 +92,10 @@ public final class Config {
public static final int MAX_DISPLAY_MESSAGE_CHARS = 4096;
+ public static final boolean ExportLogs = true; // automatically export logs
+ public static final int ExportLogs_Hour = 4; //valid values from 0 to 23
+ public static final int ExportLogs_Minute = 0; //valid values from 0 to 59
+
public static final boolean DISABLE_PROXY_LOOKUP = false; //useful to debug ibb
public static final boolean DISABLE_HTTP_UPLOAD = false;
public static final boolean DISABLE_STRING_PREP = false; // setting to true might increase startup performance
diff --git a/src/main/java/de/pixart/messenger/services/AlarmReceiver.java b/src/main/java/de/pixart/messenger/services/AlarmReceiver.java
new file mode 100644
index 000000000..0fd3ba049
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/services/AlarmReceiver.java
@@ -0,0 +1,21 @@
+package de.pixart.messenger.services;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import de.pixart.messenger.Config;
+
+public class AlarmReceiver extends BroadcastReceiver{
+ public static final int SCHEDULE_ALARM_REQUEST_CODE = 523976483;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().contains("exportlogs")) {
+ Log.d(Config.LOGTAG, "Received alarm broadcast to export logs");
+ Intent i = new Intent(context, ExportLogsService.class);
+ context.startService(i);
+ }
+ }
+}
diff --git a/src/main/java/de/pixart/messenger/services/ExportLogsService.java b/src/main/java/de/pixart/messenger/services/ExportLogsService.java
index 331321ffe..bc385b1e5 100644
--- a/src/main/java/de/pixart/messenger/services/ExportLogsService.java
+++ b/src/main/java/de/pixart/messenger/services/ExportLogsService.java
@@ -6,6 +6,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
+import android.util.Log;
import java.io.BufferedWriter;
import java.io.File;
@@ -13,19 +14,23 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
+import javax.crypto.NoSuchPaddingException;
+
+import de.pixart.messenger.Config;
import de.pixart.messenger.R;
import de.pixart.messenger.entities.Account;
import de.pixart.messenger.entities.Conversation;
import de.pixart.messenger.entities.Message;
import de.pixart.messenger.persistance.DatabaseBackend;
import de.pixart.messenger.persistance.FileBackend;
+import de.pixart.messenger.utils.EncryptDecryptFile;
import de.pixart.messenger.xmpp.jid.Jid;
public class ExportLogsService extends Service {
@@ -50,10 +55,12 @@ public class ExportLogsService extends Service {
new Thread(new Runnable() {
@Override
public void run() {
- try {
- ExportDatabase();
- } catch (IOException e) {
- e.printStackTrace();
+ if (mAccounts.size() == 1) {
+ try {
+ ExportDatabase();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
}
export();
stopForeground(true);
@@ -150,36 +157,47 @@ public class ExportLogsService extends Service {
}
public void ExportDatabase() throws IOException {
-
+ Account mAccount = mAccounts.get(0);
// Get hold of the db:
- InputStream myInput = new FileInputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME));
-
+ FileInputStream InputFile = new FileInputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME));
// Set the output folder on the SDcard
- File directory = new File(FileBackend.getConversationsDirectory() + "/.Database/");
-
+ File directory = new File(FileBackend.getConversationsDirectory() + "/database/");
// Create the folder if it doesn't exist:
if (!directory.exists()) {
directory.mkdirs();
}
-
+ //Delete old database export file
+ File temp_db_file = new File(directory + "/database.bak");
+ if (temp_db_file.exists()) {
+ Log.d(Config.LOGTAG, "Delete temp database backup file from " + temp_db_file.toString());
+ temp_db_file.delete();
+ }
// Set the output file stream up:
- OutputStream myOutput = new FileOutputStream(directory.getPath() + "/Database.bak");
+ FileOutputStream OutputFile = new FileOutputStream(directory.getPath() + "/database.db.crypt");
- // Transfer bytes from the input file to the output file
- byte[] buffer = new byte[1024];
- int length;
- while ((length = myInput.read(buffer)) > 0) {
- myOutput.write(buffer, 0, length);
- }
+ String EncryptionKey = mAccount.getPassword(); //get account password
- // Close and clear the streams
- myOutput.flush();
- myOutput.close();
- myInput.close();
+ Log.d(Config.LOGTAG,"Password for " + mAccount.getJid().toString() + " is " + EncryptionKey);
+ // encrypt database from the input file to the output file
+ try {
+ EncryptDecryptFile.encrypt(InputFile, OutputFile, EncryptionKey);
+ } catch (NoSuchAlgorithmException e) {
+ Log.d(Config.LOGTAG,"Database exporter: encryption failed with " + e);
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ Log.d(Config.LOGTAG,"Database exporter: encryption failed with " + e);
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ Log.d(Config.LOGTAG,"Database exporter: encryption failed (invalid key) with " + e);
+ e.printStackTrace();
+ } catch (IOException e) {
+ Log.d(Config.LOGTAG,"Database exporter: encryption failed (IO) with " + e);
+ e.printStackTrace();
+ }
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
index 4f12500d9..9209c399c 100644
--- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
+++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java
@@ -48,6 +48,7 @@ import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -794,6 +795,9 @@ public class XmppConnectionService extends Service {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
scheduleNextIdlePing();
}
+
+ //start export log service every day at given time
+ ScheduleAutomaticExport();
}
@Override
@@ -814,6 +818,8 @@ public class XmppConnectionService extends Service {
}
fileObserver.stopWatching();
super.onDestroy();
+ // cancel scheduled exporter
+ CancelAutomaticExport();
}
public void toggleScreenEventReceiver() {
@@ -3507,4 +3513,30 @@ public class XmppConnectionService extends Service {
return XmppConnectionService.this;
}
}
+
+ public void ScheduleAutomaticExport() {
+ //start export log service every day at given time
+ if (Config.ExportLogs) {
+ if (Config.ExportLogs_Hour >= 0 && Config.ExportLogs_Hour <= 23 && Config.ExportLogs_Minute >= 0 && Config.ExportLogs_Minute <= 59) {
+ Log.d(Config.LOGTAG, "Schedule automatic export logs at " + Config.ExportLogs_Hour + ":" + Config.ExportLogs_Minute);
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(System.currentTimeMillis());
+ calendar.set(Calendar.HOUR_OF_DAY, Config.ExportLogs_Hour);
+ calendar.set(Calendar.MINUTE, Config.ExportLogs_Minute);
+ Intent intent = new Intent(this, AlarmReceiver.class);
+ intent.setAction("exportlogs");
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, AlarmReceiver.SCHEDULE_ALARM_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ ((AlarmManager) getSystemService(ALARM_SERVICE)).setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
+ }
+ }
+ }
+
+ public void CancelAutomaticExport() {
+ if (Config.ExportLogs) {
+ Log.d(Config.LOGTAG, "Cancel scheduled automatic export");
+ Intent intent = new Intent(this, AlarmReceiver.class);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, AlarmReceiver.SCHEDULE_ALARM_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ ((AlarmManager) this.getSystemService(ALARM_SERVICE)).cancel(pendingIntent);
+ }
+ }
}
diff --git a/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java b/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java
index 0a35288d7..fcd4275a4 100644
--- a/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/UpdaterActivity.java
@@ -26,15 +26,10 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import de.pixart.messenger.Config;
import de.pixart.messenger.R;
-import de.pixart.messenger.persistance.DatabaseBackend;
+import de.pixart.messenger.services.ExportLogsService;
import de.pixart.messenger.services.UpdaterWebService;
public class UpdaterActivity extends Activity {
@@ -62,7 +57,6 @@ public class UpdaterActivity extends Activity {
installIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(installIntent);
-
UpdaterActivity.this.finish();
}
}
@@ -99,36 +93,6 @@ public class UpdaterActivity extends Activity {
}
}
- private void ExportDatabase() throws IOException {
-
- // Get hold of the db:
- InputStream myInput = new FileInputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME));
-
- // Set the output folder on the SDcard
- File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pix-Art Messenger/.Database/");
-
- // Create the folder if it doesn't exist:
- if (!directory.exists()) {
- directory.mkdirs();
- }
-
- // Set the output file stream up:
- OutputStream myOutput = new FileOutputStream(directory.getPath() + "/Database.bak");
-
- // Transfer bytes from the input file to the output file
- byte[] buffer = new byte[1024];
- int length;
- while ((length = myInput.read(buffer)) > 0) {
- myOutput.write(buffer, 0, length);
- }
-
- // Close and clear the streams
- myOutput.flush();
- myOutput.close();
- myInput.close();
- }
-
-
@Override
public void onDestroy() {
//unregister your receivers
@@ -230,11 +194,8 @@ public class UpdaterActivity extends Activity {
if (success) {
if (isStoragePermissionGranted()) {
//start backing up database
- try {
- ExportDatabase();
- } catch (IOException e) {
- e.printStackTrace();
- }
+ final Intent startIntent = new Intent(getBaseContext(), ExportLogsService.class);
+ getBaseContext().startService(startIntent);
}
//Overall information about the contents of a package
//This corresponds to all of the information collected from AndroidManifest.xml.
diff --git a/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java b/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java
index c92bb8cd4..b97dcbcfd 100644
--- a/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/WelcomeActivity.java
@@ -3,6 +3,7 @@ package de.pixart.messenger.ui;
import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -12,29 +13,33 @@ import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.Environment;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
+import android.widget.EditText;
import android.widget.TextView;
+import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
import java.util.List;
+import javax.crypto.NoSuchPaddingException;
+
import de.pixart.messenger.Config;
import de.pixart.messenger.R;
import de.pixart.messenger.persistance.DatabaseBackend;
+import de.pixart.messenger.persistance.FileBackend;
+import de.pixart.messenger.utils.EncryptDecryptFile;
public class WelcomeActivity extends Activity {
private static final int REQUEST_READ_EXTERNAL_STORAGE = 0XD737;
- boolean dbExist = false;
- boolean backup_existing = false;
@Override
protected void onCreate(final Bundle savedInstanceState) {
@@ -43,18 +48,14 @@ public class WelcomeActivity extends Activity {
//check if there is a backed up database --
if (hasStoragePermission(REQUEST_READ_EXTERNAL_STORAGE)) {
- dbExist = checkDatabase();
- }
-
- if (dbExist) {
- backup_existing = true;
+ BackupAvailable();
}
final Button ImportDatabase = (Button) findViewById(R.id.import_database);
final TextView ImportText = (TextView) findViewById(R.id.import_text);
- if (backup_existing) {
+ if (BackupAvailable()) {
ImportDatabase.setVisibility(View.VISIBLE);
ImportText.setVisibility(View.VISIBLE);
}
@@ -62,11 +63,7 @@ public class WelcomeActivity extends Activity {
ImportDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- try {
- ImportDatabase();
- } catch (IOException e) {
- e.printStackTrace();
- }
+ enterPasswordDialog();
}
});
@@ -89,16 +86,109 @@ public class WelcomeActivity extends Activity {
}
- private boolean checkDatabase() {
+ public void enterPasswordDialog() {
+ LayoutInflater li = LayoutInflater.from(WelcomeActivity.this);
+ View promptsView = li.inflate(R.layout.password, null);
+ final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(WelcomeActivity.this);
+ alertDialogBuilder.setView(promptsView);
+ final EditText userInput = (EditText) promptsView
+ .findViewById(R.id.password);
+ alertDialogBuilder.setTitle(R.string.enter_password);
+ alertDialogBuilder.setMessage(R.string.enter_account_password);
+ alertDialogBuilder
+ .setCancelable(false)
+ .setPositiveButton(R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog,int id) {
+ final String password = userInput.getText().toString();
+ final ProgressDialog pd = ProgressDialog.show(WelcomeActivity.this, getString(R.string.please_wait), getString(R.string.databaseimport_started), true);
+ if (!password.isEmpty()) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ checkDatabase(password);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ pd.dismiss();
+ }
+ }).start();
+ } else {
+ AlertDialog.Builder builder = new AlertDialog.Builder(WelcomeActivity.this);
+ builder.setTitle(R.string.error);
+ builder.setMessage(R.string.password_should_not_be_empty);
+ builder.setNegativeButton(R.string.cancel, null);
+ builder.setPositiveButton(R.string.try_again, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ enterPasswordDialog();
+ }
+ });
+ builder.create().show();
+ }
+ }
+ })
+ .setNegativeButton(R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog,int id) {
+ Toast.makeText(WelcomeActivity.this, R.string.import_canceled, Toast.LENGTH_LONG).show();
+ dialog.dismiss();
+ }
+ }
+ );
+ // create alert dialog
+ AlertDialog alertDialog = alertDialogBuilder.create();
+
+ // show it
+ alertDialog.show();
+ }
+
+ private boolean BackupAvailable() {
+ // Set the folder on the SDcard
+ File filePath = new File(FileBackend.getConversationsDirectory() + "/database/database.db.crypt");
+ Log.d(Config.LOGTAG,"DB Path: " + filePath.toString());
+ if(filePath.exists()) {
+ Log.d(Config.LOGTAG,"DB Path existing");
+ return true;
+ } else {
+ Log.d(Config.LOGTAG,"DB Path not existing");
+ return false;
+ }
+ }
+
+ private void checkDatabase(String DecryptionKey) throws IOException {
+ // Set the folder on the SDcard
+ File directory = new File(FileBackend.getConversationsDirectory() + "/database/");
+ // Set the input file stream up:
+ FileInputStream InputFile = new FileInputStream(directory.getPath() + "/database.db.crypt");
+ // Temp output for DB checks
+ File TempFile = new File(directory.getPath() + "/database.bak");
+ FileOutputStream OutputTemp = new FileOutputStream(TempFile);
+
+ try {
+ Log.d(Config.LOGTAG,"Try decryption to temp with password: " + DecryptionKey);
+ EncryptDecryptFile.decrypt(InputFile, OutputTemp, DecryptionKey);
+ } catch (NoSuchAlgorithmException e) {
+ Log.d(Config.LOGTAG,"Database importer: decryption failed with " + e);
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ Log.d(Config.LOGTAG,"Database importer: decryption failed with " + e);
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ Log.d(Config.LOGTAG,"Database importer: decryption failed (invalid key) with " + e);
+ e.printStackTrace();
+ } catch (IOException e) {
+ Log.d(Config.LOGTAG,"Database importer: decryption failed (IO) with " + e);
+ e.printStackTrace();
+ }
SQLiteDatabase checkDB = null;
- String DB_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pix-Art Messenger/.Database/";
- String DB_NAME = "Database.bak";
int DB_Version = DatabaseBackend.DATABASE_VERSION;
int Backup_DB_Version = 0;
try {
- String dbPath = DB_PATH + DB_NAME;
+ String dbPath = TempFile.toString();
checkDB = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY);
Backup_DB_Version = checkDB.getVersion();
Log.d(Config.LOGTAG, "Backup found: " + checkDB + " Version: " + checkDB.getVersion());
@@ -111,36 +201,45 @@ public class WelcomeActivity extends Activity {
if (checkDB != null) {
checkDB.close();
}
- if (checkDB != null && Backup_DB_Version <= DB_Version) {
- return true;
+ Log.d(Config.LOGTAG, "checkDB = " + checkDB.toString() + ", Backup DB = " + Backup_DB_Version + ", DB = " + DB_Version);
+ if (checkDB != null && Backup_DB_Version != 0 && Backup_DB_Version <= DB_Version) {
+ Log.d(Config.LOGTAG,"Try decryption with password: " + DecryptionKey);
+ if (TempFile.exists()) {
+ Log.d(Config.LOGTAG, "Delete temp file from " + TempFile.toString());
+ TempFile.delete();
+ }
+ ImportDatabase(DecryptionKey);
+ } else if (checkDB != null && Backup_DB_Version == 0) {
+ Toast.makeText(WelcomeActivity.this, R.string.Password_wrong, Toast.LENGTH_LONG).show();
+ enterPasswordDialog();
} else {
- return false;
+ Toast.makeText(WelcomeActivity.this, R.string.Import_failed, Toast.LENGTH_LONG).show();
}
}
- private void ImportDatabase() throws IOException {
-
+ private void ImportDatabase(final String DecryptionKey) throws IOException {
// Set location for the db:
- OutputStream myOutput = new FileOutputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME));
-
+ final FileOutputStream OutputFile = new FileOutputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME));
// Set the folder on the SDcard
- File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pix-Art Messenger/.Database/");
-
+ File directory = new File(FileBackend.getConversationsDirectory() + "/database/");
// Set the input file stream up:
- InputStream myInput = new FileInputStream(directory.getPath() + "/Database.bak");
-
- // Transfer bytes from the input file to the output file
- byte[] buffer = new byte[1024];
- int length;
- while ((length = myInput.read(buffer)) > 0) {
- myOutput.write(buffer, 0, length);
+ final FileInputStream InputFile = new FileInputStream(directory.getPath() + "/database.db.crypt");
+ Log.d(Config.LOGTAG,"Starting decryption and import of backup with password: " + DecryptionKey);
+ try {
+ EncryptDecryptFile.decrypt(InputFile, OutputFile, DecryptionKey);
+ } catch (NoSuchAlgorithmException e) {
+ Log.d(Config.LOGTAG, "Database importer: decryption failed with " + e);
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ Log.d(Config.LOGTAG, "Database importer: decryption failed with " + e);
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ Log.d(Config.LOGTAG, "Database importer: decryption failed (invalid key) with " + e);
+ e.printStackTrace();
+ } catch (IOException e) {
+ Log.d(Config.LOGTAG, "Database importer: decryption failed (IO) with " + e);
+ e.printStackTrace();
}
- Log.d(Config.LOGTAG,"Starting import of backup");
-
- // Close and clear the streams
- myOutput.flush();
- myOutput.close();
- myInput.close();
Log.d(Config.LOGTAG, "New Features - Uninstall old version of Pix-Art Messenger");
if (isPackageInstalled("eu.siacs.conversations")) {
@@ -168,7 +267,6 @@ public class WelcomeActivity extends Activity {
} else {
restart();
}
-
}
private void restart() {
diff --git a/src/main/java/de/pixart/messenger/utils/EncryptDecryptFile.java b/src/main/java/de/pixart/messenger/utils/EncryptDecryptFile.java
new file mode 100644
index 000000000..fd9392132
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/utils/EncryptDecryptFile.java
@@ -0,0 +1,73 @@
+package de.pixart.messenger.utils;
+
+import android.util.Log;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+
+import de.pixart.messenger.Config;
+
+public class EncryptDecryptFile {
+ private static String cipher_mode = "AES/ECB/PKCS5Padding";
+
+ public static void encrypt(FileInputStream iFile, FileOutputStream oFile, String iKey) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
+ byte[] key = iKey.getBytes("UTF-8");
+ Log.d(Config.LOGTAG, "Cipher key: " + Arrays.toString(key));
+ MessageDigest sha = MessageDigest.getInstance("SHA-1");
+ Log.d(Config.LOGTAG, "Cipher sha: " + sha.toString());
+ key = sha.digest(key);
+ Log.d(Config.LOGTAG, "Cipher sha key: " + Arrays.toString(key));
+ key = Arrays.copyOf(key, 16); // use only first 128 bit
+ Log.d(Config.LOGTAG, "Cipher sha key 16 bytes: " + Arrays.toString(key));
+ SecretKeySpec sks = new SecretKeySpec(key, "AES");
+ Cipher cipher = Cipher.getInstance(cipher_mode);
+ cipher.init(Cipher.ENCRYPT_MODE, sks);
+ Log.d(Config.LOGTAG, "Cipher IV: " + Arrays.toString(cipher.getIV()));
+ CipherOutputStream cos = new CipherOutputStream(oFile, cipher);
+ Log.d(Config.LOGTAG, "Encryption with: " + cos.toString());
+ int b;
+ byte[] d = new byte[8];
+ while ((b = iFile.read(d)) != -1) {
+ cos.write(d, 0, b);
+ }
+ cos.flush();
+ cos.close();
+ iFile.close();
+ }
+
+ public static void decrypt(FileInputStream iFile, FileOutputStream oFile, String iKey) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
+ byte[] key = iKey.getBytes("UTF-8");
+ Log.d(Config.LOGTAG, "Cipher key: " + Arrays.toString(key));
+ MessageDigest sha = MessageDigest.getInstance("SHA-1");
+ Log.d(Config.LOGTAG, "Cipher sha: " + sha.toString());
+ key = sha.digest(key);
+ Log.d(Config.LOGTAG, "Cipher sha key: " + Arrays.toString(key));
+ key = Arrays.copyOf(key, 16); // use only first 128 bit
+ Log.d(Config.LOGTAG, "Cipher sha key 16 bytes: " + Arrays.toString(key));
+ SecretKeySpec sks = new SecretKeySpec(key, "AES");
+ Cipher cipher = Cipher.getInstance(cipher_mode);
+ cipher.init(Cipher.DECRYPT_MODE, sks);
+ Log.d(Config.LOGTAG, "Cipher IV: " + Arrays.toString(cipher.getIV()));
+ CipherInputStream cis = new CipherInputStream(iFile, cipher);
+ Log.d(Config.LOGTAG, "Decryption with: " + cis.toString());
+ int b;
+ byte[] d = new byte[8];
+ while ((b = cis.read(d)) != -1) {
+ oFile.write(d, 0, b);
+ }
+ oFile.flush();
+ oFile.close();
+ cis.close();
+ }
+}
diff --git a/src/main/res/layout/password.xml b/src/main/res/layout/password.xml
new file mode 100644
index 000000000..5de9baa23
--- /dev/null
+++ b/src/main/res/layout/password.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical" android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <EditText
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textPassword"
+ android:hint="@string/account_settings_password"
+ android:id="@+id/password" />
+</LinearLayout> \ No newline at end of file
diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml
index a25efe5f5..7820715bc 100644
--- a/src/main/res/values-de/strings.xml
+++ b/src/main/res/values-de/strings.xml
@@ -632,5 +632,11 @@
<string name="account_status_stream_error">Strem-Fehler</string>
<string name="registration_password_too_weak">Registrierung fehlgeschlagen: Passwort zu schwach</string>
<string name="this_device_is_no_longer_in_use">Dieses Gerät wird nicht länger verwendet</string>
+ <string name="Import_failed">Datenbankimport ist fehlgeschlagen und nicht möglich.</string>
+ <string name="Password_wrong">Falsches Passwort, erneut versuchen</string>
+ <string name="enter_account_password">Bitte gib das Passwort deines Profils ein, um das Backup zu importieren.</string>
+ <string name="import_canceled">Import abgebrochen</string>
+ <string name="databaseimport_started">Backup wird importiert, dies wird eine Weile dauern.</string>
+ <string name="please_wait">Bitte warten…</string>
</resources>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 370b07224..309cdd285 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -677,4 +677,10 @@
<string name="type_tablet">Tablet</string>
<string name="type_web">Web browser</string>
<string name="type_console">Console</string>
+ <string name="import_canceled">Import canceled</string>
+ <string name="Import_failed">Database import failed, an import is not possible</string>
+ <string name="Password_wrong">Wrong password, try again</string>
+ <string name="enter_account_password">Please enter your account password to import your backup.</string>
+ <string name="please_wait">Please wait…</string>
+ <string name="databaseimport_started">Backup will be imported, this may take awhile.</string>
</resources>