json logging + fix lint

This commit is contained in:
unurled 2025-02-07 14:54:10 +01:00
parent 24f3fb9b8e
commit 13ec6e388d
Signed by: unurled
GPG key ID: EFC5F5E709B47DDD
18 changed files with 551 additions and 465 deletions

View file

@ -1,15 +1,15 @@
// @ts-ignore // @ts-ignore
await Bun.build({ await Bun.build({
entrypoints: ["./src/app.ts"], entrypoints: ['./src/app.ts'],
format: "esm", format: 'esm',
outdir: "./dist", outdir: './dist',
target: "node", target: 'node',
external: [ external: [
"@nestjs/websockets/socket-module", '@nestjs/websockets/socket-module',
"@nestjs/microservices", '@nestjs/microservices',
"class-transformer/storage", 'class-transformer/storage',
"@fastify/view", '@fastify/view',
"@nestjs/platform-express", '@nestjs/platform-express',
], ],
minify: { minify: {
whitespace: true, whitespace: true,

View file

@ -1,13 +1,13 @@
import {CacheInterceptor} from "@nestjs/cache-manager"; import { CacheInterceptor } from '@nestjs/cache-manager';
import {VersionEntity} from "./common/models/entities/version.entity"; import { VersionEntity } from './common/models/entities/version.entity';
import {Controller, Get, UseInterceptors} from "@nestjs/common"; import { Controller, Get, UseInterceptors } from '@nestjs/common';
import {ApiTags} from "@nestjs/swagger"; import { ApiTags } from '@nestjs/swagger';
@Controller() @Controller()
@ApiTags("Misc") @ApiTags('Misc')
@UseInterceptors(CacheInterceptor) @UseInterceptors(CacheInterceptor)
export class AppController { export class AppController {
@Get("version") @Get('version')
async getVersion(): Promise<VersionEntity> { async getVersion(): Promise<VersionEntity> {
return { return {
version: process.env.npm_package_version, version: process.env.npm_package_version,

View file

@ -1,33 +1,42 @@
import {FastifyAdapter, NestFastifyApplication} from "@nestjs/platform-fastify"; import {
import {CustomValidationPipe} from "./common/pipes/custom-validation.pipe"; FastifyAdapter,
import {LoggerMiddleware} from "./common/middlewares/logger.middleware"; NestFastifyApplication,
import {SwaggerTheme, SwaggerThemeNameEnum} from "swagger-themes"; } from '@nestjs/platform-fastify';
import {DocumentBuilder, SwaggerModule} from "@nestjs/swagger"; import { CustomValidationPipe } from './common/pipes/custom-validation.pipe';
import {FastifyListenOptions} from "fastify/types/instance"; import { LoggerMiddleware } from './common/middlewares/logger.middleware';
import fastifyMultipart from "@fastify/multipart"; import { SwaggerTheme, SwaggerThemeNameEnum } from 'swagger-themes';
import fastifyStatic from "@fastify/static"; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import fastifyHelmet from "@fastify/helmet"; import { FastifyListenOptions } from 'fastify/types/instance';
import {NestFactory} from "@nestjs/core"; import fastifyMultipart from '@fastify/multipart';
import {AppModule} from "./app.module"; import fastifyHelmet from '@fastify/helmet';
import {Logger} from "@nestjs/common"; import { NestFactory } from '@nestjs/core';
import * as process from "process"; import { AppModule } from './app.module';
import {join} from "node:path"; import { ConsoleLogger, Logger } from '@nestjs/common';
import * as process from 'process';
const logger: Logger = new Logger("App"); const logger: Logger = new Logger('App');
process.env.APP_NAME = process.env.npm_package_name.split("-").map((word: string): string => word.charAt(0).toUpperCase() + word.slice(1)).join(" "); process.env.APP_NAME = process.env.npm_package_name
.split('-')
.map((word: string): string => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
const port: number = parseInt(process.env.PORT) || 4000; const port: number = parseInt(process.env.PORT) || 4000;
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>( const app = await NestFactory.create<NestFastifyApplication>(
AppModule, AppModule,
new FastifyAdapter({ exposeHeadRoutes: true }), new FastifyAdapter({ exposeHeadRoutes: true }),
{
logger: new ConsoleLogger({
json: true,
}),
},
); );
await loadServer(app); await loadServer(app);
await app.listen({ await app.listen({
port: port, port: port,
host: "0.0.0.0", host: '0.0.0.0',
} as FastifyListenOptions); } as FastifyListenOptions);
app.enableShutdownHooks(); app.enableShutdownHooks();
logger.log(`Listening on http://0.0.0.0:${port}`); logger.log(`Listening on http://0.0.0.0:${port}`);
@ -37,22 +46,21 @@ async function loadServer(server: NestFastifyApplication){
// Config // Config
server.setGlobalPrefix(process.env.PREFIX); server.setGlobalPrefix(process.env.PREFIX);
server.enableCors({ server.enableCors({
origin: "*", origin: '*',
}); });
// Middlewares // Middlewares
server.use(new LoggerMiddleware().use); server.use(new LoggerMiddleware().use);
await server.register(fastifyMultipart as any); await server.register(fastifyMultipart as any);
await server.register(fastifyStatic as any, { await server.register(
root: join(process.cwd(), "public_answers"), fastifyHelmet as any,
prefix: "/public_answers/", {
});
await server.register(fastifyHelmet as any, {
contentSecurityPolicy: false, contentSecurityPolicy: false,
crossOriginEmbedderPolicy: false, crossOriginEmbedderPolicy: false,
crossOriginOpenerPolicy: false, crossOriginOpenerPolicy: false,
crossOriginResourcePolicy: false, crossOriginResourcePolicy: false,
} as any); } as any,
);
// Swagger // Swagger
const config = new DocumentBuilder() const config = new DocumentBuilder()
@ -65,14 +73,14 @@ async function loadServer(server: NestFastifyApplication){
const document = SwaggerModule.createDocument(server, config); const document = SwaggerModule.createDocument(server, config);
const theme = new SwaggerTheme(); const theme = new SwaggerTheme();
const customCss = theme.getBuffer(SwaggerThemeNameEnum.DARK); const customCss = theme.getBuffer(SwaggerThemeNameEnum.DARK);
SwaggerModule.setup("api", server, document, { SwaggerModule.setup('api', server, document, {
swaggerOptions: { swaggerOptions: {
filter: true, filter: true,
displayRequestDuration: true, displayRequestDuration: true,
persistAuthorization: true, persistAuthorization: true,
docExpansion: "none", docExpansion: 'none',
tagsSorter: "alpha", tagsSorter: 'alpha',
operationsSorter: "method", operationsSorter: 'method',
}, },
customCss, customCss,
}); });

View file

@ -1,24 +1,25 @@
import {Injectable, Logger, NestMiddleware} from "@nestjs/common"; import { Injectable, Logger, NestMiddleware } from '@nestjs/common';
import {FastifyReply, FastifyRequest} from "fastify"; import { FastifyReply, FastifyRequest } from 'fastify';
@Injectable() @Injectable()
export class LoggerMiddleware implements NestMiddleware { export class LoggerMiddleware implements NestMiddleware {
static logger: Logger = new Logger(LoggerMiddleware.name); static logger: Logger = new Logger(LoggerMiddleware.name);
use(req: FastifyRequest["raw"], res: FastifyReply["raw"], next: () => void){ use(req: FastifyRequest['raw'], res: FastifyReply['raw'], next: () => void) {
const startTime = Date.now(); const startTime = Date.now();
(res as any).on("finish", () => { (res as any).on('finish', () => {
const path = req.url; const path = req.url;
try { try {
const protocol = LoggerMiddleware.getProtocol(req); const protocol = LoggerMiddleware.getProtocol(req);
const method = req.method; const method = req.method;
if(method === "OPTIONS") if (method === 'OPTIONS') return;
return;
const statusCode = res.statusCode; const statusCode = res.statusCode;
const duration = Date.now() - startTime; const duration = Date.now() - startTime;
const resSize: any = res.getHeader("Content-Length") || "0"; const resSize: any = res.getHeader('Content-Length') || '0';
const intResSize = parseInt(resSize); const intResSize = parseInt(resSize);
LoggerMiddleware.logger.log(`${protocol} ${method} ${path} ${statusCode} ${duration}ms ${intResSize}`); LoggerMiddleware.logger.log(
`${protocol} ${method} ${path} ${statusCode} ${duration}ms ${intResSize}`,
);
LoggerMiddleware.logRequestTime(path, method, duration); LoggerMiddleware.logRequestTime(path, method, duration);
} catch (e) { } catch (e) {
LoggerMiddleware.logger.warn(`Can't log route ${path} : ${e}`); LoggerMiddleware.logger.warn(`Can't log route ${path} : ${e}`);
@ -27,11 +28,10 @@ export class LoggerMiddleware implements NestMiddleware{
next(); next();
} }
static getProtocol(req: FastifyRequest["raw"]): string{ static getProtocol(req: FastifyRequest['raw']): string {
const localPort: number = req.connection.localPort; const localPort: number = req.connection.localPort;
if(!localPort) if (!localPort) return 'H2';
return "H2"; return localPort.toString() === process.env.HTTPS_PORT ? 'HTTPS' : 'HTTP';
return localPort.toString() === process.env.HTTPS_PORT ? "HTTPS" : "HTTP";
} }
static logRequestTime(path: string, method: string, duration: number): void { static logRequestTime(path: string, method: string, duration: number): void {

View file

@ -1,4 +1,4 @@
import {IsNumber, IsOptional, Min} from "class-validator"; import { IsNumber, IsOptional, Min } from 'class-validator';
export class PaginationDto { export class PaginationDto {
@IsNumber() @IsNumber()

View file

@ -1,4 +1,4 @@
import {ApiProperty} from "@nestjs/swagger"; import { ApiProperty } from '@nestjs/swagger';
export class VersionEntity { export class VersionEntity {
@ApiProperty() @ApiProperty()

View file

@ -1,10 +1,10 @@
import { Controller, Delete, NotImplementedException } from "@nestjs/common"; import { Controller, Delete, NotImplementedException } from '@nestjs/common';
@Controller("auth") @Controller('auth')
export class AuthController { export class AuthController {
constructor() {} constructor() {}
@Delete("logout/all") @Delete('logout/all')
logoutAll() { logoutAll() {
throw new NotImplementedException(); throw new NotImplementedException();
} }

View file

@ -1,5 +1,5 @@
import {Injectable} from "@nestjs/common"; import { Injectable } from '@nestjs/common';
import {AuthGuard} from "@nestjs/passport"; import { AuthGuard } from '@nestjs/passport';
@Injectable() @Injectable()
export class JwtAuthGuard extends AuthGuard("jwt"){} export class JwtAuthGuard extends AuthGuard('jwt') {}

View file

@ -1,4 +1,4 @@
import {IsNotEmpty, IsString} from "class-validator"; import { IsNotEmpty, IsString } from 'class-validator';
export class LocalLoginDto { export class LocalLoginDto {
@IsString() @IsString()

View file

@ -1,4 +1,4 @@
import {Exclude} from "class-transformer"; import { Exclude } from 'class-transformer';
export class UserEntity { export class UserEntity {
id: string; id: string;

View file

@ -1,17 +1,20 @@
import {Injectable} from "@nestjs/common"; import { Injectable } from '@nestjs/common';
import * as crypto from "crypto"; import * as crypto from 'crypto';
@Injectable() @Injectable()
export class CipherService { export class CipherService {
// Hash functions // Hash functions
getSum(content: Bun.BlobOrStringOrBuffer): string { getSum(content: Bun.BlobOrStringOrBuffer): string {
if(!content) content = ""; if (!content) content = '';
return new Bun.CryptoHasher("sha256").update(content).digest().toString("hex"); return new Bun.CryptoHasher('sha256')
.update(content)
.digest()
.toString('hex');
} }
hashPassword(content: Bun.StringOrBuffer, cost = 10): string { hashPassword(content: Bun.StringOrBuffer, cost = 10): string {
return Bun.password.hashSync(content, { return Bun.password.hashSync(content, {
algorithm: "argon2id", algorithm: 'argon2id',
timeCost: cost, timeCost: cost,
}); });
} }
@ -23,126 +26,189 @@ export class CipherService{
// Symmetric functions // Symmetric functions
private prepareEncryptionKey(encryptionKey: string | Buffer): Buffer { private prepareEncryptionKey(encryptionKey: string | Buffer): Buffer {
let keyBuffer: Buffer; let keyBuffer: Buffer;
if(typeof encryptionKey === "string") if (typeof encryptionKey === 'string')
keyBuffer = Buffer.from(encryptionKey); keyBuffer = Buffer.from(encryptionKey);
else else keyBuffer = encryptionKey;
keyBuffer = encryptionKey;
const key = Buffer.alloc(64); const key = Buffer.alloc(64);
keyBuffer.copy(key); keyBuffer.copy(key);
return key; return key;
} }
cipherSymmetric(content: string, encryptionKey: string | Buffer): string { cipherSymmetric(content: string, encryptionKey: string | Buffer): string {
if(!content) content = ""; if (!content) content = '';
return this.cipherBufferSymmetric(Buffer.from(content, "utf-8"), encryptionKey).toString("hex"); return this.cipherBufferSymmetric(
Buffer.from(content, 'utf-8'),
encryptionKey,
).toString('hex');
} }
cipherBufferSymmetric(content: Buffer, encryptionKey: string | Buffer): Buffer{ cipherBufferSymmetric(
content: Buffer,
encryptionKey: string | Buffer,
): Buffer {
if (!content) content = Buffer.alloc(0); if (!content) content = Buffer.alloc(0);
const iv = crypto.randomBytes(12); const iv = crypto.randomBytes(12);
const key = this.prepareEncryptionKey(encryptionKey); const key = this.prepareEncryptionKey(encryptionKey);
const cipher = crypto.createCipheriv("aes-256-gcm", key.subarray(0, 32), iv); const cipher = crypto.createCipheriv(
'aes-256-gcm',
key.subarray(0, 32),
iv,
);
const encrypted = Buffer.concat([cipher.update(content), cipher.final()]); const encrypted = Buffer.concat([cipher.update(content), cipher.final()]);
const tag = cipher.getAuthTag(); const tag = cipher.getAuthTag();
return Buffer.concat([iv, encrypted, tag]); return Buffer.concat([iv, encrypted, tag]);
} }
decipherSymmetric(encryptedContent: string, encryptionKey: string | Buffer): string{ decipherSymmetric(
return this.decipherBufferSymmetric(Buffer.from(encryptedContent, "hex"), encryptionKey).toString("utf-8"); encryptedContent: string,
encryptionKey: string | Buffer,
): string {
return this.decipherBufferSymmetric(
Buffer.from(encryptedContent, 'hex'),
encryptionKey,
).toString('utf-8');
} }
decipherBufferSymmetric(encryptedContent: Buffer, encryptionKey: string | Buffer): Buffer{ decipherBufferSymmetric(
encryptedContent: Buffer,
encryptionKey: string | Buffer,
): Buffer {
const iv = encryptedContent.subarray(0, 12); const iv = encryptedContent.subarray(0, 12);
const encrypted = encryptedContent.subarray(12, encryptedContent.length - 16); const encrypted = encryptedContent.subarray(
12,
encryptedContent.length - 16,
);
const tag = encryptedContent.subarray(encryptedContent.length - 16); const tag = encryptedContent.subarray(encryptedContent.length - 16);
const key = this.prepareEncryptionKey(encryptionKey); const key = this.prepareEncryptionKey(encryptionKey);
const decipher = crypto.createDecipheriv("aes-256-gcm", key.subarray(0, 32), iv); const decipher = crypto.createDecipheriv(
'aes-256-gcm',
key.subarray(0, 32),
iv,
);
decipher.setAuthTag(tag); decipher.setAuthTag(tag);
try { try {
return Buffer.concat([decipher.update(encrypted), decipher.final()]); return Buffer.concat([decipher.update(encrypted), decipher.final()]);
} catch (_) { } catch (_) {
throw new Error("Decryption failed"); throw new Error('Decryption failed');
} }
} }
cipherHardSymmetric(content: string, encryptionKey: string | Buffer, timeCost = 200000){ cipherHardSymmetric(
if(!content) content = ""; content: string,
encryptionKey: string | Buffer,
timeCost = 200000,
) {
if (!content) content = '';
const salt = crypto.randomBytes(32); const salt = crypto.randomBytes(32);
const key = crypto.pbkdf2Sync(encryptionKey, salt, timeCost, 64, "sha512"); const key = crypto.pbkdf2Sync(encryptionKey, salt, timeCost, 64, 'sha512');
const iv = crypto.randomBytes(16); const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv("aes-256-cbc", key.subarray(0, 32), iv); const cipher = crypto.createCipheriv(
let encrypted = cipher.update(content, "utf-8", "hex"); 'aes-256-cbc',
encrypted += cipher.final("hex"); key.subarray(0, 32),
const hmac = crypto.createHmac("sha256", key.subarray(32)); iv,
hmac.update(`${salt.toString("hex")}:${iv.toString("hex")}:${encrypted}`); );
const digest = hmac.digest("hex"); let encrypted = cipher.update(content, 'utf-8', 'hex');
return `${salt.toString("hex")}:${iv.toString("hex")}:${encrypted}:${digest}`; encrypted += cipher.final('hex');
const hmac = crypto.createHmac('sha256', key.subarray(32));
hmac.update(`${salt.toString('hex')}:${iv.toString('hex')}:${encrypted}`);
const digest = hmac.digest('hex');
return `${salt.toString('hex')}:${iv.toString('hex')}:${encrypted}:${digest}`;
} }
decipherHardSymmetric(encryptedContent: string, encryptionKey: string | Buffer, timeCost = 200000){ decipherHardSymmetric(
const [saltString, ivString, encryptedString, digest] = encryptedContent.split(":"); encryptedContent: string,
const salt = Buffer.from(saltString, "hex"); encryptionKey: string | Buffer,
const key = crypto.pbkdf2Sync(encryptionKey, salt, timeCost, 64, "sha512"); timeCost = 200000,
const iv = Buffer.from(ivString, "hex"); ) {
const hmac = crypto.createHmac("sha256", key.subarray(32)); const [saltString, ivString, encryptedString, digest] =
encryptedContent.split(':');
const salt = Buffer.from(saltString, 'hex');
const key = crypto.pbkdf2Sync(encryptionKey, salt, timeCost, 64, 'sha512');
const iv = Buffer.from(ivString, 'hex');
const hmac = crypto.createHmac('sha256', key.subarray(32));
hmac.update(`${saltString}:${ivString}:${encryptedString}`); hmac.update(`${saltString}:${ivString}:${encryptedString}`);
const calculatedDigest = hmac.digest("hex"); const calculatedDigest = hmac.digest('hex');
if(calculatedDigest !== digest) if (calculatedDigest !== digest) throw new Error('Integrity check failed');
throw new Error("Integrity check failed"); const decipher = crypto.createDecipheriv(
const decipher = crypto.createDecipheriv("aes-256-cbc", key.subarray(0, 32), iv); 'aes-256-cbc',
let decrypted = decipher.update(encryptedString, "hex", "utf-8"); key.subarray(0, 32),
decrypted += decipher.final("utf-8"); iv,
);
let decrypted = decipher.update(encryptedString, 'hex', 'utf-8');
decrypted += decipher.final('utf-8');
return decrypted; return decrypted;
} }
// Asymmetric functions // Asymmetric functions
generateKeyPair(modulusLength = 4096, privateEncryptionKey = null): crypto.KeyPairSyncResult<string, string>{ generateKeyPair(
modulusLength = 4096,
privateEncryptionKey = null,
): crypto.KeyPairSyncResult<string, string> {
if (!privateEncryptionKey) if (!privateEncryptionKey)
console.warn("No private encryption key provided, the private key will not be encrypted"); console.warn(
'No private encryption key provided, the private key will not be encrypted',
);
let options = undefined; let options = undefined;
if (privateEncryptionKey) { if (privateEncryptionKey) {
options = { options = {
cipher: "aes-256-cbc", cipher: 'aes-256-cbc',
passphrase: privateEncryptionKey, passphrase: privateEncryptionKey,
}; };
} }
return crypto.generateKeyPairSync("rsa", { return crypto.generateKeyPairSync('rsa', {
modulusLength: modulusLength, modulusLength: modulusLength,
publicKeyEncoding: { publicKeyEncoding: {
type: "spki", type: 'spki',
format: "pem", format: 'pem',
}, },
privateKeyEncoding: { privateKeyEncoding: {
type: "pkcs8", type: 'pkcs8',
format: "pem", format: 'pem',
...options, ...options,
}, },
}); });
} }
encryptAsymmetric(content: string, publicKey: string | Buffer): string { encryptAsymmetric(content: string, publicKey: string | Buffer): string {
if(!content) content = ""; if (!content) content = '';
const buffer = Buffer.from(content, "utf-8"); const buffer = Buffer.from(content, 'utf-8');
const encrypted = crypto.publicEncrypt({ const encrypted = crypto.publicEncrypt(
{
key: publicKey, key: publicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
}, buffer); },
return encrypted.toString("base64"); buffer,
);
return encrypted.toString('base64');
} }
decryptAsymmetric(encryptedContent: string, privateKey: string | Buffer, privateEncryptionKey = undefined): string{ decryptAsymmetric(
const buffer = Buffer.from(encryptedContent, "base64"); encryptedContent: string,
privateKey: string | Buffer,
privateEncryptionKey = undefined,
): string {
const buffer = Buffer.from(encryptedContent, 'base64');
if (!privateEncryptionKey) if (!privateEncryptionKey)
return crypto.privateDecrypt({ return crypto
.privateDecrypt(
{
key: privateKey, key: privateKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
}, buffer).toString("utf-8"); },
buffer,
)
.toString('utf-8');
else else
return crypto.privateDecrypt({ return crypto
.privateDecrypt(
{
key: privateKey, key: privateKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
passphrase: privateEncryptionKey, passphrase: privateEncryptionKey,
}, buffer).toString("utf-8"); },
buffer,
)
.toString('utf-8');
} }
// Secret functions // Secret functions
@ -151,7 +217,7 @@ export class CipherService{
* @param bytes Number of bytes to generate * @param bytes Number of bytes to generate
*/ */
generateRandomBytes(bytes = 32): string { generateRandomBytes(bytes = 32): string {
return crypto.randomBytes(bytes).toString("hex"); return crypto.randomBytes(bytes).toString('hex');
} }
/** /**
@ -159,15 +225,24 @@ export class CipherService{
* @param numbersNumber Number of numbers to generate * @param numbersNumber Number of numbers to generate
*/ */
generateRandomNumbers(numbersNumber = 6): string { generateRandomNumbers(numbersNumber = 6): string {
return Array.from({length: numbersNumber}, () => Math.floor(Math.random() * 10)).join(""); return Array.from({ length: numbersNumber }, () =>
Math.floor(Math.random() * 10),
).join('');
} }
maskSensitiveInfo(str: string, visibleCount: number = 4, maskChar: string = "*"){ maskSensitiveInfo(
return str.slice(0, visibleCount) + maskChar.repeat(Math.max(0, str.length - visibleCount)); str: string,
visibleCount: number = 4,
maskChar: string = '*',
) {
return (
str.slice(0, visibleCount) +
maskChar.repeat(Math.max(0, str.length - visibleCount))
);
} }
maskEmail(email: string) { maskEmail(email: string) {
const [username, domain] = email.split("@"); const [username, domain] = email.split('@');
return `${this.maskSensitiveInfo(username)}@${domain}`; return `${this.maskSensitiveInfo(username)}@${domain}`;
} }
} }

View file

@ -1,5 +1,5 @@
import {Injectable, Logger, OnModuleInit} from "@nestjs/common"; import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import {PrismaClient} from "@prisma/client"; import { PrismaClient } from '@prisma/client';
@Injectable() @Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit { export class PrismaService extends PrismaClient implements OnModuleInit {
@ -15,7 +15,9 @@ export class PrismaService extends PrismaClient implements OnModuleInit{
const duration: number = Date.now() - startTime; const duration: number = Date.now() - startTime;
const requestCount: number = args.length || 1; const requestCount: number = args.length || 1;
const resultCount: number = !result ? 0 : result.length || 1; const resultCount: number = !result ? 0 : result.length || 1;
PrismaService.logger.log(`${model.toUpperCase()} ${operation.toLowerCase()} ${duration}ms ${requestCount} ${resultCount}`); PrismaService.logger.log(
`${model.toUpperCase()} ${operation.toLowerCase()} ${duration}ms ${requestCount} ${resultCount}`,
);
return result; return result;
}, },
}, },

View file

@ -1,4 +1,9 @@
import {BadRequestException, Logger, ValidationError, ValidationPipe} from "@nestjs/common"; import {
BadRequestException,
Logger,
ValidationError,
ValidationPipe,
} from '@nestjs/common';
export class CustomValidationPipe extends ValidationPipe { export class CustomValidationPipe extends ValidationPipe {
private readonly logger = new Logger(CustomValidationPipe.name); private readonly logger = new Logger(CustomValidationPipe.name);
@ -15,7 +20,7 @@ export class CustomValidationPipe extends ValidationPipe{
if (this.isDetailedOutputDisabled) { if (this.isDetailedOutputDisabled) {
return new BadRequestException(); return new BadRequestException();
} }
const messages = validationErrors.map(error => ({ const messages = validationErrors.map((error) => ({
property: error.property, property: error.property,
constraints: error.constraints, constraints: error.constraints,
})); }));

View file

@ -1,13 +1,13 @@
import {Controller, Get, Req, UseGuards} from "@nestjs/common"; import { Controller, Get, Req, UseGuards } from '@nestjs/common';
import {JwtAuthGuard} from "../../common/modules/auth/guards/jwt-auth.guard"; import { JwtAuthGuard } from '../../common/modules/auth/guards/jwt-auth.guard';
import {UserEntity} from "../../common/modules/auth/models/entities/user.entity"; import { UserEntity } from '../../common/modules/auth/models/entities/user.entity';
import {ApiBearerAuth} from "@nestjs/swagger"; import { ApiBearerAuth } from '@nestjs/swagger';
@Controller("users") @Controller('users')
export class UsersController { export class UsersController {
constructor() {} constructor() {}
@Get("me") @Get('me')
@UseGuards(JwtAuthGuard) @UseGuards(JwtAuthGuard)
@ApiBearerAuth() @ApiBearerAuth()
getMyself(@Req() req: any): UserEntity { getMyself(@Req() req: any): UserEntity {

View file

@ -1,6 +1,6 @@
import {Module} from "@nestjs/common"; import { Module } from '@nestjs/common';
import {UsersService} from "./users.service"; import { UsersService } from './users.service';
import {UsersController} from "./users.controller"; import { UsersController } from './users.controller';
@Module({ @Module({
providers: [UsersService], providers: [UsersService],

View file

@ -1,12 +1,10 @@
import {Injectable, NotFoundException} from "@nestjs/common"; import { Injectable, NotFoundException } from '@nestjs/common';
import {UserEntity} from "../../common/modules/auth/models/entities/user.entity"; import { UserEntity } from '../../common/modules/auth/models/entities/user.entity';
import {PrismaService} from "../../common/modules/helper/prisma.service"; import { PrismaService } from '../../common/modules/helper/prisma.service';
@Injectable() @Injectable()
export class UsersService { export class UsersService {
constructor( constructor(private readonly prismaService: PrismaService) {}
private readonly prismaService: PrismaService,
){}
async getUserById(id: string) { async getUserById(id: string) {
const user = await this.prismaService.users.findUnique({ const user = await this.prismaService.users.findUnique({
@ -17,8 +15,7 @@ export class UsersService{
email_verifications: true, email_verifications: true,
}, },
}); });
if(!user) if (!user) throw new NotFoundException('User not found');
throw new NotFoundException("User not found");
return new UserEntity({ return new UserEntity({
id: user.id, id: user.id,
username: user.username, username: user.username,
@ -40,8 +37,7 @@ export class UsersService{
email_verifications: true, email_verifications: true,
}, },
}); });
if(!user) if (!user) throw new NotFoundException('User not found');
throw new NotFoundException("User not found");
return new UserEntity({ return new UserEntity({
id: user.id, id: user.id,
username: user.username, username: user.username,