Se generalizó envio de correos a diferentes sistemas
This commit is contained in:
+5
-2
@@ -12,7 +12,10 @@ import { SistemaModule } from './sistema/sistema.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot(),
|
||||
ConfigModule.forRoot(
|
||||
{isGlobal: true}
|
||||
),
|
||||
|
||||
TypeOrmModule.forRoot({
|
||||
type: 'mysql',
|
||||
host: process.env.db_host,
|
||||
@@ -21,7 +24,7 @@ import { SistemaModule } from './sistema/sistema.module';
|
||||
password: process.env.db_password,
|
||||
port: Number(process.env.db_port),
|
||||
synchronize: true,
|
||||
dropSchema: true, // elimina la base de datos
|
||||
dropSchema: false, // elimina la base de datos
|
||||
// logging: true, // Habilita los logs para depuración
|
||||
autoLoadEntities: true, // Carga automáticamente las entidades
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// auth.module.ts
|
||||
import { Module } from '@nestjs/common';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule, // Ya es global, pero lo puedes dejar
|
||||
JwtModule.registerAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: (config: ConfigService) => ({
|
||||
secret: config.get('JWT_SECRET'),
|
||||
signOptions: { expiresIn: '1d' },
|
||||
}),
|
||||
}),
|
||||
],
|
||||
providers: [AuthService],
|
||||
exports: [AuthService, JwtModule],
|
||||
})
|
||||
export class AuthModule {}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(private jwtService: JwtService) {}
|
||||
|
||||
generarToken(payload: any) {
|
||||
return this.jwtService.sign(payload, {
|
||||
secret: process.env.JWT_SECRET, // <-- Aquí lo defines explícitamente
|
||||
expiresIn: '1d',
|
||||
});
|
||||
}
|
||||
|
||||
verificarToken(token: string) {
|
||||
try {
|
||||
return this.jwtService.verify(token, {
|
||||
secret: process.env.JWT_SECRET, // <-- También aquí
|
||||
});
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
export function encrypt(text: string) {
|
||||
const secret = process.env.KEY_SECRET;
|
||||
if (!secret) throw new Error('Falta la variable de entorno KEY_SECRET');
|
||||
|
||||
const key = crypto.scryptSync(secret, 'salt', 32);
|
||||
const iv = crypto.randomBytes(16);
|
||||
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
|
||||
|
||||
let encrypted = cipher.update(text, 'utf8', 'hex');
|
||||
encrypted += cipher.final('hex');
|
||||
|
||||
return {
|
||||
iv: iv.toString('hex'),
|
||||
encryptedData: encrypted,
|
||||
};
|
||||
}
|
||||
|
||||
export function decrypt(encryptedData: string, ivHex: string) {
|
||||
const secret = process.env.KEY_SECRET;
|
||||
if (!process.env.KEY_SECRET) {
|
||||
throw new Error('Falta la variable de entorno KEY_SECRET');
|
||||
}
|
||||
if (!secret) throw new Error('Falta la variable de entorno KEY_SECRET');
|
||||
|
||||
const key = crypto.scryptSync(secret, 'salt', 32);
|
||||
const iv = Buffer.from(ivHex, 'hex');
|
||||
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
|
||||
|
||||
let decrypted = decipher.update(encryptedData, 'hex', 'utf8');
|
||||
decrypted += decipher.final('utf8');
|
||||
|
||||
return decrypted;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { IsString, IsEmail, IsDate, IsOptional } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
export class SendCorreoDto {
|
||||
@IsEmail()
|
||||
to: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
subject: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
text: string;
|
||||
|
||||
@IsDate()
|
||||
@Type(() => Date)
|
||||
fecha_recibido: Date;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
html: string;
|
||||
|
||||
@IsOptional()
|
||||
adjuntos: any;
|
||||
|
||||
|
||||
|
||||
}
|
||||
+57
-35
@@ -6,24 +6,30 @@ import {
|
||||
Headers,
|
||||
UnauthorizedException,
|
||||
Get,
|
||||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
import { MailService } from './mail.service';
|
||||
import { ExcelService } from 'src/excel/excel.service';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { ApiFindAllMails, ApiSendMail, ApiSendMailExcel} from './mail.decorators';
|
||||
import { ApiSendMail} from './mail.decorators';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Sistema } from 'src/typeorm/votacionesPrueba.entity';
|
||||
import { Sistema } from 'src/typeorm/entidades';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { SistemaService } from 'src/sistema/sistema.service';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { SendCorreoDto } from 'src/mail/dto/send-email.dto';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import { AuthService } from 'src/auth/auth.service';
|
||||
|
||||
|
||||
@ApiTags('Mail') // Grupo de endpoints
|
||||
@Controller('mail')
|
||||
export class MailController {
|
||||
constructor(
|
||||
private readonly sistemaService: SistemaService,
|
||||
private readonly mailService: MailService,
|
||||
private readonly excelService: ExcelService,
|
||||
@InjectRepository(Sistema) private readonly sistemaRepository: Repository<Sistema>,
|
||||
// private readonly excelService: ExcelService,
|
||||
private readonly authService: AuthService
|
||||
|
||||
) {}
|
||||
|
||||
@@ -35,22 +41,32 @@ export class MailController {
|
||||
@ApiSendMail()
|
||||
async sendMail(
|
||||
@Headers() headers:{token:string},
|
||||
@Body() body: { to: string; subject: string; text: string; fecha_recibido: Date, html:string, adjuntos:any }
|
||||
@Body() body: SendCorreoDto
|
||||
) {
|
||||
|
||||
if (!headers.token) {
|
||||
throw new UnauthorizedException('Header "token" es requerido');
|
||||
}
|
||||
const sistem=await this.sistemaRepository.findOne({where:{token:headers.token}})
|
||||
if(!sistem){
|
||||
throw new UnauthorizedException('Password incorrecto');
|
||||
}
|
||||
let payload
|
||||
|
||||
const { to, subject, text, html, fecha_recibido, adjuntos } = body;
|
||||
payload = await this.authService.verificarToken(headers.token);
|
||||
|
||||
|
||||
if (!payload || !payload.nombre) {
|
||||
throw new UnauthorizedException('Token inválido o incompleto');
|
||||
}
|
||||
|
||||
const sistem= await this.sistemaService.findByNombre(payload.nombre)
|
||||
|
||||
|
||||
if(!sistem){
|
||||
throw new UnauthorizedException('sistema No encontrado');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const result = await this.mailService.sendMail(to, subject, text,html, fecha_recibido,sistem,adjuntos); // sistem
|
||||
const result = await this.mailService.sendMail(body,sistem); // sistem
|
||||
return result;
|
||||
|
||||
|
||||
@@ -58,42 +74,48 @@ export class MailController {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@Post('send-excel')
|
||||
@UseInterceptors(FileInterceptor('file'))
|
||||
@ApiSendMailExcel()
|
||||
async sendMailExcel(@Headers() headers:{password:string},@Body() file: Express.Multer.File) {
|
||||
|
||||
if (!headers.password) {
|
||||
throw new UnauthorizedException('Header "Password" es requerido');
|
||||
async sendMailExcel(
|
||||
@Headers() headers: { token: string },
|
||||
@UploadedFile() file: Express.Multer.File
|
||||
) {
|
||||
if (!headers.token) {
|
||||
throw new UnauthorizedException('Header "token" es requerido');
|
||||
}
|
||||
|
||||
const sistem = await this.sistemaRepository.findOne({ where: { token: headers.password } });
|
||||
|
||||
|
||||
let payload;
|
||||
try {
|
||||
payload = await this.jwtService.verify(headers.token);
|
||||
} catch {
|
||||
throw new UnauthorizedException('Token inválido');
|
||||
}
|
||||
|
||||
const sistem = await this.sistemaService.findByNombre(payload.nombre);
|
||||
if (!sistem) {
|
||||
throw new UnauthorizedException('Password incorrecto');
|
||||
throw new UnauthorizedException('Sistema no encontrado');
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
|
||||
throw new Error('Archivo Excel no encontrado');
|
||||
}
|
||||
|
||||
const emails=this.excelService.readEmailsFromExcel(file);
|
||||
let fechaActual: Date = new Date();
|
||||
|
||||
for (const email of await emails) {
|
||||
}
|
||||
|
||||
const emails = await this.excelService.readEmailsFromExcel(file);
|
||||
const fechaActual: Date = new Date();
|
||||
|
||||
for (const email of emails) {
|
||||
try {
|
||||
await this.mailService.sendMail(email, "subject", "text","html", fechaActual,sistem);
|
||||
console.log(`📧 Enviado a: ${email}`);
|
||||
await this.mailService.sendMail(email, 'subject', 'text', 'html', fechaActual, sistem);
|
||||
console.log(`Enviado a: ${email}`);
|
||||
} catch (error) {
|
||||
console.error(`❌ Error enviando a ${email}:`, error.message);
|
||||
console.error(`Error enviando a ${email}:`, error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiFindAllMails()
|
||||
async findAll(@Headers() headers:{token:string}){
|
||||
|
||||
return await this.mailService.findAll(headers.token)
|
||||
return { message: 'Correos enviados (si no hubo errores)' };
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
+33
-129
File diff suppressed because one or more lines are too long
@@ -7,11 +7,13 @@ import {
|
||||
Status,
|
||||
Correo,
|
||||
Sistema,
|
||||
}from 'src/typeorm/votacionesPrueba.entity'
|
||||
}from 'src/typeorm/entidades'
|
||||
import { SistemaModule } from 'src/sistema/sistema.module';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { AuthService } from 'src/auth/auth.service';
|
||||
|
||||
@Module({
|
||||
providers: [MailService],
|
||||
providers: [MailService,JwtService,AuthService],
|
||||
imports: [
|
||||
ExcelModule,
|
||||
SistemaModule,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { MailService } from './mail.service';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Correo, Sistema, Status } from '../typeorm/votacionesPrueba.entity'; // Ajusta si es necesario
|
||||
import { Correo, Sistema, Status } from '../typeorm/entidades'; // Ajusta si es necesario
|
||||
|
||||
describe('MailService', () => {
|
||||
let service: MailService;
|
||||
|
||||
+69
-25
@@ -3,18 +3,25 @@ import * as nodemailer from 'nodemailer';
|
||||
import * as dotenv from 'dotenv';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Correo, Sistema, Status } from '../typeorm/votacionesPrueba.entity';
|
||||
import { Correo, Sistema, Status } from '../typeorm/entidades';
|
||||
import { SistemaService } from 'src/sistema/sistema.service';
|
||||
import { SendCorreoDto } from 'src/mail/dto/send-email.dto';
|
||||
import { AuthService } from 'src/auth/auth.service';
|
||||
import { decrypt } from '../crypto/crypto.util';
|
||||
|
||||
|
||||
dotenv.config();
|
||||
|
||||
@Injectable()
|
||||
export class MailService {
|
||||
private transporter;
|
||||
|
||||
constructor(
|
||||
private readonly sistemaService: SistemaService,
|
||||
private readonly authService: AuthService,
|
||||
@InjectRepository(Correo) private readonly correoRepository: Repository<Correo>,
|
||||
@InjectRepository(Status) private readonly statusRepository: Repository<Status>,
|
||||
@InjectRepository(Sistema) private readonly sistemaRepository: Repository<Sistema>
|
||||
@InjectRepository(Sistema) private readonly sistemaRepositosistemaRepositoryry: Repository<Sistema>
|
||||
|
||||
|
||||
) {
|
||||
|
||||
@@ -31,6 +38,8 @@ export class MailService {
|
||||
},
|
||||
}); */
|
||||
|
||||
|
||||
/*
|
||||
this.transporter = nodemailer.createTransport({
|
||||
host: 'smtp.gmail.com', // o smtp‑relay.gmail.com (ver punto 2)
|
||||
port: 587,
|
||||
@@ -45,7 +54,7 @@ export class MailService {
|
||||
});
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
this.transporter = nodemailer.createTransport({
|
||||
@@ -57,39 +66,74 @@ export class MailService {
|
||||
}
|
||||
|
||||
|
||||
async findAll(TOKEN:string){
|
||||
|
||||
async findAllBySistema(TOKEN:string,nombreSistema:string){
|
||||
|
||||
|
||||
if (!TOKEN) {
|
||||
throw new UnauthorizedException('Header "Password" es requerido');
|
||||
}
|
||||
|
||||
const sistem = await this.sistemaRepository.findOne({ where: { token:TOKEN } });
|
||||
|
||||
if (!sistem) {
|
||||
|
||||
|
||||
|
||||
const sistem=await this.sistemaService.acceso(TOKEN)
|
||||
if(!sistem){
|
||||
throw new UnauthorizedException('Password incorrecto');
|
||||
}
|
||||
|
||||
|
||||
const result= await this.correoRepository.find()
|
||||
const result= await this.correoRepository.find({where:{
|
||||
id_sistema:{nombre_sistema:nombreSistema}
|
||||
},
|
||||
relations: {
|
||||
id_sistema: true,
|
||||
id_status: true,
|
||||
},}
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
async sendMail(to: string, subject: string, text: string, html: string, fecha_recibido: Date, sistema, adjuntos?: any[] ) {
|
||||
async sendMail(sendEmail:SendCorreoDto,sistem:Sistema,) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const decryptedPassword = decrypt(
|
||||
sistem.email_password_encrypted,
|
||||
sistem.email_password_iv
|
||||
);
|
||||
|
||||
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: 'smtp.gmail.com', // o smtp‑relay.gmail.com (ver punto 2)
|
||||
port: 587,
|
||||
secure: false,
|
||||
requireTLS: true, // TLS STARTTLS
|
||||
auth: { user:sistem.email, pass:decryptedPassword},
|
||||
pool: true, // <‑‑ activa reuse
|
||||
maxConnections: 1, // una sola conexión viva
|
||||
maxMessages: 100, // reabrir después de 100 envíos
|
||||
rateDelta: 2000, // ventana 1 s
|
||||
rateLimit: 1 // máx. 5 mensajes/seg
|
||||
});
|
||||
|
||||
|
||||
|
||||
console.log("estos son los archivos adjuntos en el service",adjuntos);
|
||||
|
||||
|
||||
|
||||
console.log("estos son los archivos adjuntos en el service",sendEmail.adjuntos);
|
||||
|
||||
|
||||
|
||||
const mailOptions = {
|
||||
from: process.env.USER_GMAIL,
|
||||
to,
|
||||
subject,
|
||||
text,
|
||||
html,
|
||||
from: sistem.email,
|
||||
to:sendEmail.to,
|
||||
subject:sendEmail.subject,
|
||||
text: sendEmail.text,
|
||||
html:sendEmail.html,
|
||||
|
||||
// OJO: nodemailer usa 'attachments', no 'adjuntos'
|
||||
attachments: (adjuntos || []).map((adj) => {
|
||||
attachments: (sendEmail.adjuntos || []).map((adj) => {
|
||||
// Asegúrate de no incluir 'data:image/png;base64,' en 'content'
|
||||
let base64Clean = adj.content;
|
||||
// Si viene con prefijo "data:image...", lo quitamos
|
||||
@@ -114,7 +158,7 @@ export class MailService {
|
||||
|
||||
|
||||
|
||||
let resMail = await this.transporter.sendMail(mailOptions);
|
||||
let resMail = await transporter.sendMail(mailOptions);
|
||||
const statusTexto = resMail.accepted.length > 0 ? "Enviado" : "Fallido";
|
||||
|
||||
|
||||
@@ -128,10 +172,10 @@ export class MailService {
|
||||
|
||||
const info= this.correoRepository.create({
|
||||
id_status: status,
|
||||
id_sistema: sistema,
|
||||
fecha_recibido: fecha_recibido,
|
||||
id_sistema: sistem,
|
||||
fecha_recibido: sendEmail.fecha_recibido,
|
||||
fecha_enviado: new Date(),
|
||||
destinatario: to,
|
||||
destinatario: sendEmail.to,
|
||||
remitente: process.env.USER_GMAIL,
|
||||
|
||||
});
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { IsString, IsOptional, IsBoolean, IsNotEmpty } from 'class-validator';
|
||||
|
||||
// comprobar-sistema.dto.ts
|
||||
export class ComprobarSistemaDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
token: string;
|
||||
|
||||
}
|
||||
password: string;
|
||||
}
|
||||
|
||||
@@ -13,4 +13,14 @@ export class CreateSistemaDto {
|
||||
@IsString()
|
||||
password: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
email: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
email_password:string
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
|
||||
import { Controller, Get, Post, Body, Patch, Param, Query } from '@nestjs/common';
|
||||
import { SistemaService } from './sistema.service';
|
||||
import { CreateSistemaDto } from './dto/create-sistema.dto';
|
||||
import { ApiCreateSistema, ApiGenerarToken } from './sistema.decorators';
|
||||
|
||||
import { ComprobarSistemaDto } from './dto/comprobar-sistema';
|
||||
import { ApiAccesoSistema, ApiCreateSistema, ApiGenerarToken } from './sistema.decorators';
|
||||
|
||||
@Controller('sistema')
|
||||
export class SistemaController {
|
||||
@@ -16,7 +16,16 @@ export class SistemaController {
|
||||
|
||||
@Patch(':nombre_sistema')
|
||||
@ApiGenerarToken()
|
||||
update(@Param('nombre_sistema') nombre_sistema: string, @Body() password: string) {
|
||||
return this.sistemaService.Generar_Token(nombre_sistema, password);
|
||||
update(
|
||||
@Param('nombre_sistema') nombre_sistema: string,
|
||||
@Body() comprobarSistemaDto: ComprobarSistemaDto,
|
||||
) {
|
||||
return this.sistemaService.Generar_Token(nombre_sistema, comprobarSistemaDto.password);
|
||||
}
|
||||
|
||||
@ApiAccesoSistema()
|
||||
@Get('acceso')
|
||||
async acceso(@Query('token') token: string) {
|
||||
return this.sistemaService.acceso(token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,47 @@
|
||||
import { applyDecorators } from '@nestjs/common';
|
||||
import { ApiBody, ApiOperation, ApiParam } from '@nestjs/swagger';
|
||||
import { ApiBody, ApiOperation, ApiParam, ApiQuery } from '@nestjs/swagger';
|
||||
|
||||
export const ApiCreateSistema = () => {
|
||||
return applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Registrar un nuevo sistema',
|
||||
description: `Este endpoint permite dar de alta un sistema para poder utilizar funcionalidades autenticadas mediante contraseña.
|
||||
Se debe proporcionar:
|
||||
- **Nombre**: Nombre único del sistema.
|
||||
- **ip**: Dirección IP desde la cual se harán peticiones.
|
||||
- **password**: Contraseña segura que el sistema usará para autenticarse.`,
|
||||
description: `Este endpoint permite registrar un sistema que podrá autenticarse y utilizar servicios protegidos.
|
||||
Debe incluirse la contraseña maestra del administrador para autorizar la creación.
|
||||
Además, se deben proporcionar las credenciales del correo que el sistema usará para enviar emails.`,
|
||||
}),
|
||||
ApiBody({
|
||||
description: 'Datos del sistema a registrar',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
Nombre: { type: 'string', example: 'Sistema de Reportes' },
|
||||
ip: { type: 'string', example: '192.168.1.100' },
|
||||
password: { type: 'string', example: 'clave-segura-123' },
|
||||
Nombre: {
|
||||
type: 'string',
|
||||
example: 'Sistema de Notificaciones',
|
||||
description: 'Nombre único del sistema a registrar',
|
||||
},
|
||||
ip: {
|
||||
type: 'string',
|
||||
example: '192.168.0.10',
|
||||
description: 'Dirección IP desde donde se harán las peticiones',
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
format: 'email',
|
||||
example: 'sistema@gmail.com',
|
||||
description: 'Correo electrónico del sistema para enviar emails',
|
||||
},
|
||||
email_password: {
|
||||
type: 'string',
|
||||
example: 'contraseña-de-aplicacion',
|
||||
description: 'Contraseña de aplicación del correo proporcionado',
|
||||
},
|
||||
password: {
|
||||
type: 'string',
|
||||
example: 'clave-admin-secreta',
|
||||
description: 'Contraseña maestra para autorizar el registro',
|
||||
},
|
||||
},
|
||||
required: ['Nombre', 'ip', 'password'],
|
||||
required: ['Nombre', 'ip', 'email', 'email_password', 'password'],
|
||||
},
|
||||
})
|
||||
);
|
||||
@@ -30,21 +51,43 @@ export const ApiGenerarToken = () => {
|
||||
return applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Generar token JWT para un sistema',
|
||||
description: `Este endpoint permite generar un token de acceso válido para el sistema registrado.
|
||||
Se debe enviar el nombre del sistema como parámetro de ruta y la contraseña como cuerpo.`,
|
||||
description: `Este endpoint permite generar un token de autenticación JWT para un sistema previamente registrado.
|
||||
Se debe enviar el nombre del sistema como parámetro de ruta y su contraseña de registro en el cuerpo.`,
|
||||
}),
|
||||
ApiParam({
|
||||
name: 'nombre_sistema',
|
||||
required: true,
|
||||
description: 'Nombre exacto del sistema registrado',
|
||||
example: 'Sistema de Reportes',
|
||||
example: 'Sistema de Notificaciones',
|
||||
}),
|
||||
ApiBody({
|
||||
description: 'Contraseña del sistema',
|
||||
description: 'Contraseña del sistema para verificar identidad',
|
||||
schema: {
|
||||
type: 'string',
|
||||
example: 'clave-segura-123',
|
||||
type: 'object',
|
||||
properties: {
|
||||
password: {
|
||||
type: 'string',
|
||||
example: 'clave-admin-secreta',
|
||||
description: 'Contraseña de autenticación del sistema',
|
||||
},
|
||||
},
|
||||
required: ['password'],
|
||||
},
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
export const ApiAccesoSistema = () => {
|
||||
return applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Verificar acceso del sistema mediante token',
|
||||
description: `Este endpoint permite verificar si un token JWT enviado por un sistema es válido y tiene acceso.`,
|
||||
}),
|
||||
ApiQuery({
|
||||
name: 'token',
|
||||
required: true,
|
||||
description: 'Token JWT del sistema',
|
||||
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,14 +2,16 @@ import { Module } from '@nestjs/common';
|
||||
import { SistemaService } from './sistema.service';
|
||||
import { SistemaController } from './sistema.controller';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Sistema } from 'src/typeorm/votacionesPrueba.entity';
|
||||
import { Sistema } from 'src/typeorm/entidades';
|
||||
import { AuthModule } from 'src/auth/auth.module';
|
||||
|
||||
@Module({
|
||||
controllers: [SistemaController],
|
||||
providers: [SistemaService],
|
||||
imports:[
|
||||
TypeOrmModule.forFeature([
|
||||
Sistema])
|
||||
Sistema]),
|
||||
AuthModule
|
||||
],
|
||||
exports:[SistemaModule,SistemaService]
|
||||
})
|
||||
|
||||
@@ -1,63 +1,71 @@
|
||||
import { Injectable, NotFoundException, UnauthorizedException } from '@nestjs/common';
|
||||
import { CreateSistemaDto } from './dto/create-sistema.dto';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Sistema } from 'src/typeorm/votacionesPrueba.entity';
|
||||
import { Sistema } from 'src/typeorm/entidades';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { randomBytes } from 'crypto';
|
||||
import { ComprobarSistemaDto } from './dto/comprobar-sistema';
|
||||
import { AuthService } from 'src/auth/auth.service';
|
||||
import { encrypt } from 'src/crypto/crypto.util';
|
||||
|
||||
@Injectable()
|
||||
export class SistemaService {
|
||||
constructor(
|
||||
@InjectRepository(Sistema) private readonly sistemaRepository: Repository<Sistema>
|
||||
@InjectRepository(Sistema) private readonly sistemaRepository: Repository<Sistema>,
|
||||
private readonly authService: AuthService
|
||||
) {}
|
||||
|
||||
){}
|
||||
|
||||
generarPassword(longitud = 12): string {
|
||||
return randomBytes(longitud)
|
||||
.toString('base64')
|
||||
.slice(0, longitud)
|
||||
.replace(/[+/=]/g, () => String.fromCharCode(33 + Math.floor(Math.random() * 94))); // reemplaza caracteres raros
|
||||
}
|
||||
|
||||
|
||||
async Generar_Token(nombreSistema:string,adminPasword:string) {
|
||||
if(adminPasword!==process.env.ADMIN_PASSWORD){
|
||||
throw new UnauthorizedException('Password erroneo');
|
||||
async Generar_Token(nombreSistema: string, adminPassword: string) {
|
||||
if (adminPassword !== process.env.ADMIN_PASSWORD) {
|
||||
throw new UnauthorizedException('Password erróneo');
|
||||
}
|
||||
const sistema = await this.sistemaRepository.findOneBy({nombre_sistema:nombreSistema})
|
||||
if(!sistema){
|
||||
throw new NotFoundException('Sistema no encontrado')
|
||||
}
|
||||
sistema.token=this.generarPassword()
|
||||
|
||||
this.sistemaRepository.save(sistema)
|
||||
return sistema.token;
|
||||
const sistema = await this.sistemaRepository.findOneBy({ nombre_sistema: nombreSistema });
|
||||
if (!sistema) {
|
||||
throw new NotFoundException('Sistema no encontrado');
|
||||
}
|
||||
|
||||
const token = this.authService.generarToken({ sistemaId: sistema.id_sistema, nombre: sistema.nombre_sistema, ip:sistema.ip });
|
||||
return token;
|
||||
}
|
||||
|
||||
async acceso(TOKEN:string){
|
||||
const result = await this.sistemaRepository.findOne({where:{token:TOKEN}})
|
||||
if(!result){
|
||||
throw new UnauthorizedException('token erroneo')
|
||||
async acceso(token: string) {
|
||||
const decoded = this.authService.verificarToken(token);
|
||||
if (!decoded) {
|
||||
throw new UnauthorizedException('Token inválido');
|
||||
}
|
||||
return true
|
||||
|
||||
const sistema = await this.sistemaRepository.findOneBy({ id_sistema: decoded.sistemaId });
|
||||
if (!sistema) {
|
||||
throw new UnauthorizedException('Sistema no encontrado');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async create(createSistemaDto: CreateSistemaDto) {
|
||||
if(createSistemaDto.password!==process.env.ADMIN_PASSWORD){
|
||||
throw new UnauthorizedException('Password erroneo');
|
||||
if (createSistemaDto.password !== process.env.ADMIN_PASSWORD) {
|
||||
throw new UnauthorizedException('Password erróneo');
|
||||
}
|
||||
|
||||
const sistem = this.sistemaRepository.create({
|
||||
nombre_sistema:createSistemaDto.Nombre,
|
||||
ip:createSistemaDto.ip,
|
||||
});
|
||||
await this.sistemaRepository.save(sistem)
|
||||
const { encryptedData, iv } = encrypt(createSistemaDto.email_password);
|
||||
|
||||
return this.Generar_Token(createSistemaDto.Nombre,createSistemaDto.password);
|
||||
const sistema = this.sistemaRepository.create({
|
||||
nombre_sistema: createSistemaDto.Nombre,
|
||||
ip: createSistemaDto.ip,
|
||||
email:createSistemaDto.email,
|
||||
email_password_encrypted: encryptedData,
|
||||
email_password_iv: iv
|
||||
});
|
||||
await this.sistemaRepository.save(sistema);
|
||||
|
||||
return this.Generar_Token(createSistemaDto.Nombre, createSistemaDto.password);
|
||||
}
|
||||
|
||||
|
||||
async findByNombre(sistema:string){
|
||||
const sistem= this.sistemaRepository.findOne({where:{nombre_sistema:sistema}})
|
||||
if(!sistem){
|
||||
throw new UnauthorizedException('Password erróneo');
|
||||
|
||||
}
|
||||
return sistem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,21 @@ export class Sistema {
|
||||
@PrimaryGeneratedColumn()
|
||||
id_sistema: number;
|
||||
|
||||
@Column({ type: 'varchar', length: 255, nullable: true })
|
||||
token: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 50 })
|
||||
nombre_sistema: string;
|
||||
|
||||
@Column({ type: 'varchar', length: 50 })
|
||||
ip:string;
|
||||
|
||||
@Column()
|
||||
email: string;
|
||||
|
||||
@Column()
|
||||
email_password_encrypted: string;
|
||||
|
||||
@Column()
|
||||
email_password_iv: string;
|
||||
|
||||
@OneToMany(() => Correo, (correo) => correo.id_sistema)
|
||||
correos: Correo[];
|
||||
}
|
||||
Reference in New Issue
Block a user