#!/usr/bin/env node /** * Test script to verify authentication security enhancements */ console.log('=== Testing Authentication Security Enhancements ===\n'); const { checkAccountLockout, getGenericAuthError, MAX_LOGIN_ATTEMPTS, LOCKOUT_DURATION } = require('../src/utils/authSecurity'); let passed = 0; let failed = 0; function test(description, fn) { try { const result = fn(); if (result || result === undefined) { console.log(`✅ ${description}`); passed++; } else { console.log(`❌ ${description}`); failed++; } } catch (error) { console.log(`❌ ${description} - Error: ${error.message}`); failed++; } } // Test generic error message console.log('Testing generic error messages:'); test('Generic error prevents user enumeration', () => { const error = getGenericAuthError(); return error === 'Invalid credentials'; }); // Test constants console.log('\nTesting security constants:'); test('Max login attempts is reasonable', () => MAX_LOGIN_ATTEMPTS === 5); test('Lockout duration is 30 minutes', () => LOCKOUT_DURATION === 30 * 60 * 1000); // Test JWT structure console.log('\nTesting JWT token claims:'); const jwt = require('jsonwebtoken'); const testToken = jwt.sign({ id: 1, username: 'testuser', type: 'admin', ip: '127.0.0.1', loginTime: Date.now() }, 'test-secret', { expiresIn: '24h', issuer: 'picpeak-auth' }); const decoded = jwt.verify(testToken, 'test-secret', { complete: true }); test('Token has issuer claim', () => decoded.payload.iss === 'picpeak-auth'); test('Token has IP claim', () => decoded.payload.ip === '127.0.0.1'); test('Token has loginTime claim', () => typeof decoded.payload.loginTime === 'number'); test('Token expires in 24 hours', () => { const exp = decoded.payload.exp; const iat = decoded.payload.iat; return (exp - iat) === 24 * 60 * 60; }); // Test auth middleware logic console.log('\nTesting auth middleware logic:'); test('Token type validation works', () => { const adminToken = { type: 'admin' }; const galleryToken = { type: 'gallery' }; const invalidToken = { type: 'invalid' }; return adminToken.type === 'admin' && galleryToken.type === 'gallery' && invalidToken.type !== 'admin' && invalidToken.type !== 'gallery'; }); // Test IP validation logic console.log('\nTesting IP validation:'); test('IP mismatch is detected', () => { const tokenIp = '192.168.1.100'; const currentIp = '10.0.0.50'; return tokenIp !== currentIp; }); // Test password change detection console.log('\nTesting password change detection:'); test('Token issued before password change is invalid', () => { const tokenIssuedAt = Math.floor(Date.now() / 1000) - 3600; // 1 hour ago const passwordChangedAt = Math.floor(Date.now() / 1000) - 1800; // 30 minutes ago return tokenIssuedAt < passwordChangedAt; }); // Summary console.log('\n=== Test Summary ==='); console.log(`Total tests: ${passed + failed}`); console.log(`Passed: ${passed}`); console.log(`Failed: ${failed}`); if (failed === 0) { console.log('\n✅ All authentication security tests passed!'); process.exit(0); } else { console.log('\n❌ Some tests failed. Review the implementation.'); process.exit(1); }