mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-20 03:59:35 +01:00
Significant work on push notifications
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
7f12da21f7
commit
0a6f54cedf
@ -55,6 +55,7 @@ android {
|
|||||||
|
|
||||||
ext {
|
ext {
|
||||||
supportLibraryVersion = '26.1.0'
|
supportLibraryVersion = '26.1.0'
|
||||||
|
googleLibraryVersion = '11.4.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -69,7 +70,7 @@ dependencies {
|
|||||||
implementation 'com.bluelinelabs:conductor:2.1.4'
|
implementation 'com.bluelinelabs:conductor:2.1.4'
|
||||||
implementation 'com.bluelinelabs:conductor-support:2.1.4'
|
implementation 'com.bluelinelabs:conductor-support:2.1.4'
|
||||||
|
|
||||||
implementation 'com.squareup.okhttp3:okhttp:3.8.1'
|
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
|
||||||
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.6.0'
|
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.6.0'
|
||||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0'
|
implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0'
|
||||||
|
|
||||||
@ -121,6 +122,13 @@ dependencies {
|
|||||||
implementation 'org.webrtc:google-webrtc:1.0.+'
|
implementation 'org.webrtc:google-webrtc:1.0.+'
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}"
|
||||||
|
|
||||||
|
implementation 'com.evernote:android-job:1.2.0'
|
||||||
|
|
||||||
|
implementation "com.google.firebase:firebase-messaging:${googleLibraryVersion}"
|
||||||
|
implementation "com.google.android.gms:play-services-base:${googleLibraryVersion}"
|
||||||
|
implementation "com.google.android.gms:play-services-gcm:${googleLibraryVersion}"
|
||||||
|
implementation "com.google.firebase:firebase-core:${googleLibraryVersion}"
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation ('com.android.support.test.espresso:espresso-core:3.0.1', {
|
androidTestImplementation ('com.android.support.test.espresso:espresso-core:3.0.1', {
|
||||||
exclude group: 'com.android.support', module: 'support-annotations'
|
exclude group: 'com.android.support', module: 'support-annotations'
|
||||||
|
@ -38,5 +38,19 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".services.firebase.MagicFirebaseMessagingService">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".services.firebase.MagicFirebaseInstanceIDService">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -24,6 +24,7 @@ import com.nextcloud.talk.api.models.json.call.CallOverall;
|
|||||||
import com.nextcloud.talk.api.models.json.generic.Status;
|
import com.nextcloud.talk.api.models.json.generic.Status;
|
||||||
import com.nextcloud.talk.api.models.json.participants.AddParticipantOverall;
|
import com.nextcloud.talk.api.models.json.participants.AddParticipantOverall;
|
||||||
import com.nextcloud.talk.api.models.json.participants.ParticipantsOverall;
|
import com.nextcloud.talk.api.models.json.participants.ParticipantsOverall;
|
||||||
|
import com.nextcloud.talk.api.models.json.push.PushRegistrationOverall;
|
||||||
import com.nextcloud.talk.api.models.json.rooms.RoomOverall;
|
import com.nextcloud.talk.api.models.json.rooms.RoomOverall;
|
||||||
import com.nextcloud.talk.api.models.json.rooms.RoomsOverall;
|
import com.nextcloud.talk.api.models.json.rooms.RoomsOverall;
|
||||||
import com.nextcloud.talk.api.models.json.sharees.ShareesOverall;
|
import com.nextcloud.talk.api.models.json.sharees.ShareesOverall;
|
||||||
@ -33,6 +34,8 @@ import java.util.Map;
|
|||||||
|
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import retrofit2.http.DELETE;
|
import retrofit2.http.DELETE;
|
||||||
|
import retrofit2.http.FieldMap;
|
||||||
|
import retrofit2.http.FormUrlEncoded;
|
||||||
import retrofit2.http.GET;
|
import retrofit2.http.GET;
|
||||||
import retrofit2.http.Header;
|
import retrofit2.http.Header;
|
||||||
import retrofit2.http.POST;
|
import retrofit2.http.POST;
|
||||||
@ -176,4 +179,29 @@ public interface NcApi {
|
|||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
Observable<Status> getServerStatus(@Url String url);
|
Observable<Status> getServerStatus(@Url String url);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
QueryMap items are as follows:
|
||||||
|
- "format" : "json"
|
||||||
|
- "pushTokenHash" : ""
|
||||||
|
- "devicePublicKey" : ""
|
||||||
|
- "proxyServer" : ""
|
||||||
|
|
||||||
|
Server URL is: baseUrl + ocsApiVersion + "/apps/notifications/api/v2/push
|
||||||
|
*/
|
||||||
|
|
||||||
|
@POST
|
||||||
|
Observable<PushRegistrationOverall> registerDeviceForNotificationsWithNextcloud(@Header("Authorization")
|
||||||
|
String authorization,
|
||||||
|
@Url String url,
|
||||||
|
@QueryMap Map<String,
|
||||||
|
String> options);
|
||||||
|
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST
|
||||||
|
Observable<Void> registerDeviceForNotificationsWithProxy(@Header("Authorization") String authorization,
|
||||||
|
@Url String url,
|
||||||
|
@FieldMap Map<String, String> fields);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,9 @@ package com.nextcloud.talk.api.helpers.api;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import com.nextcloud.talk.BuildConfig;
|
import com.nextcloud.talk.BuildConfig;
|
||||||
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.api.models.RetrofitBucket;
|
import com.nextcloud.talk.api.models.RetrofitBucket;
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -138,4 +140,13 @@ public class ApiHelper {
|
|||||||
public static String getCredentials(String username, String token) {
|
public static String getCredentials(String username, String token) {
|
||||||
return Credentials.basic(username, token);
|
return Credentials.basic(username, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getUrlNextcloudPush(String baseUrl) {
|
||||||
|
return baseUrl + ocsApiVersion + "/apps/notifications/api/v2/push";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getUrlPushProxy(String baseUrl) {
|
||||||
|
return NextcloudTalkApplication.getSharedApplication().
|
||||||
|
getApplicationContext().getResources().getString(R.string.nc_push_server_url) + "/devices";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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 lombok.Data;
|
||||||
|
|
||||||
|
@Parcel
|
||||||
|
@Data
|
||||||
|
public class PushConfigurationState {
|
||||||
|
String pushToken;
|
||||||
|
String deviceIdentifier;
|
||||||
|
String deviceIdentifierSignature;
|
||||||
|
String userPublicKey;
|
||||||
|
boolean shouldBeDeleted;
|
||||||
|
boolean usesRegularPass;
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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 PushRegistration {
|
||||||
|
@JsonField(name = "publicKey")
|
||||||
|
String publicKey;
|
||||||
|
|
||||||
|
@JsonField(name = "deviceIdentifier")
|
||||||
|
String deviceIdentifier;
|
||||||
|
|
||||||
|
@JsonField(name = "signature")
|
||||||
|
String signature;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.nextcloud.talk.api.models.json.generic.GenericOCS;
|
||||||
|
|
||||||
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Parcel
|
||||||
|
@JsonObject
|
||||||
|
public class PushRegistrationOCS extends GenericOCS {
|
||||||
|
@JsonField(name = "data")
|
||||||
|
PushRegistration data;
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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 PushRegistrationOverall {
|
||||||
|
@JsonField(name = "ocs")
|
||||||
|
PushRegistrationOCS ocs;
|
||||||
|
}
|
@ -24,11 +24,15 @@ import android.content.Context;
|
|||||||
import android.support.multidex.MultiDex;
|
import android.support.multidex.MultiDex;
|
||||||
import android.support.multidex.MultiDexApplication;
|
import android.support.multidex.MultiDexApplication;
|
||||||
|
|
||||||
|
import com.evernote.android.job.JobManager;
|
||||||
|
import com.evernote.android.job.JobRequest;
|
||||||
import com.nextcloud.talk.BuildConfig;
|
import com.nextcloud.talk.BuildConfig;
|
||||||
import com.nextcloud.talk.dagger.modules.BusModule;
|
import com.nextcloud.talk.dagger.modules.BusModule;
|
||||||
import com.nextcloud.talk.dagger.modules.ContextModule;
|
import com.nextcloud.talk.dagger.modules.ContextModule;
|
||||||
import com.nextcloud.talk.dagger.modules.DatabaseModule;
|
import com.nextcloud.talk.dagger.modules.DatabaseModule;
|
||||||
import com.nextcloud.talk.dagger.modules.RestModule;
|
import com.nextcloud.talk.dagger.modules.RestModule;
|
||||||
|
import com.nextcloud.talk.jobs.PushRegistrationJob;
|
||||||
|
import com.nextcloud.talk.jobs.creator.MagicJobCreator;
|
||||||
import com.nextcloud.talk.utils.database.cache.CacheModule;
|
import com.nextcloud.talk.utils.database.cache.CacheModule;
|
||||||
import com.nextcloud.talk.utils.database.user.UserModule;
|
import com.nextcloud.talk.utils.database.user.UserModule;
|
||||||
import com.squareup.leakcanary.LeakCanary;
|
import com.squareup.leakcanary.LeakCanary;
|
||||||
@ -76,6 +80,8 @@ public class NextcloudTalkApplication extends MultiDexApplication {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
JobManager.create(this).addJobCreator(new MagicJobCreator());
|
||||||
|
|
||||||
sharedApplication = this;
|
sharedApplication = this;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -88,6 +94,9 @@ public class NextcloudTalkApplication extends MultiDexApplication {
|
|||||||
|
|
||||||
componentApplication.inject(this);
|
componentApplication.inject(this);
|
||||||
refWatcher = LeakCanary.install(this);
|
refWatcher = LeakCanary.install(this);
|
||||||
|
|
||||||
|
new JobRequest.Builder(PushRegistrationJob.TAG).setUpdateCurrent(true).startNow();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ public class AccountVerificationController extends BaseController {
|
|||||||
|
|
||||||
if (!TextUtils.isEmpty(displayName)) {
|
if (!TextUtils.isEmpty(displayName)) {
|
||||||
dbQueryDisposable = userUtils.createOrUpdateUser(username, token,
|
dbQueryDisposable = userUtils.createOrUpdateUser(username, token,
|
||||||
baseUrl, displayName)
|
baseUrl, displayName, null)
|
||||||
.subscribeOn(Schedulers.newThread())
|
.subscribeOn(Schedulers.newThread())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(userEntity -> {
|
.subscribe(userEntity -> {
|
||||||
|
@ -41,6 +41,7 @@ import com.nextcloud.talk.api.helpers.api.ApiHelper;
|
|||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
import com.nextcloud.talk.controllers.base.BaseController;
|
import com.nextcloud.talk.controllers.base.BaseController;
|
||||||
import com.nextcloud.talk.models.LoginData;
|
import com.nextcloud.talk.models.LoginData;
|
||||||
|
import com.nextcloud.talk.persistence.entities.UserEntity;
|
||||||
import com.nextcloud.talk.utils.bundle.BundleBuilder;
|
import com.nextcloud.talk.utils.bundle.BundleBuilder;
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
||||||
import com.nextcloud.talk.utils.database.user.UserUtils;
|
import com.nextcloud.talk.utils.database.user.UserUtils;
|
||||||
@ -134,6 +135,7 @@ public class WebViewLoginController extends BaseController {
|
|||||||
|
|
||||||
webView.setWebViewClient(new WebViewClient() {
|
webView.setWebViewClient(new WebViewClient() {
|
||||||
private boolean basePageLoaded;
|
private boolean basePageLoaded;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||||
if (url.startsWith(assembledPrefix)) {
|
if (url.startsWith(assembledPrefix)) {
|
||||||
@ -160,7 +162,7 @@ public class WebViewLoginController extends BaseController {
|
|||||||
SslCertificate sslCertificate = error.getCertificate();
|
SslCertificate sslCertificate = error.getCertificate();
|
||||||
Field f = sslCertificate.getClass().getDeclaredField("mX509Certificate");
|
Field f = sslCertificate.getClass().getDeclaredField("mX509Certificate");
|
||||||
f.setAccessible(true);
|
f.setAccessible(true);
|
||||||
X509Certificate cert = (X509Certificate)f.get(sslCertificate);
|
X509Certificate cert = (X509Certificate) f.get(sslCertificate);
|
||||||
|
|
||||||
if (cert == null) {
|
if (cert == null) {
|
||||||
handler.cancel();
|
handler.cancel();
|
||||||
@ -201,11 +203,20 @@ public class WebViewLoginController extends BaseController {
|
|||||||
if (loginData != null) {
|
if (loginData != null) {
|
||||||
dispose();
|
dispose();
|
||||||
|
|
||||||
|
UserEntity currentUser = userUtils.getCurrentUser();
|
||||||
|
|
||||||
|
String displayName = null;
|
||||||
|
String pushConfiguration = null;
|
||||||
|
|
||||||
|
if (currentUser != null) {
|
||||||
|
displayName = currentUser.getDisplayName();
|
||||||
|
pushConfiguration = currentUser.getPushConfigurationState();
|
||||||
|
}
|
||||||
// We use the URL user entered because one provided by the server is NOT reliable
|
// We use the URL user entered because one provided by the server is NOT reliable
|
||||||
userQueryDisposable = userUtils.createOrUpdateUser(loginData.getUsername(), loginData.getToken(),
|
userQueryDisposable = userUtils.createOrUpdateUser(loginData.getUsername(), loginData.getToken(),
|
||||||
baseUrl, null).subscribe(userEntity -> {
|
baseUrl, displayName, pushConfiguration).
|
||||||
|
subscribe(userEntity -> {
|
||||||
if (!isPasswordUpdate) {
|
if (!isPasswordUpdate) {
|
||||||
|
|
||||||
BundleBuilder bundleBuilder = new BundleBuilder(new Bundle());
|
BundleBuilder bundleBuilder = new BundleBuilder(new Bundle());
|
||||||
bundleBuilder.putString(BundleKeys.KEY_USERNAME, userEntity.getUsername());
|
bundleBuilder.putString(BundleKeys.KEY_USERNAME, userEntity.getUsername());
|
||||||
bundleBuilder.putString(BundleKeys.KEY_TOKEN, userEntity.getToken());
|
bundleBuilder.putString(BundleKeys.KEY_TOKEN, userEntity.getToken());
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.jobs;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.evernote.android.job.Job;
|
||||||
|
import com.nextcloud.talk.utils.PushUtils;
|
||||||
|
|
||||||
|
public class PushRegistrationJob extends Job {
|
||||||
|
public static final String TAG = "PushRegistrationJob";
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Result onRunJob(Params params) {
|
||||||
|
PushUtils pushUtils = new PushUtils();
|
||||||
|
|
||||||
|
pushUtils.generateRsa2048KeyPair();
|
||||||
|
pushUtils.pushRegistrationToServer();
|
||||||
|
|
||||||
|
return Result.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.jobs.creator;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.evernote.android.job.Job;
|
||||||
|
import com.evernote.android.job.JobCreator;
|
||||||
|
import com.nextcloud.talk.jobs.PushRegistrationJob;
|
||||||
|
|
||||||
|
public class MagicJobCreator implements JobCreator {
|
||||||
|
private static final String TAG = "MagicJobCreator";
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Job create(@NonNull String tag) {
|
||||||
|
switch (tag) {
|
||||||
|
case PushRegistrationJob.TAG:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -42,4 +42,6 @@ public interface User extends Parcelable, Persistable, Serializable {
|
|||||||
String getToken();
|
String getToken();
|
||||||
|
|
||||||
String getDisplayName();
|
String getDisplayName();
|
||||||
|
|
||||||
|
String getPushConfigurationState();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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.services.firebase;
|
||||||
|
|
||||||
|
import com.evernote.android.job.JobRequest;
|
||||||
|
import com.google.firebase.iid.FirebaseInstanceId;
|
||||||
|
import com.google.firebase.iid.FirebaseInstanceIdService;
|
||||||
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
|
import com.nextcloud.talk.jobs.PushRegistrationJob;
|
||||||
|
import com.nextcloud.talk.utils.preferences.AppPreferences;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import autodagger.AutoInjector;
|
||||||
|
|
||||||
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
|
public class MagicFirebaseInstanceIDService extends FirebaseInstanceIdService {
|
||||||
|
private static final String TAG = "MagicFirebaseInstanceIDService";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AppPreferences appPreferences;
|
||||||
|
|
||||||
|
public MagicFirebaseInstanceIDService() {
|
||||||
|
super();
|
||||||
|
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTokenRefresh() {
|
||||||
|
appPreferences.setPushtoken(FirebaseInstanceId.getInstance().getToken());
|
||||||
|
|
||||||
|
new JobRequest.Builder(PushRegistrationJob.TAG).setUpdateCurrent(true).startNow();
|
||||||
|
}
|
||||||
|
}
|
@ -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.services.firebase;
|
||||||
|
|
||||||
|
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||||
|
import com.google.firebase.messaging.RemoteMessage;
|
||||||
|
|
||||||
|
public class MagicFirebaseMessagingService extends FirebaseMessagingService {
|
||||||
|
private static final String TAG = "MagicFirebaseMessagingService";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessageReceived(RemoteMessage remoteMessage) {
|
||||||
|
super.onMessageReceived(remoteMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
317
app/src/main/java/com/nextcloud/talk/utils/PushUtils.java
Normal file
317
app/src/main/java/com/nextcloud/talk/utils/PushUtils.java
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
* 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.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Base64;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
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.application.NextcloudTalkApplication;
|
||||||
|
import com.nextcloud.talk.persistence.entities.UserEntity;
|
||||||
|
import com.nextcloud.talk.utils.database.user.UserUtils;
|
||||||
|
import com.nextcloud.talk.utils.preferences.AppPreferences;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import autodagger.AutoInjector;
|
||||||
|
import io.reactivex.functions.Consumer;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
|
public class PushUtils {
|
||||||
|
private static final String TAG = "PushUtils";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
UserUtils userUtils;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AppPreferences appPreferences;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
NcApi ncApi;
|
||||||
|
|
||||||
|
private File keysFile;
|
||||||
|
private File publicKeyFile;
|
||||||
|
private File privateKeyFile;
|
||||||
|
|
||||||
|
private String proxyServer;
|
||||||
|
|
||||||
|
public PushUtils() {
|
||||||
|
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
|
||||||
|
|
||||||
|
keysFile = NextcloudTalkApplication.getSharedApplication().getDir("PushKeyStore", Context.MODE_PRIVATE);
|
||||||
|
publicKeyFile = new File(NextcloudTalkApplication.getSharedApplication().getDir("PushKeystore",
|
||||||
|
Context.MODE_PRIVATE), "push_key.pub");
|
||||||
|
privateKeyFile = new File(NextcloudTalkApplication.getSharedApplication().getDir("PushKeystore",
|
||||||
|
Context.MODE_PRIVATE), "push_key.priv");
|
||||||
|
proxyServer = NextcloudTalkApplication.getSharedApplication().getResources().
|
||||||
|
getString(R.string.nc_push_server_url);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int saveKeyToFile(Key key, String path) {
|
||||||
|
byte[] encoded = key.getEncoded();
|
||||||
|
FileOutputStream keyFileOutputStream = null;
|
||||||
|
try {
|
||||||
|
if (!new File(path).exists()) {
|
||||||
|
new File(path).createNewFile();
|
||||||
|
}
|
||||||
|
keyFileOutputStream = new FileOutputStream(path);
|
||||||
|
keyFileOutputStream.write(encoded);
|
||||||
|
keyFileOutputStream.close();
|
||||||
|
return 0;
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.d(TAG, "Failed to save key to file");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "Failed to save key to file via IOException");
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateSHA512Hash(String pushToken) {
|
||||||
|
MessageDigest messageDigest = null;
|
||||||
|
try {
|
||||||
|
messageDigest = MessageDigest.getInstance("SHA-512");
|
||||||
|
messageDigest.update(pushToken.getBytes());
|
||||||
|
return bytesToHex(messageDigest.digest());
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
Log.d(TAG, "SHA-512 algorithm not supported");
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String bytesToHex(byte[] bytes) {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
for (byte individualByte : bytes) {
|
||||||
|
result.append(Integer.toString((individualByte & 0xff) + 0x100, 16)
|
||||||
|
.substring(1));
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteRegistrationForAccount(UserEntity userEntity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public int generateRsa2048KeyPair() {
|
||||||
|
if (!publicKeyFile.exists() && !privateKeyFile.exists()) {
|
||||||
|
if (!keysFile.exists()) {
|
||||||
|
keysFile.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyPairGenerator keyGen = null;
|
||||||
|
try {
|
||||||
|
keyGen = KeyPairGenerator.getInstance("RSA");
|
||||||
|
keyGen.initialize(2048);
|
||||||
|
|
||||||
|
KeyPair pair = keyGen.generateKeyPair();
|
||||||
|
int statusPrivate = saveKeyToFile(pair.getPrivate(), privateKeyFile.getAbsolutePath());
|
||||||
|
int statusPublic = saveKeyToFile(pair.getPublic(), publicKeyFile.getAbsolutePath());
|
||||||
|
|
||||||
|
if (statusPrivate == 0 && statusPublic == 0) {
|
||||||
|
// all went well
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
Log.d(TAG, "RSA algorithm not supported");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We already have the key
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we failed to generate the key
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pushRegistrationToServer() {
|
||||||
|
String token = appPreferences.getPushToken();
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(token)) {
|
||||||
|
String pushTokenHash = generateSHA512Hash(token).toLowerCase();
|
||||||
|
PublicKey devicePublicKey = (PublicKey) readKeyFromFile(true);
|
||||||
|
if (devicePublicKey != null) {
|
||||||
|
byte[] publicKeyBytes = Base64.encode(devicePublicKey.getEncoded(), Base64.NO_WRAP);
|
||||||
|
String publicKey = new String(publicKeyBytes);
|
||||||
|
publicKey = publicKey.replaceAll("(.{64})", "$1\n");
|
||||||
|
|
||||||
|
publicKey = "-----BEGIN PUBLIC KEY-----\n" + publicKey + "\n-----END PUBLIC KEY-----\n";
|
||||||
|
|
||||||
|
if (userUtils.anyUserExists()) {
|
||||||
|
String providerValue;
|
||||||
|
PushConfigurationState accountPushData = null;
|
||||||
|
for (UserEntity userEntity : userUtils.getUsers()) {
|
||||||
|
providerValue = userEntity.getPushConfigurationState();
|
||||||
|
if (!TextUtils.isEmpty(providerValue)) {
|
||||||
|
try {
|
||||||
|
accountPushData = LoganSquare.parse(providerValue, PushConfigurationState.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "Failed to parse account push data");
|
||||||
|
accountPushData = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
accountPushData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountPushData != null && !accountPushData.getPushToken().equals(token) &&
|
||||||
|
!accountPushData.isShouldBeDeleted() ||
|
||||||
|
TextUtils.isEmpty(providerValue)) {
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, String> queryMap = new HashMap<>();
|
||||||
|
queryMap.put("format", "json");
|
||||||
|
queryMap.put("pushTokenHash", pushTokenHash);
|
||||||
|
queryMap.put("devicePublicKey", publicKey);
|
||||||
|
queryMap.put("proxyServer", proxyServer);
|
||||||
|
|
||||||
|
ncApi.registerDeviceForNotificationsWithNextcloud(
|
||||||
|
ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken()),
|
||||||
|
ApiHelper.getUrlNextcloudPush(userEntity.getBaseUrl()), queryMap)
|
||||||
|
.subscribeOn(Schedulers.newThread())
|
||||||
|
.subscribe(pushRegistrationOverall -> {
|
||||||
|
Map<String, String> proxyMap = new HashMap<>();
|
||||||
|
proxyMap.put("pushToken", token);
|
||||||
|
proxyMap.put("deviceIdentifier", pushRegistrationOverall.getOcs().getData().
|
||||||
|
getDeviceIdentifier());
|
||||||
|
proxyMap.put("deviceIdentifierSignature", pushRegistrationOverall.getOcs()
|
||||||
|
.getData().getSignature());
|
||||||
|
proxyMap.put("userPublicKey", pushRegistrationOverall.getOcs()
|
||||||
|
.getData().getPublicKey());
|
||||||
|
|
||||||
|
|
||||||
|
ncApi.registerDeviceForNotificationsWithProxy(ApiHelper.getCredentials
|
||||||
|
(userEntity.getUsername(), userEntity.getToken()),
|
||||||
|
ApiHelper.getUrlPushProxy(userEntity.getBaseUrl()), proxyMap)
|
||||||
|
.subscribeOn(Schedulers.newThread())
|
||||||
|
.subscribe(new Consumer<Void>() {
|
||||||
|
@Override
|
||||||
|
public void accept(Void aVoid) throws Exception {
|
||||||
|
|
||||||
|
PushConfigurationState pushConfigurationState =
|
||||||
|
new PushConfigurationState();
|
||||||
|
pushConfigurationState.setPushToken(token);
|
||||||
|
pushConfigurationState.setDeviceIdentifier(
|
||||||
|
pushRegistrationOverall.getOcs()
|
||||||
|
.getData().getDeviceIdentifier());
|
||||||
|
pushConfigurationState.setDeviceIdentifierSignature(
|
||||||
|
pushRegistrationOverall
|
||||||
|
.getOcs().getData().getSignature());
|
||||||
|
pushConfigurationState.setUserPublicKey(
|
||||||
|
pushRegistrationOverall.getOcs()
|
||||||
|
.getData().getPublicKey());
|
||||||
|
pushConfigurationState.setShouldBeDeleted(false);
|
||||||
|
pushConfigurationState.setUsesRegularPass(false);
|
||||||
|
|
||||||
|
userUtils.createOrUpdateUser(userEntity.getUsername(),
|
||||||
|
userEntity.getToken(), userEntity.getBaseUrl(),
|
||||||
|
userEntity.getDisplayName(),
|
||||||
|
LoganSquare.serialize(pushConfigurationState));
|
||||||
|
|
||||||
|
}
|
||||||
|
}, new Consumer<Throwable>() {
|
||||||
|
@Override
|
||||||
|
public void accept(Throwable throwable) throws Exception {
|
||||||
|
// something went wrong
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}, new Consumer<Throwable>() {
|
||||||
|
@Override
|
||||||
|
public void accept(Throwable throwable) throws Exception {
|
||||||
|
// TODO: If 400, we're using regular token
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Key readKeyFromFile(boolean readPublicKey) {
|
||||||
|
String path;
|
||||||
|
|
||||||
|
if (readPublicKey) {
|
||||||
|
path = publicKeyFile.getAbsolutePath();
|
||||||
|
} else {
|
||||||
|
path = privateKeyFile.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileInputStream fileInputStream = null;
|
||||||
|
try {
|
||||||
|
fileInputStream = new FileInputStream(path);
|
||||||
|
byte[] bytes = new byte[fileInputStream.available()];
|
||||||
|
fileInputStream.read(bytes);
|
||||||
|
fileInputStream.close();
|
||||||
|
|
||||||
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||||
|
|
||||||
|
if (readPublicKey) {
|
||||||
|
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
|
||||||
|
return keyFactory.generatePublic(keySpec);
|
||||||
|
} else {
|
||||||
|
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
|
||||||
|
return keyFactory.generatePrivate(keySpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.d(TAG, "Failed to find path while reading the Key");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "IOException while reading the key");
|
||||||
|
} catch (InvalidKeySpecException e) {
|
||||||
|
Log.d(TAG, "InvalidKeySpecException while reading the key");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
Log.d(TAG, "RSA algorithm not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,10 +22,15 @@ package com.nextcloud.talk.utils.database.user;
|
|||||||
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
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.User;
|
||||||
import com.nextcloud.talk.persistence.entities.UserEntity;
|
import com.nextcloud.talk.persistence.entities.UserEntity;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.Completable;
|
import io.reactivex.Completable;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
@ -35,6 +40,7 @@ import io.requery.query.Result;
|
|||||||
import io.requery.reactivex.ReactiveEntityStore;
|
import io.requery.reactivex.ReactiveEntityStore;
|
||||||
|
|
||||||
public class UserUtils {
|
public class UserUtils {
|
||||||
|
private static final String TAG = "UserUtils";
|
||||||
private ReactiveEntityStore<Persistable> dataStore;
|
private ReactiveEntityStore<Persistable> dataStore;
|
||||||
|
|
||||||
UserUtils(ReactiveEntityStore<Persistable> dataStore) {
|
UserUtils(ReactiveEntityStore<Persistable> dataStore) {
|
||||||
@ -46,6 +52,12 @@ public class UserUtils {
|
|||||||
return (dataStore.count(User.class).limit(1).get().value() > 0);
|
return (dataStore.count(User.class).limit(1).get().value() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<UserEntity> getUsers() {
|
||||||
|
Result findUsersQueryResult = dataStore.select(User.class).get();
|
||||||
|
|
||||||
|
return findUsersQueryResult.toList();
|
||||||
|
}
|
||||||
|
|
||||||
// temporary method while we only support 1 user
|
// temporary method while we only support 1 user
|
||||||
public UserEntity getCurrentUser() {
|
public UserEntity getCurrentUser() {
|
||||||
Result findUserQueryResult = dataStore.select(User.class).limit(1).get();
|
Result findUserQueryResult = dataStore.select(User.class).limit(1).get();
|
||||||
@ -66,7 +78,8 @@ public class UserUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Observable<UserEntity> createOrUpdateUser(String username, String token, String serverUrl,
|
public Observable<UserEntity> createOrUpdateUser(String username, String token, String serverUrl,
|
||||||
@Nullable String displayName) {
|
@Nullable String displayName,
|
||||||
|
@Nullable String pushConfigurationState) {
|
||||||
Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.USERNAME.eq(username).
|
Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.USERNAME.eq(username).
|
||||||
and(UserEntity.BASE_URL.eq(serverUrl.toLowerCase()))).limit(1).get();
|
and(UserEntity.BASE_URL.eq(serverUrl.toLowerCase()))).limit(1).get();
|
||||||
|
|
||||||
@ -82,6 +95,14 @@ public class UserUtils {
|
|||||||
user.setDisplayName(displayName);
|
user.setDisplayName(displayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pushConfigurationState != null) {
|
||||||
|
try {
|
||||||
|
user.setPushConfigurationState(LoganSquare.serialize(pushConfigurationState));
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "Failed to serialize push configuration state");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!token.equals(user.getToken())) {
|
if (!token.equals(user.getToken())) {
|
||||||
user.setToken(token);
|
user.setToken(token);
|
||||||
@ -90,6 +111,14 @@ public class UserUtils {
|
|||||||
if (!TextUtils.isEmpty(displayName) && !displayName.equals(user.getDisplayName())) {
|
if (!TextUtils.isEmpty(displayName) && !displayName.equals(user.getDisplayName())) {
|
||||||
user.setDisplayName(displayName);
|
user.setDisplayName(displayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dataStore.upsert(user)
|
return dataStore.upsert(user)
|
||||||
|
@ -45,6 +45,15 @@ public interface AppPreferences {
|
|||||||
@RemoveMethod
|
@RemoveMethod
|
||||||
void removeProxyServer();
|
void removeProxyServer();
|
||||||
|
|
||||||
|
@KeyByString("push_token")
|
||||||
|
String getPushToken();
|
||||||
|
|
||||||
|
@KeyByString("push_token")
|
||||||
|
void setPushtoken(String pushToken);
|
||||||
|
|
||||||
|
@KeyByString("push_token")
|
||||||
|
void removePushToken();
|
||||||
|
|
||||||
@ClearMethod
|
@ClearMethod
|
||||||
void clear();
|
void clear();
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ import javax.net.ssl.SSLSocket
|
|||||||
import javax.net.ssl.SSLSocketFactory
|
import javax.net.ssl.SSLSocketFactory
|
||||||
import javax.net.ssl.X509TrustManager
|
import javax.net.ssl.X509TrustManager
|
||||||
|
|
||||||
class SSLSocketFactoryCompat(trustManager: X509TrustManager): SSLSocketFactory() {
|
class SSLSocketFactoryCompat(trustManager: X509TrustManager) : SSLSocketFactory() {
|
||||||
|
|
||||||
private var delegate: SSLSocketFactory
|
private var delegate: SSLSocketFactory
|
||||||
|
|
||||||
@ -29,6 +29,7 @@ class SSLSocketFactoryCompat(trustManager: X509TrustManager): SSLSocketFactory()
|
|||||||
// https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
|
// https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
|
||||||
var protocols: Array<String>? = null
|
var protocols: Array<String>? = null
|
||||||
var cipherSuites: Array<String>? = null
|
var cipherSuites: Array<String>? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (Build.VERSION.SDK_INT >= 23) {
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
// Since Android 6.0 (API level 23),
|
// Since Android 6.0 (API level 23),
|
||||||
@ -87,7 +88,7 @@ class SSLSocketFactoryCompat(trustManager: X509TrustManager): SSLSocketFactory()
|
|||||||
|
|
||||||
cipherSuites = _cipherSuites.toTypedArray()
|
cipherSuites = _cipherSuites.toTypedArray()
|
||||||
}
|
}
|
||||||
} catch(e: IOException) {
|
} catch (e: IOException) {
|
||||||
} finally {
|
} finally {
|
||||||
socket?.close() // doesn't implement Closeable on all supported Android versions
|
socket?.close() // doesn't implement Closeable on all supported Android versions
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/background_color">
|
android:background="@color/nc_background_color">
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/progress_bar"
|
android:id="@+id/progress_bar"
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
android:id="@+id/swipe_refresh_layout"
|
android:id="@+id/swipe_refresh_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/background_color">
|
android:background="@color/nc_background_color">
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/recycler_view"
|
android:id="@+id/recycler_view"
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/background_color">
|
android:background="@color/nc_background_color">
|
||||||
|
|
||||||
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
|
<studio.carbonylgroup.textfieldboxes.TextFieldBoxes
|
||||||
android:id="@+id/text_field_boxes"
|
android:id="@+id/text_field_boxes"
|
||||||
|
@ -7,5 +7,8 @@
|
|||||||
<string name="nc_app_name">Nextcloud Talk</string>
|
<string name="nc_app_name">Nextcloud Talk</string>
|
||||||
<string name="nc_server_product_name">Nextcloud</string>
|
<string name="nc_server_product_name">Nextcloud</string>
|
||||||
|
|
||||||
<color name="background_color">@color/per70white</color>
|
<color name="nc_background_color">@color/per70white</color>
|
||||||
|
|
||||||
|
<string name="nc_push_server_url">https://push-notifications.nextcloud.com</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue
Block a user