Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
255 lines
8.0 KiB
255 lines
8.0 KiB
3 years ago
|
/*
|
||
|
* https://github.com/morethanwords/tweb
|
||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||
|
*
|
||
|
* Originally from:
|
||
|
* https://github.com/zhukov/webogram
|
||
|
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
|
||
|
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
||
|
*/
|
||
|
|
||
|
import type { NotificationSettings } from "../appManagers/appNotificationsManager";
|
||
|
import { MOUNT_CLASS_TO } from "../../config/debug";
|
||
|
import { copy } from "../../helpers/object";
|
||
|
import { logger } from "../logger";
|
||
|
import rootScope from "../rootScope";
|
||
|
import { ServiceWorkerNotificationsClearTask, ServiceWorkerPingTask, ServiceWorkerPushClickTask } from "../serviceWorker/index.service";
|
||
|
import apiManager from "./mtprotoworker";
|
||
|
import I18n, { LangPackKey } from "../langPack";
|
||
|
import { isMobile } from "../../helpers/userAgent";
|
||
|
|
||
|
export type PushSubscriptionNotifyType = 'init' | 'subscribe' | 'unsubscribe';
|
||
|
export type PushSubscriptionNotifyEvent = `push_${PushSubscriptionNotifyType}`;
|
||
|
|
||
|
export type PushSubscriptionNotify = {
|
||
|
tokenType: number,
|
||
|
tokenValue: string
|
||
|
};
|
||
|
|
||
|
export class WebPushApiManager {
|
||
|
public isAvailable = true;
|
||
|
private isPushEnabled = false;
|
||
|
private localNotificationsAvailable = true;
|
||
|
private started = false;
|
||
|
private settings: NotificationSettings & {baseUrl?: string} = {} as any;
|
||
|
private isAliveTO: any;
|
||
|
private isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||
|
private userVisibleOnly = this.isFirefox ? false : true;
|
||
|
private log = logger('PM');
|
||
|
|
||
|
constructor() {
|
||
|
if(!('PushManager' in window) ||
|
||
|
!('Notification' in window) ||
|
||
|
!('serviceWorker' in navigator)) {
|
||
|
this.log.warn('Push messaging is not supported.');
|
||
|
this.isAvailable = false;
|
||
|
this.localNotificationsAvailable = false;
|
||
|
}
|
||
|
|
||
|
if(this.isAvailable && Notification.permission === 'denied') {
|
||
|
this.log.warn('The user has blocked notifications.');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public start() {
|
||
|
if(!this.started) {
|
||
|
this.started = true;
|
||
|
this.getSubscription();
|
||
|
this.setUpServiceWorkerChannel();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public setLocalNotificationsDisabled() {
|
||
|
this.localNotificationsAvailable = false;
|
||
|
}
|
||
|
|
||
|
public getSubscription() {
|
||
|
if(!this.isAvailable) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
navigator.serviceWorker.ready.then((reg) => {
|
||
|
reg.pushManager.getSubscription().then((subscription) => {
|
||
|
this.isPushEnabled = !!subscription;
|
||
|
this.pushSubscriptionNotify('init', subscription);
|
||
|
}).catch((err) => {
|
||
|
this.log.error('Error during getSubscription()', err);
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public subscribe = () => {
|
||
|
if(!this.isAvailable) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
navigator.serviceWorker.ready.then((reg) => {
|
||
|
reg.pushManager.subscribe({userVisibleOnly: this.userVisibleOnly}).then((subscription) => {
|
||
|
// The subscription was successful
|
||
|
this.isPushEnabled = true;
|
||
|
this.pushSubscriptionNotify('subscribe', subscription);
|
||
|
}).catch((e) => {
|
||
|
if(Notification.permission === 'denied') {
|
||
|
this.log('Permission for Notifications was denied');
|
||
|
} else {
|
||
|
this.log('Unable to subscribe to push.', e);
|
||
|
if(!this.userVisibleOnly) {
|
||
|
this.userVisibleOnly = true;
|
||
|
setTimeout(this.subscribe, 0);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public unsubscribe() {
|
||
|
if(!this.isAvailable) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
navigator.serviceWorker.ready.then((reg) => {
|
||
|
reg.pushManager.getSubscription().then((subscription) => {
|
||
|
this.isPushEnabled = false;
|
||
|
|
||
|
if(subscription) {
|
||
|
this.pushSubscriptionNotify('unsubscribe', subscription);
|
||
|
|
||
|
setTimeout(() => {
|
||
|
subscription.unsubscribe().then((successful) => {
|
||
|
this.isPushEnabled = false;
|
||
|
}).catch((e) => {
|
||
|
this.log.error('Unsubscription error: ', e);
|
||
|
});
|
||
|
}, 3000);
|
||
|
}
|
||
|
}).catch((e) => {
|
||
|
this.log.error('Error thrown while unsubscribing from ' +
|
||
|
'push messaging.', e);
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public forceUnsubscribe() {
|
||
|
if(!this.isAvailable) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
navigator.serviceWorker.ready.then((reg) => {
|
||
|
reg.pushManager.getSubscription().then((subscription) => {
|
||
|
this.log.warn('force unsubscribe', subscription);
|
||
|
if(subscription) {
|
||
|
subscription.unsubscribe().then((successful) => {
|
||
|
this.log.warn('force unsubscribe successful', successful);
|
||
|
this.isPushEnabled = false;
|
||
|
}).catch((e) => {
|
||
|
this.log.error('Unsubscription error: ', e);
|
||
|
});
|
||
|
}
|
||
|
}).catch((e) => {
|
||
|
this.log.error('Error thrown while unsubscribing from ' +
|
||
|
'push messaging.', e);
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public isAliveNotify = () => {
|
||
|
if(!this.isAvailable || rootScope.idle && rootScope.idle.deactivated) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this.settings.baseUrl = (location.href || '').replace(/#.*$/, '') + '#/im';
|
||
|
|
||
|
const lang: ServiceWorkerPingTask['payload']['lang'] = {} as any;
|
||
|
const ACTIONS_LANG_MAP: Record<keyof ServiceWorkerPingTask['payload']['lang'], LangPackKey> = {
|
||
|
push_action_mute1d: isMobile ? 'PushNotification.Action.Mute1d.Mobile' : 'PushNotification.Action.Mute1d',
|
||
|
push_action_settings: isMobile ? 'PushNotification.Action.Settings.Mobile' : 'PushNotification.Action.Settings',
|
||
|
push_message_nopreview: 'PushNotification.Message.NoPreview'
|
||
|
};
|
||
|
|
||
|
for(const action in ACTIONS_LANG_MAP) {
|
||
|
lang[action as keyof typeof ACTIONS_LANG_MAP] = I18n.format(ACTIONS_LANG_MAP[action as keyof typeof ACTIONS_LANG_MAP], true);
|
||
|
}
|
||
|
|
||
|
const task: ServiceWorkerPingTask = {
|
||
|
type: 'ping',
|
||
|
payload: {
|
||
|
localNotifications: this.localNotificationsAvailable,
|
||
|
lang: lang,
|
||
|
settings: this.settings
|
||
|
}
|
||
|
};
|
||
|
|
||
|
if(navigator.serviceWorker.controller) {
|
||
|
navigator.serviceWorker.controller.postMessage(task);
|
||
|
}
|
||
|
|
||
|
this.isAliveTO = setTimeout(this.isAliveNotify, 10000);
|
||
|
}
|
||
|
|
||
|
public setSettings(newSettings: WebPushApiManager['settings']) {
|
||
|
this.settings = copy(newSettings);
|
||
|
clearTimeout(this.isAliveTO);
|
||
|
this.isAliveNotify();
|
||
|
}
|
||
|
|
||
|
public hidePushNotifications() {
|
||
|
if(!this.isAvailable) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(navigator.serviceWorker.controller) {
|
||
|
const task: ServiceWorkerNotificationsClearTask = {type: 'notifications_clear'};
|
||
|
navigator.serviceWorker.controller.postMessage(task);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public setUpServiceWorkerChannel() {
|
||
|
if(!this.isAvailable) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
apiManager.addServiceWorkerTaskListener('push_click', (task: ServiceWorkerPushClickTask) => {
|
||
|
if(rootScope.idle && rootScope.idle.deactivated) {
|
||
|
// AppRuntimeManager.reload(); // WARNING
|
||
|
location.reload();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
rootScope.dispatchEvent('push_notification_click', task.payload);
|
||
|
});
|
||
|
|
||
|
navigator.serviceWorker.ready.then(this.isAliveNotify);
|
||
|
}
|
||
|
|
||
|
public pushSubscriptionNotify(event: PushSubscriptionNotifyType, subscription?: PushSubscription) {
|
||
|
if(subscription) {
|
||
|
const subscriptionObj: PushSubscriptionJSON = subscription.toJSON();
|
||
|
if(!subscriptionObj ||
|
||
|
!subscriptionObj.endpoint ||
|
||
|
!subscriptionObj.keys ||
|
||
|
!subscriptionObj.keys.p256dh ||
|
||
|
!subscriptionObj.keys.auth) {
|
||
|
this.log.warn('Invalid push subscription', subscriptionObj);
|
||
|
this.unsubscribe();
|
||
|
this.isAvailable = false;
|
||
|
this.pushSubscriptionNotify(event);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this.log.warn('Push', event, subscriptionObj);
|
||
|
rootScope.dispatchEvent(('push_' + event) as PushSubscriptionNotifyEvent, {
|
||
|
tokenType: 10,
|
||
|
tokenValue: JSON.stringify(subscriptionObj)
|
||
|
});
|
||
|
} else {
|
||
|
this.log.warn('Push', event, false);
|
||
|
rootScope.dispatchEvent(('push_' + event) as PushSubscriptionNotifyEvent, false as any);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const webPushApiManager = new WebPushApiManager();
|
||
|
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.webPushApiManager = webPushApiManager);
|
||
|
export default webPushApiManager;
|