UNPKG

lockbyte

Version:

Enterprise-grade password hashing and user authentication library with Argon2-inspired algorithm, memory-hard functions, and comprehensive security features

207 lines 7.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UserAuth = void 0; const crypto_1 = __importDefault(require("crypto")); const crypto_2 = require("./crypto"); class UserAuth { constructor(cryptoConfig) { this.users = new Map(); this.sessions = new Map(); this.crypto = new crypto_2.SecureCrypto(cryptoConfig); } generateUserId() { return crypto_1.default.randomBytes(16).toString('hex'); } generateSessionToken() { return crypto_1.default.randomBytes(32).toString('hex'); } validateEmail(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } validatePassword(password) { const errors = []; if (password.length < 8) { errors.push('Password must be at least 8 characters long'); } if (!/[A-Z]/.test(password)) { errors.push('Password must contain at least one uppercase letter'); } if (!/[a-z]/.test(password)) { errors.push('Password must contain at least one lowercase letter'); } if (!/\d/.test(password)) { errors.push('Password must contain at least one number'); } if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) { errors.push('Password must contain at least one special character'); } return { valid: errors.length === 0, errors }; } async register(data) { try { if (!this.validateEmail(data.email)) { return { success: false, error: 'Invalid email format' }; } const passwordValidation = this.validatePassword(data.password); if (!passwordValidation.valid) { return { success: false, error: `Password validation failed: ${passwordValidation.errors.join(', ')}` }; } if (this.getUserByEmail(data.email)) { return { success: false, error: 'User already exists with this email' }; } const hashResult = this.crypto.hash(data.password); const userId = this.generateUserId(); const user = { id: userId, email: data.email.toLowerCase(), hashedPassword: hashResult.hash, hashVersion: hashResult.version, algorithm: hashResult.algorithm, createdAt: new Date() }; this.users.set(user.email, user); const sessionToken = this.generateSessionToken(); this.sessions.set(sessionToken, { userId: user.id, expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours }); return { success: true, user: { ...user, hashedPassword: '[HIDDEN]' }, sessionToken }; } catch (error) { return { success: false, error: `Registration failed: ${error instanceof Error ? error.message : 'Unknown error'}` }; } } async login(data) { try { if (!this.validateEmail(data.email)) { return { success: false, error: 'Invalid email format' }; } const user = this.getUserByEmail(data.email); if (!user) { return { success: false, error: 'Invalid credentials' }; } const isValidPassword = this.crypto.verify(data.password, user.hashedPassword); if (!isValidPassword) { return { success: false, error: 'Invalid credentials' }; } user.lastLogin = new Date(); this.users.set(user.email, user); const sessionToken = this.generateSessionToken(); this.sessions.set(sessionToken, { userId: user.id, expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours }); return { success: true, user: { ...user, hashedPassword: '[HIDDEN]' }, sessionToken }; } catch (error) { return { success: false, error: `Login failed: ${error instanceof Error ? error.message : 'Unknown error'}` }; } } logout(sessionToken) { return this.sessions.delete(sessionToken); } validateSession(sessionToken) { const session = this.sessions.get(sessionToken); if (!session) { return { valid: false }; } if (session.expiresAt < new Date()) { this.sessions.delete(sessionToken); return { valid: false }; } const user = this.getUserById(session.userId); if (!user) { this.sessions.delete(sessionToken); return { valid: false }; } return { valid: true, user: { ...user, hashedPassword: '[HIDDEN]' } }; } changePassword(sessionToken, oldPassword, newPassword) { try { const sessionValidation = this.validateSession(sessionToken); if (!sessionValidation.valid || !sessionValidation.user) { return { success: false, error: 'Invalid session' }; } const user = this.getUserById(sessionValidation.user.id); if (!user) { return { success: false, error: 'User not found' }; } const isValidOldPassword = this.crypto.verify(oldPassword, user.hashedPassword); if (!isValidOldPassword) { return { success: false, error: 'Current password is incorrect' }; } const passwordValidation = this.validatePassword(newPassword); if (!passwordValidation.valid) { return { success: false, error: `New password validation failed: ${passwordValidation.errors.join(', ')}` }; } const hashResult = this.crypto.hash(newPassword); user.hashedPassword = hashResult.hash; user.hashVersion = hashResult.version; user.algorithm = hashResult.algorithm; this.users.set(user.email, user); return { success: true }; } catch (error) { return { success: false, error: `Password change failed: ${error instanceof Error ? error.message : 'Unknown error'}` }; } } getUserByEmail(email) { return this.users.get(email.toLowerCase()); } getUserById(id) { for (const user of this.users.values()) { if (user.id === id) { return user; } } return undefined; } getUserStats() { const now = new Date(); let activeSessions = 0; for (const [token, session] of this.sessions.entries()) { if (session.expiresAt > now) { activeSessions++; } else { this.sessions.delete(token); } } return { totalUsers: this.users.size, activeSessions }; } } exports.UserAuth = UserAuth; //# sourceMappingURL=auth.js.map