Se agregó módulo de sistemas

This commit is contained in:
2025-04-09 11:10:28 -06:00
parent 38ea46c8ad
commit 1895e29cf2
13 changed files with 220 additions and 10 deletions
+2
View File
@@ -5,6 +5,7 @@ import { MailModule } from './mail/mail.module';
import {ExcelModule} from './excel/excel.module'
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule } from '@nestjs/config';
import { SistemaModule } from './sistema/sistema.module';
@@ -28,6 +29,7 @@ import { ConfigModule } from '@nestjs/config';
MailModule,
ExcelModule,
SistemaModule,
],
+6 -6
View File
@@ -30,24 +30,24 @@ export class MailController {
@Post('send')
@ApiSendMail()
async sendMail(
@Headers() headers:{password:string},
@Headers() headers:{token:string},
@Body() body: { to: string; subject: string; text: string; fecha_recibido: Date, html:string, adjuntos:any }) {
/*
// esta parte hay que rehacerla, se tiene que obtener la contraseña del sistema en base a la clave del sistema.
// debe de existir un modulo para crear contraseñas para las apis y administrar esas contraseñas
if (!headers.password) {
if (!headers.token) {
throw new UnauthorizedException('Header "Password" es requerido');
}
const sistem = await this.sistemaRepository.findOne({ where: { password: headers.password } });
const sistem = await this.sistemaRepository.findOne({ where: { token: headers.token } });
if (!sistem) {
throw new UnauthorizedException('Password incorrecto');
} */
}
@@ -73,7 +73,7 @@ export class MailController {
throw new UnauthorizedException('Header "Password" es requerido');
}
const sistem = await this.sistemaRepository.findOne({ where: { password: headers.password } });
const sistem = await this.sistemaRepository.findOne({ where: { token: headers.password } });
if (!sistem) {
throw new UnauthorizedException('Password incorrecto');
+12 -2
View File
@@ -10,8 +10,18 @@ export const ApiSendMail = () => {
- **subject**: Asunto del correo.
- **text**: Cuerpo del mensaje.
- **fecha_recibido**: Fecha en que se registró la solicitud.
- **sistema**: contraseña del sistema.`,
}),
- **sistema**: contraseña del sistema.
- **html**: se puede mandar html
- **adjuntos**:mandar qr
(Se requiere una contraseña de aplicación
No caducan automáticamente.
Pero se invalidan si:
Cambias la contraseña de tu cuenta.
Desactivas la verificación en dos pasos.
Revocas el acceso desde https://myaccount.google.com/apppasswords.
Google detecta actividad sospechosa o problemas de seguridad.))`,
}),
ApiHeader({
name: 'password',
description: 'Contraseña del sistema para autenticación',
+2
View File
@@ -8,11 +8,13 @@ import {
Correo,
Sistema,
}from 'src/typeorm/votacionesPrueba.entity'
import { SistemaModule } from 'src/sistema/sistema.module';
@Module({
providers: [MailService],
imports: [
ExcelModule,
SistemaModule,
TypeOrmModule.forFeature([
Status,
Correo,
+16
View File
@@ -0,0 +1,16 @@
import { IsString, IsOptional, IsBoolean, IsNotEmpty } from 'class-validator';
export class CreateSistemaDto {
@IsNotEmpty()
@IsString()
Nombre:string;
@IsNotEmpty()
@IsString()
ip:string;
@IsNotEmpty()
@IsString()
password: string;
}
+22
View File
@@ -0,0 +1,22 @@
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import { SistemaService } from './sistema.service';
import { CreateSistemaDto } from './dto/create-sistema.dto';
import { ApiCreateSistema, ApiGenerarToken } from './sistema.decorators';
@Controller('sistema')
export class SistemaController {
constructor(private readonly sistemaService: SistemaService) {}
@Post()
@ApiCreateSistema()
create(@Body() createSistemaDto: CreateSistemaDto, password:string) {
return this.sistemaService.create(createSistemaDto);
}
@Patch(':nombre_sistema')
@ApiGenerarToken()
update(@Param('nombre_sistema') nombre_sistema: string, @Body() password: string) {
return this.sistemaService.Generar_Token(nombre_sistema, password);
}
}
+50
View File
@@ -0,0 +1,50 @@
import { applyDecorators } from '@nestjs/common';
import { ApiBody, ApiOperation, ApiParam } 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.`,
}),
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' },
},
required: ['Nombre', 'ip', 'password'],
},
})
);
};
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.`,
}),
ApiParam({
name: 'nombre_sistema',
required: true,
description: 'Nombre exacto del sistema registrado',
example: 'Sistema de Reportes',
}),
ApiBody({
description: 'Contraseña del sistema',
schema: {
type: 'string',
example: 'clave-segura-123',
},
})
);
};
+16
View File
@@ -0,0 +1,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';
@Module({
controllers: [SistemaController],
providers: [SistemaService],
imports:[
TypeOrmModule.forFeature([
Sistema])
],
exports:[SistemaModule]
})
export class SistemaModule {}
+53
View File
@@ -0,0 +1,53 @@
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 { Repository } from 'typeorm';
import { randomBytes } from 'crypto';
@Injectable()
export class SistemaService {
constructor(
@InjectRepository(Sistema) private readonly sistemaRepository: Repository<Sistema>
){}
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');
}
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;
}
async create(createSistemaDto: CreateSistemaDto) {
if(createSistemaDto.password!==process.env.ADMIN_PASSWORD){
throw new UnauthorizedException('Password erroneo');
}
const sistem = this.sistemaRepository.create({
nombre_sistema:createSistemaDto.Nombre,
ip:createSistemaDto.ip,
});
await this.sistemaRepository.save(sistem)
return this.Generar_Token(createSistemaDto.Nombre,createSistemaDto.password);
}
}
+6 -2
View File
@@ -1,3 +1,4 @@
import { isEmpty } from 'class-validator';
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, JoinColumn } from 'typeorm';
@Entity()
@@ -5,12 +6,15 @@ export class Sistema {
@PrimaryGeneratedColumn()
id_sistema: number;
@Column({ type: 'varchar', length: 50 })
password: string;
@Column({ type: 'varchar', length: 255, nullable: true })
token: string;
@Column({ type: 'varchar', length: 50 })
nombre_sistema: string;
@Column({ type: 'varchar', length: 50 })
ip:string
@OneToMany(() => Correo, (correo) => correo.id_sistema)
correos: Correo[];
}