Explorar o código

Implement push with decryption & verifications

Signed-off-by: Mario Danic <mario@lovelyhq.com>
Mario Danic %!s(int64=7) %!d(string=hai) anos
pai
achega
fb5107124d
Modificáronse 18 ficheiros con 332 adicións e 75 borrados
  1. 1 1
      app/src/main/java/com/nextcloud/talk/api/helpers/api/ApiHelper.java
  2. 0 34
      app/src/main/java/com/nextcloud/talk/api/models/RetrofitBucket.java
  3. 39 0
      app/src/main/java/com/nextcloud/talk/api/models/json/push/DecryptedPushMessage.java
  4. 51 0
      app/src/main/java/com/nextcloud/talk/api/models/json/push/PushConfigurationState.java
  5. 5 9
      app/src/main/java/com/nextcloud/talk/api/models/json/push/PushMessage.java
  6. 4 2
      app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java
  7. 6 0
      app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.java
  8. 1 1
      app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java
  9. 1 0
      app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java
  10. 2 3
      app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java
  11. 0 1
      app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationJob.java
  12. 1 3
      app/src/main/java/com/nextcloud/talk/jobs/creator/MagicJobCreator.java
  13. 33 0
      app/src/main/java/com/nextcloud/talk/models/RetrofitBucket.java
  14. 34 0
      app/src/main/java/com/nextcloud/talk/models/SignatureVerification.java
  15. 3 2
      app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseInstanceIDService.java
  16. 53 2
      app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.java
  17. 96 4
      app/src/main/java/com/nextcloud/talk/utils/PushUtils.java
  18. 2 13
      app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java

+ 1 - 1
app/src/main/java/com/nextcloud/talk/api/helpers/api/ApiHelper.java

@@ -23,8 +23,8 @@ import android.net.Uri;
 
 import com.nextcloud.talk.BuildConfig;
 import com.nextcloud.talk.R;
-import com.nextcloud.talk.api.models.RetrofitBucket;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.models.RetrofitBucket;
 
 import java.util.HashMap;
 import java.util.Map;

+ 0 - 34
app/src/main/java/com/nextcloud/talk/api/models/RetrofitBucket.java

