File auth-module.js of Package PersistenceOS
/**
* PersistenceOS Authentication Module
* Handles user authentication, session management, and security
*
* Depends on: core-utils.js
*/
// =============================================================================
// AUTHENTICATION STATE
// =============================================================================
const authState = {
isAuthenticated: false,
currentUser: null,
token: null,
loginAttempts: 0,
maxLoginAttempts: 5,
lockoutTime: 300000 // 5 minutes
};
// =============================================================================
// AUTHENTICATION FUNCTIONS
// =============================================================================
/**
* Initialize authentication system
*/
function initializeAuth() {
console.log('đ Initializing authentication system...');
// Check for existing authentication
const token = localStorage.getItem('access_token');
const userData = PersistenceCore.getStorageItem('user_data');
const authenticated = localStorage.getItem('authenticated') === 'true';
if (token && userData && authenticated) {
authState.isAuthenticated = true;
authState.currentUser = userData;
authState.token = token;
console.log('â
User already authenticated:', userData.username);
} else {
console.log('âšī¸ No valid authentication found');
clearAuthState();
}
return authState.isAuthenticated;
}
/**
* Perform user login
* @param {string} username - Username
* @param {string} password - Password
* @returns {Promise<boolean>} - Success status
*/
async function login(username, password) {
console.log(`đ Attempting login for user: ${username}`);
// Check for lockout
if (isAccountLocked()) {
const remainingTime = getRemainingLockoutTime();
PersistenceCore.showNotification(
`Account locked. Try again in ${Math.ceil(remainingTime / 60000)} minutes.`,
'error'
);
return false;
}
try {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
});
if (response.ok) {
const data = await response.json();
// Store authentication data
localStorage.setItem('access_token', data.access_token);
localStorage.setItem('authenticated', 'true');
localStorage.setItem('username', username);
PersistenceCore.setStorageItem('user_data', {
username: username,
loginTime: new Date().toISOString(),
permissions: data.permissions || ['read', 'write']
});
// Update auth state
authState.isAuthenticated = true;
authState.currentUser = { username, permissions: data.permissions || ['read', 'write'] };
authState.token = data.access_token;
authState.loginAttempts = 0;
// Clear lockout data
localStorage.removeItem('lockout_time');
localStorage.removeItem('login_attempts');
console.log('â
Login successful');
PersistenceCore.showNotification('Login successful!', 'success');
return true;
} else {
// Handle login failure
authState.loginAttempts++;
localStorage.setItem('login_attempts', authState.loginAttempts.toString());
if (authState.loginAttempts >= authState.maxLoginAttempts) {
const lockoutTime = Date.now() + authState.lockoutTime;
localStorage.setItem('lockout_time', lockoutTime.toString());
PersistenceCore.showNotification(
`Too many failed attempts. Account locked for ${authState.lockoutTime / 60000} minutes.`,
'error'
);
} else {
const remainingAttempts = authState.maxLoginAttempts - authState.loginAttempts;
PersistenceCore.showNotification(
`Invalid credentials. ${remainingAttempts} attempts remaining.`,
'error'
);
}
console.log('â Login failed');
return false;
}
} catch (error) {
console.error('â Login error:', error);
PersistenceCore.showNotification('Login failed: Network error', 'error');
return false;
}
}
/**
* Perform user logout
*/
function logout() {
console.log('đ Logging out user...');
// Clear authentication data
clearAuthState();
// Notify user
PersistenceCore.showNotification('Logged out successfully', 'info');
// Redirect to login page
setTimeout(() => {
window.location.href = '/login.html';
}, 1000);
}
/**
* Clear authentication state
*/
function clearAuthState() {
// Clear localStorage
localStorage.removeItem('access_token');
localStorage.removeItem('user_data');
localStorage.removeItem('authenticated');
localStorage.removeItem('username');
localStorage.removeItem('fallback_auth');
// Clear auth state
authState.isAuthenticated = false;
authState.currentUser = null;
authState.token = null;
}
/**
* Check if account is locked due to failed login attempts
* @returns {boolean}
*/
function isAccountLocked() {
const lockoutTime = localStorage.getItem('lockout_time');
if (!lockoutTime) return false;
const lockoutExpiry = parseInt(lockoutTime);
return Date.now() < lockoutExpiry;
}
/**
* Get remaining lockout time in milliseconds
* @returns {number}
*/
function getRemainingLockoutTime() {
const lockoutTime = localStorage.getItem('lockout_time');
if (!lockoutTime) return 0;
const lockoutExpiry = parseInt(lockoutTime);
return Math.max(0, lockoutExpiry - Date.now());
}
/**
* Check if user has specific permission
* @param {string} permission - Permission to check
* @returns {boolean}
*/
function hasPermission(permission) {
if (!authState.isAuthenticated || !authState.currentUser) {
return false;
}
const permissions = authState.currentUser.permissions || [];
return permissions.includes(permission) || permissions.includes('admin');
}
/**
* Require authentication for function execution
* @param {Function} func - Function to execute if authenticated
* @param {string} requiredPermission - Optional required permission
* @returns {Function}
*/
function requireAuth(func, requiredPermission = null) {
return function(...args) {
if (!authState.isAuthenticated) {
PersistenceCore.showNotification('Authentication required', 'warning');
logout();
return;
}
if (requiredPermission && !hasPermission(requiredPermission)) {
PersistenceCore.showNotification('Insufficient permissions', 'error');
return;
}
return func.apply(this, args);
};
}
/**
* Refresh authentication token
* @returns {Promise<boolean>}
*/
async function refreshToken() {
if (!authState.token) return false;
try {
const response = await fetch('/api/auth/refresh', {
method: 'POST',
headers: {
'Authorization': `Bearer ${authState.token}`,
'Content-Type': 'application/json'
}
});
if (response.ok) {
const data = await response.json();
localStorage.setItem('access_token', data.access_token);
authState.token = data.access_token;
console.log('â
Token refreshed successfully');
return true;
} else {
console.log('â Token refresh failed');
logout();
return false;
}
} catch (error) {
console.error('â Token refresh error:', error);
return false;
}
}
/**
* Setup automatic token refresh
*/
function setupTokenRefresh() {
// Refresh token every 30 minutes
setInterval(async () => {
if (authState.isAuthenticated) {
await refreshToken();
}
}, 30 * 60 * 1000);
}
// =============================================================================
// INITIALIZATION
// =============================================================================
// Initialize authentication on module load
document.addEventListener('DOMContentLoaded', () => {
initializeAuth();
setupTokenRefresh();
// Dispatch authentication state change event
window.dispatchEvent(new CustomEvent('auth-state-changed', {
detail: {
isAuthenticated: authState.isAuthenticated,
user: authState.currentUser
}
}));
});
// =============================================================================
// EXPORT FOR MODULE SYSTEM
// =============================================================================
window.PersistenceAuth = {
state: authState,
initializeAuth,
login,
logout,
clearAuthState,
isAccountLocked,
getRemainingLockoutTime,
hasPermission,
requireAuth,
refreshToken,
setupTokenRefresh
};
console.log('â
PersistenceOS Authentication Module loaded');