json logging + fix lint
This commit is contained in:
parent
24f3fb9b8e
commit
13ec6e388d
18 changed files with 551 additions and 465 deletions
18
build.ts
18
build.ts
|
@ -1,15 +1,15 @@
|
|||
// @ts-ignore
|
||||
await Bun.build({
|
||||
entrypoints: ["./src/app.ts"],
|
||||
format: "esm",
|
||||
outdir: "./dist",
|
||||
target: "node",
|
||||
entrypoints: ['./src/app.ts'],
|
||||
format: 'esm',
|
||||
outdir: './dist',
|
||||
target: 'node',
|
||||
external: [
|
||||
"@nestjs/websockets/socket-module",
|
||||
"@nestjs/microservices",
|
||||
"class-transformer/storage",
|
||||
"@fastify/view",
|
||||
"@nestjs/platform-express",
|
||||
'@nestjs/websockets/socket-module',
|
||||
'@nestjs/microservices',
|
||||
'class-transformer/storage',
|
||||
'@fastify/view',
|
||||
'@nestjs/platform-express',
|
||||
],
|
||||
minify: {
|
||||
whitespace: true,
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import {CacheInterceptor} from "@nestjs/cache-manager";
|
||||
import {VersionEntity} from "./common/models/entities/version.entity";
|
||||
import {Controller, Get, UseInterceptors} from "@nestjs/common";
|
||||
import {ApiTags} from "@nestjs/swagger";
|
||||
import { CacheInterceptor } from '@nestjs/cache-manager';
|
||||
import { VersionEntity } from './common/models/entities/version.entity';
|
||||
import { Controller, Get, UseInterceptors } from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
|
||||
@Controller()
|
||||
@ApiTags("Misc")
|
||||
@ApiTags('Misc')
|
||||
@UseInterceptors(CacheInterceptor)
|
||||
export class AppController {
|
||||
@Get("version")
|
||||
@Get('version')
|
||||
async getVersion(): Promise<VersionEntity> {
|
||||
return {
|
||||
version: process.env.npm_package_version,
|
||||
|
|
64
src/app.ts
64
src/app.ts
|
@ -1,33 +1,42 @@
|
|||
import {FastifyAdapter, NestFastifyApplication} from "@nestjs/platform-fastify";
|
||||
import {CustomValidationPipe} from "./common/pipes/custom-validation.pipe";
|
||||
import {LoggerMiddleware} from "./common/middlewares/logger.middleware";
|
||||
import {SwaggerTheme, SwaggerThemeNameEnum} from "swagger-themes";
|
||||
import {DocumentBuilder, SwaggerModule} from "@nestjs/swagger";
|
||||
import {FastifyListenOptions} from "fastify/types/instance";
|
||||
import fastifyMultipart from "@fastify/multipart";
|
||||
import fastifyStatic from "@fastify/static";
|
||||
import fastifyHelmet from "@fastify/helmet";
|
||||
import {NestFactory} from "@nestjs/core";
|
||||
import {AppModule} from "./app.module";
|
||||
import {Logger} from "@nestjs/common";
|
||||
import * as process from "process";
|
||||
import {join} from "node:path";
|
||||
import {
|
||||
FastifyAdapter,
|
||||
NestFastifyApplication,
|
||||
} from '@nestjs/platform-fastify';
|
||||
import { CustomValidationPipe } from './common/pipes/custom-validation.pipe';
|
||||
import { LoggerMiddleware } from './common/middlewares/logger.middleware';
|
||||
import { SwaggerTheme, SwaggerThemeNameEnum } from 'swagger-themes';
|
||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||
import { FastifyListenOptions } from 'fastify/types/instance';
|
||||
import fastifyMultipart from '@fastify/multipart';
|
||||
import fastifyHelmet from '@fastify/helmet';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
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;
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create<NestFastifyApplication>(
|
||||
AppModule,
|
||||
new FastifyAdapter({ exposeHeadRoutes: true }),
|
||||
{
|
||||
logger: new ConsoleLogger({
|
||||
json: true,
|
||||
}),
|
||||
},
|
||||
);
|
||||
await loadServer(app);
|
||||
|
||||
await app.listen({
|
||||
port: port,
|
||||
host: "0.0.0.0",
|
||||
host: '0.0.0.0',
|
||||
} as FastifyListenOptions);
|
||||
app.enableShutdownHooks();
|
||||
logger.log(`Listening on http://0.0.0.0:${port}`);
|
||||
|
@ -37,22 +46,21 @@ async function loadServer(server: NestFastifyApplication){
|
|||
// Config
|
||||
server.setGlobalPrefix(process.env.PREFIX);
|
||||
server.enableCors({
|
||||
origin: "*",
|
||||
origin: '*',
|
||||
});
|
||||
|
||||
// Middlewares
|
||||
server.use(new LoggerMiddleware().use);
|
||||
await server.register(fastifyMultipart as any);
|
||||
await server.register(fastifyStatic as any, {
|
||||
root: join(process.cwd(), "public_answers"),
|
||||
prefix: "/public_answers/",
|
||||
});
|
||||
await server.register(fastifyHelmet as any, {
|
||||
await server.register(
|
||||
fastifyHelmet as any,
|
||||
{
|
||||
contentSecurityPolicy: false,
|
||||
crossOriginEmbedderPolicy: false,
|
||||
crossOriginOpenerPolicy: false,
|
||||
crossOriginResourcePolicy: false,
|
||||
} as any);
|
||||
} as any,
|
||||
);
|
||||
|
||||
// Swagger
|
||||
const config = new DocumentBuilder()
|
||||
|
@ -65,14 +73,14 @@ async function loadServer(server: NestFastifyApplication){
|
|||
const document = SwaggerModule.createDocument(server, config);
|
||||
const theme = new SwaggerTheme();
|
||||
const customCss = theme.getBuffer(SwaggerThemeNameEnum.DARK);
|
||||
SwaggerModule.setup("api", server, document, {
|
||||
SwaggerModule.setup('api', server, document, {
|
||||
swaggerOptions: {
|
||||
filter: true,
|
||||
displayRequestDuration: true,
|
||||
persistAuthorization: true,
|
||||
docExpansion: "none",
|
||||
tagsSorter: "alpha",
|
||||
operationsSorter: "method",
|
||||
docExpansion: 'none',
|
||||
tagsSorter: 'alpha',
|
||||
operationsSorter: 'method',
|
||||
},
|
||||
customCss,
|
||||
});
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
import {Injectable, Logger, NestMiddleware} from "@nestjs/common";
|
||||
import {FastifyReply, FastifyRequest} from "fastify";
|
||||
import { Injectable, Logger, NestMiddleware } from '@nestjs/common';
|
||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||
|
||||
@Injectable()
|
||||
export class LoggerMiddleware implements NestMiddleware {
|
||||
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();
|
||||
(res as any).on("finish", () => {
|
||||
(res as any).on('finish', () => {
|
||||
const path = req.url;
|
||||
try {
|
||||
const protocol = LoggerMiddleware.getProtocol(req);
|
||||
const method = req.method;
|
||||
if(method === "OPTIONS")
|
||||
return;
|
||||
if (method === 'OPTIONS') return;
|
||||
const statusCode = res.statusCode;
|
||||
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);
|
||||
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);
|
||||
} catch (e) {
|
||||
LoggerMiddleware.logger.warn(`Can't log route ${path} : ${e}`);
|
||||
|
@ -27,11 +28,10 @@ export class LoggerMiddleware implements NestMiddleware{
|
|||
next();
|
||||
}
|
||||
|
||||
static getProtocol(req: FastifyRequest["raw"]): string{
|
||||
static getProtocol(req: FastifyRequest['raw']): string {
|
||||
const localPort: number = req.connection.localPort;
|
||||
if(!localPort)
|
||||
return "H2";
|
||||
return localPort.toString() === process.env.HTTPS_PORT ? "HTTPS" : "HTTP";
|
||||
if (!localPort) return 'H2';
|
||||
return localPort.toString() === process.env.HTTPS_PORT ? 'HTTPS' : 'HTTP';
|
||||
}
|
||||
|
||||
static logRequestTime(path: string, method: string, duration: number): void {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {IsNumber, IsOptional, Min} from "class-validator";
|
||||
import { IsNumber, IsOptional, Min } from 'class-validator';
|
||||
|
||||
export class PaginationDto {
|
||||
@IsNumber()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {ApiProperty} from "@nestjs/swagger";
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class VersionEntity {
|
||||
@ApiProperty()
|
||||
|
|
|
@ -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 {
|
||||
constructor() {}
|
||||
|
||||
@Delete("logout/all")
|
||||
@Delete('logout/all')
|
||||
logoutAll() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {Injectable} from "@nestjs/common";
|
||||
import {AuthGuard} from "@nestjs/passport";
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard extends AuthGuard("jwt"){}
|
||||
export class JwtAuthGuard extends AuthGuard('jwt') {}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {IsNotEmpty, IsString} from "class-validator";
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class LocalLoginDto {
|
||||
@IsString()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {Exclude} from "class-transformer";
|
||||
import { Exclude } from 'class-transformer';
|
||||
|
||||
export class UserEntity {
|
||||
id: string;
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
import {Injectable} from "@nestjs/common";
|
||||
import * as crypto from "crypto";
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
@Injectable()
|
||||
export class CipherService {
|
||||
// Hash functions
|
||||
getSum(content: Bun.BlobOrStringOrBuffer): string {
|
||||
if(!content) content = "";
|
||||
return new Bun.CryptoHasher("sha256").update(content).digest().toString("hex");
|
||||
if (!content) content = '';
|
||||
return new Bun.CryptoHasher('sha256')
|
||||
.update(content)
|
||||
.digest()
|
||||
.toString('hex');
|
||||
}
|
||||
|
||||
hashPassword(content: Bun.StringOrBuffer, cost = 10): string {
|
||||
return Bun.password.hashSync(content, {
|
||||
algorithm: "argon2id",
|
||||
algorithm: 'argon2id',
|
||||
timeCost: cost,
|
||||
});
|
||||
}
|
||||
|
@ -23,126 +26,189 @@ export class CipherService{
|
|||
// Symmetric functions
|
||||
private prepareEncryptionKey(encryptionKey: string | Buffer): Buffer {
|
||||
let keyBuffer: Buffer;
|
||||
if(typeof encryptionKey === "string")
|
||||
if (typeof encryptionKey === 'string')
|
||||
keyBuffer = Buffer.from(encryptionKey);
|
||||
else
|
||||
keyBuffer = encryptionKey;
|
||||
else keyBuffer = encryptionKey;
|
||||
const key = Buffer.alloc(64);
|
||||
keyBuffer.copy(key);
|
||||
return key;
|
||||
}
|
||||
|
||||
cipherSymmetric(content: string, encryptionKey: string | Buffer): string {
|
||||
if(!content) content = "";
|
||||
return this.cipherBufferSymmetric(Buffer.from(content, "utf-8"), encryptionKey).toString("hex");
|
||||
if (!content) content = '';
|
||||
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);
|
||||
const iv = crypto.randomBytes(12);
|
||||
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 tag = cipher.getAuthTag();
|
||||
return Buffer.concat([iv, encrypted, tag]);
|
||||
}
|
||||
|
||||
decipherSymmetric(encryptedContent: string, encryptionKey: string | Buffer): string{
|
||||
return this.decipherBufferSymmetric(Buffer.from(encryptedContent, "hex"), encryptionKey).toString("utf-8");
|
||||
decipherSymmetric(
|
||||
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 encrypted = encryptedContent.subarray(12, encryptedContent.length - 16);
|
||||
const encrypted = encryptedContent.subarray(
|
||||
12,
|
||||
encryptedContent.length - 16,
|
||||
);
|
||||
const tag = encryptedContent.subarray(encryptedContent.length - 16);
|
||||
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);
|
||||
try {
|
||||
return Buffer.concat([decipher.update(encrypted), decipher.final()]);
|
||||
} catch (_) {
|
||||
throw new Error("Decryption failed");
|
||||
throw new Error('Decryption failed');
|
||||
}
|
||||
}
|
||||
|
||||
cipherHardSymmetric(content: string, encryptionKey: string | Buffer, timeCost = 200000){
|
||||
if(!content) content = "";
|
||||
cipherHardSymmetric(
|
||||
content: string,
|
||||
encryptionKey: string | Buffer,
|
||||
timeCost = 200000,
|
||||
) {
|
||||
if (!content) content = '';
|
||||
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 cipher = crypto.createCipheriv("aes-256-cbc", key.subarray(0, 32), iv);
|
||||
let encrypted = cipher.update(content, "utf-8", "hex");
|
||||
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}`;
|
||||
const cipher = crypto.createCipheriv(
|
||||
'aes-256-cbc',
|
||||
key.subarray(0, 32),
|
||||
iv,
|
||||
);
|
||||
let encrypted = cipher.update(content, 'utf-8', 'hex');
|
||||
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){
|
||||
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));
|
||||
decipherHardSymmetric(
|
||||
encryptedContent: string,
|
||||
encryptionKey: string | Buffer,
|
||||
timeCost = 200000,
|
||||
) {
|
||||
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}`);
|
||||
const calculatedDigest = hmac.digest("hex");
|
||||
if(calculatedDigest !== digest)
|
||||
throw new Error("Integrity check failed");
|
||||
const decipher = crypto.createDecipheriv("aes-256-cbc", key.subarray(0, 32), iv);
|
||||
let decrypted = decipher.update(encryptedString, "hex", "utf-8");
|
||||
decrypted += decipher.final("utf-8");
|
||||
const calculatedDigest = hmac.digest('hex');
|
||||
if (calculatedDigest !== digest) throw new Error('Integrity check failed');
|
||||
const decipher = crypto.createDecipheriv(
|
||||
'aes-256-cbc',
|
||||
key.subarray(0, 32),
|
||||
iv,
|
||||
);
|
||||
let decrypted = decipher.update(encryptedString, 'hex', 'utf-8');
|
||||
decrypted += decipher.final('utf-8');
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
// Asymmetric functions
|
||||
generateKeyPair(modulusLength = 4096, privateEncryptionKey = null): crypto.KeyPairSyncResult<string, string>{
|
||||
generateKeyPair(
|
||||
modulusLength = 4096,
|
||||
privateEncryptionKey = null,
|
||||
): crypto.KeyPairSyncResult<string, string> {
|
||||
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;
|
||||
if (privateEncryptionKey) {
|
||||
options = {
|
||||
cipher: "aes-256-cbc",
|
||||
cipher: 'aes-256-cbc',
|
||||
passphrase: privateEncryptionKey,
|
||||
};
|
||||
}
|
||||
return crypto.generateKeyPairSync("rsa", {
|
||||
return crypto.generateKeyPairSync('rsa', {
|
||||
modulusLength: modulusLength,
|
||||
publicKeyEncoding: {
|
||||
type: "spki",
|
||||
format: "pem",
|
||||
type: 'spki',
|
||||
format: 'pem',
|
||||
},
|
||||
privateKeyEncoding: {
|
||||
type: "pkcs8",
|
||||
format: "pem",
|
||||
type: 'pkcs8',
|
||||
format: 'pem',
|
||||
...options,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
encryptAsymmetric(content: string, publicKey: string | Buffer): string {
|
||||
if(!content) content = "";
|
||||
const buffer = Buffer.from(content, "utf-8");
|
||||
const encrypted = crypto.publicEncrypt({
|
||||
if (!content) content = '';
|
||||
const buffer = Buffer.from(content, 'utf-8');
|
||||
const encrypted = crypto.publicEncrypt(
|
||||
{
|
||||
key: publicKey,
|
||||
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{
|
||||
const buffer = Buffer.from(encryptedContent, "base64");
|
||||
decryptAsymmetric(
|
||||
encryptedContent: string,
|
||||
privateKey: string | Buffer,
|
||||
privateEncryptionKey = undefined,
|
||||
): string {
|
||||
const buffer = Buffer.from(encryptedContent, 'base64');
|
||||
if (!privateEncryptionKey)
|
||||
return crypto.privateDecrypt({
|
||||
return crypto
|
||||
.privateDecrypt(
|
||||
{
|
||||
key: privateKey,
|
||||
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
||||
}, buffer).toString("utf-8");
|
||||
},
|
||||
buffer,
|
||||
)
|
||||
.toString('utf-8');
|
||||
else
|
||||
return crypto.privateDecrypt({
|
||||
return crypto
|
||||
.privateDecrypt(
|
||||
{
|
||||
key: privateKey,
|
||||
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
||||
passphrase: privateEncryptionKey,
|
||||
}, buffer).toString("utf-8");
|
||||
},
|
||||
buffer,
|
||||
)
|
||||
.toString('utf-8');
|
||||
}
|
||||
|
||||
// Secret functions
|
||||
|
@ -151,7 +217,7 @@ export class CipherService{
|
|||
* @param bytes Number of bytes to generate
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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 = "*"){
|
||||
return str.slice(0, visibleCount) + maskChar.repeat(Math.max(0, str.length - visibleCount));
|
||||
maskSensitiveInfo(
|
||||
str: string,
|
||||
visibleCount: number = 4,
|
||||
maskChar: string = '*',
|
||||
) {
|
||||
return (
|
||||
str.slice(0, visibleCount) +
|
||||
maskChar.repeat(Math.max(0, str.length - visibleCount))
|
||||
);
|
||||
}
|
||||
|
||||
maskEmail(email: string) {
|
||||
const [username, domain] = email.split("@");
|
||||
const [username, domain] = email.split('@');
|
||||
return `${this.maskSensitiveInfo(username)}@${domain}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {Injectable, Logger, OnModuleInit} from "@nestjs/common";
|
||||
import {PrismaClient} from "@prisma/client";
|
||||
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
@Injectable()
|
||||
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 requestCount: number = args.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;
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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 {
|
||||
private readonly logger = new Logger(CustomValidationPipe.name);
|
||||
|
@ -15,7 +20,7 @@ export class CustomValidationPipe extends ValidationPipe{
|
|||
if (this.isDetailedOutputDisabled) {
|
||||
return new BadRequestException();
|
||||
}
|
||||
const messages = validationErrors.map(error => ({
|
||||
const messages = validationErrors.map((error) => ({
|
||||
property: error.property,
|
||||
constraints: error.constraints,
|
||||
}));
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import {Controller, Get, Req, UseGuards} from "@nestjs/common";
|
||||
import {JwtAuthGuard} from "../../common/modules/auth/guards/jwt-auth.guard";
|
||||
import {UserEntity} from "../../common/modules/auth/models/entities/user.entity";
|
||||
import {ApiBearerAuth} from "@nestjs/swagger";
|
||||
import { Controller, Get, Req, UseGuards } from '@nestjs/common';
|
||||
import { JwtAuthGuard } from '../../common/modules/auth/guards/jwt-auth.guard';
|
||||
import { UserEntity } from '../../common/modules/auth/models/entities/user.entity';
|
||||
import { ApiBearerAuth } from '@nestjs/swagger';
|
||||
|
||||
@Controller("users")
|
||||
@Controller('users')
|
||||
export class UsersController {
|
||||
constructor() {}
|
||||
|
||||
@Get("me")
|
||||
@Get('me')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
getMyself(@Req() req: any): UserEntity {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {Module} from "@nestjs/common";
|
||||
import {UsersService} from "./users.service";
|
||||
import {UsersController} from "./users.controller";
|
||||
import { Module } from '@nestjs/common';
|
||||
import { UsersService } from './users.service';
|
||||
import { UsersController } from './users.controller';
|
||||
|
||||
@Module({
|
||||
providers: [UsersService],
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import {Injectable, NotFoundException} from "@nestjs/common";
|
||||
import {UserEntity} from "../../common/modules/auth/models/entities/user.entity";
|
||||
import {PrismaService} from "../../common/modules/helper/prisma.service";
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { UserEntity } from '../../common/modules/auth/models/entities/user.entity';
|
||||
import { PrismaService } from '../../common/modules/helper/prisma.service';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(
|
||||
private readonly prismaService: PrismaService,
|
||||
){}
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async getUserById(id: string) {
|
||||
const user = await this.prismaService.users.findUnique({
|
||||
|
@ -17,8 +15,7 @@ export class UsersService{
|
|||
email_verifications: true,
|
||||
},
|
||||
});
|
||||
if(!user)
|
||||
throw new NotFoundException("User not found");
|
||||
if (!user) throw new NotFoundException('User not found');
|
||||
return new UserEntity({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
|
@ -40,8 +37,7 @@ export class UsersService{
|
|||
email_verifications: true,
|
||||
},
|
||||
});
|
||||
if(!user)
|
||||
throw new NotFoundException("User not found");
|
||||
if (!user) throw new NotFoundException('User not found');
|
||||
return new UserEntity({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
|
|
Loading…
Add table
Reference in a new issue