Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 98e5159f2f | |||
| f86c4d4f2a | |||
| ffb2a1d64a | |||
| 4660214cd7 | |||
| 8e74802de7 | |||
| ce1d1396e0 | |||
| e5076603fd |
Generated
-11
@@ -25,7 +25,6 @@
|
||||
"class-validator": "^0.13.2",
|
||||
"csvtojson": "^2.0.10",
|
||||
"dotenv": "^16.0.3",
|
||||
"hcaptcha": "^0.1.1",
|
||||
"moment": "^2.29.4",
|
||||
"mysql2": "^2.3.3",
|
||||
"nodemailer": "^6.7.8",
|
||||
@@ -5049,11 +5048,6 @@
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
|
||||
},
|
||||
"node_modules/hcaptcha": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/hcaptcha/-/hcaptcha-0.1.1.tgz",
|
||||
"integrity": "sha512-iMrDmH2VpIEKOrcKWidVjI89FdDKTEdZ7PfPWkP27sTazIIkob8YfdY2ezaufAnWBiUUcvzsn0qF+dyXtBH2Vw=="
|
||||
},
|
||||
"node_modules/hexoid": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
|
||||
@@ -13436,11 +13430,6 @@
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
|
||||
},
|
||||
"hcaptcha": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/hcaptcha/-/hcaptcha-0.1.1.tgz",
|
||||
"integrity": "sha512-iMrDmH2VpIEKOrcKWidVjI89FdDKTEdZ7PfPWkP27sTazIIkob8YfdY2ezaufAnWBiUUcvzsn0qF+dyXtBH2Vw=="
|
||||
},
|
||||
"hexoid": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
"class-validator": "^0.13.2",
|
||||
"csvtojson": "^2.0.10",
|
||||
"dotenv": "^16.0.3",
|
||||
"hcaptcha": "^0.1.1",
|
||||
"moment": "^2.29.4",
|
||||
"mysql2": "^2.3.3",
|
||||
"nodemailer": "^6.7.8",
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { ApiBody, ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { Serealize } from '../interceptors/serialize.interceptor';
|
||||
import { HcaptchaGuard } from '../guards/hcaptcha.guard';
|
||||
import { TurnstileGuard } from '../guards/turnstile.guard';
|
||||
import { AuthService } from './auth.service';
|
||||
import { LoginAdminDto } from './dto/input/login-admin.dto';
|
||||
import { LoginOperadorDto } from './dto/input/login-operador.dto';
|
||||
@@ -15,7 +15,7 @@ export class AuthController {
|
||||
constructor(private authService: AuthService) {}
|
||||
|
||||
@Serealize(AuthTokenOutputDto)
|
||||
@UseGuards(HcaptchaGuard)
|
||||
@UseGuards(TurnstileGuard)
|
||||
@Post('login-admin')
|
||||
@ApiOperation({ description: 'Login del admin.' })
|
||||
@ApiBody({
|
||||
@@ -27,7 +27,7 @@ export class AuthController {
|
||||
}
|
||||
|
||||
@Serealize(AuthTokenOutputDto)
|
||||
@UseGuards(HcaptchaGuard)
|
||||
@UseGuards(TurnstileGuard)
|
||||
@Post('login-operador')
|
||||
@ApiOperation({ description: 'Login del operador.' })
|
||||
@ApiBody({
|
||||
@@ -45,7 +45,7 @@ export class AuthController {
|
||||
}
|
||||
|
||||
@Serealize(AuthTokenOutputDto)
|
||||
@UseGuards(HcaptchaGuard)
|
||||
@UseGuards(TurnstileGuard)
|
||||
@Post('login-usuario')
|
||||
@ApiOperation({ description: 'Login del usuario.' })
|
||||
@ApiBody({
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
const { verify } = require('hcaptcha');
|
||||
import {
|
||||
BadRequestException,
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
ForbiddenException,
|
||||
Injectable,
|
||||
InternalServerErrorException,
|
||||
} from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class HcaptchaGuard implements CanActivate {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
canActivate(
|
||||
context: ExecutionContext,
|
||||
): boolean | Promise<boolean> | Observable<boolean> {
|
||||
const secret = this.configService.get<string>('HCAPTCHA_KEY');
|
||||
const token = context.switchToHttp().getRequest().headers.hcaptcha;
|
||||
|
||||
if (this.configService.get<string>('STATE') !== 'produccion') return true;
|
||||
if (!token)
|
||||
throw new BadRequestException('No se mando un token de hcaptcha.');
|
||||
return verify(secret, token)
|
||||
.then((data) => {
|
||||
if (data.success === true) return true;
|
||||
else throw new ForbiddenException('El token de hcaptcha no es válido.');
|
||||
})
|
||||
.catch((err) => {
|
||||
throw new InternalServerErrorException(
|
||||
'Ocurrió un error con el hcaptcha.',
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
ForbiddenException,
|
||||
Injectable,
|
||||
InternalServerErrorException,
|
||||
} from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import * as https from 'https';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
function verifyTurnstile(
|
||||
secret: string,
|
||||
token: string,
|
||||
): Promise<{ success: boolean }> {
|
||||
const body = new URLSearchParams({ secret, response: token }).toString();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = https.request(
|
||||
{
|
||||
hostname: 'challenges.cloudflare.com',
|
||||
path: '/turnstile/v0/siteverify',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Content-Length': Buffer.byteLength(body),
|
||||
},
|
||||
},
|
||||
(res) => {
|
||||
let data = '';
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
res.on('end', () => {
|
||||
try {
|
||||
resolve(JSON.parse(data));
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
req.on('error', reject);
|
||||
req.write(body);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class TurnstileGuard implements CanActivate {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
canActivate(
|
||||
context: ExecutionContext,
|
||||
): boolean | Promise<boolean> | Observable<boolean> {
|
||||
if (this.configService.get<string>('STATE') === 'desarrollo') return true;
|
||||
|
||||
const token = context.switchToHttp().getRequest().headers.turnstile;
|
||||
if (!token)
|
||||
throw new BadRequestException('No se envió un token de turnstile.');
|
||||
|
||||
const secret = this.configService.get<string>('TURNSTILE_SECRET_KEY');
|
||||
return verifyTurnstile(secret, token)
|
||||
.then((data) => {
|
||||
if (data.success === true) return true;
|
||||
throw new ForbiddenException('El token de turnstile no es válido.');
|
||||
})
|
||||
.catch((err) => {
|
||||
if (
|
||||
err instanceof ForbiddenException ||
|
||||
err instanceof BadRequestException
|
||||
)
|
||||
throw err;
|
||||
throw new InternalServerErrorException(
|
||||
'Ocurrió un error con turnstile.',
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -450,15 +450,35 @@ export class PrestamoService {
|
||||
if (filtros.pagina) {
|
||||
options.take = 25;
|
||||
options.skip = (parseInt(filtros.pagina) - 1) * 25;
|
||||
return this.fullInformacionPrestamoView
|
||||
.findAndCount(options)
|
||||
.then((infoPrestamos) => {
|
||||
const prestamos: Prestamo[] = [];
|
||||
|
||||
for (let i = 0; i < infoPrestamos[0].length; i++)
|
||||
prestamos.push(this.fullViewToPrestamo(infoPrestamos[0][i]));
|
||||
return [prestamos, infoPrestamos[1]];
|
||||
});
|
||||
const activoTrue =
|
||||
(typeof filtros.activo === 'boolean' && filtros.activo) ||
|
||||
(typeof filtros.activo === 'string' && filtros.activo === 'true');
|
||||
const canUseLightCount =
|
||||
activoTrue && !filtros.usuario && !filtros.id_tipo_usuario;
|
||||
|
||||
if (canUseLightCount) {
|
||||
const { usuario: _u, id_tipo_usuario: _tu, ...countWhere } =
|
||||
busqueda;
|
||||
const [rows, total] = await Promise.all([
|
||||
this.fullInformacionPrestamoView.find(options),
|
||||
this.informacionPrestamoView.count({
|
||||
where: countWhere as FindOptionsWhere<InformacionPrestamoView>,
|
||||
}),
|
||||
]);
|
||||
const prestamos = rows.map((row) => this.fullViewToPrestamo(row));
|
||||
|
||||
return [prestamos, total];
|
||||
}
|
||||
|
||||
const infoPrestamos = await this.fullInformacionPrestamoView.findAndCount(
|
||||
options,
|
||||
);
|
||||
const prestamos: Prestamo[] = [];
|
||||
|
||||
for (let i = 0; i < infoPrestamos[0].length; i++)
|
||||
prestamos.push(this.fullViewToPrestamo(infoPrestamos[0][i]));
|
||||
return [prestamos, infoPrestamos[1]];
|
||||
}
|
||||
options.order = { id_institucion: 'ASC', id_prestamo: 'ASC' };
|
||||
return this.fullInformacionPrestamoView.find(options);
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
import { Serealize } from '../interceptors/serialize.interceptor';
|
||||
import { HcaptchaGuard } from '../guards/hcaptcha.guard';
|
||||
import { TurnstileGuard } from '../guards/turnstile.guard';
|
||||
import { UsuarioService } from './usuario.service';
|
||||
import { ValidarUsuarioService } from '../validar-usuario/validar-usuario.service';
|
||||
import { Operador } from '../operador/entity/operador.entity';
|
||||
@@ -39,7 +39,7 @@ export class UsuarioController {
|
||||
|
||||
@Serealize(MessageOutputDto)
|
||||
@Post('registrar')
|
||||
@UseGuards(HcaptchaGuard)
|
||||
@UseGuards(TurnstileGuard)
|
||||
@ApiOperation({ description: 'Registro de usuario.' })
|
||||
@ApiBody({
|
||||
description: 'Variables que necesita el endpoint.',
|
||||
|
||||
Reference in New Issue
Block a user