@@ -1,34 +0,0 @@
-/*
- *
- *   Nextcloud Talk application
- *
- *   @author Mario Danic
- *   Copyright (C) 2017 Mario Danic (mario@lovelyhq.com)
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-package com.nextcloud.talk.api.models;
-
-import org.parceler.Parcel;
-
-import java.util.Map;
-
-import lombok.Data;
-
-@Parcel
-@Data
-public class RetrofitBucket {
-    String url;
-    Map<String, String> queryMap;
-}

+ 39 - 0
app/src/main/java/com/nextcloud/talk/api/models/json/push/DecryptedPushMessage.java

@@ -0,0 +1,39 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.api.models.json.push;
+
+import com.bluelinelabs.logansquare.annotation.JsonField;
+import com.bluelinelabs.logansquare.annotation.JsonObject;
+
+import org.parceler.Parcel;
+
+import lombok.Data;
+
+@Data
+@Parcel
+@JsonObject
+public class DecryptedPushMessage {
+    @JsonField(name = "app")
+    String app;
+
+    @JsonField(name = "subject")
+    String subject;
+}

+ 51 - 0
app/src/main/java/com/nextcloud/talk/api/models/json/push/PushConfigurationState.java

@@ -0,0 +1,51 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.api.models.json.push;
+
+import com.bluelinelabs.logansquare.annotation.JsonField;
+import com.bluelinelabs.logansquare.annotation.JsonObject;
+
+import org.parceler.Parcel;
+
+import lombok.Data;
+
+@Parcel
+@Data
+@JsonObject
+public class PushConfigurationState {
+    @JsonField(name = "pushToken")
+    String pushToken;
+
+    @JsonField(name = "deviceIdentifier")
+    String deviceIdentifier;
+
+    @JsonField(name = "deviceIdentifierSignature")
+    String deviceIdentifierSignature;
+
+    @JsonField(name = "userPublicKey")
+    String userPublicKey;
+
+    @JsonField(name = "shouldBeDeleted")
+    boolean shouldBeDeleted;
+
+    @JsonField(name = "usesRegularPass")
+    boolean usesRegularPass;
+}

+ 5 - 9
app/src/main/java/com/nextcloud/talk/api/models/PushConfigurationState.java → app/src/main/java/com/nextcloud/talk/api/models/json/push/PushMessage.java

@@ -18,19 +18,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-package com.nextcloud.talk.api.models;
+package com.nextcloud.talk.api.models.json.push;
 
 import org.parceler.Parcel;
 
 import lombok.Data;
 
-@Parcel
 @Data
-public class PushConfigurationState {
-    String pushToken;
-    String deviceIdentifier;
-    String deviceIdentifierSignature;
-    String userPublicKey;
-    boolean shouldBeDeleted;
-    boolean usesRegularPass;
+@Parcel
+public class PushMessage {
+    String subject;
+    String signature;
 }

+ 4 - 2
app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java

@@ -26,6 +26,7 @@ import android.support.multidex.MultiDexApplication;
 
 import com.evernote.android.job.JobManager;
 import com.evernote.android.job.JobRequest;
+import com.google.firebase.analytics.FirebaseAnalytics;
 import com.nextcloud.talk.BuildConfig;
 import com.nextcloud.talk.dagger.modules.BusModule;
 import com.nextcloud.talk.dagger.modules.ContextModule;
@@ -81,9 +82,10 @@ public class NextcloudTalkApplication extends MultiDexApplication {
     public void onCreate() {
         super.onCreate();
         JobManager.create(this).addJobCreator(new MagicJobCreator());
-
+        FirebaseAnalytics.getInstance(this).setAnalyticsCollectionEnabled(false);
         sharedApplication = this;
 
+
         try {
             buildComponent();
         } catch (final GeneralSecurityException exception) {
@@ -95,7 +97,7 @@ public class NextcloudTalkApplication extends MultiDexApplication {
         componentApplication.inject(this);
         refWatcher = LeakCanary.install(this);
 
-        new JobRequest.Builder(PushRegistrationJob.TAG).setUpdateCurrent(true).startNow();
+        new JobRequest.Builder(PushRegistrationJob.TAG).setUpdateCurrent(true).startNow().build().schedule();
 
     }
 

+ 6 - 0
app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.java

@@ -33,11 +33,13 @@ import android.widget.TextView;
 
 import com.bluelinelabs.conductor.RouterTransaction;
 import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
+import com.evernote.android.job.JobRequest;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.api.helpers.api.ApiHelper;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.base.BaseController;
+import com.nextcloud.talk.jobs.PushRegistrationJob;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
 import com.nextcloud.talk.utils.database.user.UserUtils;
 
@@ -140,6 +142,10 @@ public class AccountVerificationController extends BaseController {
                                                                 + "\n" +
                                                                 getResources().getString(
                                                                         R.string.nc_display_name_stored));
+
+                                                        new JobRequest.Builder(PushRegistrationJob.TAG).
+                                                                setUpdateCurrent(true).startNow().build().schedule();
+
                                                         getRouter().setRoot(RouterTransaction.with(new
                                                                 BottomNavigationController(R.menu.menu_navigation))
                                                                 .pushChangeHandler(new HorizontalChangeHandler())

+ 1 - 1
app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java

@@ -51,12 +51,12 @@ import com.nextcloud.talk.R;
 import com.nextcloud.talk.adapters.items.UserItem;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.api.helpers.api.ApiHelper;
-import com.nextcloud.talk.api.models.RetrofitBucket;
 import com.nextcloud.talk.api.models.User;
 import com.nextcloud.talk.api.models.json.sharees.Sharee;
 import com.nextcloud.talk.api.models.json.sharees.SharesData;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.base.BaseController;
+import com.nextcloud.talk.models.RetrofitBucket;
 import com.nextcloud.talk.persistence.entities.UserEntity;
 import com.nextcloud.talk.utils.database.cache.CacheUtils;
 import com.nextcloud.talk.utils.database.user.UserUtils;

+ 1 - 0
app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java

@@ -212,6 +212,7 @@ public class WebViewLoginController extends BaseController {
                 displayName = currentUser.getDisplayName();
                 pushConfiguration = currentUser.getPushConfigurationState();
             }
+
             // We use the URL user entered because one provided by the server is NOT reliable
             userQueryDisposable = userUtils.createOrUpdateUser(loginData.getUsername(), loginData.getToken(),
                     baseUrl, displayName, pushConfiguration).

+ 2 - 3
app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java

@@ -51,7 +51,6 @@ import okhttp3.OkHttpClient;
 import okhttp3.Request;
 import okhttp3.Response;
 import okhttp3.Route;
-import okhttp3.internal.tls.OkHostnameVerifier;
 import okhttp3.logging.HttpLoggingInterceptor;
 import retrofit2.Retrofit;
 import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
@@ -124,8 +123,8 @@ public class RestModule {
             httpClient.addInterceptor(loggingInterceptor);
         }
 
-        httpClient.sslSocketFactory(sslSocketFactoryCompat, magicTrustManager);
-        httpClient.hostnameVerifier(OkHostnameVerifier.INSTANCE);
+        //httpClient.sslSocketFactory(sslSocketFactoryCompat, magicTrustManager);
+        //httpClient.hostnameVerifier(OkHostnameVerifier.INSTANCE);
 
         if (!Proxy.NO_PROXY.equals(proxy)) {
             httpClient.proxy(proxy);

+ 0 - 1
app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationJob.java

@@ -32,7 +32,6 @@ public class PushRegistrationJob extends Job {
     @Override
     protected Result onRunJob(Params params) {
         PushUtils pushUtils = new PushUtils();
-
         pushUtils.generateRsa2048KeyPair();
         pushUtils.pushRegistrationToServer();
 

+ 1 - 3
app/src/main/java/com/nextcloud/talk/jobs/creator/MagicJobCreator.java

@@ -35,11 +35,9 @@ public class MagicJobCreator implements JobCreator {
     public Job create(@NonNull String tag) {
         switch (tag) {
             case PushRegistrationJob.TAG:
-                break;
+                return new PushRegistrationJob();
             default:
                 return null;
         }
-
-        return null;
     }
 }

+ 33 - 0
app/src/main/java/com/nextcloud/talk/models/RetrofitBucket.java

@@ -0,0 +1,33 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.nextcloud.talk.models;
+
+import org.parceler.Parcel;
+
+import java.util.Map;
+
+import lombok.Data;
+
+@Parcel
+@Data
+public class RetrofitBucket {
+    String url;
+    Map<String, String> queryMap;
+}

+ 34 - 0
app/src/main/java/com/nextcloud/talk/models/SignatureVerification.java

@@ -0,0 +1,34 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.models;
+
+import com.nextcloud.talk.persistence.entities.UserEntity;
+
+import org.parceler.Parcel;
+
+import lombok.Data;
+
+@Data
+@Parcel
+public class SignatureVerification {
+    boolean signatureValid;
+    UserEntity userEntity;
+}

+ 3 - 2
app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseInstanceIDService.java

@@ -40,13 +40,14 @@ public class MagicFirebaseInstanceIDService extends FirebaseInstanceIdService {
 
     public MagicFirebaseInstanceIDService() {
         super();
-        NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
+        NextcloudTalkApplication.getSharedApplication().getComponentApplication()
+                .inject(this);
     }
 
     @Override
     public void onTokenRefresh() {
         appPreferences.setPushtoken(FirebaseInstanceId.getInstance().getToken());
 
-        new JobRequest.Builder(PushRegistrationJob.TAG).setUpdateCurrent(true).startNow();
+        new JobRequest.Builder(PushRegistrationJob.TAG).setUpdateCurrent(true).startNow().build().schedule();
     }
 }

+ 53 - 2
app/src/main/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.java

@@ -20,15 +20,66 @@
 
 package com.nextcloud.talk.services.firebase;
 
+import android.annotation.SuppressLint;
+import android.util.Base64;
+import android.util.Log;
+
+import com.bluelinelabs.logansquare.LoganSquare;
 import com.google.firebase.messaging.FirebaseMessagingService;
 import com.google.firebase.messaging.RemoteMessage;
+import com.nextcloud.talk.api.models.json.push.DecryptedPushMessage;
+import com.nextcloud.talk.api.models.json.push.PushMessage;
+import com.nextcloud.talk.models.SignatureVerification;
+import com.nextcloud.talk.utils.PushUtils;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
 
 public class MagicFirebaseMessagingService extends FirebaseMessagingService {
     private static final String TAG = "MagicFirebaseMessagingService";
 
+    @SuppressLint("LongLogTag")
     @Override
     public void onMessageReceived(RemoteMessage remoteMessage) {
-        super.onMessageReceived(remoteMessage);
-    }
+        if (remoteMessage.getData() != null) {
+            try {
+                PushMessage pushMessage = new PushMessage();
+                pushMessage.setSubject(remoteMessage.getData().get("subject"));
+                pushMessage.setSignature(remoteMessage.getData().get("signature"));
 
+                byte[] base64DecodedSubject = android.util.Base64.decode(pushMessage.getSubject(), Base64.DEFAULT);
+                byte[] base64DecodedSignature = android.util.Base64.decode(pushMessage.getSignature(), Base64.DEFAULT);
+                PushUtils pushUtils = new PushUtils();
+                PrivateKey privateKey = (PrivateKey) pushUtils.readKeyFromFile(false);
+
+                try {
+                    SignatureVerification signatureVerification = pushUtils.verifySignature(base64DecodedSignature,
+                            base64DecodedSubject);
+
+                    if (signatureVerification.isSignatureValid()) {
+                        Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
+                        cipher.init(Cipher.DECRYPT_MODE, privateKey);
+                        byte[] decryptedSubject = cipher.doFinal(base64DecodedSubject);
+                        DecryptedPushMessage decryptedPushMessage = LoganSquare.parse(new String(decryptedSubject),
+                                DecryptedPushMessage.class);
+                    }
+                } catch (NoSuchAlgorithmException e1) {
+                    Log.d(TAG, "No proper algorithm to decrypt the message");
+                } catch (NoSuchPaddingException e1) {
+                    Log.d(TAG, "No proper padding to decrypt the message");
+                } catch (InvalidKeyException e1) {
+                    Log.d(TAG, "Invalid private key");
+                }
+            } catch (Exception exception) {
+                Log.d(TAG, "Something went very wrong" + exception.getLocalizedMessage());
+            }
+        } else {
+            Log.d(TAG, "The data we received was empty");
+
+        }
+    }
 }

+ 96 - 4
app/src/main/java/com/nextcloud/talk/utils/PushUtils.java

@@ -29,17 +29,21 @@ import com.bluelinelabs.logansquare.LoganSquare;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.api.helpers.api.ApiHelper;
-import com.nextcloud.talk.api.models.PushConfigurationState;
+import com.nextcloud.talk.api.models.json.push.PushConfigurationState;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.models.SignatureVerification;
 import com.nextcloud.talk.persistence.entities.UserEntity;
 import com.nextcloud.talk.utils.database.user.UserUtils;
 import com.nextcloud.talk.utils.preferences.AppPreferences;
 
+import org.json.JSONObject;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.security.InvalidKeyException;
 import java.security.Key;
 import java.security.KeyFactory;
 import java.security.KeyPair;
@@ -47,10 +51,13 @@ import java.security.KeyPairGenerator;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.inject.Inject;
@@ -91,7 +98,49 @@ public class PushUtils {
 
     }
 
-    private static int saveKeyToFile(Key key, String path) {
+
+    public SignatureVerification verifySignature(byte[] signatureBytes, byte[] subjectBytes) {
+        Signature signature = null;
+        PushConfigurationState pushConfigurationState;
+        PublicKey publicKey;
+        JSONObject jsonObject;
+        SignatureVerification signatureVerification = new SignatureVerification();
+        signatureVerification.setSignatureValid(false);
+
+        List<UserEntity> userEntities = userUtils.getUsers();
+        try {
+            signature = Signature.getInstance("SHA512withRSA");
+            if (userEntities != null && userEntities.size() > 0) {
+                for (UserEntity userEntity : userEntities) {
+                    if (!TextUtils.isEmpty(userEntity.getPushConfigurationState())) {
+                        pushConfigurationState = LoganSquare.parse(userEntity.getPushConfigurationState(),
+                                PushConfigurationState.class);
+                        publicKey = (PublicKey) readKeyFromString(true,
+                                pushConfigurationState.getUserPublicKey());
+                        signature.initVerify(publicKey);
+                        signature.update(subjectBytes);
+                        if (signature.verify(signatureBytes)) {
+                            signatureVerification.setSignatureValid(true);
+                            signatureVerification.setUserEntity(userEntity);
+                            return signatureVerification;
+                        }
+                    }
+                }
+            }
+        } catch (NoSuchAlgorithmException e) {
+            Log.d(TAG, "No such algorithm");
+        } catch (IOException e) {
+            Log.d(TAG, "Error while trying to parse push configuration state");
+        } catch (InvalidKeyException e) {
+            Log.d(TAG, "Invalid key while trying to verify");
+        } catch (SignatureException e) {
+            Log.d(TAG, "Signature exception while trying to verify");
+        }
+
+        return signatureVerification;
+    }
+
+    private int saveKeyToFile(Key key, String path) {
         byte[] encoded = key.getEncoded();
         FileOutputStream keyFileOutputStream = null;
         try {
@@ -250,7 +299,18 @@ public class PushUtils {
                                                         userUtils.createOrUpdateUser(userEntity.getUsername(),
                                                                 userEntity.getToken(), userEntity.getBaseUrl(),
                                                                 userEntity.getDisplayName(),
-                                                                LoganSquare.serialize(pushConfigurationState));
+                                                                LoganSquare.serialize(pushConfigurationState))
+                                                                .subscribe(new Consumer<UserEntity>() {
+                                                                    @Override
+                                                                    public void accept(UserEntity userEntity) throws Exception {
+                                                                        // all went well
+                                                                    }
+                                                                }, new Consumer<Throwable>() {
+                                                                    @Override
+                                                                    public void accept(Throwable throwable) throws Exception {
+                                                                    }
+                                                                });
+
 
                                                     }
                                                 }, new Consumer<Throwable>() {
@@ -275,7 +335,39 @@ public class PushUtils {
         }
     }
 
-    private Key readKeyFromFile(boolean readPublicKey) {
+    private Key readKeyFromString(boolean readPublicKey, String keyString) {
+        keyString = keyString.replace("-----BEGIN PUBLIC KEY-----", "");
+        keyString = keyString.replace("-----END PUBLIC KEY-----", "");
+
+        if (readPublicKey) {
+            keyString = keyString.replaceAll("\\n", "").replace("-----BEGIN PUBLIC KEY-----",
+                    "").replace("-----END PUBLIC KEY-----", "");;
+        } else {
+            keyString = keyString.replaceAll("\\n", "").replace("-----BEGIN PRIVATE KEY-----",
+                    "").replace("-----END PRIVATE KEY-----", "");
+        }
+
+        KeyFactory keyFactory = null;
+        try {
+            keyFactory = KeyFactory.getInstance("RSA");
+            if (readPublicKey) {
+                X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(keyString, Base64.DEFAULT));
+                return keyFactory.generatePublic(keySpec);
+            } else {
+                PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(keyString, Base64.DEFAULT));
+                return keyFactory.generatePrivate(keySpec);
+            }
+
+        } catch (NoSuchAlgorithmException e) {
+            Log.d("TAG", "No such algorithm while reading key from string");
+        } catch (InvalidKeySpecException e) {
+            Log.d("TAG", "Invalid key spec while reading key from string");
+        }
+
+        return null;
+    }
+
+    public Key readKeyFromFile(boolean readPublicKey) {
         String path;
 
         if (readPublicKey) {

+ 2 - 13
app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java

@@ -22,13 +22,10 @@ package com.nextcloud.talk.utils.database.user;
 
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
-import android.util.Log;
 
-import com.bluelinelabs.logansquare.LoganSquare;
 import com.nextcloud.talk.persistence.entities.User;
 import com.nextcloud.talk.persistence.entities.UserEntity;
 
-import java.io.IOException;
 import java.util.List;
 
 import io.reactivex.Completable;
@@ -96,11 +93,7 @@ public class UserUtils {
             }
 
             if (pushConfigurationState != null) {
-                try {
-                    user.setPushConfigurationState(LoganSquare.serialize(pushConfigurationState));
-                } catch (IOException e) {
-                    Log.d(TAG, "Failed to serialize push configuration state");
-                }
+                user.setPushConfigurationState(pushConfigurationState);
             }
 
         } else {
@@ -113,11 +106,7 @@ public class UserUtils {
             }
 
             if (pushConfigurationState != null && !pushConfigurationState.equals(user.getPushConfigurationState())) {
-                try {
-                    user.setPushConfigurationState(LoganSquare.serialize(pushConfigurationState));
-                } catch (IOException e) {
-                    Log.d(TAG, "Failed to serialize push configuration state");
-                }
+                user.setPushConfigurationState(pushConfigurationState);
             }
         }