Signed-off-by: ale <ale@manalejandro.com>
Este commit está contenido en:
ale
2025-09-20 18:56:16 +02:00
padre 8a4fde51c7
commit b1ff5c9cde
Se han modificado 6 ficheros con 53 adiciones y 34 borrados

Ver fichero

@@ -2,13 +2,18 @@ import { NextRequest, NextResponse } from 'next/server'
import { sign, verify } from 'jsonwebtoken' import { sign, verify } from 'jsonwebtoken'
const JWT_SECRET = process.env.JWT_SECRET || 'csf-admin-secret-key-change-this-in-production' const JWT_SECRET = process.env.JWT_SECRET || 'csf-admin-secret-key-change-this-in-production'
const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '24h'
// Simple user store - in production, use a database // Get admin credentials from environment variables
const ADMIN_USERNAME = process.env.ADMIN_USERNAME || 'admin'
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'admin123'
// Simple user store - credentials from environment variables
const ADMIN_USERS = [ const ADMIN_USERS = [
{ {
id: '1', id: '1',
username: 'admin', username: ADMIN_USERNAME,
password: 'admin123', // In production, use hashed passwords password: ADMIN_PASSWORD, // In production, use hashed passwords
role: 'admin', role: 'admin',
permissions: ['all'] permissions: ['all']
} }
@@ -36,16 +41,16 @@ export async function POST(request: NextRequest) {
} }
// Generate JWT token // Generate JWT token
const token = sign( const tokenPayload = {
{ userId: user.id,
userId: user.id, username: user.username,
username: user.username, role: user.role,
role: user.role, permissions: user.permissions
permissions: user.permissions }
},
JWT_SECRET, const token = sign(tokenPayload, JWT_SECRET, {
{ expiresIn: '24h' } expiresIn: JWT_EXPIRES_IN as string
) } as any)
// Create response with token in httpOnly cookie // Create response with token in httpOnly cookie
const response = NextResponse.json({ const response = NextResponse.json({
@@ -60,11 +65,16 @@ export async function POST(request: NextRequest) {
} }
}) })
// Calculate maxAge based on JWT_EXPIRES_IN
const maxAge = JWT_EXPIRES_IN.includes('h')
? parseInt(JWT_EXPIRES_IN.replace('h', '')) * 60 * 60
: 24 * 60 * 60 // Default 24 hours
response.cookies.set('auth-token', token, { response.cookies.set('auth-token', token, {
httpOnly: true, httpOnly: true,
secure: process.env.NODE_ENV === 'production', secure: process.env.NODE_ENV === 'production',
sameSite: 'lax', sameSite: 'lax',
maxAge: 24 * 60 * 60 // 24 hours maxAge
}) })
return response return response

Ver fichero

