/**
* This file is part of Threema Web.
*
* Threema Web is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero 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 Affero
* General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Threema Web. If not, see .
*/
import {sha256} from '../helpers/crypto';
export class PushService {
private static ARG_TYPE = 'type';
private static ARG_TOKEN = 'token';
private static ARG_SESSION = 'session';
private static ARG_VERSION = 'version';
private static ARG_ENDPOINT = 'endpoint';
private static ARG_BUNDLE_ID = 'bundleid';
private logTag: string = '[PushService]';
private $http: ng.IHttpService;
private $log: ng.ILogService;
private $httpParamSerializerJQLike;
private url: string;
private pushToken: string = null;
private pushType = threema.PushTokenType.Gcm;
private version: number = null;
public static $inject = ['$http', '$log', '$httpParamSerializerJQLike', 'CONFIG', 'PROTOCOL_VERSION'];
constructor($http: ng.IHttpService, $log: ng.ILogService, $httpParamSerializerJQLike,
CONFIG: threema.Config, PROTOCOL_VERSION: number) {
this.$http = $http;
this.$log = $log;
this.$httpParamSerializerJQLike = $httpParamSerializerJQLike;
this.url = CONFIG.PUSH_URL;
this.version = PROTOCOL_VERSION;
}
/**
* Initiate the push service with a push token.
*/
public init(pushToken: string, pushTokenType: threema.PushTokenType): void {
this.$log.info(this.logTag, 'Initialized with', pushTokenType, 'token');
this.pushToken = pushToken;
this.pushType = pushTokenType;
}
/**
* Reset the push service, remove stored push tokens.
*/
public reset(): void {
this.pushToken = null;
}
/**
* Return true if service has been initialized with a push token.
*/
public isAvailable(): boolean {
return this.pushToken != null;
}
/**
* Send a push notification for the specified session (public permanent key
* of the initiator). The promise is always resolved to a boolean.
*/
public async sendPush(session: Uint8Array): Promise {
if (!this.isAvailable()) {
return false;
}
// Calculate session hash
const sessionHash = await sha256(session.buffer);
// Prepare request
const data = {
[PushService.ARG_TYPE]: this.pushType,
[PushService.ARG_SESSION]: sessionHash,
[PushService.ARG_VERSION]: this.version,
};
if (this.pushType === threema.PushTokenType.Apns) {
// APNS token format: ";;"
const parts = this.pushToken.split(';');
if (parts.length < 3) {
this.$log.warn(this.logTag, 'APNS push token contains', parts.length, 'parts, at least 3 are required');
return false;
}
data[PushService.ARG_TOKEN] = parts[0];
data[PushService.ARG_ENDPOINT] = parts[1];
data[PushService.ARG_BUNDLE_ID] = parts[2];
} else if (this.pushType === threema.PushTokenType.Gcm) {
data[PushService.ARG_TOKEN] = this.pushToken;
} else {
this.$log.warn(this.logTag, 'Invalid push type');
return false;
}
const request = {
method: 'POST',
url: this.url,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
data: this.$httpParamSerializerJQLike(data),
};
// Send push
return new Promise((resolve) => {
this.$http(request).then(
(successResponse) => {
if (successResponse.status === 204) {
this.$log.debug(this.logTag, 'Sent push');
resolve(true);
} else {
this.$log.warn(this.logTag, 'Sending push failed: HTTP ' + successResponse.status);
resolve(false);
}
},
(errorResponse) => {
this.$log.warn(this.logTag, 'Sending push failed:', errorResponse);
resolve(false);
},
);
}) as Promise;
}
}