diff --git a/app/build.gradle b/app/build.gradle index 7efa15c55..41689e3f9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -333,4 +333,5 @@ dependencies { findbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.4.7' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' implementation 'com.github.Kennyc1012:BottomSheet:2.4.1' + implementation 'com.google.firebase:firebase-messaging:20.1.0' } diff --git a/app/gplay.gradle b/app/gplay.gradle index 78daf24e5..d51f37891 100644 --- a/app/gplay.gradle +++ b/app/gplay.gradle @@ -19,6 +19,6 @@ */ dependencies { - implementation "androidx.work:work-gcm:2.3.0-alpha02" - implementation "com.google.firebase:firebase-messaging:20.0.0" + implementation "androidx.work:work-gcm:2.3.0-beta01" + implementation "com.google.firebase:firebase-messaging:20.1.0" } diff --git a/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt b/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt index 91e5968fa..9983c13f3 100644 --- a/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt @@ -20,10 +20,8 @@ package com.nextcloud.talk.services.firebase import android.annotation.SuppressLint -import autodagger.AutoInjector import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage -import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.jobs.NotificationWorker import com.nextcloud.talk.jobs.PushRegistrationWorker import com.nextcloud.talk.utils.bundle.BundleKeys @@ -31,33 +29,31 @@ import androidx.work.Data import androidx.work.OneTimeWorkRequest import androidx.work.WorkManager import com.nextcloud.talk.utils.preferences.AppPreferences +import org.koin.core.KoinComponent +import org.koin.core.inject class MagicFirebaseMessagingService : FirebaseMessagingService(), KoinComponent { val appPreferences: AppPreferences by inject() - @Override - fun onNewToken(token: String?) { + override fun onNewToken(token: String) { super.onNewToken(token) - appPreferences.setPushToken(token) - val pushRegistrationWork: OneTimeWorkRequest = Builder(PushRegistrationWorker::class.java).build() + appPreferences.pushToken = token + val pushRegistrationWork: OneTimeWorkRequest = OneTimeWorkRequest.Builder(PushRegistrationWorker::class.java).build() WorkManager.getInstance().enqueue(pushRegistrationWork) } @SuppressLint("LongLogTag") - @Override - fun onMessageReceived(remoteMessage: RemoteMessage?) { - if (remoteMessage == null) { - return - } - if (remoteMessage.getData() != null) { - val messageData: Data = Builder() - .putString(BundleKeys.INSTANCE.getKEY_NOTIFICATION_SUBJECT(), remoteMessage.getData().get("subject")) - .putString(BundleKeys.INSTANCE.getKEY_NOTIFICATION_SIGNATURE(), remoteMessage.getData().get("signature")) + override fun onMessageReceived(remoteMessage: RemoteMessage) { + remoteMessage.data.let { + val messageData: Data = Data.Builder() + .putString(BundleKeys.KEY_NOTIFICATION_SUBJECT, it["subject"]) + .putString(BundleKeys.KEY_NOTIFICATION_SIGNATURE, it["signature"]) .build() - val pushNotificationWork: OneTimeWorkRequest = Builder(NotificationWorker::class.java) + val pushNotificationWork: OneTimeWorkRequest = OneTimeWorkRequest.Builder(NotificationWorker::class.java) .setInputData(messageData) .build() WorkManager.getInstance().enqueue(pushNotificationWork) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt index 08a92153b..4f04685e6 100644 --- a/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt +++ b/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt @@ -162,8 +162,6 @@ class NextcloudTalkApplication : Application(), LifecycleObserver { 12, TimeUnit.HOURS ) .build() - val capabilitiesUpdateWork = OneTimeWorkRequest.Builder(CapabilitiesWorker::class.java) - .build() val signalingSettingsWork = OneTimeWorkRequest.Builder(SignalingSettingsWorker::class.java) .build() @@ -171,8 +169,6 @@ class NextcloudTalkApplication : Application(), LifecycleObserver { .enqueue(pushRegistrationWork) WorkManager.getInstance() .enqueue(accountRemovalWork) - WorkManager.getInstance() - .enqueue(capabilitiesUpdateWork) WorkManager.getInstance() .enqueue(signalingSettingsWork) WorkManager.getInstance() diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt b/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt index 115aa2bae..edc39de42 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallController.kt @@ -1007,22 +1007,12 @@ class CallController(args: Bundle) : BaseController() { override fun onNext(capabilitiesOverall: CapabilitiesOverall) { isMultiSession = capabilitiesOverall.ocs.data - .capabilities != null && capabilitiesOverall.ocs.data - .capabilities.spreedCapability != null && - capabilitiesOverall.ocs.data - .capabilities.spreedCapability - .features != null && capabilitiesOverall.ocs.data .capabilities.spreedCapability - .features.contains("multi-room-users") + ?.features?.contains("multi-room-users") == true - needsPing = !(capabilitiesOverall.ocs.data - .capabilities != null && capabilitiesOverall.ocs.data - .capabilities.spreedCapability != null && - capabilitiesOverall.ocs.data - .capabilities.spreedCapability - .features != null && capabilitiesOverall.ocs.data + needsPing = capabilitiesOverall.ocs.data .capabilities.spreedCapability - .features.contains("no-ping")) + ?.features?.contains("no-ping") == false if (!hasExternalSignalingServer) { joinRoomAndCall() diff --git a/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.kt b/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.kt index afe4747e1..15774ff8f 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.kt +++ b/app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.kt @@ -59,6 +59,8 @@ import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.models.json.conversations.RoomsOverall import com.nextcloud.talk.models.json.participants.Participant import com.nextcloud.talk.models.json.participants.ParticipantsOverall +import com.nextcloud.talk.newarch.local.models.UserNgEntity +import com.nextcloud.talk.newarch.local.models.getCredentials import com.nextcloud.talk.newarch.utils.getCredentials import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.DoNotDisturbUtils @@ -108,7 +110,7 @@ class CallNotificationController(private val originalBundle: Bundle) : BaseContr @BindView(R.id.incomingTextRelativeLayout) var incomingTextRelativeLayout: RelativeLayout? = null private val roomId: String - private val userBeingCalled: UserEntity? + private val userBeingCalled: UserNgEntity? private val credentials: String? private var currentConversation: Conversation? = null private var mediaPlayer: MediaPlayer? = null @@ -282,7 +284,7 @@ class CallNotificationController(private val originalBundle: Bundle) : BaseContr var importantConversation = false val arbitraryStorageEntity: ArbitraryStorageEntity? = arbitraryStorageUtils.getStorageSetting( - userBeingCalled!!.id, + userBeingCalled!!.id!!, "important_conversation", currentConversation!!.token ) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt index b058eda8f..62e1d2ad4 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt @@ -20,30 +20,151 @@ package com.nextcloud.talk.jobs +import android.annotation.SuppressLint +import android.app.Application import android.content.Context +import android.text.TextUtils +import android.util.Base64 +import android.util.Log +import androidx.work.CoroutineWorker import androidx.work.ListenableWorker.Result -import androidx.work.Worker import androidx.work.WorkerParameters +import com.nextcloud.talk.R +import com.nextcloud.talk.api.NcApi +import com.nextcloud.talk.events.EventStatus +import com.nextcloud.talk.models.json.push.PushConfigurationState +import com.nextcloud.talk.models.json.push.PushRegistrationOverall import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository +import com.nextcloud.talk.newarch.local.models.getCredentials +import com.nextcloud.talk.newarch.utils.hashWithAlgorithm +import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.PushUtils +import com.nextcloud.talk.utils.preferences.AppPreferences +import io.reactivex.Observer +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import org.greenrobot.eventbus.EventBus import org.koin.core.KoinComponent import org.koin.core.inject +import java.security.PublicKey +import java.util.* class PushRegistrationWorker( context: Context, workerParams: WorkerParameters -) : Worker(context, workerParams), KoinComponent { +) : CoroutineWorker(context, workerParams), KoinComponent { val usersRepository: UsersRepository by inject() + val eventBus: EventBus by inject() + val appPreferences: AppPreferences by inject() + val application: Application by inject() + val ncApi: NcApi by inject() - override fun doWork(): Result { + override suspend fun doWork(): Result { val pushUtils = PushUtils(usersRepository) pushUtils.generateRsa2048KeyPair() - pushUtils.pushRegistrationToServer() + pushRegistrationToServer() return Result.success() } - companion object { - const val TAG = "PushRegistrationWorker" - } -} \ No newline at end of file + private fun pushRegistrationToServer() { + val token: String = appPreferences.pushToken + if (!TextUtils.isEmpty(token)) { + var credentials: String + val pushUtils = PushUtils(usersRepository) + val pushTokenHash = token.hashWithAlgorithm("SHA-512") + val devicePublicKey = pushUtils.readKeyFromFile(true) as PublicKey? + if (devicePublicKey != null) { + val publicKeyBytes: ByteArray? = + Base64.encode(devicePublicKey.encoded, Base64.NO_WRAP) + var publicKey = String(publicKeyBytes!!) + publicKey = publicKey.replace("(.{64})".toRegex(), "$1\n") + publicKey = "-----BEGIN PUBLIC KEY-----\n$publicKey\n-----END PUBLIC KEY-----\n" + val users = usersRepository.getUsers() + if (users.count() > 0) { + var accountPushData: PushConfigurationState? + for (userEntityObject in users) { + accountPushData = userEntityObject.pushConfiguration + if (accountPushData == null || accountPushData.pushToken != token) { + val queryMap: MutableMap = + HashMap() + queryMap["format"] = "json" + queryMap["pushTokenHash"] = pushTokenHash + queryMap["devicePublicKey"] = publicKey + queryMap["proxyServer"] = application.getString(R.string.nc_push_server_url) + credentials = userEntityObject.getCredentials() + ncApi.registerDeviceForNotificationsWithNextcloud( + credentials, + ApiUtils.getUrlNextcloudPush(userEntityObject.baseUrl), + queryMap + ) + .blockingSubscribe(object : Observer { + override fun onSubscribe(d: Disposable) {} + @SuppressLint("CheckResult") + override fun onNext(pushRegistrationOverall: PushRegistrationOverall) { + val proxyMap: MutableMap = + HashMap() + proxyMap["pushToken"] = token + proxyMap["deviceIdentifier"] = + pushRegistrationOverall.ocs.data.deviceIdentifier + proxyMap["deviceIdentifierSignature"] = pushRegistrationOverall.ocs + .data.signature + proxyMap["userPublicKey"] = pushRegistrationOverall.ocs + .data.publicKey + ncApi.registerDeviceForNotificationsWithProxy( + ApiUtils.getUrlPushProxy(), proxyMap + ).subscribe({ + val pushConfigurationState = PushConfigurationState() + pushConfigurationState.pushToken = token + pushConfigurationState.deviceIdentifier = proxyMap["deviceIdentifier"] + pushConfigurationState.deviceIdentifierSignature = proxyMap["deviceIdentifierSignature"] + pushConfigurationState.userPublicKey = proxyMap["userPublicKey"] + pushConfigurationState.usesRegularPass = false + GlobalScope.launch { + val user = usersRepository.getUserWithId(userEntityObject.id!!) + user.pushConfiguration = pushConfigurationState + usersRepository.updateUser(user) + } + + eventBus.post( + EventStatus( + userEntityObject.id!!, + EventStatus.EventType.PUSH_REGISTRATION, + true + ) + ) + }, { + eventBus.post( + EventStatus( + userEntityObject.id!!, + EventStatus.EventType.PUSH_REGISTRATION, + false)) + + }) + } + + override fun onError(e: Throwable) { + eventBus.post( + EventStatus( + userEntityObject.id!!, + EventStatus.EventType.PUSH_REGISTRATION, + false + ) + ) + } + + override fun onComplete() {} + }) + } + } + } + } + } + } + + companion object { + const val TAG = "PushRegistrationWorker" + } + } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt b/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt index 48012fa42..ccdfcb76f 100644 --- a/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt +++ b/app/src/main/java/com/nextcloud/talk/models/ExternalSignalingServer.kt @@ -36,8 +36,6 @@ data class ExternalSignalingServer( var externalSignalingServer: String? = null, @JsonField(name = ["externalSignalingTicket"]) var externalSignalingTicket: String? = null - - ) : Parcelable { override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.java b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.java deleted file mode 100644 index 7494dee1d..000000000 --- a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * Copyright (C) 2017-2018 Mario Danic - * - * 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 . - */ - -package com.nextcloud.talk.models.json.capabilities; - -import com.bluelinelabs.logansquare.annotation.JsonField; -import com.bluelinelabs.logansquare.annotation.JsonObject; - -import org.parceler.Parcel; - -import java.util.HashMap; -import java.util.List; -import java.util.Objects; - -import lombok.Data; - -@Parcel -@Data -@JsonObject -public class Capabilities { - @JsonField(name = "spreed") - public SpreedCapability spreedCapability; - - @JsonField(name = "notifications") - public NotificationsCapability notificationsCapability; - - @JsonField(name = "theming") - public ThemingCapability themingCapability; - - /*@JsonField(name = "external") - public HashMap> externalCapability;*/ - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Capabilities)) return false; - Capabilities that = (Capabilities) o; - return Objects.equals(spreedCapability, that.spreedCapability) && - Objects.equals(notificationsCapability, that.notificationsCapability) && - Objects.equals(themingCapability, that.themingCapability); - } - - @Override - public int hashCode() { - return Objects.hash(spreedCapability, notificationsCapability, themingCapability); - } -} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.kt b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.kt new file mode 100644 index 000000000..269ba95fe --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.kt @@ -0,0 +1,53 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2018 Mario Danic + * + * 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 . + */ +package com.nextcloud.talk.models.json.capabilities + +import android.os.Parcelable +import com.bluelinelabs.logansquare.annotation.JsonField +import com.bluelinelabs.logansquare.annotation.JsonObject +import kotlinx.android.parcel.Parcelize +import lombok.Data +import org.parceler.Parcel +import java.util.* + +@Data +@Parcel +@JsonObject +@Parcelize +data class Capabilities( + @JsonField(name = ["spreed"]) + var spreedCapability: SpreedCapability? = null, + @JsonField(name = ["notifications"]) + var notificationsCapability: NotificationsCapability? = null, + @JsonField(name = ["theming"]) + var themingCapability: ThemingCapability? = null +): Parcelable { + override fun equals(o: Any?): Boolean { + if (this === o) return true + if (o !is Capabilities) return false + return (spreedCapability == o.spreedCapability && + notificationsCapability == o.notificationsCapability && + themingCapability == o.themingCapability) + } + + override fun hashCode(): Int { + return Objects.hash(spreedCapability, notificationsCapability, themingCapability) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/NotificationsCapability.java b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/NotificationsCapability.kt similarity index 52% rename from app/src/main/java/com/nextcloud/talk/models/json/capabilities/NotificationsCapability.java rename to app/src/main/java/com/nextcloud/talk/models/json/capabilities/NotificationsCapability.kt index a42778589..ddc1d9271 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/NotificationsCapability.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/NotificationsCapability.kt @@ -17,36 +17,32 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +package com.nextcloud.talk.models.json.capabilities -package com.nextcloud.talk.models.json.capabilities; - -import com.bluelinelabs.logansquare.annotation.JsonField; -import com.bluelinelabs.logansquare.annotation.JsonObject; - -import org.parceler.Parcel; - -import java.util.List; -import java.util.Objects; - -import lombok.Data; +import android.os.Parcelable +import com.bluelinelabs.logansquare.annotation.JsonField +import com.bluelinelabs.logansquare.annotation.JsonObject +import kotlinx.android.parcel.Parcelize +import lombok.Data +import org.parceler.Parcel +import java.util.* @Parcel @Data @JsonObject -public class NotificationsCapability { - @JsonField(name = "ocs-endpoints") - public List features; +@Parcelize +data class NotificationsCapability( + @JsonField(name = ["ocs-endpoints"]) + var features: List? = null +): Parcelable { - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof NotificationsCapability)) return false; - NotificationsCapability that = (NotificationsCapability) o; - return Objects.equals(features, that.features); + override fun equals(o: Any?): Boolean { + if (this === o) return true + if (o !is NotificationsCapability) return false + return features == o.features } - @Override - public int hashCode() { - return Objects.hash(features); + override fun hashCode(): Int { + return Objects.hash(features) } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/SpreedCapability.java b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/SpreedCapability.java deleted file mode 100644 index 7d7a854ea..000000000 --- a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/SpreedCapability.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * Copyright (C) 2017-2018 Mario Danic - * - * 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 . - */ - -package com.nextcloud.talk.models.json.capabilities; - -import com.bluelinelabs.logansquare.annotation.JsonField; -import com.bluelinelabs.logansquare.annotation.JsonObject; - -import org.parceler.Parcel; - -import java.util.HashMap; -import java.util.List; -import java.util.Objects; - -import lombok.Data; - -@Parcel -@Data -@JsonObject -public class SpreedCapability { - @JsonField(name = "features") - public List features; - - @JsonField(name = "config") - public HashMap> config; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof SpreedCapability)) return false; - SpreedCapability that = (SpreedCapability) o; - return Objects.equals(features, that.features) && - Objects.equals(config, that.config); - } - - @Override - public int hashCode() { - return Objects.hash(features, config); - } -} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/SpreedCapability.kt b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/SpreedCapability.kt new file mode 100644 index 000000000..e05474015 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/SpreedCapability.kt @@ -0,0 +1,52 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2018 Mario Danic + * + * 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 . + */ +package com.nextcloud.talk.models.json.capabilities + +import android.os.Parcelable +import com.bluelinelabs.logansquare.annotation.JsonField +import com.bluelinelabs.logansquare.annotation.JsonObject +import kotlinx.android.parcel.Parcelize +import lombok.Data +import org.parceler.Parcel +import java.util.* + +@Parcel +@Data +@JsonObject +@Parcelize +data class SpreedCapability( + @JsonField(name = ["features"]) + var features: List? = null, + @JsonField(name = ["config"]) + var config: HashMap>? = null +): Parcelable { + + override fun equals(o: Any?): Boolean { + if (this === o) return true + if (o !is SpreedCapability) return false + val that = o + return features == that.features && + config == that.config + } + + override fun hashCode(): Int { + return Objects.hash(features, config) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.java b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.java deleted file mode 100644 index ac197ab0a..000000000 --- a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * Copyright (C) 2017-2019 Mario Danic - * - * 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 . - */ - -package com.nextcloud.talk.models.json.capabilities; - -import com.bluelinelabs.logansquare.annotation.JsonField; -import com.bluelinelabs.logansquare.annotation.JsonObject; - -import org.parceler.Parcel; - -import java.util.Objects; - -import lombok.Data; - -@Parcel -@Data -@JsonObject -class ThemingCapability { - @JsonField(name = "name") - String name; - - @JsonField(name = "url") - String url; - - @JsonField(name = "slogan") - String slogan; - - @JsonField(name = "color") - String color; - - @JsonField(name = "color-text") - String colorText; - - @JsonField(name = "color-element") - String colorElement; - - @JsonField(name = "logo") - String logo; - - @JsonField(name = "background") - String background; - - @JsonField(name = "background-plain") - boolean backgroundPlain; - - @JsonField(name = "background-default") - boolean backgroundDefault; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ThemingCapability)) return false; - ThemingCapability that = (ThemingCapability) o; - return backgroundPlain == that.backgroundPlain && - backgroundDefault == that.backgroundDefault && - Objects.equals(name, that.name) && - Objects.equals(url, that.url) && - Objects.equals(slogan, that.slogan) && - Objects.equals(color, that.color) && - Objects.equals(colorText, that.colorText) && - Objects.equals(colorElement, that.colorElement) && - Objects.equals(logo, that.logo) && - Objects.equals(background, that.background); - } - - @Override - public int hashCode() { - return Objects.hash(name, url, slogan, color, colorText, colorElement, logo, background, backgroundPlain, backgroundDefault); - } -} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.kt b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.kt new file mode 100644 index 000000000..5bc75a79c --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.kt @@ -0,0 +1,75 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2019 Mario Danic + * + * 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 . + */ +package com.nextcloud.talk.models.json.capabilities + +import android.os.Parcelable +import com.bluelinelabs.logansquare.annotation.JsonField +import com.bluelinelabs.logansquare.annotation.JsonObject +import kotlinx.android.parcel.Parcelize +import lombok.Data +import org.parceler.Parcel +import java.util.* + +@Parcel +@Data +@JsonObject +@Parcelize +data class ThemingCapability( + @JsonField(name = ["name"]) + var name: String? = null, + @JsonField(name = ["url"]) + var url: String? = null, + @JsonField(name = ["slogan"]) + var slogan: String? = null, + @JsonField(name = ["color"]) + var color: String? = null, + @JsonField(name = ["color-text"]) + var colorText: String? = null, + @JsonField(name = ["color-element"]) + var colorElement: String? = null, + @JsonField(name = ["logo"]) + var logo: String? = null, + @JsonField(name = ["background"]) + var background: String? = null, + @JsonField(name = ["background-plain"]) + var backgroundPlain: Boolean = false, + @JsonField(name = ["background-default"]) + var backgroundDefault: Boolean = false +): Parcelable { + + override fun equals(o: Any?): Boolean { + if (this === o) return true + if (o !is ThemingCapability) return false + val that = o + return backgroundPlain == that.backgroundPlain && backgroundDefault == that.backgroundDefault && + name == that.name && + url == that.url && + slogan == that.slogan && + color == that.color && + colorText == that.colorText && + colorElement == that.colorElement && + logo == that.logo && + background == that.background + } + + override fun hashCode(): Int { + return Objects.hash(name, url, slogan, color, colorText, colorElement, logo, background, backgroundPlain, backgroundDefault) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/models/json/push/PushConfigurationState.kt b/app/src/main/java/com/nextcloud/talk/models/json/push/PushConfigurationState.kt index 9aaec666e..637e7d2f2 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/push/PushConfigurationState.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/push/PushConfigurationState.kt @@ -31,7 +31,7 @@ import org.parceler.Parcel @Data @JsonObject @Parcelize -class PushConfigurationState( +data class PushConfigurationState( @JsonField(name = ["pushToken"]) var pushToken: String? = null, @JsonField(name = ["deviceIdentifier"]) diff --git a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt index 52156a968..95fe9740d 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/features/conversationsList/ConversationsListView.kt @@ -216,7 +216,6 @@ class ConversationsListView : BaseView(), OnQueryTextListener, }) conversationsLiveData.observe(this@ConversationsListView, Observer { - Log.d("MARIO", "TRIGGER") if (it.isEmpty()) { if (viewState.value != LOADED_EMPTY) { viewState.value = LOADED_EMPTY diff --git a/app/src/main/java/com/nextcloud/talk/newarch/local/models/UserNgEntity.kt b/app/src/main/java/com/nextcloud/talk/newarch/local/models/UserNgEntity.kt index 9b0b60f91..cad19d085 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/local/models/UserNgEntity.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/local/models/UserNgEntity.kt @@ -20,7 +20,9 @@ package com.nextcloud.talk.newarch.local.models +import android.os.Parcel import android.os.Parcelable +import android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey @@ -29,8 +31,10 @@ import com.nextcloud.talk.models.json.capabilities.Capabilities import com.nextcloud.talk.models.json.push.PushConfigurationState import com.nextcloud.talk.newarch.local.models.other.UserStatus import com.nextcloud.talk.utils.ApiUtils +import kotlinx.android.parcel.Parceler import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.RawValue +import org.parceler.Parcels @Parcelize @Entity(tableName = "users") @@ -44,7 +48,7 @@ data class UserNgEntity( @ColumnInfo( name = "push_configuration" ) var pushConfiguration: PushConfigurationState? = null, - @ColumnInfo(name = "capabilities") var capabilities: @RawValue Capabilities? = null, + @ColumnInfo(name = "capabilities") var capabilities: Capabilities? = null, @ColumnInfo(name = "client_auth_cert") var clientCertificate: String? = null, @ColumnInfo( name = "external_signaling" diff --git a/app/src/main/java/com/nextcloud/talk/newarch/utils/Extensions.kt b/app/src/main/java/com/nextcloud/talk/newarch/utils/Extensions.kt index 474e583c2..3361273ec 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/utils/Extensions.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/utils/Extensions.kt @@ -22,5 +22,11 @@ package com.nextcloud.talk.newarch.utils import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.utils.ApiUtils +import java.security.MessageDigest fun UserEntity.getCredentials() = ApiUtils.getCredentials(username, token) +fun String.hashWithAlgorithm(algorithm: String): String { + val digest = MessageDigest.getInstance(algorithm) + val bytes = digest.digest(this.toByteArray(Charsets.UTF_8)) + return bytes.fold("", { str, it -> str + "%02x".format(it) }) +} diff --git a/app/src/main/java/com/nextcloud/talk/utils/PushUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/PushUtils.kt index 52b02106a..350774ea9 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/PushUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/PushUtils.kt @@ -36,7 +36,6 @@ import com.nextcloud.talk.models.json.push.PushConfigurationState import com.nextcloud.talk.models.json.push.PushRegistrationOverall import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository import com.nextcloud.talk.newarch.local.models.UserNgEntity -import com.nextcloud.talk.utils.database.user.UserUtils import com.nextcloud.talk.utils.preferences.AppPreferences import io.reactivex.Observer import io.reactivex.disposables.Disposable @@ -53,14 +52,12 @@ import java.util.* import kotlin.experimental.and class PushUtils(val usersRepository: UsersRepository) : KoinComponent { - val userUtils: UserUtils by inject() val appPreferences: AppPreferences by inject() val eventBus: EventBus by inject() val ncApi: NcApi by inject() private val keysFile: File private val publicKeyFile: File private val privateKeyFile: File - private val proxyServer: String fun verifySignature( signatureBytes: ByteArray?, subjectBytes: ByteArray? @@ -74,7 +71,7 @@ class PushUtils(val usersRepository: UsersRepository) : KoinComponent { val userEntities: List = usersRepository.getUsers() try { signature = Signature.getInstance("SHA512withRSA") - if (userEntities.size > 0) { + if (userEntities.isNotEmpty()) { for (userEntity in userEntities) { pushConfigurationState = userEntity.pushConfiguration if (pushConfigurationState?.userPublicKey != null) { @@ -127,29 +124,6 @@ class PushUtils(val usersRepository: UsersRepository) : KoinComponent { return -1 } - private fun generateSHA512Hash(pushToken: String): String { - var messageDigest: MessageDigest? = null - try { - messageDigest = MessageDigest.getInstance("SHA-512") - messageDigest.update(pushToken.toByteArray()) - return bytesToHex(messageDigest.digest()) - } catch (e: NoSuchAlgorithmException) { - Log.d(TAG, "SHA-512 algorithm not supported") - } - return "" - } - - private fun bytesToHex(bytes: ByteArray): String { - val result = StringBuilder() - for (individualByte in bytes) { - result.append( - ((individualByte and 0xff.toByte()) + 0x100).toString(16) - .substring(1) - ) - } - return result.toString() - } - fun generateRsa2048KeyPair(): Int { if (!publicKeyFile.exists() && !privateKeyFile.exists()) { if (!keysFile.exists()) { @@ -186,139 +160,6 @@ class PushUtils(val usersRepository: UsersRepository) : KoinComponent { return -2 } - fun pushRegistrationToServer() { - val token: String = appPreferences.pushToken - if (!TextUtils.isEmpty(token)) { - var credentials: String - val pushTokenHash = generateSHA512Hash(token).toLowerCase() - val devicePublicKey = - readKeyFromFile(true) as PublicKey? - if (devicePublicKey != null) { - val publicKeyBytes: ByteArray? = - Base64.encode(devicePublicKey.encoded, Base64.NO_WRAP) - var publicKey = String(publicKeyBytes!!) - publicKey = publicKey.replace("(.{64})".toRegex(), "$1\n") - publicKey = "-----BEGIN PUBLIC KEY-----\n$publicKey\n-----END PUBLIC KEY-----\n" - if (userUtils.anyUserExists()) { - var accountPushData: PushConfigurationState? = null - for (userEntityObject in usersRepository.getUsers()) { - val userEntity = userEntityObject - accountPushData = userEntity.pushConfiguration - if (accountPushData == null || accountPushData.pushToken != token) { - val queryMap: MutableMap = - HashMap() - queryMap["format"] = "json" - queryMap["pushTokenHash"] = pushTokenHash - queryMap["devicePublicKey"] = publicKey - queryMap["proxyServer"] = proxyServer - credentials = ApiUtils.getCredentials( - userEntity.username, userEntity.token - ) - val finalCredentials = credentials - ncApi.registerDeviceForNotificationsWithNextcloud( - credentials, - ApiUtils.getUrlNextcloudPush(userEntity.baseUrl), - queryMap - ) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) {} - override fun onNext(pushRegistrationOverall: PushRegistrationOverall) { - val proxyMap: MutableMap = - HashMap() - proxyMap["pushToken"] = token - proxyMap["deviceIdentifier"] = - pushRegistrationOverall.ocs.data.deviceIdentifier - proxyMap["deviceIdentifierSignature"] = pushRegistrationOverall.ocs - .data.signature - proxyMap["userPublicKey"] = pushRegistrationOverall.ocs - .data.publicKey - ncApi.registerDeviceForNotificationsWithProxy( - ApiUtils.getUrlPushProxy(), proxyMap - ) - .subscribeOn(Schedulers.io()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) {} - override fun onNext(aVoid: Void) { - val pushConfigurationState = - PushConfigurationState() - pushConfigurationState.pushToken = token - pushConfigurationState.deviceIdentifier = pushRegistrationOverall - .ocs.data.deviceIdentifier - pushConfigurationState.deviceIdentifierSignature = - pushRegistrationOverall.ocs.data.signature - pushConfigurationState.userPublicKey = pushRegistrationOverall.ocs - .data.publicKey - pushConfigurationState.usesRegularPass = false - try { - userUtils.createOrUpdateUser( - null, - null, null, - userEntity.displayName, - LoganSquare.serialize( - pushConfigurationState - ), null, - null, userEntity.id, null, null, null - ) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) {} - override fun onNext(userEntity: UserEntity) { - eventBus.post( - EventStatus( - userEntity.id, - PUSH_REGISTRATION, - true - ) - ) - } - - override fun onError(e: Throwable) { - eventBus.post( - EventStatus( - userEntity.id!!, - PUSH_REGISTRATION, false - ) - ) - } - - override fun onComplete() {} - }) - } catch (e: IOException) { - Log.e(TAG, "IOException while updating user") - } - } - - override fun onError(e: Throwable) { - eventBus.post( - EventStatus( - userEntity.id!!, - PUSH_REGISTRATION, - false - ) - ) - } - - override fun onComplete() {} - }) - } - - override fun onError(e: Throwable) { - eventBus.post( - EventStatus( - userEntity.id!!, - PUSH_REGISTRATION, - false - ) - ) - } - - override fun onComplete() {} - }) - } - } - } - } - } - } private fun readKeyFromString( readPublicKey: Boolean, @@ -417,8 +258,5 @@ class PushUtils(val usersRepository: UsersRepository) : KoinComponent { Context.MODE_PRIVATE ), "push_key.priv" ) - proxyServer = - sharedApplication!!.resources - .getString(string.nc_push_server_url) } } \ No newline at end of file