Files
picpeak/backend/scripts/add-auth-tables.js
T
paul e35ac6a41c
Test Gitea Actions / test (push) Successful in 20s
continuous-integration/drone/push Build is passing
feat: implement critical security fixes for SQL injection and authentication vulnerabilities
Security Enhancements:
- Fix SQL injection vulnerabilities by replacing whereRaw queries with parameterized queries
- Add LIKE pattern escaping to prevent SQL injection in search functionality
- Implement account lockout protection (5 failed attempts = 30 min lockout)
- Add comprehensive login attempt tracking and audit trail
- Enhance JWT tokens with issuer validation, IP tracking, and password change detection
- Add logout endpoint and session management
- Prevent user enumeration with generic error messages

Database Changes:
- Add login_attempts table for authentication tracking
- Add security columns to admin_users (password_changed_at, last_login_ip, two_factor_enabled)

New Security Features:
- Brute force protection with configurable lockout duration
- Automatic cleanup of old login attempts
- Enhanced authentication middleware with stricter validation
- Monitoring scripts for security health checks

All fixes are backward compatible and production-ready with rollback plans included.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-13 00:40:05 +02:00

94 lines
3.2 KiB
JavaScript

#!/usr/bin/env node
/**
* Add authentication security tables to existing database
*/
const { db } = require('../src/database/db');
async function addAuthTables() {
console.log('Adding authentication security tables...\n');
try {
// 1. Create login_attempts table
const hasLoginAttempts = await db.schema.hasTable('login_attempts');
if (!hasLoginAttempts) {
await db.schema.createTable('login_attempts', table => {
table.increments('id').primary();
table.string('identifier').notNullable();
table.string('ip_address', 45).notNullable();
table.text('user_agent');
table.timestamp('attempt_time').defaultTo(db.fn.now());
table.boolean('success').defaultTo(false);
// Indexes for performance
table.index('identifier');
table.index('attempt_time');
table.index(['identifier', 'success', 'attempt_time']);
});
console.log('✓ Created login_attempts table');
} else {
console.log('! login_attempts table already exists');
}
// 2. Add columns to admin_users
const hasPasswordChangedAt = await db.schema.hasColumn('admin_users', 'password_changed_at');
if (!hasPasswordChangedAt) {
await db.schema.table('admin_users', table => {
table.timestamp('password_changed_at').nullable();
});
console.log('✓ Added password_changed_at column');
}
const hasLastLoginIp = await db.schema.hasColumn('admin_users', 'last_login_ip');
if (!hasLastLoginIp) {
await db.schema.table('admin_users', table => {
table.string('last_login_ip', 45).nullable();
});
console.log('✓ Added last_login_ip column');
}
const hasTwoFactorEnabled = await db.schema.hasColumn('admin_users', 'two_factor_enabled');
if (!hasTwoFactorEnabled) {
await db.schema.table('admin_users', table => {
table.boolean('two_factor_enabled').defaultTo(false);
});
console.log('✓ Added two_factor_enabled column');
}
const hasTwoFactorSecret = await db.schema.hasColumn('admin_users', 'two_factor_secret');
if (!hasTwoFactorSecret) {
await db.schema.table('admin_users', table => {
table.string('two_factor_secret').nullable();
});
console.log('✓ Added two_factor_secret column');
}
// 3. Verify everything
console.log('\nVerifying tables...');
const loginAttemptsInfo = await db('login_attempts').columnInfo();
console.log('✓ login_attempts columns:', Object.keys(loginAttemptsInfo).join(', '));
const adminUsersInfo = await db('admin_users').columnInfo();
const securityColumns = ['password_changed_at', 'last_login_ip', 'two_factor_enabled', 'two_factor_secret'];
const hasAllColumns = securityColumns.every(col => adminUsersInfo[col]);
if (hasAllColumns) {
console.log('✓ All security columns present in admin_users');
} else {
console.log('✗ Some security columns missing from admin_users');
}
console.log('\n✅ Authentication security tables ready!');
await db.destroy();
process.exit(0);
} catch (error) {
console.error('\n❌ Error adding auth tables:', error);
await db.destroy();
process.exit(1);
}
}
addAuthTables();