소스 검색

Support multiple push token types

Danilo Bargen 7 년 전
부모
커밋
213a6296d0
5개의 변경된 파일90개의 추가작업 그리고 11개의 파일을 삭제
  1. 3 2
      src/partials/welcome.ts
  2. 43 5
      src/services/keystore.ts
  3. 5 1
      src/services/push.ts
  4. 22 2
      src/services/webclient.ts
  5. 17 1
      src/threema.d.ts

+ 3 - 2
src/partials/welcome.ts

@@ -271,8 +271,9 @@ class WelcomeController {
         this.setupBroadcastChannel(keyStore.publicKeyHex);
 
         // Initialize push service
-        if (decrypted.pushToken !== null) {
-            this.pushService.init(decrypted.pushToken);
+        if (decrypted.pushToken !== null && decrypted.pushTokenType !== null) {
+            this.webClientService.updatePushToken(decrypted.pushToken, decrypted.pushTokenType);
+            this.pushService.init(decrypted.pushToken, decrypted.pushTokenType);
             this.$log.debug(this.logTag, 'Initialize push service');
         }
 

+ 43 - 5
src/services/keystore.ts

@@ -24,7 +24,8 @@ import {stringToUtf8a, utf8aToString} from '../helpers';
  *
  * Data is encrypted as follows:
  *
- *     plaintext = <ownPubKey> + <ownSecKey> + <peerPubKey> [+ <pushtoken]
+ *     plaintext = <ownPubKey> + <ownSecKey> + <peerPubKey>
+ *                 [+ <pushtoken-type-prefix> + ':' + <pushtoken>]
  *     encrypted = nacl.secretbox(plaintext, <nonce>, <key>)
  *
  * The data is encrypted using the first 32 bytes of the SHA512 hash of the
@@ -90,12 +91,29 @@ export class TrustedKeyStoreService {
      * storage. Encrypt it using NaCl with the provided password.
      */
     public storeTrustedKey(ownPublicKey: Uint8Array, ownSecretKey: Uint8Array,
-                           peerPublicKey: Uint8Array, pushToken: string | null,
+                           peerPublicKey: Uint8Array,
+                           pushToken: string | null, pushTokenType: threema.PushTokenType | null,
                            password: string): void {
         const nonce: Uint8Array = nacl.randomBytes(nacl.secretbox.nonceLength);
-        const token: Uint8Array = (pushToken == null) ? new Uint8Array(0) : stringToUtf8a(pushToken);
+
+        // Add prefix to push token string
+        let pushTokenString = null;
+        if (pushToken !== null && pushTokenType !== null) {
+            switch (pushTokenType) {
+                case threema.PushTokenType.Gcm:
+                    pushTokenString = threema.PushTokenPrefix.Gcm + ':' + pushToken;
+                    break;
+                case threema.PushTokenType.Apns:
+                    pushTokenString = threema.PushTokenPrefix.Apns + ':' + pushToken;
+                    break;
+            }
+        }
+        const token: Uint8Array = (pushTokenString == null)
+                                ? new Uint8Array(0)
+                                : stringToUtf8a(pushTokenString);
+
         const data = new Uint8Array(3 * 32 + token.byteLength);
-        // TODO public release: Stop storing public key (redundant)
+        // TODO: Stop storing public key (redundant)
         data.set(ownPublicKey, 0);
         data.set(ownSecretKey, 32);
         data.set(peerPublicKey, 64);
@@ -135,12 +153,32 @@ export class TrustedKeyStoreService {
             return null;
         }
 
+        // Parse push token
         const tokenBytes = (decrypted as Uint8Array).slice(96);
+        const tokenString: string | null = tokenBytes.byteLength > 0 ? utf8aToString(tokenBytes) : null;
+        let tokenType = threema.PushTokenType.Gcm;
+        let token: string;
+        if (tokenString[1] === ':') {
+            switch (tokenString[0]) {
+                case threema.PushTokenPrefix.Gcm:
+                    tokenType = threema.PushTokenType.Gcm;
+                    break;
+                case threema.PushTokenPrefix.Apns:
+                    tokenType = threema.PushTokenType.Apns;
+                    break;
+            }
+            token = tokenString.slice(2);
+        } else {
+            // Compat
+            token = tokenString;
+        }
+
         return {
             ownPublicKey: (decrypted as Uint8Array).slice(0, 32),
             ownSecretKey: (decrypted as Uint8Array).slice(32, 64),
             peerPublicKey: (decrypted as Uint8Array).slice(64, 96),
-            pushToken: tokenBytes.byteLength > 0 ? utf8aToString(tokenBytes) : null,
+            pushToken: token,
+            pushTokenType: tokenType,
         };
     }
 

+ 5 - 1
src/services/push.ts

@@ -16,6 +16,7 @@
  */
 
 export class PushService {
+    private static ARG_TYPE = 'type';
     private static ARG_TOKEN = 'token';
     private static ARG_SESSION = 'session';
     private static ARG_VERSION = 'version';
@@ -25,6 +26,7 @@ export class PushService {
 
     private url: string;
     private pushToken: string = null;
+    private pushType = threema.PushTokenType.Gcm;
     private version: number = null;
 
     public static $inject = ['$http', '$httpParamSerializerJQLike', 'CONFIG', 'PROTOCOL_VERSION'];
@@ -39,8 +41,9 @@ export class PushService {
     /**
      * Initiate the push service with a push token.
      */
-    public init(pushToken: string): void {
+    public init(pushToken: string, pushTokenType: threema.PushTokenType): void {
         this.pushToken = pushToken;
+        this.pushType = pushTokenType;
     }
 
     /**
@@ -74,6 +77,7 @@ export class PushService {
                 'Content-Type': 'application/x-www-form-urlencoded',
             },
             data: this.$httpParamSerializerJQLike({
+                [PushService.ARG_TYPE]: this.pushType,
                 [PushService.ARG_SESSION]: sha256(session),
                 [PushService.ARG_TOKEN]: this.pushToken,
                 [PushService.ARG_VERSION]: this.version,

+ 22 - 2
src/services/webclient.ts

@@ -156,6 +156,7 @@ export class WebClientService {
     public receivers: threema.Container.Receivers;
     public alerts: threema.Alert[] = [];
     private pushToken: string = null;
+    private pushTokenType: threema.PushTokenType = null;
 
     // Other
     private config: threema.Config;
@@ -559,7 +560,7 @@ export class WebClientService {
             this.pushService.sendPush(this.salty.permanentKeyBytes)
                 .catch(() => this.$log.warn('Could not notify app!'))
                 .then(() => {
-                    this.$log.debug('Requested app wakeup');
+                    this.$log.debug('Requested app wakeup via', this.pushTokenType);
                     this.$rootScope.$apply(() => {
                         this.stateService.updateConnectionBuildupState('push');
                     });
@@ -2131,7 +2132,19 @@ export class WebClientService {
         // Store push token
         if (this.clientInfo.pushToken) {
             this.pushToken = this.clientInfo.pushToken;
-            this.pushService.init(this.pushToken);
+            switch (this.clientInfo.os) {
+                case threema.OperatingSystem.Android:
+                    this.pushTokenType = threema.PushTokenType.Gcm;
+                    break;
+                case threema.OperatingSystem.Ios:
+                    this.pushTokenType = threema.PushTokenType.Apns;
+                    break;
+                default:
+                    this.$log.error(this.logTag, 'Invalid operating system in client info');
+            }
+        }
+        if (this.pushToken && this.pushTokenType) {
+            this.pushService.init(this.pushToken, this.pushTokenType);
         }
 
         this.registerInitializationStep(InitializationStep.ClientInfo);
@@ -2327,6 +2340,7 @@ export class WebClientService {
                 this.salty.keyStore.secretKeyBytes,
                 this.salty.peerPermanentKeyBytes,
                 this.pushToken,
+                this.pushTokenType,
                 password,
             );
             this.$log.info('Stored trusted key');
@@ -2335,6 +2349,12 @@ export class WebClientService {
         return false;
     }
 
+    public updatePushToken(token: string, tokenType: threema.PushTokenType): void {
+        this.$log.debug(this.logTag, 'Updating', tokenType, 'push token');
+        this.pushToken = token;
+        this.pushTokenType = tokenType;
+    }
+
     private _sendRequest(type, args?: object, data?: object): void {
         const message: threema.WireMessage = {
             type: WebClientService.TYPE_REQUEST,

+ 17 - 1
src/threema.d.ts

@@ -390,11 +390,22 @@ declare namespace threema {
         text: string;
     }
 
+    const enum PushTokenType {
+        Gcm = 'gcm',
+        Apns = 'apns',
+    }
+
+    const enum PushTokenPrefix {
+        Gcm = 'g',
+        Apns = 'a',
+    }
+
     interface TrustedKeyStoreData {
         ownPublicKey: Uint8Array;
         ownSecretKey: Uint8Array;
         peerPublicKey: Uint8Array;
         pushToken: string | null;
+        pushTokenType: PushTokenType | null;
     }
 
     const enum BrowserName {
@@ -547,9 +558,14 @@ declare namespace threema {
         isCharging: boolean;
     }
 
+    const enum OperatingSystem {
+        Android = 'android',
+        Ios = 'ios',
+    }
+
     interface ClientInfo {
         device: string;
-        os: string;
+        os: OperatingSystem;
         osVersion: string;
         isWork: boolean;
         pushToken?: string;