@@ -1,9 +1,9 @@
import { NextRequest, NextResponse } from 'next/server' import { NextRequest, NextResponse } from 'next/server'
import fs from 'fs/promises' import { promises as fs } from 'fs'
import path from 'path' import { join } from 'path'
const CSF_CONFIG_PATH = '/etc/csf' const CSF_CONFIG_PATH = process.env.CSF_CONFIG_PATH || '/etc/csf'
const CSF_CONF_FILE = path.join(CSF_CONFIG_PATH, 'csf.conf') const CSF_CONF_FILE = join(CSF_CONFIG_PATH, 'csf.conf')
interface CSFConfigValue { interface CSFConfigValue {
key: string key: string

Ver fichero

@@ -1,12 +1,12 @@
import { NextRequest, NextResponse } from 'next/server' import { NextRequest, NextResponse } from 'next/server'
import { exec } from 'child_process' import { exec } from 'child_process'
import { promisify } from 'util' import { promisify } from 'util'
import path from 'path'
const execAsync = promisify(exec) const execAsync = promisify(exec)
// CSF command paths - adjust based on actual CSF installation const CSF_PATH = process.env.CSF_BIN_PATH ? path.join(process.env.CSF_BIN_PATH, 'csf') : '/usr/local/csf/bin/csf'
const CSF_PATH = '/usr/local/csf/bin/csf' const CSF_CONFIG_PATH = process.env.CSF_CONFIG_PATH || '/etc/csf'
const CSF_CONFIG_PATH = '/etc/csf'
interface CSFCommandResult { interface CSFCommandResult {
success: boolean success: boolean

Ver fichero

@@ -7,7 +7,8 @@ import path from 'path'
const execAsync = promisify(exec) const execAsync = promisify(exec)
// CSF configuration paths // CSF configuration paths
const CSF_CONFIG_PATH = '/etc/csf' const CSF_CONFIG_PATH = process.env.CSF_CONFIG_PATH || '/etc/csf'
const CSF_BIN_PATH = process.env.CSF_BIN_PATH || '/usr/local/csf/bin'
const CSF_CONF_FILE = path.join(CSF_CONFIG_PATH, 'csf.conf') const CSF_CONF_FILE = path.join(CSF_CONFIG_PATH, 'csf.conf')
const CSF_ALLOW_FILE = path.join(CSF_CONFIG_PATH, 'csf.allow') const CSF_ALLOW_FILE = path.join(CSF_CONFIG_PATH, 'csf.allow')
const CSF_DENY_FILE = path.join(CSF_CONFIG_PATH, 'csf.deny') const CSF_DENY_FILE = path.join(CSF_CONFIG_PATH, 'csf.deny')
@@ -36,7 +37,7 @@ export async function GET(request: NextRequest) {
case 'temp': case 'temp':
// Get temporary bans from CSF // Get temporary bans from CSF
const { stdout } = await execAsync('/usr/local/csf/bin/csf --temp') const { stdout } = await execAsync(`${CSF_BIN_PATH}/csf --temp`)
const tempRules = parseTempRules(stdout) const tempRules = parseTempRules(stdout)
return NextResponse.json({ return NextResponse.json({
success: true, success: true,
@@ -141,11 +142,11 @@ export async function POST(request: NextRequest) {
} }
// Execute the CSF command // Execute the CSF command
const fullCommand = `/usr/local/csf/bin/csf ${command} ${args.join(' ')}` const fullCommand = `${CSF_BIN_PATH}/csf ${command} ${args.join(' ')}`
const { stdout, stderr } = await execAsync(fullCommand, { timeout: 15000 }) const { stdout, stderr } = await execAsync(fullCommand, { timeout: 15000 })
// Restart CSF to apply changes // Restart CSF to apply changes
await execAsync('/usr/local/csf/bin/csf --restart', { timeout: 30000 }) await execAsync(`${CSF_BIN_PATH}/csf --restart`, { timeout: 30000 })
return NextResponse.json({ return NextResponse.json({
success: true, success: true,
@@ -179,12 +180,12 @@ export async function DELETE(request: NextRequest) {
try { try {
const command = type === 'allow' ? '--allowrm' : '--denyrm' const command = type === 'allow' ? '--allowrm' : '--denyrm'
const fullCommand = `/usr/local/csf/bin/csf ${command} ${ip}` const fullCommand = `${CSF_BIN_PATH}/csf ${command} ${ip}`
const { stdout } = await execAsync(fullCommand, { timeout: 15000 }) const { stdout } = await execAsync(fullCommand, { timeout: 15000 })
// Restart CSF to apply changes // Restart CSF to apply changes
await execAsync('/usr/local/csf/bin/csf --restart', { timeout: 30000 }) await execAsync(`${CSF_BIN_PATH}/csf --restart`, { timeout: 30000 })
return NextResponse.json({ return NextResponse.json({
success: true, success: true,

Ver fichero

@@ -5,6 +5,10 @@ import fs from 'fs/promises'
const execAsync = promisify(exec) const execAsync = promisify(exec)
// CSF configuration from environment variables
const CSF_CONFIG_PATH = process.env.CSF_CONFIG_PATH || '/etc/csf'
const CSF_BIN_PATH = process.env.CSF_BIN_PATH || '/usr/local/csf/bin'
export async function GET() { export async function GET() {
try { try {
// Get server statistics // Get server statistics
@@ -134,7 +138,7 @@ async function getCSFStats(): Promise<{
// Check CSF status // Check CSF status
let status = 'unknown' let status = 'unknown'
try { try {
await execAsync('/usr/local/csf/bin/csf --status >/dev/null 2>&1') await execAsync(`${CSF_BIN_PATH}/csf --status >/dev/null 2>&1`)
status = 'active' status = 'active'
} catch { } catch {
status = 'inactive' status = 'inactive'
@@ -146,21 +150,21 @@ async function getCSFStats(): Promise<{
let tempBlocks = 0 let tempBlocks = 0
try { try {
const denyContent = await fs.readFile('/etc/csf/csf.deny', 'utf-8') const denyContent = await fs.readFile(`${CSF_CONFIG_PATH}/csf.deny`, 'utf-8')
blockedIps = denyContent.split('\\n').filter(line => blockedIps = denyContent.split('\\n').filter(line =>
line.trim() && !line.trim().startsWith('#') line.trim() && !line.trim().startsWith('#')
).length ).length
} catch {} } catch {}
try { try {
const allowContent = await fs.readFile('/etc/csf/csf.allow', 'utf-8') const allowContent = await fs.readFile(`${CSF_CONFIG_PATH}/csf.allow`, 'utf-8')
allowedIps = allowContent.split('\\n').filter(line => allowedIps = allowContent.split('\\n').filter(line =>
line.trim() && !line.trim().startsWith('#') line.trim() && !line.trim().startsWith('#')
).length ).length
} catch {} } catch {}
try { try {
const { stdout } = await execAsync('/usr/local/csf/bin/csf --temp 2>/dev/null | grep -c "Temporary" || echo "0"') const { stdout } = await execAsync(`${CSF_BIN_PATH}/csf --temp 2>/dev/null | grep -c "Temporary" || echo "0"`)
tempBlocks = parseInt(stdout.trim()) || 0 tempBlocks = parseInt(stdout.trim()) || 0
} catch {} } catch {}

Ver fichero

@@ -7,6 +7,10 @@ import fs from 'fs/promises'
const execAsync = promisify(exec) const execAsync = promisify(exec)
// CSF configuration from environment variables
const CSF_CONFIG_PATH = process.env.CSF_CONFIG_PATH || '/etc/csf'
const CSF_LOG_PATH = process.env.CSF_LOG_PATH || '/var/log'
// Configuración del servidor Socket.IO // Configuración del servidor Socket.IO
let io: SocketIOServer | null = null let io: SocketIOServer | null = null
@@ -74,14 +78,14 @@ async function getSystemStats(): Promise<CSFStats> {
let allowedIps = 0 let allowedIps = 0
try { try {
const denyContent = await fs.readFile('/etc/csf/csf.deny', 'utf-8') const denyContent = await fs.readFile(`${CSF_CONFIG_PATH}/csf.deny`, 'utf-8')
blockedIps = denyContent.split('\n').filter(line => blockedIps = denyContent.split('\n').filter(line =>
line.trim() && !line.trim().startsWith('#') line.trim() && !line.trim().startsWith('#')
).length ).length
} catch {} } catch {}
try { try {
const allowContent = await fs.readFile('/etc/csf/csf.allow', 'utf-8') const allowContent = await fs.readFile(`${CSF_CONFIG_PATH}/csf.allow`, 'utf-8')
allowedIps = allowContent.split('\n').filter(line => allowedIps = allowContent.split('\n').filter(line =>
line.trim() && !line.trim().startsWith('#') line.trim() && !line.trim().startsWith('#')
).length ).length
@@ -121,7 +125,7 @@ async function getSystemStats(): Promise<CSFStats> {
// Función para obtener logs recientes // Función para obtener logs recientes
async function getRecentLogs(limit: number = 50): Promise<LogEntry[]> { async function getRecentLogs(limit: number = 50): Promise<LogEntry[]> {
try { try {
const { stdout } = await execAsync(`tail -${limit} /var/log/syslog | grep -E "(CSF|iptables|lfd)" || echo ""`) const { stdout } = await execAsync(`tail -${limit} ${CSF_LOG_PATH}/syslog | grep -E "(CSF|iptables|lfd)" || echo ""`)
const logs: LogEntry[] = [] const logs: LogEntry[] = []
const lines = stdout.split('\n').filter(line => line.trim()) const lines = stdout.split('\n').filter(line => line.trim())