updated temp user control access and limited data send for temps
This commit is contained in:
parent
2ebbb2dc44
commit
2591cfe8a8
@ -44,6 +44,44 @@ class LocationsController {
|
|||||||
|
|
||||||
logger.info(`Retrieved ${validLocations.length} valid locations out of ${locations.length} total`);
|
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({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
count: validLocations.length,
|
count: validLocations.length,
|
||||||
|
|||||||
@ -40,8 +40,29 @@ const authLimiter = rateLimit({
|
|||||||
skipSuccessfulRequests: true
|
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 = {
|
module.exports = {
|
||||||
apiLimiter,
|
apiLimiter,
|
||||||
strictLimiter,
|
strictLimiter,
|
||||||
authLimiter
|
authLimiter,
|
||||||
|
tempUserLimiter,
|
||||||
|
conditionalTempLimiter
|
||||||
};
|
};
|
||||||
@ -29,15 +29,25 @@ let originalIcon = null;
|
|||||||
|
|
||||||
export async function loadLocations() {
|
export async function loadLocations() {
|
||||||
try {
|
try {
|
||||||
|
showStatus('Loading locations...', 'info');
|
||||||
|
|
||||||
const response = await fetch('/api/locations');
|
const response = await fetch('/api/locations');
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success) {
|
if (!data.success) {
|
||||||
displayLocations(data.locations);
|
|
||||||
updateLocationCount(data.locations.length);
|
|
||||||
} else {
|
|
||||||
throw new Error(data.error || 'Failed to load locations');
|
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) {
|
} catch (error) {
|
||||||
console.error('Error loading locations:', error);
|
console.error('Error loading locations:', error);
|
||||||
showStatus('Failed to load 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) {
|
function createLocationMarker(location) {
|
||||||
@ -211,7 +226,10 @@ function createLocationMarker(location) {
|
|||||||
marker.bindPopup(popupContent);
|
marker.bindPopup(popupContent);
|
||||||
marker._locationData = location;
|
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;
|
return marker;
|
||||||
}
|
}
|
||||||
@ -219,14 +237,45 @@ function createLocationMarker(location) {
|
|||||||
function createPopupContent(location) {
|
function createPopupContent(location) {
|
||||||
const locationId = location.Id || location.id || location.ID || location._id;
|
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 `
|
||||||
|
<div class="popup-content">
|
||||||
|
<h3>${escapeHtml(name)}</h3>
|
||||||
|
<p><strong>Address:</strong> ${escapeHtml(address)}</p>
|
||||||
|
<p><strong>Support:</strong> ${escapeHtml(supportLevel)}</p>
|
||||||
|
${location.Sign ? '<p>🏁 Has campaign sign</p>' : ''}
|
||||||
|
${location.Notes ? `<p><strong>Notes:</strong> ${escapeHtml(location.Notes)}</p>` : ''}
|
||||||
|
<div class="popup-meta">
|
||||||
|
<p>ID: ${locationId || 'Unknown'}</p>
|
||||||
|
</div>
|
||||||
|
<div class="popup-actions">
|
||||||
|
<button class="btn btn-primary btn-sm edit-location-popup-btn"
|
||||||
|
data-location='${escapeHtml(JSON.stringify(location))}'>
|
||||||
|
✏️ Edit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full information for regular users and admins
|
||||||
const name = [location['First Name'], location['Last Name']]
|
const name = [location['First Name'], location['Last Name']]
|
||||||
.filter(Boolean).join(' ') || 'Unknown';
|
.filter(Boolean).join(' ') || 'Unknown';
|
||||||
const address = location.Address || 'No address';
|
const address = location.Address || 'No address';
|
||||||
const supportLevel = location['Support Level'] ?
|
const supportLevel = location['Support Level'] ?
|
||||||
`Level ${location['Support Level']}` : 'Not specified';
|
`Level ${location['Support Level']}` : 'Not specified';
|
||||||
|
|
||||||
// Add debugging
|
// Add debugging only for non-temp users
|
||||||
console.log('Creating popup for location:', locationId, location);
|
if (currentUser?.userType !== 'temp') {
|
||||||
|
console.log('Creating popup for location:', locationId, location);
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="popup-content">
|
<div class="popup-content">
|
||||||
@ -319,6 +368,11 @@ export function openEditForm(location) {
|
|||||||
// Extract ID - check multiple possible field names
|
// Extract ID - check multiple possible field names
|
||||||
const locationId = location.Id || location.id || location.ID || location._id;
|
const locationId = location.Id || location.id || location.ID || location._id;
|
||||||
|
|
||||||
|
// Add debugging for temp users
|
||||||
|
console.log('Opening edit form for location:', location);
|
||||||
|
console.log('Extracted ID:', locationId);
|
||||||
|
console.log('Available keys:', Object.keys(location));
|
||||||
|
|
||||||
if (!locationId) {
|
if (!locationId) {
|
||||||
console.error('No ID found in location object. Available fields:', Object.keys(location));
|
console.error('No ID found in location object. Available fields:', Object.keys(location));
|
||||||
showStatus('Error: Location ID not found. Check console for details.', 'error');
|
showStatus('Error: Location ID not found. Check console for details.', 'error');
|
||||||
@ -803,7 +857,10 @@ function createMultiUnitMarker(group) {
|
|||||||
setupAppApartmentPopupListeners(group);
|
setupAppApartmentPopupListeners(group);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Created multi-unit marker at ${lat}, ${lng} with ${locations.length} units`);
|
// Only log multi-unit marker creation for non-temp users
|
||||||
|
if (currentUser?.userType !== 'temp') {
|
||||||
|
console.log(`Created multi-unit marker at ${lat}, ${lng} with ${locations.length} units`);
|
||||||
|
}
|
||||||
|
|
||||||
return marker;
|
return marker;
|
||||||
}
|
}
|
||||||
@ -883,8 +940,11 @@ function createUnitDetailsHTML(location, index) {
|
|||||||
const name = [location['First Name'], location['Last Name']].filter(Boolean).join(' ') || 'Unknown';
|
const name = [location['First Name'], location['Last Name']].filter(Boolean).join(' ') || 'Unknown';
|
||||||
const unit = location['Unit Number'] || `Unit ${index + 1}`;
|
const unit = location['Unit Number'] || `Unit ${index + 1}`;
|
||||||
const supportLevel = location['Support Level'] ? `Level ${location['Support Level']}` : 'Not specified';
|
const supportLevel = location['Support Level'] ? `Level ${location['Support Level']}` : 'Not specified';
|
||||||
const email = location.Email || '';
|
|
||||||
const phone = location.Phone || '';
|
// For temp users, hide sensitive contact information
|
||||||
|
const isTemp = currentUser?.userType === 'temp';
|
||||||
|
const email = !isTemp ? (location.Email || '') : '';
|
||||||
|
const phone = !isTemp ? (location.Phone || '') : '';
|
||||||
|
|
||||||
// Truncate long values for mobile
|
// Truncate long values for mobile
|
||||||
const truncatedEmail = email.length > 25 ? email.substring(0, 25) + '...' : email;
|
const truncatedEmail = email.length > 25 ? email.substring(0, 25) + '...' : email;
|
||||||
@ -920,11 +980,13 @@ function createUnitDetailsHTML(location, index) {
|
|||||||
style="background: #a02c8d; border: none; padding: 3px 6px; border-radius: 3px; font-size: 9px; cursor: pointer; flex: 1; min-width: 45%;">
|
style="background: #a02c8d; border: none; padding: 3px 6px; border-radius: 3px; font-size: 9px; cursor: pointer; flex: 1; min-width: 45%;">
|
||||||
✏️ Edit
|
✏️ Edit
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-primary btn-sm move-unit-btn"
|
${currentUser.userType !== 'temp' ? `
|
||||||
data-location='${escapeHtml(JSON.stringify(location))}'
|
<button class="btn btn-primary btn-sm move-unit-btn"
|
||||||
style="background: #6c757d; border: none; padding: 3px 6px; border-radius: 3px; font-size: 9px; cursor: pointer; flex: 1; min-width: 45%;">
|
data-location='${escapeHtml(JSON.stringify(location))}'
|
||||||
📍 Move
|
style="background: #6c757d; border: none; padding: 3px 6px; border-radius: 3px; font-size: 9px; cursor: pointer; flex: 1; min-width: 45%;">
|
||||||
</button>
|
📍 Move
|
||||||
|
</button>
|
||||||
|
` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
|
|||||||
@ -30,6 +30,9 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
// First check authentication
|
// First check authentication
|
||||||
await checkAuth();
|
await checkAuth();
|
||||||
|
|
||||||
|
// Setup temp user security measures after authentication
|
||||||
|
setupTempUserSecurity();
|
||||||
|
|
||||||
// Then initialize the map
|
// Then initialize the map
|
||||||
await initializeMap();
|
await initializeMap();
|
||||||
|
|
||||||
@ -99,3 +102,64 @@ async function initializeUnifiedSearch() {
|
|||||||
console.error('Error setting up unified search:', error);
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const locationsController = require('../controllers/locationsController');
|
const locationsController = require('../controllers/locationsController');
|
||||||
const { strictLimiter } = require('../middleware/rateLimiter');
|
const { strictLimiter, conditionalTempLimiter } = require('../middleware/rateLimiter');
|
||||||
const { requireAuth, requireDeletePermission } = require('../middleware/auth');
|
const { requireAuth, requireDeletePermission } = require('../middleware/auth');
|
||||||
|
|
||||||
// Get all locations (public)
|
// Get all locations (apply stricter rate limiting for temp users)
|
||||||
router.get('/', locationsController.getAll);
|
router.get('/', conditionalTempLimiter, locationsController.getAll);
|
||||||
|
|
||||||
// Get single location (public)
|
// Get single location (apply stricter rate limiting for temp users)
|
||||||
router.get('/:id', locationsController.getById);
|
router.get('/:id', conditionalTempLimiter, locationsController.getById);
|
||||||
|
|
||||||
// Create location (requires authentication)
|
// Create location (requires authentication)
|
||||||
router.post('/', requireAuth, strictLimiter, locationsController.create);
|
router.post('/', requireAuth, strictLimiter, locationsController.create);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user