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);
}));
});