我们被来自我们自己的客户端(已知 IP)的大量请求击中了“/assets/workers/null”端点。
我们可能会在 2 分钟的窗口内看到来自 25 个已知 IP 地址的 6000 个请求,几个小时后会看到少数对该端点的请求。
这看起来与我们的浏览器推送事件通知服务工作者有关,它托管为“/assets/workers/notification.service.worker.js”,但我看不到任何看起来会解析为“null”的东西”。
我没有编写原始代码,并且在这一点上与浏览器服务人员合作的机会有限,我正在尝试确定是否有任何东西可以解释“/assets/workers/null”的奇怪流量。任何帮助是极大的赞赏。
这是服务工作者的代码:
// ╔═══╦══════════════════════════════════════════════════════════════════════════╗
// ║ @ ║ Service worker responsible to manage browser push notifications ║
// ╠═══╬══════════════════════════════════════════════════════════════════════════╣
// ║ ! ║ Change this module structure can compromise the functionality ║
// ╠═══╩══════════════════════════════════════════════════════════════════════════╣
// ║ This worker depends on the SystemUI object to be initialized, so the ║
// ║ worker should be register and initialized after the application is loaded ║
// ╚══════════════════════════════════════════════════════════════════════════════╝
'use strict';
// ╔═══╦══════════════════════════════════════════════════════════════════════════╗
// ║ § ║ Event listener for notifications received by the service worker ║
// ╚═══╩══════════════════════════════════════════════════════════════════════════╝
self.addEventListener('push', function (event) { event.waitUntil(ParseReceivedEvent(event)); });
async function ParseReceivedEvent(event) {
try {
// => ~/assets/workers/notification.service.worker.js?m=1&c=APP.Configuration.Web&v=0.1.8
const moduleId = new URL(event.currentTarget.location.href).searchParams.get('m');
// => { PushNotificationMessage } from '../push.notification.model.ts'
const data = event.data.json();
if (data.VisualMessage != undefined) {
if (data.Module == moduleId || data.Module == undefined || data.Module == 0) {
// If the client is not focused, send the message to the desktop/mobile
if (!await isClientFocused()) {
const title = data.VisualMessage.Title;
const options = BuildNotificationMessage(data);
await self.registration.showNotification(title, options);
// We mark the message as silent, since we already displayed the notification
data.Silent = true;
}
}
}
await SendClientsMessage('message', null, data);
return SendClientsMessage('log', '[Service Worker] Push Received.', data);
}
catch (ex) { console.error('[Service Worker] ParseReceivedEvent Error', ex); }
}
// ╔═══╦══════════════════════════════════════════════════════════════════════════╗
// ║ § ║ Event listener for clicks on the desktop/mobile notification pop-up ║
// ╚═══╩══════════════════════════════════════════════════════════════════════════╝
self.addEventListener('notificationclick', function (event) { event.waitUntil(ParseNotificationClick(event)); });
async function ParseNotificationClick(event) {
try {
await event.notification.close();
if (event.notification.data != undefined && event.notification.data.Url != undefined && event.action == 'open') {
const data = event.notification.data;
const urlToOpen = new URL(data.Url, self.location.origin).href;
const windowClients = await clients.matchAll({ type: 'window', includeUncontrolled: true });
let matchingClient = windowClients.find(function (item) { return item.url === urlToOpen; });
if (matchingClient) {
// There is already a client with this URL
await matchingClient.focus();
}
else {
let urlObject = new URL(urlToOpen);
let matchingClientHost = await findClientHost(urlObject.host);
// There is a client open with the same web module
if (matchingClientHost) {
await SendClientsMessage('redirect', urlObject.pathname);
}
// Check if this URL can be docked
else if (event.notification.data.Dock && event.notification.data.RecordId != undefined) {
let matchingClientDomain = await findClientHost(urlObject.hostname, true);
if (matchingClientDomain) {
SendClientMessage(matchingClientDomain, 'dock', event.notification.data.RecordId, event.notification.data);
}
// There is not client with the web module, so open another tab
else { await clients.openWindow(urlToOpen); }
}
// There is not client with the web module, so open another tab
else { await clients.openWindow(urlToOpen); }
}
}
}
catch (ex) { console.error('[ServiceWorker] Error parsing notification click', ex); }
return SendClientsMessage('log', `[Service Worker] Notification click Received (Action)="${event.action || 'None'}"`, event.notification.data);
}
// ╔═══╦══════════════════════════════════════════════════════════════════════════╗
// ║ § ║ Send a message to all listening clients with the specified data ║
// ╚═══╩══════════════════════════════════════════════════════════════════════════╝
async function SendClientsMessage(type, message, value) {
return clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function (windowClients) {
windowClients.forEach(function (windowClient) {
windowClient.postMessage({ type: type, message: message, value: value });
});
});
}
function SendClientMessage(client, type, message, value) {
client.postMessage({ type: type, message: message, value: value });
}
// ╔═══╦══════════════════════════════════════════════════════════════════════════╗
// ║ § ║ Check if tab of this event is currently focused ║
// ╚═══╩══════════════════════════════════════════════════════════════════════════╝
async function isClientFocused() {
return clients.matchAll({ type: 'window', frameType: 'top-level', includeUncontrolled: true })
.then((windowClients) => {
let clientIsFocused = false;
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
if (windowClient.focused) {
clientIsFocused = true;
break;
}
}
return clientIsFocused;
});
}
// ╔═══╦══════════════════════════════════════════════════════════════════════════╗
// ║ § ║ Finds a client tag with the same URL host as the defined parameter ║
// ╚═══╩══════════════════════════════════════════════════════════════════════════╝
async function findClientHost(host, useHostName) {
return clients.matchAll({ type: 'window', frameType: 'top-level', includeUncontrolled: true })
.then((windowClients) => {
let clientFound = undefined;
for (let i = 0; i < windowClients.length; i++) {
const windowClient = windowClients[i];
var found = (!useHostName ?
new URL(windowClient.url).host :
new URL(windowClient.url).hostname) == host;
if (found) { clientFound = windowClient; break; }
}
return clientFound;
});
}
// ╔═══╦══════════════════════════════════════════════════════════════════════════╗
// ║ § ║ Build the notification message to broadcast ║
// ╚═══╩══════════════════════════════════════════════════════════════════════════╝
function BuildNotificationMessage(data) {
const options = data.VisualMessage;
var res = {
data: options,
tag: options.Group,
icon: options.Icon,
badge: options.Badge,
image: options.Image,
body: options.Message,
message: options.Message,
requireInteraction: options.RequireInteraction
};
if (options.Actions && options.Actions.length > 0) {
res.actions = options.Actions.map(function (item) { return { action: item.Name, title: item.Title, icon: item.Icon }; });
}
return res;
}