primer cambio
This commit is contained in:
102
src/controladores/autentificacion/Autentificacion.controller.js
Normal file
102
src/controladores/autentificacion/Autentificacion.controller.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
import dotenv from 'dotenv';
|
||||
import { dbasistente } from "../../db.js";
|
||||
|
||||
// Configuración de variables de entorno
|
||||
dotenv.config();
|
||||
|
||||
async function autentificacion(req, res) {
|
||||
try {
|
||||
let username, password;
|
||||
|
||||
// 1. Intentar obtener de cabecera Authorization (Basic Auth)
|
||||
const authHeader = req.headers.authorization;
|
||||
if (authHeader && authHeader.startsWith('Basic ')) {
|
||||
const base64Credentials = authHeader.split(' ')[1];
|
||||
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
|
||||
[username, password] = credentials.split(':');
|
||||
}
|
||||
// 2. Si no hay cabecera, intentar obtener del body (JSON)
|
||||
else if (req.body.username && req.body.password) {
|
||||
username = req.body.username;
|
||||
password = req.body.password;
|
||||
}
|
||||
|
||||
// Validar que tengamos credenciales
|
||||
if (!username || !password) {
|
||||
return res.status(401).json({
|
||||
error: "Credenciales faltantes",
|
||||
mensaje: "Se requiere autenticación básica o un cuerpo JSON con {username, password}"
|
||||
});
|
||||
}
|
||||
|
||||
// Consulta a la nueva tabla soporte_copy en dbasistente
|
||||
const [db_user] = await dbasistente.query(
|
||||
"SELECT CODIGO_SOP, NOMBRE_SOP, USUARIO_SOP, NIVEL_SOP FROM soporte_copy WHERE USUARIO_SOP = ? AND CLAVE_SOP = ? AND ESTADO_SOP = 'V'",
|
||||
{
|
||||
replacements: [username, password]
|
||||
}
|
||||
);
|
||||
|
||||
// Verificar si se encontró el usuario
|
||||
if (db_user.length === 0) {
|
||||
return res.status(401).json({
|
||||
error: "Credenciales inválidas",
|
||||
mensaje: "Usuario o contraseña incorrectos"
|
||||
});
|
||||
}
|
||||
|
||||
const userRecord = db_user[0];
|
||||
|
||||
// Determinar privilegio basado en NIVEL_SOP
|
||||
// NIVEL_SOP 1 = solo lectura (READ), 4 = admin (CRUD)
|
||||
let privilegio = "READ";
|
||||
if (userRecord.NIVEL_SOP === 4 || userRecord.NIVEL_SOP === '4') {
|
||||
privilegio = "CRUD";
|
||||
}
|
||||
|
||||
// Verificar clave secreta JWT
|
||||
if (!process.env.SECRET) {
|
||||
throw new Error("La clave secreta JWT no está configurada");
|
||||
}
|
||||
|
||||
// Crear payload del token
|
||||
const payload = {
|
||||
id: userRecord.CODIGO_SOP,
|
||||
username: userRecord.USUARIO_SOP,
|
||||
nombre: userRecord.NOMBRE_SOP,
|
||||
privilegio: privilegio
|
||||
};
|
||||
|
||||
// Generar token JWT
|
||||
const token = jwt.sign(
|
||||
payload,
|
||||
process.env.SECRET,
|
||||
{ expiresIn: '3h' }
|
||||
);
|
||||
|
||||
// Respuesta exitosa según el formato solicitado
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
message: "Login exitoso",
|
||||
token: token,
|
||||
user: {
|
||||
id: userRecord.CODIGO_SOP,
|
||||
username: userRecord.USUARIO_SOP,
|
||||
nombre: userRecord.NOMBRE_SOP,
|
||||
privilegio: privilegio
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error en autenticación:", error);
|
||||
|
||||
// Error genérico
|
||||
return res.status(500).json({
|
||||
error: "Error interno del servidor",
|
||||
detalles: process.env.NODE_ENV === 'development' ? error.message : undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { autentificacion };
|
||||
15
src/controladores/autentificacion/Locales.controller.js
Normal file
15
src/controladores/autentificacion/Locales.controller.js
Normal file
@@ -0,0 +1,15 @@
|
||||
// Locales.controller.js
|
||||
async function obtener_locales(req, res, dbecommerce) {
|
||||
try {
|
||||
const result = await dbecommerce.query("SELECT b.numbodega, b.nombrebodega FROM bodegas_ecommerce b ORDER BY b.numbodega ASC");
|
||||
|
||||
// Enviar la respuesta al cliente como JSON
|
||||
res.status(200).json(result[0]);
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
// Enviar un mensaje de error al cliente si ocurre un problema
|
||||
res.status(500).json({ error: "Hubo un error en el servidor" });
|
||||
}
|
||||
}
|
||||
|
||||
export { obtener_locales };
|
||||
273
src/controladores/sql/C_sql_inyec.js
Normal file
273
src/controladores/sql/C_sql_inyec.js
Normal file
@@ -0,0 +1,273 @@
|
||||
|
||||
async function sql_inyec(req, res, dbcentral) {
|
||||
try {
|
||||
const store_id = req.query.store_id;
|
||||
const id_cliente = req.query.id_cliente;
|
||||
|
||||
if (!store_id) {
|
||||
return res.status(400).json({ error: "store_id es requerido" });
|
||||
}
|
||||
|
||||
// Validar que store_id sea un número para evitar errores de tipo en la DB
|
||||
if (isNaN(store_id)) {
|
||||
return res.status(400).json({
|
||||
error: "store_id inválido",
|
||||
message: "El store_id debe ser un valor numérico"
|
||||
});
|
||||
}
|
||||
|
||||
// Registrar/Actualizar Heartbeat cada vez que una tienda consulta
|
||||
await dbcentral.query(
|
||||
`INSERT INTO tb_store_process_heartbeat
|
||||
(store_id, process_name, instance_id, status, extra_info, id_cliente)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
status = 'alive',
|
||||
last_ping = CURRENT_TIMESTAMP;`,
|
||||
{
|
||||
replacements: [
|
||||
store_id,
|
||||
'sql_inyector',
|
||||
'sql_inyector',
|
||||
'alive',
|
||||
JSON.stringify({ message: 'Consultando comandos', timestamp: new Date() }),
|
||||
id_cliente || null
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
// Consultar comandos pendientes para este store_id
|
||||
const [results] = await dbcentral.query(
|
||||
"SELECT * FROM tb_sql_inyector WHERE store_id = ? and id_cliente=? AND estado = '0' LIMIT 1",
|
||||
{
|
||||
replacements: [store_id, id_cliente]
|
||||
}
|
||||
);
|
||||
|
||||
if (results.length === 0) {
|
||||
return res.status(204).json({
|
||||
message: "No hay comandos pendientes"
|
||||
});
|
||||
}
|
||||
|
||||
const command = results[0];
|
||||
|
||||
// Construir la respuesta solicitada
|
||||
const response = {
|
||||
command_id: command.command_id,
|
||||
sql: command.sql,
|
||||
privilegio: command.privilegio || "READ" // Valor por defecto si no existe la columna
|
||||
};
|
||||
|
||||
// Respuesta
|
||||
res.status(200).json(response);
|
||||
|
||||
} catch (error) {
|
||||
console.error("❌ Error al procesar consulta sql_inyec:", error.message);
|
||||
res.status(500).json({
|
||||
error: "Error interno del servidor",
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function save_result_inyec(req, res, dbcentral) {
|
||||
try {
|
||||
let { command_id, result } = req.body;
|
||||
|
||||
if (!command_id) {
|
||||
return res.status(400).json({ error: "command_id es requerido" });
|
||||
}
|
||||
|
||||
// Si no se envía una propiedad 'result' explícita, asumimos que todo el body es la respuesta
|
||||
if (result === undefined) {
|
||||
result = req.body;
|
||||
}
|
||||
|
||||
// Serializar el resultado a JSON si es un objeto
|
||||
const jsonResponse = typeof result === 'object' ? JSON.stringify(result) : result;
|
||||
|
||||
const [updateResult] = await dbcentral.query(
|
||||
`UPDATE tb_sql_inyector SET json_response = ?, estado = '1' WHERE command_id = ?`,
|
||||
{
|
||||
replacements: [jsonResponse, command_id]
|
||||
}
|
||||
);
|
||||
|
||||
// En algunas configuraciones de Sequelize/MySQL, el resultado de un update puede variar.
|
||||
// Verificamos si hubo cambios (affectedRows) si está disponible en updateResult.
|
||||
// Nota: updateResult suele ser un objeto con info del resultado en raw query.
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: "Resultado guardado correctamente"
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("❌ Error al guardar resultado:", error.message);
|
||||
res.status(500).json({
|
||||
error: "Error interno del servidor",
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function create_command(req, res, dbcentral) {
|
||||
try {
|
||||
const { store_id, sql, privilegio, id_user, id_cliente } = req.body;
|
||||
|
||||
if (!store_id || !sql) {
|
||||
return res.status(400).json({ error: "store_id y sql son requeridos" });
|
||||
}
|
||||
|
||||
if (isNaN(store_id)) {
|
||||
return res.status(400).json({
|
||||
error: "store_id inválido",
|
||||
message: "El store_id debe ser un valor numérico"
|
||||
});
|
||||
}
|
||||
|
||||
const [commandId] = await dbcentral.query(
|
||||
"INSERT INTO tb_sql_inyector (store_id, `sql`, privilegio, id_user, id_cliente, estado) VALUES (?, ?, ?, ?, ?, '0')",
|
||||
{
|
||||
replacements: [store_id, sql, privilegio || 'READ', id_user || null, id_cliente || null]
|
||||
}
|
||||
);
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: "Comando creado exitosamente",
|
||||
command_id: commandId
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("❌ Error al crear comando:", error.message);
|
||||
res.status(500).json({
|
||||
error: "Error interno del servidor",
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function get_command_status(req, res, dbcentral) {
|
||||
try {
|
||||
const command_id = req.params.command_id;
|
||||
|
||||
if (!command_id) {
|
||||
return res.status(400).json({ error: "command_id es requerido" });
|
||||
}
|
||||
|
||||
const [results] = await dbcentral.query(
|
||||
`SELECT * FROM tb_sql_inyector WHERE command_id = ? AND estado = '1'`,
|
||||
{
|
||||
replacements: [command_id]
|
||||
}
|
||||
);
|
||||
|
||||
if (results.length === 0) {
|
||||
// Verificamos si existe pero está en otro estado para dar un mensaje más claro,
|
||||
// o simplemente retornamos 404 si no se encuentra completado.
|
||||
// Para ser simple y directo como en los otros endpoints:
|
||||
return res.status(404).json({
|
||||
message: "Comando no encontrado o aún no completado"
|
||||
});
|
||||
}
|
||||
|
||||
const command = results[0];
|
||||
// Intentar parsear el json_response si es un string
|
||||
let jsonResponse = command.json_response;
|
||||
try {
|
||||
if (typeof jsonResponse === 'string') {
|
||||
jsonResponse = JSON.parse(jsonResponse);
|
||||
}
|
||||
} catch (e) {
|
||||
// Si falla el parseo, dejamos el string original
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
command_id: command.command_id,
|
||||
status: "completed",
|
||||
result: jsonResponse,
|
||||
processed_at: command.fecha_proceso
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error("❌ Error al obtener estado del comando:", error.message);
|
||||
res.status(500).json({
|
||||
error: "Error interno del servidor",
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function get_commands_by_user(req, res, dbcentral) {
|
||||
try {
|
||||
const id_user = req.params.id_user;
|
||||
const limit = req.query.limit || 50;
|
||||
|
||||
if (!id_user) {
|
||||
return res.status(400).json({ error: "id_user es requerido" });
|
||||
}
|
||||
|
||||
const [results] = await dbcentral.query(
|
||||
`SELECT command_id, store_id, \`sql\`, privilegio, estado, fecha_solicitud, fecha_proceso, json_response
|
||||
FROM tb_sql_inyector
|
||||
WHERE id_user = ?
|
||||
ORDER BY command_id DESC
|
||||
LIMIT ?`,
|
||||
{
|
||||
replacements: [id_user, parseInt(limit)]
|
||||
}
|
||||
);
|
||||
|
||||
// Parsear cada json_response si es necesario
|
||||
const formattedResults = results.map(cmd => {
|
||||
let jsonResponse = cmd.json_response;
|
||||
try {
|
||||
if (typeof jsonResponse === 'string') {
|
||||
jsonResponse = JSON.parse(jsonResponse);
|
||||
}
|
||||
} catch (e) { }
|
||||
|
||||
return {
|
||||
...cmd,
|
||||
json_response: jsonResponse
|
||||
};
|
||||
});
|
||||
|
||||
res.status(200).json(formattedResults);
|
||||
|
||||
} catch (error) {
|
||||
console.error("❌ Error al obtener comandos por usuario:", error.message);
|
||||
res.status(500).json({
|
||||
error: "Error interno del servidor",
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function get_online_stores(req, res, dbcentral) {
|
||||
try {
|
||||
// Obtenemos los locales y su último ping
|
||||
// Consideramos "Online" si el ping fue hace menos de 2 minutos
|
||||
const [results] = await dbcentral.query(
|
||||
`SELECT
|
||||
h.store_id,
|
||||
h.last_ping,
|
||||
h.status,
|
||||
IF(TIMESTAMPDIFF(SECOND, h.last_ping, CURRENT_TIMESTAMP) <= 120, 'ONLINE', 'OFFLINE') as connectivity
|
||||
FROM tb_store_process_heartbeat h
|
||||
WHERE h.process_name = 'sql_inyector'
|
||||
ORDER BY h.last_ping DESC`
|
||||
);
|
||||
|
||||
res.status(200).json(results);
|
||||
} catch (error) {
|
||||
console.error("❌ Error al obtener tiendas online:", error.message);
|
||||
res.status(500).json({
|
||||
error: "Error interno del servidor"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { sql_inyec, save_result_inyec, create_command, get_command_status, get_commands_by_user, get_online_stores };
|
||||
77
src/controladores/webhoock/Newpeticio.js
Normal file
77
src/controladores/webhoock/Newpeticio.js
Normal file
@@ -0,0 +1,77 @@
|
||||
import defineLogHookProcesos from '../../database/modelos/M_webhoock.js';
|
||||
// Asegurarnos de que el modelo esté definido una sola vez
|
||||
let modeloDefined = false;
|
||||
|
||||
async function webhoock(req, res, dbcentral) {
|
||||
try {
|
||||
const body = req.body;
|
||||
// Validación rápida inicial
|
||||
if (!body || typeof body !== 'object') {
|
||||
return res.status(400).json({ error: "El cuerpo del webhook es inválido" });
|
||||
}
|
||||
// Validación de contenido
|
||||
const keys = Object.keys(body);
|
||||
if (keys.length === 0) {
|
||||
return res.status(400).json({ error: "El cuerpo del webhook está vacío" });
|
||||
}
|
||||
|
||||
// Definir el modelo solo si no está definido
|
||||
if (!modeloDefined) {
|
||||
await defineLogHookProcesos(dbcentral);
|
||||
modeloDefined = true;
|
||||
}
|
||||
|
||||
// Validar que IdMnt existe antes de procesar
|
||||
if (!body.IdMnt) {
|
||||
return res.status(400).json({
|
||||
error: "Campo requerido faltante",
|
||||
message: "El campo IdMnt es obligatorio para procesar el webhook"
|
||||
});
|
||||
}
|
||||
|
||||
// Verificar si el registro ya existe
|
||||
const existingRecord = await dbcentral.models.log_hook_procesos.findOne({
|
||||
where: {
|
||||
OrderId: body.IdMnt.toString()
|
||||
}
|
||||
});
|
||||
|
||||
if (existingRecord) {
|
||||
return res.status(409).json({
|
||||
error: "Registro duplicado",
|
||||
message: "Ya existe un registro con este OrderId",
|
||||
id: existingRecord.id
|
||||
});
|
||||
}
|
||||
|
||||
// Crear el registro directamente sin sanitización redundante
|
||||
const result = await dbcentral.models.log_hook_procesos.create({
|
||||
json: JSON.stringify(body),
|
||||
OrderId: body.IdMnt.toString(),
|
||||
NroPaquete: body.NroPaquete || null,
|
||||
estatus: body.estatus || null,
|
||||
tipo: body.TipoMnt ? body.TipoMnt.toString() : null
|
||||
}, {
|
||||
logging: false, // Desactivar logging SQL
|
||||
returning: ['id'] // Solo retornar el ID
|
||||
});
|
||||
|
||||
|
||||
// Respuesta rápida
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: 'Webhook almacenado correctamente',
|
||||
id: result.id
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
// Log simplificado del error
|
||||
console.error("❌ Error al procesar webhook:", error.message);
|
||||
res.status(500).json({
|
||||
error: "Error al procesar el webhook",
|
||||
message: process.env.NODE_ENV === 'development' ? error.message : 'Error interno del servidor'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { webhoock };
|
||||
Reference in New Issue
Block a user