fix eslint errors
Some checks failed
SonarQube Scan / SonarQube Trigger (push) Failing after 1m8s

This commit is contained in:
unurled 2025-02-07 20:24:16 +01:00
parent b4eb949a3e
commit 418a9e2c7a
Signed by: unurled
GPG key ID: EFC5F5E709B47DDD
17 changed files with 105 additions and 78 deletions

View file

@ -1,4 +1,4 @@
// @ts-ignore
// @ts-expect-error bun build process
await Bun.build({
entrypoints: ['./src/app.ts'],
format: 'esm',

View file

@ -6,7 +6,7 @@ import tseslint from 'typescript-eslint';
export default tseslint.config(
{
ignores: ['eslint.config.mjs'],
ignores: ['eslint.config.mjs', 'dist/', 'node_modules/'],
},
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
@ -29,7 +29,7 @@ export default tseslint.config(
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-unsafe-argument': 'warn'
'@typescript-eslint/no-unsafe-argument': 'warn',
},
},
);

View file

@ -8,7 +8,7 @@ import { ApiTags } from '@nestjs/swagger';
@UseInterceptors(CacheInterceptor)
export class AppController {
@Get('version')
async getVersion(): Promise<VersionEntity> {
getVersion(): VersionEntity {
return {
version: process.env.npm_package_version,
};

View file

@ -24,10 +24,14 @@ import KeyvRedis from '@keyv/redis';
ScheduleModule.forRoot(),
CacheModule.registerAsync({
isGlobal: true,
useFactory: async (): Promise<any> => {
const redisUrl: string | undefined = process.env.REDIS_URL;
// eslint-disable-next-line @typescript-eslint/require-await
useFactory: async () => {
return {
stores: [redisUrl ? new KeyvRedis(redisUrl) : new CacheableMemory()],
stores: [
process.env.REDIS_URL
? new KeyvRedis(process.env.REDIS_URL)
: new CacheableMemory(),
],
};
},
}),

View file

@ -13,6 +13,8 @@ import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ConsoleLogger, Logger } from '@nestjs/common';
import * as process from 'process';
import { FastifyReply } from 'fastify/types/reply';
import { FastifyRequest } from 'fastify/types/request';
const logger: Logger = new Logger('App');
@ -50,17 +52,20 @@ async function loadServer(server: NestFastifyApplication) {
});
// Middlewares
server.use(new LoggerMiddleware().use);
await server.register(fastifyMultipart as any);
await server.register(
fastifyHelmet as any,
{
const loggerMiddleware = new LoggerMiddleware();
const loggerMiddlewareUse = (
req: FastifyRequest['raw'],
res: FastifyReply['raw'],
next: () => void,
) => loggerMiddleware.use(req, res, next);
server.use(loggerMiddlewareUse);
await server.register(fastifyMultipart);
await server.register(fastifyHelmet, {
contentSecurityPolicy: false,
crossOriginEmbedderPolicy: false,
crossOriginOpenerPolicy: false,
crossOriginResourcePolicy: false,
} as any,
);
});
// Swagger
const config = new DocumentBuilder()
@ -88,4 +93,6 @@ async function loadServer(server: NestFastifyApplication) {
server.useGlobalPipes(new CustomValidationPipe());
}
bootstrap();
bootstrap().catch((err) => {
console.error(err);
});

View file

@ -7,7 +7,7 @@ export class LoggerMiddleware implements NestMiddleware {
use(req: FastifyRequest['raw'], res: FastifyReply['raw'], next: () => void) {
const startTime = Date.now();
(res as any).on('finish', () => {
res.on('finish', () => {
const path = req.url;
try {
const protocol = LoggerMiddleware.getProtocol(req);
@ -15,7 +15,7 @@ export class LoggerMiddleware implements NestMiddleware {
if (method === 'OPTIONS') return;
const statusCode = res.statusCode;
const duration = Date.now() - startTime;
const resSize: any = res.getHeader('Content-Length') || '0';
const resSize = res.getHeader('Content-Length').toString() || '0';
const intResSize = parseInt(resSize);
LoggerMiddleware.logger.log(
`${protocol} ${method} ${path} ${statusCode} ${duration}ms ${intResSize}`,

View file

@ -1,11 +1,18 @@
import { Controller, Delete, NotImplementedException } from '@nestjs/common';
import { Controller, Delete, UseGuards } from '@nestjs/common';
import { UserEntity } from './models/entities/user.entity';
import { User } from './decorators/user.decorator';
import { JwtAuthGuard } from './guards/jwt-auth.guard';
import { AuthService } from './auth.service';
import { ApiBearerAuth } from '@nestjs/swagger';
@Controller('auth')
export class AuthController {
constructor() {}
constructor(private readonly authService: AuthService) {}
@Delete('logout/all')
logoutAll() {
throw new NotImplementedException();
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
async logoutAll(@User() user: UserEntity) {
await this.authService.invalidateTokens(user);
}
}

View file

@ -9,10 +9,17 @@ import { RegisterService } from './register.service';
import { UsersModule } from '../../../modules/users/users.module';
import { ConfigService } from '@nestjs/config';
import { AuthJwtStrategy } from './strategies/auth-jwt.strategy';
import { AuthService } from './auth.service';
@Module({
controllers: [AuthController, LoginController, RegisterController],
providers: [JwtStrategy, AuthJwtStrategy, LoginService, RegisterService],
providers: [
JwtStrategy,
AuthJwtStrategy,
LoginService,
RegisterService,
AuthService,
],
imports: [
JwtModule.registerAsync({
inject: [ConfigService],

View file

@ -0,0 +1,23 @@
import { CipherService } from '../helper/cipher.service';
import { PrismaService } from '../helper/prisma.service';
import { Injectable } from '@nestjs/common';
import { UserEntity } from './models/entities/user.entity';
@Injectable()
export class AuthService {
constructor(
private readonly prismaService: PrismaService,
private readonly cipherService: CipherService,
) {}
async invalidateTokens(user: UserEntity): Promise<void> {
await this.prismaService.users.update({
where: {
id: user.id,
},
data: {
token_id: this.cipherService.generateRandomBytes(),
},
});
}
}

View file

@ -0,0 +1,12 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { UserEntity } from '../models/entities/user.entity';
export const User = createParamDecorator(
(_: unknown, ctx: ExecutionContext): UserEntity => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const request: any = ctx.switchToHttp().getRequest();
if (request.user.user) return request.user.user as UserEntity;
return request.user as UserEntity;
},
);

View file

@ -1,10 +1,7 @@
import {
Body,
Controller,
HttpCode,
NotImplementedException,
Post,
Req,
UnauthorizedException,
UseGuards,
} from '@nestjs/common';
@ -16,6 +13,7 @@ import { LoginService } from './login.service';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { AuthGuard } from '@nestjs/passport';
import { UsersService } from '../../../modules/users/users.service';
import { User } from './decorators/user.decorator';
@Controller('auth/login')
@ApiTags('Auth')
@ -60,35 +58,15 @@ export class LoginController {
@Post('callback')
@UseGuards(AuthGuard('auth-jwt'))
@ApiBearerAuth()
loginCallback(@Req() req: any): Promise<LoginPayload> {
// TODO: Fix this line
req = req.user;
if (req.scope === JwtScope.MAGIC) {
// Check for 2FA/Passkey
const token: string = this.loginService.generateToken(
req.user.id,
req.user.tokenId,
JwtScope.USAGE,
);
return new LoginPayload({
user: req.user,
token,
});
}
loginCallback(@User() user: UserEntity): LoginPayload {
const authToken: string = this.loginService.generateToken(
req.user.id,
req.user.tokenId,
user.id,
user.tokenId,
JwtScope.USAGE,
);
return new LoginPayload({
user: req.user,
user,
token: authToken,
});
}
@Post('passkey')
loginPasskey() {
// Generate JWT token
throw new NotImplementedException();
}
}

View file

@ -1,8 +1,4 @@
import {
Injectable,
NotFoundException,
UnauthorizedException,
} from '@nestjs/common';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UserEntity } from './models/entities/user.entity';
import { CipherService } from '../helper/cipher.service';
import { PrismaService } from '../helper/prisma.service';

View file

@ -1,17 +1,7 @@
import {
ConflictException,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { ConflictException, Injectable } from '@nestjs/common';
import { PrismaService } from '../helper/prisma.service';
import { CipherService } from '../helper/cipher.service';
import {
EmailVerifications,
Passkeys,
TwoFactorAuth,
Users,
} from '@prisma/client';
import { UserEntity } from './models/entities/user.entity';
import { Users } from '@prisma/client';
@Injectable()
export class RegisterService {

View file

@ -26,7 +26,7 @@ export class AuthJwtStrategy extends PassportStrategy(Strategy, 'auth-jwt') {
throw new UnauthorizedException('Invalid token');
return {
user,
scope: payload.scope,
scope: JwtScope.USAGE,
};
}
}

View file

@ -88,7 +88,7 @@ export class CipherService {
decipher.setAuthTag(tag);
try {
return Buffer.concat([decipher.update(encrypted), decipher.final()]);
} catch (_) {
} catch {
throw new Error('Decryption failed');
}
}
@ -142,13 +142,13 @@ export class CipherService {
// Asymmetric functions
generateKeyPair(
modulusLength = 4096,
privateEncryptionKey = null,
privateEncryptionKey: string | null = null,
): crypto.KeyPairSyncResult<string, string> {
if (!privateEncryptionKey)
console.warn(
'No private encryption key provided, the private key will not be encrypted',
);
let options = undefined;
let options: { cipher: string; passphrase: string } | undefined = undefined;
if (privateEncryptionKey) {
options = {
cipher: 'aes-256-cbc',
@ -185,7 +185,7 @@ export class CipherService {
decryptAsymmetric(
encryptedContent: string,
privateKey: string | Buffer,
privateEncryptionKey = undefined,
privateEncryptionKey: string | undefined = undefined,
): string {
const buffer = Buffer.from(encryptedContent, 'base64');
if (!privateEncryptionKey)

View file

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

View file

@ -1,7 +1,8 @@
import { Controller, Get, Req, UseGuards } from '@nestjs/common';
import { Controller, Get, 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 { User } from 'src/common/modules/auth/decorators/user.decorator';
@Controller('users')
export class UsersController {
@ -10,7 +11,7 @@ export class UsersController {
@Get('me')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
getMyself(@Req() req: any): UserEntity {
return req.user;
getMyself(@User() user: UserEntity): UserEntity {
return user;
}
}