Harden client and WebSocket proxy

This commit is contained in:
2026-09-09 13:04:56 +02:00
parent f4f95ffff4
commit 8986f6270f
64 changed files with 4410 additions and 7313 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

-59
View File
@@ -1,59 +0,0 @@
{
"name": "SvelteMUD Client",
"short_name": "SvelteMUD",
"description": "A modern MUD client built with Svelte",
"start_url": "/",
"display": "standalone",
"background_color": "#282a36",
"theme_color": "#6272a4",
"icons": [
{
"src": "icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}
-35
View File
@@ -1,35 +0,0 @@
// Check if service workers are supported
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker registered with scope:', registration.scope);
// Check for updates to the Service Worker
registration.addEventListener('updatefound', () => {
const newWorker = registration.installing;
console.log('Service Worker update found!');
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// New content is available, notify user
console.log('New version available! Reload to update.');
// Optionally, display a notification to the user
if (window.confirm('A new version of this app is available. Reload to update?')) {
window.location.reload();
}
} else {
// First time install
console.log('App is now available offline!');
}
}
});
});
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
});
}
-98
View File
@@ -1,98 +0,0 @@
// Service worker for SvelteMUD Client PWA
const CACHE_NAME = 'svelte-mud-v1';
const ASSETS_TO_CACHE = [
'/',
'/index.html',
'/manifest.json',
'/favicon.ico',
'/global.css',
'/build/bundle.css',
'/build/bundle.js'
];
// Install event - cache critical assets
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => {
return cache.addAll(ASSETS_TO_CACHE);
})
.then(() => {
return self.skipWaiting();
})
);
});
// Activate event - clean up old caches
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
}).then(() => {
return self.clients.claim();
})
);
});
// Fetch event - serve from cache if available, otherwise fetch from network
self.addEventListener('fetch', (event) => {
// Skip cross-origin requests
if (!event.request.url.startsWith(self.location.origin) ||
event.request.method !== 'GET') {
return;
}
// For navigation requests (HTML pages), use a network-first strategy
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request)
.catch(() => {
return caches.match(event.request);
})
);
return;
}
// For all other requests, use a cache-first strategy
event.respondWith(
caches.match(event.request)
.then((response) => {
if (response) {
return response;
}
// Clone the request because it's a one-time use stream
const fetchRequest = event.request.clone();
return fetch(fetchRequest).then((response) => {
// Check if valid response
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// Clone the response because it's a one-time use stream
const responseToCache = response.clone();
caches.open(CACHE_NAME)
.then((cache) => {
cache.put(event.request, responseToCache);
});
return response;
});
})
);
});
// Listen for messages from clients
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});