Bunch of updates for temp users and logging securely.
This commit is contained in:
parent
3b88eef397
commit
960bd39e21
@ -215,7 +215,7 @@ The build script automatically creates the following table structure:
|
|||||||
- `Password` (Single Line Text): User password (required)
|
- `Password` (Single Line Text): User password (required)
|
||||||
- `Name` (Single Line Text): User display name
|
- `Name` (Single Line Text): User display name
|
||||||
- `Admin` (Checkbox): Admin privileges
|
- `Admin` (Checkbox): Admin privileges
|
||||||
- `UserType` (Single Select): Options: "user" (Blue), "temp" (Orange) - User role type
|
- `UserType` or `User Type` (Single Select): Options: "user" (Blue), "temp" (Orange) - User role type
|
||||||
- `ExpiresAt` (DateTime): Expiration date for temporary users
|
- `ExpiresAt` (DateTime): Expiration date for temporary users
|
||||||
- `ExpireDays` (Number): Number of days until temp user expires
|
- `ExpireDays` (Number): Number of days until temp user expires
|
||||||
- `Created At` (DateTime): Account creation timestamp
|
- `Created At` (DateTime): Account creation timestamp
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class AuthController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if temp user has expired
|
// Check if temp user has expired
|
||||||
const userType = user.UserType || user.userType || 'user';
|
const userType = user['User Type'] || user.UserType || user.userType || 'user';
|
||||||
if (userType === 'temp') {
|
if (userType === 'temp') {
|
||||||
const expiration = user.ExpiresAt || user.expiresAt || user.Expiration || user.expiration;
|
const expiration = user.ExpiresAt || user.expiresAt || user.Expiration || user.expiration;
|
||||||
if (expiration) {
|
if (expiration) {
|
||||||
@ -91,11 +91,23 @@ class AuthController {
|
|||||||
req.session.userEmail = user.email || user.Email; // Make sure this is set
|
req.session.userEmail = user.email || user.Email; // Make sure this is set
|
||||||
req.session.userName = user.name || user.Name;
|
req.session.userName = user.name || user.Name;
|
||||||
req.session.isAdmin = user.admin || user.Admin || false;
|
req.session.isAdmin = user.admin || user.Admin || false;
|
||||||
req.session.userType = user.UserType || user.userType || (req.session.isAdmin ? 'admin' : 'user');
|
|
||||||
|
|
||||||
logger.info('User logged in:', {
|
// More explicit userType determination with proper fallback - handle both field name variations
|
||||||
email: req.session.userEmail,
|
let sessionUserType = 'user'; // default
|
||||||
admin: req.session.isAdmin
|
if (user['User Type']) {
|
||||||
|
sessionUserType = user['User Type'].toLowerCase();
|
||||||
|
} else if (user.UserType) {
|
||||||
|
sessionUserType = user.UserType.toLowerCase();
|
||||||
|
} else if (user.userType) {
|
||||||
|
sessionUserType = user.userType.toLowerCase();
|
||||||
|
} else if (req.session.isAdmin) {
|
||||||
|
sessionUserType = 'admin';
|
||||||
|
}
|
||||||
|
|
||||||
|
req.session.userType = sessionUserType;
|
||||||
|
|
||||||
|
logger.info('User logged in successfully', {
|
||||||
|
userType: req.session.userType
|
||||||
});
|
});
|
||||||
|
|
||||||
// Force session save
|
// Force session save
|
||||||
|
|||||||
@ -334,6 +334,14 @@ class LocationsController {
|
|||||||
|
|
||||||
async delete(req, res) {
|
async delete(req, res) {
|
||||||
try {
|
try {
|
||||||
|
// Check if user is temp and deny delete
|
||||||
|
if (req.session?.userType === 'temp') {
|
||||||
|
return res.status(403).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Temporary users cannot delete locations'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const locationId = req.params.id;
|
const locationId = req.params.id;
|
||||||
|
|
||||||
// Validate ID
|
// Validate ID
|
||||||
|
|||||||
@ -100,6 +100,7 @@ class UsersController {
|
|||||||
name: name || '',
|
name: name || '',
|
||||||
Admin: isAdmin === true,
|
Admin: isAdmin === true,
|
||||||
admin: isAdmin === true,
|
admin: isAdmin === true,
|
||||||
|
'User Type': userType || 'user', // Handle space in field name
|
||||||
UserType: userType || 'user',
|
UserType: userType || 'user',
|
||||||
userType: userType || 'user',
|
userType: userType || 'user',
|
||||||
CreatedAt: new Date().toISOString(),
|
CreatedAt: new Date().toISOString(),
|
||||||
@ -121,6 +122,7 @@ class UsersController {
|
|||||||
Email: email,
|
Email: email,
|
||||||
Name: name,
|
Name: name,
|
||||||
Admin: isAdmin,
|
Admin: isAdmin,
|
||||||
|
'User Type': userType, // Handle space in field name
|
||||||
UserType: userType,
|
UserType: userType,
|
||||||
'Created At': new Date().toISOString(),
|
'Created At': new Date().toISOString(),
|
||||||
ExpiresAt: expiresAt
|
ExpiresAt: expiresAt
|
||||||
|
|||||||
@ -28,4 +28,30 @@ a.temp-restricted,
|
|||||||
body.temp-user a[href="/shifts.html"],
|
body.temp-user a[href="/shifts.html"],
|
||||||
body.temp-user .mobile-dropdown-item a[href="/shifts.html"] {
|
body.temp-user .mobile-dropdown-item a[href="/shifts.html"] {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide delete button for temp users - MOST AGGRESSIVE RULES */
|
||||||
|
body.temp-user #delete-location-btn,
|
||||||
|
body.temp-user .delete-location-btn,
|
||||||
|
body.temp-user .btn-danger[id*="delete"],
|
||||||
|
body.temp-user button[id*="delete"],
|
||||||
|
body.temp-user .form-actions .btn-danger,
|
||||||
|
body.temp-user .form-actions button[type="button"].btn-danger,
|
||||||
|
.temp-hidden,
|
||||||
|
[hidden] {
|
||||||
|
display: none !important;
|
||||||
|
visibility: hidden !important;
|
||||||
|
opacity: 0 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
position: absolute !important;
|
||||||
|
left: -9999px !important;
|
||||||
|
width: 0 !important;
|
||||||
|
height: 0 !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide move location button for temp users */
|
||||||
|
body.temp-user .move-location-btn,
|
||||||
|
body.temp-user #move-location-btn {
|
||||||
|
display: none !important;
|
||||||
}
|
}
|
||||||
@ -431,7 +431,7 @@
|
|||||||
<div class="spinner"></div>
|
<div class="spinner"></div>
|
||||||
<p>Authenticating...</p>
|
<p>Authenticating...</p>
|
||||||
<p class="loading-patience-message">
|
<p class="loading-patience-message">
|
||||||
Loading map for the first time can take several seconds, even up to a minute. Please be patient.
|
Loading map can take several seconds, even up to a minute. Please be patient.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -25,6 +25,27 @@ export async function checkAuth() {
|
|||||||
currentUser = data.user;
|
currentUser = data.user;
|
||||||
currentUser.userType = data.user.userType || 'user'; // Ensure userType is set
|
currentUser.userType = data.user.userType || 'user'; // Ensure userType is set
|
||||||
|
|
||||||
|
// IMMEDIATE console blocking for all non-admin users - before any other code runs
|
||||||
|
if (currentUser.userType !== 'admin') {
|
||||||
|
const noop = () => {};
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log = noop;
|
||||||
|
console.debug = noop;
|
||||||
|
console.info = noop;
|
||||||
|
console.warn = noop;
|
||||||
|
console.error = noop;
|
||||||
|
console.trace = noop;
|
||||||
|
console.dir = noop;
|
||||||
|
console.dirxml = noop;
|
||||||
|
console.group = noop;
|
||||||
|
console.groupEnd = noop;
|
||||||
|
console.time = noop;
|
||||||
|
console.timeEnd = noop;
|
||||||
|
console.assert = noop;
|
||||||
|
console.profile = noop;
|
||||||
|
}, 1000); // Give 1 second for initialization logs, then block
|
||||||
|
}
|
||||||
|
|
||||||
// Authentication successful - show the app
|
// Authentication successful - show the app
|
||||||
document.body.classList.remove('authenticating');
|
document.body.classList.remove('authenticating');
|
||||||
document.body.classList.add('authenticated');
|
document.body.classList.add('authenticated');
|
||||||
@ -43,9 +64,19 @@ export async function checkAuth() {
|
|||||||
export function updateUserInterface() {
|
export function updateUserInterface() {
|
||||||
if (!currentUser) return;
|
if (!currentUser) return;
|
||||||
|
|
||||||
/* NEW – add a body class we can target with CSS */
|
// CRITICAL: Add body class for temp users FIRST
|
||||||
document.body.classList.toggle('temp-user', currentUser.userType === 'temp');
|
if (currentUser.userType === 'temp') {
|
||||||
document.body.classList.toggle('admin-user', currentUser.isAdmin === true);
|
document.body.classList.add('temp-user');
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove('temp-user');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also add admin class for consistency
|
||||||
|
if (currentUser.isAdmin === true) {
|
||||||
|
document.body.classList.add('admin-user');
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove('admin-user');
|
||||||
|
}
|
||||||
|
|
||||||
// ----- existing code that manipulates DOM -----
|
// ----- existing code that manipulates DOM -----
|
||||||
// Update user email in both desktop and mobile
|
// Update user email in both desktop and mobile
|
||||||
@ -119,6 +150,21 @@ export function updateUserInterface() {
|
|||||||
if (currentUser.isAdmin) {
|
if (currentUser.isAdmin) {
|
||||||
addAdminLinks();
|
addAdminLinks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CRITICAL: Final check to hide delete buttons for temp users
|
||||||
|
if (currentUser.userType === 'temp') {
|
||||||
|
// Use setTimeout to ensure this runs after all other DOM operations
|
||||||
|
setTimeout(() => {
|
||||||
|
const deleteButtons = document.querySelectorAll('#delete-location-btn, .delete-location-btn, .btn-danger[id*="delete"]');
|
||||||
|
deleteButtons.forEach(btn => {
|
||||||
|
btn.style.display = 'none';
|
||||||
|
btn.style.visibility = 'hidden';
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.classList.add('temp-hidden');
|
||||||
|
btn.setAttribute('hidden', 'true');
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAdminLinks() {
|
function addAdminLinks() {
|
||||||
|
|||||||
@ -413,13 +413,26 @@ export function openEditForm(location) {
|
|||||||
document.getElementById('edit-location-lng').value = location.longitude || '';
|
document.getElementById('edit-location-lng').value = location.longitude || '';
|
||||||
document.getElementById('edit-geo-location').value = location['Geo-Location'] || '';
|
document.getElementById('edit-geo-location').value = location['Geo-Location'] || '';
|
||||||
|
|
||||||
// Show/hide delete button based on user type
|
// Hide delete button for temp users - use multiple approaches
|
||||||
const deleteBtn = document.getElementById('delete-location-btn');
|
const deleteBtn = document.getElementById('delete-location-btn');
|
||||||
if (deleteBtn) {
|
if (deleteBtn) {
|
||||||
if (currentUser?.userType === 'temp') {
|
// Check both currentUser and body class to ensure restriction
|
||||||
|
const isTemp = currentUser?.userType === 'temp' || document.body.classList.contains('temp-user');
|
||||||
|
|
||||||
|
if (isTemp) {
|
||||||
deleteBtn.style.display = 'none';
|
deleteBtn.style.display = 'none';
|
||||||
|
deleteBtn.style.visibility = 'hidden';
|
||||||
|
deleteBtn.disabled = true;
|
||||||
|
deleteBtn.classList.add('temp-hidden');
|
||||||
|
deleteBtn.setAttribute('hidden', 'true');
|
||||||
|
// Remove the button from DOM completely for temp users
|
||||||
|
deleteBtn.remove();
|
||||||
} else {
|
} else {
|
||||||
deleteBtn.style.display = '';
|
deleteBtn.style.display = 'inline-block';
|
||||||
|
deleteBtn.style.visibility = 'visible';
|
||||||
|
deleteBtn.disabled = false;
|
||||||
|
deleteBtn.classList.remove('temp-hidden');
|
||||||
|
deleteBtn.removeAttribute('hidden');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,8 +37,8 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
|
|
||||||
console.log('Authentication confirmed, initializing application...');
|
console.log('Authentication confirmed, initializing application...');
|
||||||
|
|
||||||
// Setup temp user security measures after authentication
|
// Setup temp user security measures immediately after authentication
|
||||||
setupTempUserSecurity();
|
await setupUserSecurity();
|
||||||
|
|
||||||
// Then initialize the map
|
// Then initialize the map
|
||||||
updateLoadingMessage('Initializing map...');
|
updateLoadingMessage('Initializing map...');
|
||||||
@ -177,63 +177,55 @@ async function initializeUnifiedSearch() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup security measures for temp users
|
// Setup security measures for non-admin users
|
||||||
function setupTempUserSecurity() {
|
async function setupUserSecurity() {
|
||||||
// Import currentUser from auth module
|
// Import currentUser from auth module
|
||||||
import('./auth.js').then(authModule => {
|
const { currentUser } = await import('./auth.js');
|
||||||
const { currentUser } = authModule;
|
|
||||||
|
if (currentUser?.userType !== 'admin') {
|
||||||
|
// Override console methods for all non-admin users
|
||||||
|
const noop = () => {};
|
||||||
|
console.log = noop;
|
||||||
|
console.debug = noop;
|
||||||
|
console.info = noop;
|
||||||
|
console.warn = noop;
|
||||||
|
console.error = noop;
|
||||||
|
console.trace = noop;
|
||||||
|
console.dir = noop;
|
||||||
|
console.dirxml = noop;
|
||||||
|
console.group = noop;
|
||||||
|
console.groupEnd = noop;
|
||||||
|
console.time = noop;
|
||||||
|
console.timeEnd = noop;
|
||||||
|
console.assert = noop;
|
||||||
|
console.profile = noop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional temp user specific restrictions
|
||||||
|
if (currentUser?.userType === 'temp') {
|
||||||
|
// Disable right-click context menu
|
||||||
|
document.addEventListener('contextmenu', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
if (currentUser?.userType === 'temp') {
|
// Disable common keyboard shortcuts for developer tools
|
||||||
console.log('Applying temp user security measures...');
|
document.addEventListener('keydown', (e) => {
|
||||||
|
// F12
|
||||||
// Disable right-click context menu
|
if (e.keyCode === 123) {
|
||||||
document.addEventListener('contextmenu', (e) => {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
});
|
}
|
||||||
|
// Ctrl+Shift+I, Ctrl+Shift+J, Ctrl+U
|
||||||
// Basic developer tools detection
|
if (e.ctrlKey && e.shiftKey && (e.keyCode === 73 || e.keyCode === 74)) {
|
||||||
const devtools = { open: false };
|
e.preventDefault();
|
||||||
let devtoolsTimer = setInterval(() => {
|
return false;
|
||||||
// Detect if developer tools are open by checking window dimensions
|
}
|
||||||
if (window.outerHeight - window.innerHeight > 200 ||
|
// Ctrl+U (view source)
|
||||||
window.outerWidth - window.innerWidth > 200) {
|
if (e.ctrlKey && e.keyCode === 85) {
|
||||||
if (!devtools.open) {
|
e.preventDefault();
|
||||||
console.clear();
|
return false;
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user