From 2591cfe8a8a9ceb8ddfb21a342d4c97945cac4b5 Mon Sep 17 00:00:00 2001 From: admin Date: Mon, 4 Aug 2025 12:54:04 -0600 Subject: [PATCH] updated temp user control access and limited data send for temps --- map/app/controllers/locationsController.js | 38 +++++++++ map/app/middleware/rateLimiter.js | 23 +++++- map/app/public/js/location-manager.js | 94 ++++++++++++++++++---- map/app/public/js/main.js | 64 +++++++++++++++ map/app/routes/locations.js | 10 +-- 5 files changed, 207 insertions(+), 22 deletions(-) diff --git a/map/app/controllers/locationsController.js b/map/app/controllers/locationsController.js index db97286..96b1143 100644 --- a/map/app/controllers/locationsController.js +++ b/map/app/controllers/locationsController.js @@ -44,6 +44,44 @@ class LocationsController { logger.info(`Retrieved ${validLocations.length} valid locations out of ${locations.length} total`); + // Check if user is temp user and limit data accordingly + if (req.session?.userType === 'temp') { + // For temp users, return limited data but include necessary fields for functionality + const limitedLocations = validLocations.map(loc => { + const locationId = loc.id || loc.Id || loc.ID || loc._id; + return { + // Include ID with all possible variants for compatibility + id: locationId, + Id: locationId, + ID: locationId, + _id: locationId, + 'Geo-Location': loc['Geo-Location'], + latitude: loc.latitude, + longitude: loc.longitude, + // Include display fields needed for map functionality + 'First Name': loc['First Name'] || '', + 'Last Name': loc['Last Name'] || '', // Include last name for display + 'Support Level': loc['Support Level'], + Address: loc.Address || '', + 'Unit Number': loc['Unit Number'] || '', + Notes: loc.Notes || '', + Sign: loc.Sign, + 'Sign Size': loc['Sign Size'] || '', + // Exclude sensitive fields like Email, Phone + }; + }); + + logger.info(`Returning limited data for temp user: ${limitedLocations.length} locations`); + + return res.json({ + success: true, + count: limitedLocations.length, + total: response.pageInfo?.totalRows || limitedLocations.length, + locations: limitedLocations, + isLimited: true // Flag to indicate limited data + }); + } + res.json({ success: true, count: validLocations.length, diff --git a/map/app/middleware/rateLimiter.js b/map/app/middleware/rateLimiter.js index 6f14e59..a67d2c7 100644 --- a/map/app/middleware/rateLimiter.js +++ b/map/app/middleware/rateLimiter.js @@ -40,8 +40,29 @@ const authLimiter = rateLimit({ skipSuccessfulRequests: true }); +// Temp user rate limiter - much stricter limits +const tempUserLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 10, // Much lower limit for temp users + keyGenerator, + standardHeaders: true, + legacyHeaders: false, + trustProxy: true, + message: 'Too many requests for temporary account. Please contact an administrator for full access.' +}); + +// Conditional rate limiter that applies stricter limits to temp users +const conditionalTempLimiter = (req, res, next) => { + if (req.session?.userType === 'temp') { + return tempUserLimiter(req, res, next); + } + return apiLimiter(req, res, next); +}; + module.exports = { apiLimiter, strictLimiter, - authLimiter + authLimiter, + tempUserLimiter, + conditionalTempLimiter }; \ No newline at end of file diff --git a/map/app/public/js/location-manager.js b/map/app/public/js/location-manager.js index c4d1cea..c9cb5c9 100644 --- a/map/app/public/js/location-manager.js +++ b/map/app/public/js/location-manager.js @@ -29,15 +29,25 @@ let originalIcon = null; export async function loadLocations() { try { + showStatus('Loading locations...', 'info'); + const response = await fetch('/api/locations'); const data = await response.json(); - if (data.success) { - displayLocations(data.locations); - updateLocationCount(data.locations.length); - } else { + if (!data.success) { throw new Error(data.error || 'Failed to load locations'); } + + // Check if data is limited (temp user) + if (data.isLimited && currentUser?.userType === 'temp') { + console.log('Map data loaded'); // Generic message for temp users + } else { + console.log(`Loaded ${data.count} locations from NocoDB`); + } + + displayLocations(data.locations); + updateLocationCount(data.locations.length); + } catch (error) { console.error('Error loading locations:', error); showStatus('Failed to load locations', 'error'); @@ -91,7 +101,12 @@ export function displayLocations(locations) { } }); - console.log(`Displayed ${markers.length} location markers (${locations.length} total locations)`); + // Limit console output for temp users + if (currentUser?.userType === 'temp') { + console.log('Map built successfully'); + } else { + console.log(`Displayed ${markers.length} location markers (${locations.length} total locations)`); + } } function createLocationMarker(location) { @@ -211,7 +226,10 @@ function createLocationMarker(location) { marker.bindPopup(popupContent); marker._locationData = location; - console.log(`Created marker at ${lat}, ${lng} with color ${markerColor}`); + // Only log marker creation for non-temp users + if (currentUser?.userType !== 'temp') { + console.log(`Created marker at ${lat}, ${lng} with color ${markerColor}`); + } return marker; } @@ -219,14 +237,45 @@ function createLocationMarker(location) { function createPopupContent(location) { const locationId = location.Id || location.id || location.ID || location._id; + // If current user is temp, show limited information but allow editing + if (currentUser?.userType === 'temp') { + const name = [location['First Name'], location['Last Name']] + .filter(Boolean).join(' ') || 'Unknown'; + const address = location.Address || 'No address'; + const supportLevel = location['Support Level'] ? + `Level ${location['Support Level']}` : 'Not specified'; + + return ` + + `; + } + + // Full information for regular users and admins const name = [location['First Name'], location['Last Name']] .filter(Boolean).join(' ') || 'Unknown'; const address = location.Address || 'No address'; const supportLevel = location['Support Level'] ? `Level ${location['Support Level']}` : 'Not specified'; - // Add debugging - console.log('Creating popup for location:', locationId, location); + // Add debugging only for non-temp users + if (currentUser?.userType !== 'temp') { + console.log('Creating popup for location:', locationId, location); + } return ` ` : ''} diff --git a/map/app/public/js/main.js b/map/app/public/js/main.js index ee218e1..43adcf3 100644 --- a/map/app/public/js/main.js +++ b/map/app/public/js/main.js @@ -30,6 +30,9 @@ document.addEventListener('DOMContentLoaded', async () => { // First check authentication await checkAuth(); + // Setup temp user security measures after authentication + setupTempUserSecurity(); + // Then initialize the map await initializeMap(); @@ -99,3 +102,64 @@ async function initializeUnifiedSearch() { console.error('Error setting up unified search:', error); } } + +// Setup security measures for temp users +function setupTempUserSecurity() { + // Import currentUser from auth module + import('./auth.js').then(authModule => { + const { currentUser } = authModule; + + if (currentUser?.userType === 'temp') { + console.log('Applying temp user security measures...'); + + // Disable right-click context menu + document.addEventListener('contextmenu', (e) => { + e.preventDefault(); + return false; + }); + + // Basic developer tools detection + const devtools = { open: false }; + let devtoolsTimer = setInterval(() => { + // Detect if developer tools are open by checking window dimensions + if (window.outerHeight - window.innerHeight > 200 || + window.outerWidth - window.innerWidth > 200) { + if (!devtools.open) { + console.clear(); + console.log('Access to developer tools is restricted for temporary accounts.'); + console.log('Please contact an administrator for full access.'); + } + devtools.open = true; + } else { + devtools.open = false; + } + }, 1000); + + // Clear interval on page unload + window.addEventListener('beforeunload', () => { + if (devtoolsTimer) { + clearInterval(devtoolsTimer); + } + }); + + // Disable common keyboard shortcuts for developer tools + document.addEventListener('keydown', (e) => { + // F12 + if (e.keyCode === 123) { + e.preventDefault(); + return false; + } + // Ctrl+Shift+I, Ctrl+Shift+J, Ctrl+U + if (e.ctrlKey && e.shiftKey && (e.keyCode === 73 || e.keyCode === 74)) { + e.preventDefault(); + return false; + } + // Ctrl+U (view source) + if (e.ctrlKey && e.keyCode === 85) { + e.preventDefault(); + return false; + } + }); + } + }); +} diff --git a/map/app/routes/locations.js b/map/app/routes/locations.js index 5e07dea..31a1707 100644 --- a/map/app/routes/locations.js +++ b/map/app/routes/locations.js @@ -1,14 +1,14 @@ const express = require('express'); const router = express.Router(); const locationsController = require('../controllers/locationsController'); -const { strictLimiter } = require('../middleware/rateLimiter'); +const { strictLimiter, conditionalTempLimiter } = require('../middleware/rateLimiter'); const { requireAuth, requireDeletePermission } = require('../middleware/auth'); -// Get all locations (public) -router.get('/', locationsController.getAll); +// Get all locations (apply stricter rate limiting for temp users) +router.get('/', conditionalTempLimiter, locationsController.getAll); -// Get single location (public) -router.get('/:id', locationsController.getById); +// Get single location (apply stricter rate limiting for temp users) +router.get('/:id', conditionalTempLimiter, locationsController.getById); // Create location (requires authentication) router.post('/', requireAuth, strictLimiter, locationsController.create);