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
JavaScript
;
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