HEX
Server: Apache/2.2.34 (Unix) mod_fastcgi/mod_fastcgi-SNAP-0910052141
System: Linux Kou-Etsu-Dou 4.4.59+ #25556 SMP PREEMPT Thu Mar 4 18:03:46 CST 2021 x86_64
User: hosam (1026)
PHP: 7.2.29
Disabled: NONE
Upload Files
File: /volume1/@appstore/SynologyApplicationService/ui/browser_pair/service-worker.js
const NOTIFICATION_TIMEOUT_MSEC = 5000;

self.importScripts('../indexeddb.min.js');
self.importScripts('../sodium.min.js');

self.addEventListener('activate', event => {
	clients.claim();
});

self.addEventListener('push', function (event) {
	var notificationTitle = 'Synology';
	var notificationOptions = {
		body: '',
		icon: './images/notify_system.png',
		data: {}
	};

	if (event.data) {
		var dataText = event.data.text();
		if (dataText == '') {
			return;
		}

		var data = JSON.parse(dataText);

		if (typeof(data.notify_url) != 'undefined') {
			notificationOptions.data.url = data.notify_url;
		}

		if (typeof(data.event_category) != 'undefined') {
			notificationTitle = data.event_category;
			if (data.event_category == 'Chat') {
				notificationOptions.icon = './images/notify_chat.png';
				notificationOptions.data.event_category = 'SYNO.SDS.Chat.Application';
			} else if (data.event_category == 'Calendar') {
				notificationOptions.icon = './images/notify_calendar.png';
				notificationOptions.data.event_category = 'SYNO.Cal.Application';
			} else if (data.event_category == 'MailClient') {
				notificationOptions.icon = './images/notify_mailclient.png';
				notificationOptions.data.event_category = 'SYNO.SDS.MailClient.Application';
			} else if (data.event_category == 'Spreadsheet') {
				notificationOptions.icon = './images/notify_office.png';
				notificationOptions.data.event_category = 'SYNO.SDS.Office.Application';
			}
		}

		if (typeof(data.title) != 'undefined' && data.title != '') {
			notificationTitle = data.title;
		}

		if (typeof(data.encrypted_data) != 'undefined') {
			// package is encrypted and device has shared key
			try {
				var payload = JSON.parse(SYNO.SAS.sodium.to_string(SYNO.SAS.sodium.from_base64(data.encrypted_data)));

				event.waitUntil(
					idbkeyval.get(payload.browser_key).then(function(b64sharedkey) {
						if (typeof(b64sharedkey) == 'undefined') {
							notificationOptions.body = data.raw_data || "Reinstall push service";
						} else {
							var sharedkey = SYNO.SAS.sodium.from_base64(b64sharedkey).subarray(0, SYNO.SAS.sodium.crypto_kx_SECRETKEYBYTES);
							var nonce = SYNO.SAS.sodium.from_base64(payload.nonce);
							var ciphermsg = SYNO.SAS.sodium.from_base64(payload.ciphertext);
							var message = SYNO.SAS.sodium.to_string(SYNO.SAS.sodium.crypto_secretbox_open_easy(ciphermsg, nonce, sharedkey));
							notificationOptions.body = message;
						}
						return self.registration.showNotification(notificationTitle, notificationOptions);
					})
					.then(() => self.registration.getNotifications())
					.then(function(notifications) {
						setTimeout(() => notifications.forEach(notification => notification.close()), NOTIFICATION_TIMEOUT_MSEC);
					})
				);
			} catch (e) {
				notificationOptions.body = data.raw_data || "Server Error";
				event.waitUntil(
					self.registration.showNotification(notificationTitle, notificationOptions)
						.then(() => self.registration.getNotifications())
						.then(function(notifications) {
							setTimeout(() => notifications.forEach(notification => notification.close()), NOTIFICATION_TIMEOUT_MSEC);
						})
				);
			}
		} else if (typeof(data.raw_data) != 'undefined') {
			notificationOptions.body = data.raw_data;
			event.waitUntil(
				self.registration.showNotification(notificationTitle, notificationOptions)
					.then(() => self.registration.getNotifications())
					.then(function(notifications) {
						setTimeout(() => notifications.forEach(notification => notification.close()), NOTIFICATION_TIMEOUT_MSEC);
					})
			);
		}
	}
});

function sendMessageToClient(client, msg, result){
	return new Promise(function(resolve, reject){
		var msgChannel = new MessageChannel();

		msgChannel.port1.onmessage = function(event){
			if (!result.isWindowOpened && event && event.data && event.data.method && event.data.method == 'check' && event.data.isPkgClient) {
				return client.focus().then(function(client) {
						if (client.url == event.data.url) {
							return true;
						}
						return client.navigate(event.data.url);
					}).then(function() {
						resolve(true);
					});
			}
		};

		client.postMessage(msg, [msgChannel.port2]);
		setTimeout(function(){ resolve(false); }, 1200);
	});
}

self.addEventListener('notificationclick', function (event) {
	event.notification.close();

	if (!event.notification.data || !event.notification.data.url) {
		return;
	}

	event.waitUntil(clients.matchAll({
		includeUncontrolled: true, type: 'window'
	}).then(function(clientList) {
		if (0 == clientList.length) {
			return clients.openWindow(event.notification.data.url);
		}

		var req = {
			'method': 'check',
			'event_category': event.notification.data.event_category,
			'url': event.notification.data.url
		};

		var sendMsgToClientHandlers = [];
		var result = { isWindowOpened: false };
		for (var i = 0;i < clientList.length; i++) {
			sendMsgToClientHandlers.push(sendMessageToClient(clientList[i], req, result));
		}

		return Promise.race(sendMsgToClientHandlers);
	}).then(function(isWindowOpened) {
		if (isWindowOpened) {
			return true;
		}
		return clients.openWindow(event.notification.data.url);
	}));
});