enhanced security and optimization
This commit is contained in:
@@ -1,63 +1,121 @@
|
||||
const CACHE_NAME = 'fleet-c2-v2'; // Incrementiamo la versione
|
||||
const urlsToCache = [
|
||||
const CACHE_NAME = 'fleet-c2-v3'; // incrementare a ogni modifica degli asset precaricati
|
||||
const PRECACHE_URLS = [
|
||||
'/',
|
||||
'/manifest.json',
|
||||
'/icon-512.png'
|
||||
];
|
||||
|
||||
// --- 1. GESTIONE CACHE (Il tuo codice originale) ---
|
||||
// --- 1. INSTALL: precache "best effort" -------------------------------------
|
||||
// Se un file manca (es. icona non ancora caricata) l'installazione NON fallisce:
|
||||
// un SW che non si installa significa niente notifiche push.
|
||||
self.addEventListener('install', event => {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME)
|
||||
.then(cache => cache.addAll(urlsToCache))
|
||||
.then(cache => Promise.allSettled(PRECACHE_URLS.map(url => cache.add(url))))
|
||||
.then(() => self.skipWaiting())
|
||||
);
|
||||
});
|
||||
|
||||
// --- 2. ACTIVATE: elimina le cache delle versioni precedenti -----------------
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(
|
||||
caches.keys()
|
||||
.then(keys => Promise.all(keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k))))
|
||||
.then(() => self.clients.claim())
|
||||
);
|
||||
});
|
||||
|
||||
// --- 3. FETCH: network-first, cache come ripiego offline ---------------------
|
||||
// Gestiamo solo le GET della nostra origine. API e WebSocket (socket.io) passano
|
||||
// sempre direttamente dalla rete: i dati della flotta non vanno mai serviti "vecchi".
|
||||
self.addEventListener('fetch', event => {
|
||||
const req = event.request;
|
||||
if (req.method !== 'GET') return;
|
||||
|
||||
const url = new URL(req.url);
|
||||
if (url.origin !== self.location.origin) return;
|
||||
if (url.pathname.startsWith('/api/') ||
|
||||
url.pathname.startsWith('/socket.io/') ||
|
||||
url.pathname === '/sw.js') return;
|
||||
|
||||
event.respondWith(
|
||||
fetch(event.request).catch(() => caches.match(event.request))
|
||||
fetch(req)
|
||||
.then(res => {
|
||||
if (res && res.ok && res.type === 'basic') {
|
||||
const copy = res.clone();
|
||||
caches.open(CACHE_NAME).then(cache => cache.put(req, copy)).catch(() => {});
|
||||
}
|
||||
return res;
|
||||
})
|
||||
.catch(async () => {
|
||||
const cached = await caches.match(req);
|
||||
if (cached) return cached;
|
||||
if (req.mode === 'navigate') {
|
||||
const shell = await caches.match('/');
|
||||
if (shell) return shell;
|
||||
}
|
||||
return new Response('Offline', {
|
||||
status: 503,
|
||||
statusText: 'Offline',
|
||||
headers: { 'Content-Type': 'text/plain; charset=utf-8' }
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// --- 2. GESTIONE NOTIFICHE PUSH (Il nuovo codice) ---
|
||||
self.addEventListener('push', function(event) {
|
||||
console.log('[Service Worker] Notifica Push ricevuta.');
|
||||
// --- 4. NOTIFICHE PUSH -------------------------------------------------------
|
||||
self.addEventListener('push', event => {
|
||||
let data = { title: 'Fleet Alert', body: 'Nuovo messaggio dal sistema.' };
|
||||
|
||||
let data = { title: 'Fleet Alert', body: 'Nuovo messaggio dal sistema.' };
|
||||
if (event.data) {
|
||||
try {
|
||||
data = Object.assign(data, event.data.json());
|
||||
} catch (e) {
|
||||
data.body = event.data.text();
|
||||
}
|
||||
}
|
||||
|
||||
if (event.data) {
|
||||
try {
|
||||
data = event.data.json();
|
||||
} catch (e) {
|
||||
data.body = event.data.text();
|
||||
const options = {
|
||||
body: data.body,
|
||||
icon: '/icon-512.png',
|
||||
badge: '/icon-512.png',
|
||||
vibrate: [200, 100, 200],
|
||||
// Stesso tag = la nuova notifica dello stesso nodo sostituisce la precedente
|
||||
// (invece di accumulare 10 notifiche) e rifà vibrare/suonare.
|
||||
tag: data.tag || 'fleet-alert',
|
||||
renotify: true,
|
||||
data: {
|
||||
dateOfArrival: Date.now(),
|
||||
url: data.url || '/'
|
||||
},
|
||||
actions: [
|
||||
{ action: 'explore', title: 'Apri Dashboard' },
|
||||
{ action: 'close', title: 'Chiudi' }
|
||||
]
|
||||
};
|
||||
|
||||
event.waitUntil(
|
||||
self.registration.showNotification(data.title, options)
|
||||
);
|
||||
});
|
||||
|
||||
// --- 5. CLICK SULLA NOTIFICA -------------------------------------------------
|
||||
// Click sul corpo O su "Apri Dashboard": porta in primo piano la finestra già aperta,
|
||||
// altrimenti ne apre una nuova. "Chiudi" chiude soltanto.
|
||||
self.addEventListener('notificationclick', event => {
|
||||
event.notification.close();
|
||||
if (event.action === 'close') return;
|
||||
|
||||
const target = new URL((event.notification.data && event.notification.data.url) || '/', self.location.origin).href;
|
||||
|
||||
event.waitUntil(
|
||||
clients.matchAll({ type: 'window', includeUncontrolled: true }).then(list => {
|
||||
for (const client of list) {
|
||||
if (new URL(client.url).origin === self.location.origin && 'focus' in client) {
|
||||
return client.focus();
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
body: data.body,
|
||||
icon: '/icon-512.png',
|
||||
badge: '/icon-512.png',
|
||||
vibrate: [200, 100, 200],
|
||||
data: {
|
||||
dateOfArrival: Date.now(),
|
||||
primaryKey: '1'
|
||||
},
|
||||
actions: [
|
||||
{ action: 'explore', title: 'Apri Dashboard' },
|
||||
{ action: 'close', title: 'Chiudi' }
|
||||
]
|
||||
};
|
||||
|
||||
event.waitUntil(
|
||||
self.registration.showNotification(data.title, options)
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('notificationclick', function(event) {
|
||||
event.notification.close();
|
||||
if (event.action === 'explore') {
|
||||
event.waitUntil(
|
||||
clients.openWindow('/')
|
||||
);
|
||||
}
|
||||
}
|
||||
return clients.openWindow(target);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user