diff --git a/source-code/mmria/mmria-server/Views/Shared/_LayoutBase.cshtml b/source-code/mmria/mmria-server/Views/Shared/_LayoutBase.cshtml
index 7c6a02080..ba06923ce 100644
--- a/source-code/mmria/mmria-server/Views/Shared/_LayoutBase.cshtml
+++ b/source-code/mmria/mmria-server/Views/Shared/_LayoutBase.cshtml
@@ -79,6 +79,7 @@ if (top !== self) top.location.replace(self.location.href);
@if(ViewBag.is_offline_mode_enabled == true){
+
}
diff --git a/source-code/mmria/mmria-server/wwwroot/scripts/offline/offline-session-validator.js b/source-code/mmria/mmria-server/wwwroot/scripts/offline/offline-session-validator.js
index ce240b1d0..424e01c02 100644
--- a/source-code/mmria/mmria-server/wwwroot/scripts/offline/offline-session-validator.js
+++ b/source-code/mmria/mmria-server/wwwroot/scripts/offline/offline-session-validator.js
@@ -82,11 +82,154 @@ function is_offline_mode() {
}
// Expose the offline session validator API to the global scope
+// Helper function to get session data for validation
+async function getSessionDataForValidation() {
+ // Try service worker first
+ if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
+ try {
+ const sessionData = await requestSessionDataFromServiceWorker();
+ if (sessionData) {
+ return sessionData;
+ }
+ } catch (error) {
+ console.warn('Failed to get session data from service worker:', error);
+ }
+ }
+
+ // Fallback to global variable
+ if (window.mmria_offline_session_data) {
+ return window.mmria_offline_session_data;
+ }
+
+ // Last resort: localStorage
+ try {
+ const storedData = localStorage.getItem('mmria_offline_session');
+ if (storedData) {
+ return JSON.parse(storedData);
+ }
+ } catch (error) {
+ console.warn('localStorage not available for session data:', error);
+ }
+
+ return null;
+}
+
+/**
+ * Validates the current offline session
+ * @returns {boolean} - Whether the offline session is valid
+ */
+function validateOfflineSession() {
+ try {
+ const sessionData = localStorage.getItem('mmria_offline_session');
+ if (!sessionData) return false;
+
+ const session = JSON.parse(sessionData);
+ return session && session.user_id;
+ } catch (error) {
+ console.error('Error validating offline session:', error);
+ return false;
+ }
+}
+
+/**
+ * Clears offline session state but preserves session data for re-login
+ */
+function clearOfflineSessionData() {
+ localStorage.setItem('has_active_offline_session', 'false');
+
+ // Clear all case data from localStorage for security
+ try {
+ const keysToRemove = [];
+ for (let i = 0; i < localStorage.length; i++) {
+ const key = localStorage.key(i);
+ if (key && key.startsWith('case_')) {
+ keysToRemove.push(key);
+ }
+ }
+
+ // Remove all case-related keys
+ keysToRemove.forEach(key => {
+ localStorage.removeItem(key);
+ });
+
+ // Clear the case index as well
+ localStorage.removeItem('case_index');
+
+ console.log(`Cleared ${keysToRemove.length} case data items from localStorage on logout`);
+ } catch (error) {
+ console.error('Error clearing case data on logout:', error);
+ }
+
+ // Notify service worker of status change
+ if (window.ServiceWorkerManager) {
+ window.ServiceWorkerManager.notifyActiveOfflineSessionChange();
+ }
+}
+
+/**
+ * Logs offline events for audit purposes
+ * @param {string} action - The action being performed
+ * @param {string} message - Description of the action
+ */
+function logOfflineEvent(action, message) {
+ try {
+ const events = JSON.parse(localStorage.getItem('offline_audit_log') || '[]');
+ const sessionData = JSON.parse(localStorage.getItem('mmria_offline_session') || '{}');
+
+ events.push({
+ action,
+ message,
+ timestamp: new Date().toISOString(),
+ user: sessionData.user_id || 'unknown',
+ sessionId: localStorage.getItem('offline_session_id') || 'unknown'
+ });
+
+ // Keep only last 100 events to prevent localStorage overflow
+ if (events.length > 100) {
+ events.splice(0, events.length - 100);
+ }
+
+ localStorage.setItem('offline_audit_log', JSON.stringify(events));
+ } catch (error) {
+ console.error('Error logging offline event:', error);
+ }
+}
+
+/**
+ * Checks if user has a valid offline session and redirects to login if not
+ * Should be called on page load for protected routes
+ */
+function checkOfflineSessionAndRedirect() {
+ const isOfflineMode = localStorage.getItem('is_offline') === 'true';
+ const hasActiveSession = localStorage.getItem('has_active_offline_session') === 'true';
+
+ if (isOfflineMode && !hasActiveSession) {
+ console.log('Session validation failed: No active offline session, redirecting to offline login');
+
+ // Log the event for audit purposes
+ logOfflineEvent('session_invalid', 'User attempted to access protected route without valid session');
+
+ // Clear any potentially stale data
+ clearOfflineSessionData();
+
+ // Redirect to offline login
+ window.location.href = '/Account/OfflineLogin';
+ return false; // Session invalid
+ }
+
+ return true; // Session valid or not in offline mode
+}
+
window.OfflineSessionValidator = {
validateKey: validate_offline_key,
getSessionData: get_offline_session_data,
validateKeyAgainstSession: validate_offline_key_against_session,
- isOfflineMode: is_offline_mode
+ isOfflineMode: is_offline_mode,
+ getSessionDataForValidation: getSessionDataForValidation,
+ validateOfflineSession: validateOfflineSession,
+ clearOfflineSessionData: clearOfflineSessionData,
+ logOfflineEvent: logOfflineEvent,
+ checkOfflineSessionAndRedirect: checkOfflineSessionAndRedirect
};
console.log('Offline Session Validator module loaded');
diff --git a/source-code/mmria/mmria-server/wwwroot/scripts/shared/logout-handler.js b/source-code/mmria/mmria-server/wwwroot/scripts/shared/logout-handler.js
index 9c80276be..0d168fa46 100644
--- a/source-code/mmria/mmria-server/wwwroot/scripts/shared/logout-handler.js
+++ b/source-code/mmria/mmria-server/wwwroot/scripts/shared/logout-handler.js
@@ -15,7 +15,7 @@ async function encryptCasesOnOfflineLogout(enteredKey) {
return;
}
- const sessionData = await getSessionDataForValidation();
+ const sessionData = await window.OfflineSessionValidator.getSessionDataForValidation();
if (!sessionData || !sessionData.keySalt) return;
// Send password to service worker to derive and set key
@@ -39,38 +39,6 @@ async function encryptCasesOnOfflineLogout(enteredKey) {
}
}
-// Helper function to get session data for validation
-async function getSessionDataForValidation() {
- // Try service worker first
- if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
- try {
- const sessionData = await requestSessionDataFromServiceWorker();
- if (sessionData) {
- return sessionData;
- }
- } catch (error) {
- console.warn('Failed to get session data from service worker:', error);
- }
- }
-
- // Fallback to global variable
- if (window.mmria_offline_session_data) {
- return window.mmria_offline_session_data;
- }
-
- // Last resort: localStorage
- try {
- const storedData = localStorage.getItem('mmria_offline_session');
- if (storedData) {
- return JSON.parse(storedData);
- }
- } catch (error) {
- console.warn('localStorage not available for session data:', error);
- }
-
- return null;
-}
-
async function handleLogout(event) {
const isOffline = localStorage.getItem('is_offline') === 'true';
@@ -79,9 +47,9 @@ async function handleLogout(event) {
event.preventDefault();
// Validate offline session before logout
- if (validateOfflineSession()) {
+ if (window.OfflineSessionValidator.validateOfflineSession()) {
// Log the logout event for audit purposes
- logOfflineEvent('logout', 'User logged out in offline mode');
+ window.OfflineSessionValidator.logOfflineEvent('logout', 'User logged out in offline mode');
// Show a brief message before redirecting
//showLogoutMessage('Logging out of offline mode...');
@@ -91,7 +59,7 @@ async function handleLogout(event) {
//await encryptCasesOnOfflineLogout("sssDDDkkk@@@2d");
// Clear all offline data securely
- await clearOfflineSessionData();
+ await window.OfflineSessionValidator.clearOfflineSessionData();
// Small delay to show message, then redirect
setTimeout(() => {
@@ -105,87 +73,6 @@ async function handleLogout(event) {
return true;
}
-/**
- * Validates the current offline session
- * @returns {boolean} - Whether the offline session is valid
- */
-function validateOfflineSession() {
- try {
- const sessionData = localStorage.getItem('mmria_offline_session');
- if (!sessionData) return false;
-
- const session = JSON.parse(sessionData);
- return session && session.user_id;
- } catch (error) {
- console.error('Error validating offline session:', error);
- return false;
- }
-}
-
-/**
- * Clears offline session state but preserves session data for re-login
- */
-function clearOfflineSessionData() {
- localStorage.setItem('has_active_offline_session', 'false');
-
- // Clear all case data from localStorage for security
- try {
- const keysToRemove = [];
- for (let i = 0; i < localStorage.length; i++) {
- const key = localStorage.key(i);
- if (key && key.startsWith('case_')) {
- keysToRemove.push(key);
- }
- }
-
- // Remove all case-related keys
- keysToRemove.forEach(key => {
- localStorage.removeItem(key);
- });
-
- // Clear the case index as well
- localStorage.removeItem('case_index');
-
- console.log(`Cleared ${keysToRemove.length} case data items from localStorage on logout`);
- } catch (error) {
- console.error('Error clearing case data on logout:', error);
- }
-
- // Notify service worker of status change
- if (window.ServiceWorkerManager) {
- window.ServiceWorkerManager.notifyActiveOfflineSessionChange();
- }
-}
-
-/**
- * Logs offline events for audit purposes
- * @param {string} action - The action being performed
- * @param {string} message - Description of the action
- */
-function logOfflineEvent(action, message) {
- try {
- const events = JSON.parse(localStorage.getItem('offline_audit_log') || '[]');
- const sessionData = JSON.parse(localStorage.getItem('mmria_offline_session') || '{}');
-
- events.push({
- action,
- message,
- timestamp: new Date().toISOString(),
- user: sessionData.user_id || 'unknown',
- sessionId: localStorage.getItem('offline_session_id') || 'unknown'
- });
-
- // Keep only last 100 events to prevent localStorage bloat
- if (events.length > 100) {
- events.splice(0, events.length - 100);
- }
-
- localStorage.setItem('offline_audit_log', JSON.stringify(events));
- } catch (error) {
- console.error('Error logging offline event:', error);
- }
-}
-
/**
* Shows a logout message to the user
* @param {string} message - Message to display
@@ -215,31 +102,6 @@ function showLogoutMessage(message) {
}, 3000);
}
-/**
- * Checks if user has a valid offline session and redirects to login if not
- * Should be called on page load for protected routes
- */
-function checkOfflineSessionAndRedirect() {
- const isOfflineMode = localStorage.getItem('is_offline') === 'true';
- const hasActiveSession = localStorage.getItem('has_active_offline_session') === 'true';
-
- if (isOfflineMode && !hasActiveSession) {
- console.log('Session validation failed: No active offline session, redirecting to offline login');
-
- // Log the event for audit purposes
- logOfflineEvent('session_invalid', 'User attempted to access protected route without valid session');
-
- // Clear any potentially stale data
- clearOfflineSessionData();
-
- // Redirect to offline login
- window.location.href = '/Account/OfflineLogin';
- return false; // Session invalid
- }
-
- return true; // Session valid or not in offline mode
-}
-
/**
* Initialize logout handlers and session validation when DOM is ready
* This provides an alternative to inline onsubmit handlers
@@ -261,12 +123,12 @@ document.addEventListener('DOMContentLoaded', function() {
const currentPath = window.location.pathname.toLowerCase();
if (currentPath.includes('/case') || currentPath.includes('/home')) {
console.log('Protected route detected, validating offline session...');
- checkOfflineSessionAndRedirect();
+ window.OfflineSessionValidator.checkOfflineSessionAndRedirect();
}
});
// Make functions globally available
window.handleLogout = handleLogout;
-window.clearOfflineSessionData = clearOfflineSessionData;
-window.validateOfflineSession = validateOfflineSession;
-window.checkOfflineSessionAndRedirect = checkOfflineSessionAndRedirect;
\ No newline at end of file
+window.clearOfflineSessionData = window.OfflineSessionValidator.clearOfflineSessionData;
+window.validateOfflineSession = window.OfflineSessionValidator.validateOfflineSession;
+window.checkOfflineSessionAndRedirect = window.OfflineSessionValidator.checkOfflineSessionAndRedirect;
\ No newline at end of file