Skip to content

Commit

Permalink
use sse for push notification, #386
Browse files Browse the repository at this point in the history
  • Loading branch information
bdeterding committed Jun 14, 2018
1 parent 6ac0270 commit 449c36e
Show file tree
Hide file tree
Showing 166 changed files with 888 additions and 333 deletions.
4 changes: 3 additions & 1 deletion app-android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ dependencies {
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation "com.google.android.gms:play-services-gcm:10.2.1"
implementation 'commons-io:commons-io:2.4'
implementation 'org.jdeferred:jdeferred-core:1.2.4'
implementation 'com.android.support:support-compat:27.1.1'
implementation 'com.android.support:support-core-utils:27.1.1'

testImplementation 'junit:junit:4.12'
testImplementation "org.robolectric:robolectric:3.3.2"
androidTestImplementation 'org.codehaus.jackson:jackson-mapper-asl:1.9.2'
Expand Down
81 changes: 30 additions & 51 deletions app-android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,71 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.tutao.tutanota">
package="de.tutao.tutanota">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE"/>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale"
android:launchMode="singleInstance"
android:theme="@style/SplashTheme">
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale"
android:launchMode="singleInstance"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_MULTIPLE"/>

<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="*/*"/>
</intent-filter>
</activity>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${contentProviderAuthority}"
android:exported="false"
android:grantUriPermissions="true">
android:name="android.support.v4.content.FileProvider"
android:authorities="${contentProviderAuthority}"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/paths" />
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/paths"/>
</provider>
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.example.gcm" />
</intent-filter>
</receiver>

<service
android:name="de.tutao.tutanota.push.GcmListener"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name="de.tutao.tutanota.push.PushInstanceIdListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
<service
android:name="de.tutao.tutanota.push.GcmRegistrationService"
android:exported="false" />
android:name=".push.PushNotificationService"
android:enabled="true"
android:exported="false"
android:process=":pushprocess"/>
</application>

</manifest>
13 changes: 7 additions & 6 deletions app-android/app/src/main/java/de/tutao/tutanota/Crypto.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.util.Log;

import org.apache.commons.io.IOUtils;
import org.json.JSONException;
Expand Down Expand Up @@ -59,15 +58,15 @@ public final class Crypto {

private static final Integer ANDROID_6_SDK_VERSION = 23;

private final MainActivity activity;
private final Context context;

static {
// see: http://android-developers.blogspot.de/2013/08/some-securerandom-thoughts.html
PRNGFixes.apply();
}

public Crypto(MainActivity activity) {
this.activity = activity;
public Crypto(Context context) {
this.context = context;
this.randomizer = new SecureRandom();
}

Expand Down Expand Up @@ -176,7 +175,6 @@ public static SecretKeySpec bytesToKey(byte[] key) {
}

String aesEncryptFile(final byte[] key, final String fileUrl, final byte[] iv) throws IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
Context context = activity.getWebView().getContext();
File inputFile = Utils.uriToFile(context, fileUrl);
File encryptedDir = new File(Utils.getDir(context), TEMP_DIR_ENCRYPTED);
encryptedDir.mkdirs();
Expand Down Expand Up @@ -213,7 +211,6 @@ private String aesDecrypt(final byte[] key, final byte[] cipherText) throws Inva
}

String aesDecryptFile(final byte[] key, final String fileUrl) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchPaddingException {
Context context = activity.getWebView().getContext();
File inputFile = Utils.uriToFile(context, fileUrl);
File decryptedDir = new File(Utils.getDir(context), TEMP_DIR_DECRYPTED);
decryptedDir.mkdirs();
Expand Down Expand Up @@ -244,6 +241,10 @@ public void aesDecrypt(final byte[] key, InputStream in, OutputStream out) throw
}
}

public SecureRandom getRandomizer() {
return randomizer;
}

private InputStream getCipherInputStream(InputStream in, Cipher cipher) {
if (Build.VERSION.SDK_INT < ANDROID_6_SDK_VERSION) {
// Use the tutao cipher suite implementation to increase download performance.
Expand Down
26 changes: 4 additions & 22 deletions app-android/app/src/main/java/de/tutao/tutanota/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;

import org.jdeferred.Deferred;
import org.jdeferred.DoneCallback;
import org.jdeferred.Promise;
Expand All @@ -31,7 +28,7 @@
import java.io.FileNotFoundException;
import java.util.HashMap;

import de.tutao.tutanota.push.GcmRegistrationService;
import de.tutao.tutanota.push.PushNotificationService;

public class MainActivity extends Activity {

Expand All @@ -48,6 +45,8 @@ public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

this.setupPushNotifications();

webView = new WebView(this);
webView.setBackgroundColor(getResources().getColor(android.R.color.transparent));
setContentView(webView);
Expand Down Expand Up @@ -85,7 +84,6 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
});
this.webView.loadUrl(appUrl);
nativeImpl.setup();

}

@Override
Expand Down Expand Up @@ -157,23 +155,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}

void setupPushNotifications() {
if (gcmIsAvailable()) {
// gcm registration
Intent intent = new Intent(MainActivity.this, GcmRegistrationService.class);
startService(intent);
}
}

/**
* @return true, if the GCM is available.
*/
private boolean gcmIsAvailable() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
return false;
}
return true;
startService(new Intent(this, PushNotificationService.class));
}

public void bringToForeground() {
Expand Down
12 changes: 12 additions & 0 deletions app-android/app/src/main/java/de/tutao/tutanota/Native.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import java.util.HashMap;
import java.util.Map;

import de.tutao.tutanota.push.SseStorage;

/**
* Created by mpfau on 4/8/17.
*/
Expand All @@ -34,6 +36,7 @@ public final class Native {
Crypto crypto;
FileUtil files;
Contact contact;
SseStorage sseStorage;
Map<String, DeferredObject<JSONObject, Exception, ?>> queue = new HashMap<>();
private final MainActivity activity;
private volatile DeferredObject<Void, Void, Void> webAppInitialized = new DeferredObject<>();
Expand All @@ -44,6 +47,7 @@ public final class Native {
crypto = new Crypto(activity);
contact = new Contact(activity);
files = new FileUtil(activity);
sseStorage = new SseStorage(activity);
}

public void setup() {
Expand Down Expand Up @@ -219,6 +223,14 @@ private Promise invokeMethod(String method, JSONArray args) {
case "openLink":
promise.resolve(openLink(args.getString(0)));
break;
case "getPushIdentifier":
promise.resolve(sseStorage.getPushIdentifier());
break;
case "storePushIdentifierLocally":
sseStorage.storePushIdentifier(args.getString(0), args.getString(1),
args.getString(2));
promise.resolve(true);
break;
default:
throw new Exception("unsupported method: " + method);
}
Expand Down
5 changes: 5 additions & 0 deletions app-android/app/src/main/java/de/tutao/tutanota/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ public static byte[] base64ToBytes(String base64) {
return Base64.decode(base64, Base64.NO_WRAP);
}

public static String base64ToBase64Url(String base64) {
return base64.replaceAll("\\+", "-")
.replaceAll("/", "_")
.replaceAll("=", "");
}



Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Loading

1 comment on commit 449c36e

@MartinHennrich
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this commit is wonderful! 😍
Finally the push service is handled by a Tutao operated server and not on a Google machine. 👍

Please sign in to comment.