diff --git a/apps/api/nest-cli.json b/apps/api/nest-cli.json index 2566481..686843e 100644 --- a/apps/api/nest-cli.json +++ b/apps/api/nest-cli.json @@ -1,5 +1,20 @@ { "$schema": "https://json.schemastore.org/nest-cli", "collection": "@nestjs/schematics", - "sourceRoot": "src" + "sourceRoot": "src", + "compilerOptions": { + "plugins": [ + { + "name": "@nestjs/swagger/plugin", + "options": { + "dtoFileNameSuffix": [".entity.ts", ".dto.ts"], + "controllerFileNameSuffix": [".controller.ts"], + "classValidatorShim": true, + "dtoKeyOfComment": "description", + "controllerKeyOfComment": "description", + "introspectComments": true + } + } + ] + } } diff --git a/apps/api/package.json b/apps/api/package.json index 7ebecfa..15057ca 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -23,6 +23,7 @@ }, "dependencies": { "@fastify/cookie": "^9.1.0", + "@fastify/static": "^6.12.0", "@nestjs/cache-manager": "^2.1.0", "@nestjs/cli": "^10.1.18", "@nestjs/common": "^10.2.7", @@ -30,11 +31,18 @@ "@nestjs/core": "^10.2.7", "@nestjs/jwt": "^10.1.1", "@nestjs/mapped-types": "*", + "@nestjs/mongoose": "^10.0.1", "@nestjs/platform-express": "^10.2.7", "@nestjs/platform-fastify": "^10.2.7", + "@nestjs/swagger": "^7.1.14", + "bcrypt": "^5.1.1", "cache-manager": "^5.2.4", "cache-manager-ioredis": "^2.1.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", "ldap-authentication": "2.3.1", + "mongoose": "^7.6.3", + "radash": "^11.0.0", "reflect-metadata": "^0.1.13", "rimraf": "^5.0.5", "rxjs": "^7.8.1", @@ -43,6 +51,7 @@ "devDependencies": { "@nestjs/schematics": "^10.0.2", "@nestjs/testing": "^10.2.7", + "@types/bcrypt": "^5.0.1", "@types/cache-manager": "^4.0.3", "@types/ioredis": "^4.28.10", "@types/jest": "29.5.5", diff --git a/apps/api/src/account/account.controller.ts b/apps/api/src/account/account.controller.ts new file mode 100644 index 0000000..72b17a7 --- /dev/null +++ b/apps/api/src/account/account.controller.ts @@ -0,0 +1,99 @@ +/* eslint-disable @typescript-eslint/explicit-member-accessibility */ +/* eslint-disable class-methods-use-this */ +/* eslint-disable import/no-extraneous-dependencies */ +import { AccountService } from './account.service'; +import { CreateAccountDto } from './dto/create-account.dto'; +import { + Body, + Controller, + Delete, + Get, + HttpException, + HttpStatus, + Post, + Query, + Req, + Res, + UnauthorizedException, +} from '@nestjs/common'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; +import { FastifyReply, FastifyRequest } from 'fastify'; +import { cookieOptions } from 'src/config/cookie'; +import { env } from 'src/config/env'; +import { Credentials } from 'src/dto/credentials'; +import { Account } from 'src/schemas/account.schema'; + +@Controller('account') +@ApiTags('account') +export class AccountController { + constructor(private readonly accountService: AccountService) {} + + private clearCookies(req, reply) { + if (req.cookies) { + Object.keys(req.cookies).forEach((cookieName) => { + reply.clearCookie(cookieName, { + path: '/', + }); + }); + } + } + + @Post('/create') + @ApiResponse({ + status: HttpStatus.CREATED, + type: Account, + }) + async create(@Body() createAccountDto: CreateAccountDto, @Res() reply: FastifyReply) { + try { + const createdAccount = await this.accountService.create(createAccountDto); + + return reply.status(HttpStatus.CREATED).send(createdAccount); + } catch (error) { + throw new HttpException(error, HttpStatus.BAD_REQUEST); + } + } + + @Get() + async findAll() { + return this.accountService.findAll(); + } + + @Delete('/delete') + @ApiResponse({ + status: HttpStatus.OK, + type: Account, + }) + // @ApiQuery({ name: 'username', type: CreateAccountDto['username'] }) + async delete(@Query('username') username: string) { + return this.accountService.delete(username); + } + + @Post('/signin') + async login(@Body() credentials: Credentials, @Res() reply: FastifyReply) { + try { + const token = await this.accountService.login(credentials); + + return reply.setCookie(env.COOKIE_TOKEN_NAME, token, cookieOptions).status(200).send(); + } catch { + throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED); + } + } + + @Get('/logout') + async logout(@Req() req: FastifyRequest, @Res() reply: FastifyReply) { + this.clearCookies(req, reply); + + return reply.status(302).redirect('/login'); + } + + @Get('/get-user') + async getUser(@Req() req: FastifyRequest, @Res() reply: FastifyReply) { + const token = req.cookies[env.COOKIE_TOKEN_NAME]; + if (!token) throw new UnauthorizedException(); + + const account = await this.accountService.getUser(token); + if (!account) throw new UnauthorizedException('Account not found'); + + return reply.send(account); + } +} diff --git a/apps/api/src/account/account.module.ts b/apps/api/src/account/account.module.ts new file mode 100644 index 0000000..f87c10f --- /dev/null +++ b/apps/api/src/account/account.module.ts @@ -0,0 +1,14 @@ +import { AccountController } from './account.controller'; +import { AccountService } from './account.service'; +import { Module } from '@nestjs/common'; +import { MongooseModule } from '@nestjs/mongoose'; +import { Account, AccountSchema } from 'src/schemas/account.schema'; + +@Module({ + controllers: [AccountController], + exports: [], + imports: [MongooseModule.forFeature([{ name: Account.name, schema: AccountSchema }])], + providers: [AccountService], +}) +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +export class AccountModule {} diff --git a/apps/api/src/account/account.service.ts b/apps/api/src/account/account.service.ts new file mode 100644 index 0000000..d1b123b --- /dev/null +++ b/apps/api/src/account/account.service.ts @@ -0,0 +1,67 @@ +import type { CreateAccountDto } from './dto/create-account.dto'; +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { InjectModel } from '@nestjs/mongoose'; +import * as bcrypt from 'bcrypt'; +import { Model } from 'mongoose'; +import { omit } from 'radash'; +import type { Credentials } from 'src/dto/credentials'; +import type { TokenPayload } from 'src/ldap/types/jwt'; +import { Account } from 'src/schemas/account.schema'; +import { generatePassword } from 'src/utils/password'; + +@Injectable() +export class AccountService { + constructor( + private readonly jwtService: JwtService, + @InjectModel(Account.name) private accountModel: Model + ) {} + + public async create(createAccountDto: CreateAccountDto): Promise { + const password = createAccountDto.password || generatePassword(); + + const createdAccount = new this.accountModel({ ...createAccountDto, password }); + + createdAccount.save(); + + return { ...createdAccount.toJSON(), password }; + } + + public async findAll(): Promise { + return this.accountModel.find().exec(); + } + + public async delete(username: string) { + return this.accountModel.findOneAndDelete({ username }).exec(); + } + + public async login({ login, password }: Credentials) { + try { + const account = await this.accountModel.findOne({ username: login }); + if (!account) { + throw new UnauthorizedException('Account not found'); + } + const passwordMatch = await bcrypt.compare(password, account.password); + if (!passwordMatch) { + throw new UnauthorizedException('Invalid login credentials'); + } + + const payload: TokenPayload = { + username: login, + ...omit(account.toJSON(), ['password']), + }; + + return this.jwtService.sign(payload); + } catch (error) { + throw new UnauthorizedException(error); + } + } + + public async getUser(token: string) { + try { + return this.jwtService.verify(token); + } catch { + throw new UnauthorizedException('Invalid token'); + } + } +} diff --git a/apps/api/src/account/dto/create-account.dto.ts b/apps/api/src/account/dto/create-account.dto.ts new file mode 100644 index 0000000..c37a53d --- /dev/null +++ b/apps/api/src/account/dto/create-account.dto.ts @@ -0,0 +1,17 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { IsNotEmpty, IsOptional, IsString, MinLength } from 'class-validator'; + +export class CreateAccountDto { + @ApiProperty() + @IsString() + @IsNotEmpty() + public readonly username: string; + + @ApiPropertyOptional({}) + @IsString() + @MinLength(10) + @IsOptional() + public readonly password: string; + + readonly [key: string]: unknown; +} diff --git a/apps/api/src/app.controller.spec.ts b/apps/api/src/app.controller.spec.ts deleted file mode 100644 index e3e4f2d..0000000 --- a/apps/api/src/app.controller.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { AppController } from './app.controller'; -import { AppService } from './app.service'; -import type { TestingModule } from '@nestjs/testing'; -import { Test } from '@nestjs/testing'; - -describe('AppController', () => { - let appController: AppController; - - beforeEach(async () => { - const app: TestingModule = await Test.createTestingModule({ - controllers: [AppController], - providers: [AppService], - }).compile(); - - appController = app.get(AppController); - }); - - describe('root', () => { - it('should return "Hello World!"', () => { - expect(appController.getHello()).toBe('Hello World!'); - }); - }); -}); diff --git a/apps/api/src/app.controller.ts b/apps/api/src/app.controller.ts index fcfae70..490d528 100644 --- a/apps/api/src/app.controller.ts +++ b/apps/api/src/app.controller.ts @@ -1,12 +1,29 @@ import { AppService } from './app.service'; -import { Controller, Get } from '@nestjs/common'; +import { env } from './config/env'; +import { Controller, Get, HttpStatus, Req, Res } from '@nestjs/common'; +import { ApiExcludeController } from '@nestjs/swagger'; +import { FastifyReply, FastifyRequest } from 'fastify'; @Controller() +@ApiExcludeController() export class AppController { constructor(private readonly appService: AppService) {} + @Get('auth') + public async auth(@Req() req: FastifyRequest, @Res() reply: FastifyReply) { + const token = req.cookies[env.COOKIE_TOKEN_NAME]; - @Get() - getHello(): string { - return this.appService.getHello(); + try { + this.appService.checkToken(token); + + return reply.send(); + } catch { + // if (error.name === 'TokenExpiredError') { + // const newToken = this.appService.refreshToken(token); + + // return reply.setCookie(env.COOKIE_TOKEN_NAME, newToken, cookieOptions).send(); + // } + + return reply.status(HttpStatus.UNAUTHORIZED).send(); + } } } diff --git a/apps/api/src/app.module.ts b/apps/api/src/app.module.ts index 9b3fd35..f855004 100644 --- a/apps/api/src/app.module.ts +++ b/apps/api/src/app.module.ts @@ -1,12 +1,12 @@ +import { AccountModule } from './account/account.module'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { AuthModule } from './auth/auth.module'; import { env } from './config/env'; import { LdapModule } from './ldap/ldap.module'; -import { UsersModule } from './users/users.module'; import { Global, Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { JwtModule } from '@nestjs/jwt'; +import { MongooseModule } from '@nestjs/mongoose'; @Global() @Module({ @@ -22,9 +22,9 @@ import { JwtModule } from '@nestjs/jwt'; expiresIn: env.API_TOKEN_TTL, }, }), - AuthModule, - UsersModule, LdapModule, + AccountModule, + MongooseModule.forRoot(`mongodb://${env.MONGO_HOST}`), ], providers: [AppService], }) diff --git a/apps/api/src/app.service.ts b/apps/api/src/app.service.ts index 927d7cc..cc4d9bb 100644 --- a/apps/api/src/app.service.ts +++ b/apps/api/src/app.service.ts @@ -1,8 +1,19 @@ +import type { DecodedToken } from './ldap/types/jwt'; import { Injectable } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { omit } from 'radash'; @Injectable() export class AppService { - getHello(): string { - return 'Hello World!'; + constructor(private readonly jwtService: JwtService) {} + + public checkToken(token: string) { + this.jwtService.verify(token); + } + + public refreshToken(token: string) { + const payload = this.jwtService.decode(token) as DecodedToken; + + return this.jwtService.sign(omit(payload, ['iat', 'exp'])); } } diff --git a/apps/api/src/auth/auth.controller.spec.ts b/apps/api/src/auth/auth.controller.spec.ts deleted file mode 100644 index 2aa6ec7..0000000 --- a/apps/api/src/auth/auth.controller.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { AuthController } from './auth.controller'; -import { AuthService } from './auth.service'; -import type { TestingModule } from '@nestjs/testing'; -import { Test } from '@nestjs/testing'; - -describe('AuthController', () => { - let controller: AuthController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [AuthController], - providers: [AuthService], - }).compile(); - - controller = module.get(AuthController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/apps/api/src/auth/auth.controller.ts b/apps/api/src/auth/auth.controller.ts deleted file mode 100644 index f93f9f3..0000000 --- a/apps/api/src/auth/auth.controller.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* eslint-disable @typescript-eslint/explicit-member-accessibility */ -/* eslint-disable class-methods-use-this */ -/* eslint-disable import/no-extraneous-dependencies */ -import { AuthService } from './auth.service'; -import { Credentials } from './types/request'; -import type { CookieSerializeOptions } from '@fastify/cookie'; -import { Body, Controller, Get, HttpException, HttpStatus, Post, Req, Res } from '@nestjs/common'; -import { FastifyReply, FastifyRequest } from 'fastify'; -import { env } from 'src/config/env'; - -@Controller() -export class AuthController { - cookieOptions: CookieSerializeOptions; - constructor(private readonly authService: AuthService) { - this.cookieOptions = { - httpOnly: true, - maxAge: env.API_TOKEN_TTL, - path: '/', - secure: true, - }; - } - - private clearCookies(req, reply) { - if (req.cookies) { - Object.keys(req.cookies).forEach((cookieName) => { - reply.clearCookie(cookieName, { - path: '/', - }); - }); - } - } - - @Post('/signin') - async login(@Body() credentials: Credentials, @Res() reply: FastifyReply) { - const { login, password } = credentials; - - try { - const token = await this.authService.login(login, password); - - return reply.setCookie(env.COOKIE_TOKEN_NAME, token, this.cookieOptions).status(200).send(); - } catch { - throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED); - } - } - - @Get('/logout') - async logout(@Req() req: FastifyRequest, @Res() reply: FastifyReply) { - const token = req.cookies[env.COOKIE_TOKEN_NAME]; - if (token) await this.authService.logout(token); - - this.clearCookies(req, reply); - - return reply.status(302).redirect('/login'); - } - - @Get('/auth') - async auth(@Req() req: FastifyRequest, @Res() reply: FastifyReply) { - const token = req.cookies[env.COOKIE_TOKEN_NAME]; - - try { - this.authService.checkToken(token); - - return reply.send(); - } catch (error) { - if (error.name === 'TokenExpiredError') { - const newToken = this.authService.refreshToken(token); - - return reply.setCookie(env.COOKIE_TOKEN_NAME, newToken, this.cookieOptions).send(); - } - - return reply.status(HttpStatus.UNAUTHORIZED).send(); - } - } -} diff --git a/apps/api/src/auth/auth.module.ts b/apps/api/src/auth/auth.module.ts deleted file mode 100644 index 410c056..0000000 --- a/apps/api/src/auth/auth.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { LdapModule } from '../ldap/ldap.module'; -import { UsersModule } from '../users/users.module'; -import { AuthController } from './auth.controller'; -import { AuthService } from './auth.service'; -import { Module } from '@nestjs/common'; - -@Module({ - controllers: [AuthController], - imports: [UsersModule, LdapModule], - providers: [AuthService], -}) -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class AuthModule {} diff --git a/apps/api/src/auth/auth.service.spec.ts b/apps/api/src/auth/auth.service.spec.ts deleted file mode 100644 index 207bb16..0000000 --- a/apps/api/src/auth/auth.service.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { AuthService } from './auth.service'; -import type { TestingModule } from '@nestjs/testing'; -import { Test } from '@nestjs/testing'; - -describe('AuthService', () => { - let service: AuthService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [AuthService], - }).compile(); - - service = module.get(AuthService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/apps/api/src/auth/auth.service.ts b/apps/api/src/auth/auth.service.ts deleted file mode 100644 index 5d09216..0000000 --- a/apps/api/src/auth/auth.service.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { LdapService } from '../ldap/ldap.service'; -import { UsersCache } from '../users/users.cache'; -import type { DecodedToken, TokenPayload } from './types/jwt'; -import { Injectable } from '@nestjs/common'; -import { JwtService } from '@nestjs/jwt'; -import { env } from 'src/config/env'; - -@Injectable() -export class AuthService { - constructor( - private readonly ldapService: LdapService, - private readonly usersCache: UsersCache, - private readonly jwtService: JwtService - ) {} - - public async login(login: string, password: string) { - const user = await this.ldapService.authenticate(login, password); - const { username } = user; - - await this.usersCache.addUser(username, user); - - const payload: TokenPayload = { - domain: env.LDAP_DOMAIN, - username, - }; - - return this.jwtService.sign(payload); - } - - public async logout(token: string) { - const { username } = this.jwtService.decode(token) as DecodedToken; - await this.usersCache.deleteUser(username); - } - - public checkToken(token: string) { - this.jwtService.verify(token); - } - - public refreshToken(token: string) { - const { exp, iat, ...payload } = this.jwtService.decode(token) as DecodedToken; - - return this.jwtService.sign(payload); - } -} diff --git a/apps/api/src/auth/types/request.ts b/apps/api/src/auth/types/request.ts deleted file mode 100644 index 538f351..0000000 --- a/apps/api/src/auth/types/request.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type Credentials = { - login: string; - password: string; -}; diff --git a/apps/api/src/config/cookie.ts b/apps/api/src/config/cookie.ts new file mode 100644 index 0000000..d9799cb --- /dev/null +++ b/apps/api/src/config/cookie.ts @@ -0,0 +1,9 @@ +import type { CookieSerializeOptions } from '@fastify/cookie'; +import { env } from 'src/config/env'; + +export const cookieOptions: CookieSerializeOptions = { + httpOnly: true, + maxAge: env.API_TOKEN_TTL, + path: '/', + secure: true, +}; diff --git a/apps/api/src/config/schema/env.ts b/apps/api/src/config/schema/env.ts index 5d9e890..107f866 100644 --- a/apps/api/src/config/schema/env.ts +++ b/apps/api/src/config/schema/env.ts @@ -12,6 +12,11 @@ const envSchema = z.object({ LDAP_BIND_DN: z.string(), LDAP_DOMAIN: z.string(), LDAP_URL: z.string().url(), + MONGO_HOST: z.string(), + MONGO_PORT: z + .string() + .transform((val) => Number.parseInt(val, 10)) + .default('27017'), REDIS_HOST: z.string(), REDIS_PORT: z .string() diff --git a/apps/api/src/dto/credentials.ts b/apps/api/src/dto/credentials.ts new file mode 100644 index 0000000..858522d --- /dev/null +++ b/apps/api/src/dto/credentials.ts @@ -0,0 +1,14 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsString } from 'class-validator'; + +export class Credentials { + @ApiProperty() + @IsString() + @IsNotEmpty() + readonly login: string; + + @ApiProperty() + @IsString() + @IsNotEmpty() + readonly password: string; +} diff --git a/apps/api/src/ldap/ldap.controller.ts b/apps/api/src/ldap/ldap.controller.ts new file mode 100644 index 0000000..5cc45a0 --- /dev/null +++ b/apps/api/src/ldap/ldap.controller.ts @@ -0,0 +1,80 @@ +/* eslint-disable @typescript-eslint/explicit-member-accessibility */ +/* eslint-disable class-methods-use-this */ +/* eslint-disable import/no-extraneous-dependencies */ +import { Credentials } from '../dto/credentials'; +import { LdapService } from './ldap.service'; +import type { CookieSerializeOptions } from '@fastify/cookie'; +import { + Body, + Controller, + Get, + HttpException, + HttpStatus, + Post, + Req, + Res, + UnauthorizedException, +} from '@nestjs/common'; +import { ApiResponse, ApiTags } from '@nestjs/swagger'; +import { FastifyReply, FastifyRequest } from 'fastify'; +import { cookieOptions } from 'src/config/cookie'; +import { env } from 'src/config/env'; +import { User } from 'src/utils/ldap'; + +@Controller('ldap') +@ApiTags('ldap') +export class LdapController { + cookieOptions: CookieSerializeOptions; + constructor(private readonly ldapService: LdapService) {} + + private clearCookies(req, reply) { + if (req.cookies) { + Object.keys(req.cookies).forEach((cookieName) => { + reply.clearCookie(cookieName, { + path: '/', + }); + }); + } + } + + @Post('/signin') + @ApiResponse({ + status: HttpStatus.OK, + }) + async login(@Body() credentials: Credentials, @Res() reply: FastifyReply) { + try { + const token = await this.ldapService.login(credentials); + + return reply.setCookie(env.COOKIE_TOKEN_NAME, token, cookieOptions).status(200).send(); + } catch { + throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED); + } + } + + @Get('/logout') + async logout(@Req() req: FastifyRequest, @Res() reply: FastifyReply) { + const token = req.cookies[env.COOKIE_TOKEN_NAME]; + if (token) await this.ldapService.logout(token); + + this.clearCookies(req, reply); + + return reply.status(302).redirect('/login'); + } + + @Get('/get-user') + @ApiResponse({ + status: HttpStatus.OK, + type: User, + }) + async getUser(@Req() req: FastifyRequest, @Res() reply: FastifyReply) { + const token = req.cookies[env.COOKIE_TOKEN_NAME]; + + if (!token) throw new UnauthorizedException(); + + const user = await this.ldapService.getUser(token); + + if (!user) throw new UnauthorizedException('User not found'); + + return reply.send(user); + } +} diff --git a/apps/api/src/ldap/ldap.module.ts b/apps/api/src/ldap/ldap.module.ts index 2fae433..58b5265 100644 --- a/apps/api/src/ldap/ldap.module.ts +++ b/apps/api/src/ldap/ldap.module.ts @@ -1,8 +1,21 @@ +import { LdapController } from './ldap.controller'; import { LdapService } from './ldap.service'; +import { CacheModule } from '@nestjs/cache-manager'; import { Module } from '@nestjs/common'; +import * as redisStore from 'cache-manager-ioredis'; +import type { RedisOptions } from 'ioredis'; +import { env } from 'src/config/env'; @Module({ - exports: [LdapService], + controllers: [LdapController], + imports: [ + CacheModule.register({ + host: env.REDIS_HOST, + port: env.REDIS_PORT, + store: redisStore, + ttl: env.API_CACHE_TTL, + }), + ], providers: [LdapService], }) // eslint-disable-next-line @typescript-eslint/no-extraneous-class diff --git a/apps/api/src/ldap/ldap.service.spec.ts b/apps/api/src/ldap/ldap.service.spec.ts deleted file mode 100644 index d5ed721..0000000 --- a/apps/api/src/ldap/ldap.service.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { LdapService } from './ldap.service'; -import type { TestingModule } from '@nestjs/testing'; -import { Test } from '@nestjs/testing'; - -describe('LdapService', () => { - let service: LdapService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [LdapService], - }).compile(); - - service = module.get(LdapService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/apps/api/src/ldap/ldap.service.ts b/apps/api/src/ldap/ldap.service.ts index 1eaab34..eb9dcc5 100644 --- a/apps/api/src/ldap/ldap.service.ts +++ b/apps/api/src/ldap/ldap.service.ts @@ -1,44 +1,58 @@ -import { env } from '../config/env'; -import type { User } from '../types/user'; -import type { LdapUser } from './types/user'; -import { Injectable } from '@nestjs/common'; -import type { AuthenticationOptions } from 'ldap-authentication'; -import { authenticate } from 'ldap-authentication'; +import type { DecodedToken, TokenPayload } from './types/jwt'; +import { CACHE_MANAGER } from '@nestjs/cache-manager'; +import { Inject, Injectable, UnauthorizedException } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; +import { Cache } from 'cache-manager'; +import { env } from 'src/config/env'; +import type { Credentials } from 'src/dto/credentials'; +import * as ldap from 'src/utils/ldap'; @Injectable() export class LdapService { - public async authenticate(login: string, password?: string) { - const options: AuthenticationOptions = { - adminDn: env.LDAP_BIND_DN, - adminPassword: env.LDAP_BIND_CREDENTIALS, - ldapOpts: { - url: env.LDAP_URL, - }, - userPassword: password, - userSearchBase: env.LDAP_BASE, - username: login, - usernameAttribute: env.LDAP_ATTRIBUTE, - verifyUserExists: password === undefined, - }; + constructor( + @Inject(CACHE_MANAGER) private readonly cacheManager: Cache, + private readonly jwtService: JwtService + ) {} - const { - displayName, - department, - title, - mail, - sAMAccountName: username, - }: LdapUser = await authenticate(options); + public async login({ login, password }: Credentials) { + const user = await ldap.authenticate(login, password); + const { username } = user; - const user: User = { - department, - displayName, + await this.cacheManager.set(username, user); + + const payload: TokenPayload = { domain: env.LDAP_DOMAIN, - domainName: `${env.LDAP_DOMAIN}\\${username}`, - mail, - position: title, username, }; - return user; + return this.jwtService.sign(payload); + } + + public async logout(token: string) { + const { username } = this.jwtService.decode(token) as DecodedToken; + + if (this.cacheManager.get(username)) { + await this.cacheManager.del(username); + } + } + + public async getUser(token: string) { + try { + const { username } = this.jwtService.verify(token) as DecodedToken; + + const cachedUser = (await this.cacheManager.get(username)) as ldap.User; + + if (!cachedUser) { + const user = await ldap.authenticate(username); + + await this.cacheManager.set(username, user); + + return user; + } + + return cachedUser; + } catch { + throw new UnauthorizedException('Invalid token'); + } } } diff --git a/apps/api/src/auth/types/jwt.ts b/apps/api/src/ldap/types/jwt.ts similarity index 83% rename from apps/api/src/auth/types/jwt.ts rename to apps/api/src/ldap/types/jwt.ts index 619c81b..1e58a0f 100644 --- a/apps/api/src/auth/types/jwt.ts +++ b/apps/api/src/ldap/types/jwt.ts @@ -1,6 +1,6 @@ export type TokenPayload = { + [key: string]: unknown; username: string; - domain: string; }; export type DecodedToken = { diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index b70de73..fab6f67 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -1,10 +1,24 @@ +/* eslint-disable import/no-duplicates */ /* eslint-disable unicorn/prefer-top-level-await */ import { AppModule } from './app.module'; import { env } from './config/env'; import { fastifyCookie } from '@fastify/cookie'; +import type { INestApplication } from '@nestjs/common'; +import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import type { NestFastifyApplication } from '@nestjs/platform-fastify'; import { FastifyAdapter } from '@nestjs/platform-fastify'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; + +function setupOpenApi(app: INestApplication) { + const config = new DocumentBuilder() + .setTitle('Evo.Auth') + .setVersion('1.0') + // .addTag('api') + .build(); + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup('swagger', app, document, { useGlobalPrefix: true }); +} async function bootstrap() { const app = await NestFactory.create( @@ -18,6 +32,10 @@ async function bootstrap() { secret: env.API_SECRET, }); + app.useGlobalPipes(new ValidationPipe({ stopAtFirstError: true })); + + setupOpenApi(app); + await app.listen(env.API_PORT, '0.0.0.0'); } diff --git a/apps/api/src/schemas/account.schema.ts b/apps/api/src/schemas/account.schema.ts new file mode 100644 index 0000000..2f57073 --- /dev/null +++ b/apps/api/src/schemas/account.schema.ts @@ -0,0 +1,35 @@ +/* eslint-disable @babel/no-invalid-this */ +import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; +import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; +import * as bcrypt from 'bcrypt'; +import type { HydratedDocument } from 'mongoose'; + +export type UserDocument = HydratedDocument; + +@Schema({ strict: false }) +export class Account { + @ApiResponseProperty() + @ApiProperty() + @Prop({ index: { unique: true }, required: true }) + username: string; + + @ApiResponseProperty() + @ApiProperty() + @Prop({ required: true }) + password: string; +} + +export const AccountSchema = SchemaFactory.createForClass(Account); + +AccountSchema.pre('save', async function (next) { + try { + if (!this.isModified('password')) return next(); + + const hash = await bcrypt.hash(this.password, 10); + this.password = hash; + + return next(); + } catch (error) { + return next(error); + } +}); diff --git a/apps/api/src/types/user.ts b/apps/api/src/types/user.ts deleted file mode 100644 index 8fb227d..0000000 --- a/apps/api/src/types/user.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type User = { - department: string; - displayName: string; - domain: string; - domainName: string; - mail: string; - position: string; - username: string; -}; diff --git a/apps/api/src/users/users.cache.ts b/apps/api/src/users/users.cache.ts deleted file mode 100644 index 41cc2f1..0000000 --- a/apps/api/src/users/users.cache.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { User } from '../types/user'; -import { CACHE_MANAGER } from '@nestjs/cache-manager'; -import { Inject, Injectable } from '@nestjs/common'; -import { Cache } from 'cache-manager'; - -@Injectable() -export class UsersCache { - constructor(@Inject(CACHE_MANAGER) private readonly cacheManager: Cache) {} - async getUser(username: string) { - return (await this.cacheManager.get(username)) as User; - } - - async addUser(username: string, user: User) { - await this.cacheManager.set(username, user); - } - - async deleteUser(username: string) { - if (this.cacheManager.get(username)) { - await this.cacheManager.del(username); - } - } -} diff --git a/apps/api/src/users/users.controller.spec.ts b/apps/api/src/users/users.controller.spec.ts deleted file mode 100644 index 71c1341..0000000 --- a/apps/api/src/users/users.controller.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { UsersController } from './users.controller'; -import { UsersService } from './users.service'; -import type { TestingModule } from '@nestjs/testing'; -import { Test } from '@nestjs/testing'; - -describe('UsersController', () => { - let controller: UsersController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [UsersController], - providers: [UsersService], - }).compile(); - - controller = module.get(UsersController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/apps/api/src/users/users.controller.ts b/apps/api/src/users/users.controller.ts deleted file mode 100644 index f4db6c4..0000000 --- a/apps/api/src/users/users.controller.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable @typescript-eslint/explicit-member-accessibility */ -/* eslint-disable class-methods-use-this */ -/* eslint-disable import/no-extraneous-dependencies */ -import { UsersService } from './users.service'; -import { Controller, Get, Req, Res } from '@nestjs/common'; -import { FastifyReply, FastifyRequest } from 'fastify'; -import { env } from 'src/config/env'; - -@Controller() -export class UsersController { - constructor(private readonly usersService: UsersService) {} - - @Get('/get-user') - async getUser(@Req() req: FastifyRequest, @Res() reply: FastifyReply) { - const token = req.cookies[env.COOKIE_TOKEN_NAME]; - - const user = await this.usersService.getUser(token); - - return reply.send(user); - } -} diff --git a/apps/api/src/users/users.module.ts b/apps/api/src/users/users.module.ts deleted file mode 100644 index 3d09092..0000000 --- a/apps/api/src/users/users.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { LdapModule } from '../ldap/ldap.module'; -import { UsersCache } from './users.cache'; -import { UsersController } from './users.controller'; -import { UsersService } from './users.service'; -import { CacheModule } from '@nestjs/cache-manager'; -import { Module } from '@nestjs/common'; -import * as redisStore from 'cache-manager-ioredis'; -import type { RedisOptions } from 'ioredis'; -import { env } from 'src/config/env'; - -@Module({ - controllers: [UsersController], - exports: [UsersCache], - imports: [ - CacheModule.register({ - host: env.REDIS_HOST, - port: env.REDIS_PORT, - store: redisStore, - ttl: env.API_CACHE_TTL, - }), - LdapModule, - ], - providers: [UsersService, UsersCache], -}) -// eslint-disable-next-line @typescript-eslint/no-extraneous-class -export class UsersModule {} diff --git a/apps/api/src/users/users.service.spec.ts b/apps/api/src/users/users.service.spec.ts deleted file mode 100644 index c619357..0000000 --- a/apps/api/src/users/users.service.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { UsersService } from './users.service'; -import type { TestingModule } from '@nestjs/testing'; -import { Test } from '@nestjs/testing'; - -describe('UsersService', () => { - let service: UsersService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [UsersService], - }).compile(); - - service = module.get(UsersService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/apps/api/src/users/users.service.ts b/apps/api/src/users/users.service.ts deleted file mode 100644 index 78f253c..0000000 --- a/apps/api/src/users/users.service.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { DecodedToken } from '../auth/types/jwt'; -import { LdapService } from '../ldap/ldap.service'; -import { UsersCache } from './users.cache'; -import { Injectable } from '@nestjs/common'; -import { JwtService } from '@nestjs/jwt'; - -@Injectable() -export class UsersService { - constructor( - private readonly usersCache: UsersCache, - private readonly jwtService: JwtService, - private readonly ldapService: LdapService - ) {} - - public async getUser(token: string) { - const { username } = this.jwtService.decode(token) as DecodedToken; - - const cachedUser = await this.usersCache.getUser(username); - - if (!cachedUser) { - const user = await this.ldapService.authenticate(username); - - await this.usersCache.addUser(username, user); - - return user; - } - - return cachedUser; - } -} diff --git a/apps/api/src/ldap/types/user.ts b/apps/api/src/utils/ldap.ts similarity index 52% rename from apps/api/src/ldap/types/user.ts rename to apps/api/src/utils/ldap.ts index 76368c8..8b070cf 100644 --- a/apps/api/src/ldap/types/user.ts +++ b/apps/api/src/utils/ldap.ts @@ -1,3 +1,25 @@ +import { ApiResponseProperty } from '@nestjs/swagger'; +import type { AuthenticationOptions } from 'ldap-authentication'; +import * as ldap from 'ldap-authentication'; +import { env } from 'src/config/env'; + +export class User { + @ApiResponseProperty() + public department: string; + @ApiResponseProperty() + public displayName: string; + @ApiResponseProperty() + public domain: string; + @ApiResponseProperty() + public domainName: string; + @ApiResponseProperty() + public mail: string; + @ApiResponseProperty() + public position: string; + @ApiResponseProperty() + public username: string; +} + export type LdapUser = { accountExpires: string; badPasswordTime: string; @@ -61,3 +83,42 @@ export type LdapUser = { whenChanged: string; whenCreated: string; }; + +const BASE_OPTIONS: AuthenticationOptions = { + adminDn: env.LDAP_BIND_DN, + adminPassword: env.LDAP_BIND_CREDENTIALS, + ldapOpts: { + url: env.LDAP_URL, + }, + userSearchBase: env.LDAP_BASE, + usernameAttribute: env.LDAP_ATTRIBUTE, +}; + +export async function authenticate(login: string, password?: string) { + const options: AuthenticationOptions = { + ...BASE_OPTIONS, + userPassword: password, + username: login, + verifyUserExists: password === undefined, + }; + + const { + displayName, + department, + title, + mail, + sAMAccountName: username, + }: LdapUser = await ldap.authenticate(options); + + const user: User = { + department, + displayName, + domain: env.LDAP_DOMAIN, + domainName: `${env.LDAP_DOMAIN}\\${username}`, + mail, + position: title, + username, + }; + + return user; +} diff --git a/apps/api/src/utils/password.ts b/apps/api/src/utils/password.ts new file mode 100644 index 0000000..a47b834 --- /dev/null +++ b/apps/api/src/utils/password.ts @@ -0,0 +1,7 @@ +const characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@-#$'; + +export function generatePassword(length = 10) { + return Array.from(crypto.getRandomValues(new Uint32Array(length))) + .map((x) => characters[x % characters.length]) + .join(''); +} diff --git a/docker-compose.yml b/docker-compose.yml index c9c702f..c601ed5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,6 +24,7 @@ services: - API_TOKEN_TTL=${API_TOKEN_TTL} - API_CACHE_TTL=${API_CACHE_TTL} - REDIS_HOST=redis + - MONGO_HOST=mongo restart: always networks: - auth_network @@ -35,6 +36,14 @@ services: networks: - auth_network + mongo: + image: mongo:latest + networks: + - auth_network + restart: always + volumes: + - /opt/docker-volumes/auth_dev:/data/db + server: extends: file: docker-compose.traefik.yml @@ -49,6 +58,9 @@ services: networks: - auth_network +volumes: + mongo: + networks: auth_network: external: diff --git a/yarn.lock b/yarn.lock index 595c223..1deede1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -457,6 +457,11 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa" integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg== +"@fastify/accept-negotiator@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz#c1c66b3b771c09742a54dd5bc87c582f6b0630ff" + integrity sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ== + "@fastify/ajv-compiler@^3.5.0": version "3.5.0" resolved "https://registry.yarnpkg.com/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz#459bff00fefbf86c96ec30e62e933d2379e46670" @@ -517,6 +522,29 @@ path-to-regexp "^6.1.0" reusify "^1.0.4" +"@fastify/send@^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@fastify/send/-/send-2.1.0.tgz#1aa269ccb4b0940a2dadd1f844443b15d8224ea0" + integrity sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA== + dependencies: + "@lukeed/ms" "^2.0.1" + escape-html "~1.0.3" + fast-decode-uri-component "^1.0.1" + http-errors "2.0.0" + mime "^3.0.0" + +"@fastify/static@^6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@fastify/static/-/static-6.12.0.tgz#f3d55dda201c072bae0593e5d45dde8fd235c288" + integrity sha512-KK1B84E6QD/FcQWxDI2aiUCwHxMJBI1KeCUzm1BwYpPY1b742+jeKruGHP2uOluuM6OkBPI8CIANrXcCRtC2oQ== + dependencies: + "@fastify/accept-negotiator" "^1.0.0" + "@fastify/send" "^2.0.0" + content-disposition "^0.5.3" + fastify-plugin "^4.0.0" + glob "^8.0.1" + p-limit "^3.1.0" + "@fontsource/montserrat@^5.0.13": version "5.0.13" resolved "https://registry.yarnpkg.com/@fontsource/montserrat/-/montserrat-5.0.13.tgz#e9e78a726e4a452b820c8c0bdcddf4444c922db6" @@ -1027,6 +1055,33 @@ resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.1.0.tgz#1e3e4bd05c1cc7a0b2ddbd8a03f39f6e4b5e6cfe" integrity sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA== +"@lukeed/ms@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@lukeed/ms/-/ms-2.0.1.tgz#3c2bbc258affd9cc0e0cc7828477383c73afa6ee" + integrity sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA== + +"@mapbox/node-pre-gyp@^1.0.11": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" + integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== + dependencies: + detect-libc "^2.0.0" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.7" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + +"@mongodb-js/saslprep@^1.1.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz#9a6c2516bc9188672c4d953ec99760ba49970da7" + integrity sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ== + dependencies: + sparse-bitfield "^3.0.3" + "@nestjs/cache-manager@^2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@nestjs/cache-manager/-/cache-manager-2.1.0.tgz#e4dadc4ba9c02c059db4dac5e0b5513466e2895a" @@ -1099,11 +1154,16 @@ "@types/jsonwebtoken" "9.0.2" jsonwebtoken "9.0.0" -"@nestjs/mapped-types@*": +"@nestjs/mapped-types@*", "@nestjs/mapped-types@2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.0.2.tgz#c8a090a8d22145b85ed977414c158534210f2e4f" integrity sha512-V0izw6tWs6fTp9+KiiPUbGHWALy563Frn8X6Bm87ANLRuE46iuBMD5acKBDP5lKL/75QFvrzSJT7HkCbB0jTpg== +"@nestjs/mongoose@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@nestjs/mongoose/-/mongoose-10.0.1.tgz#f55f4bf79d08f4a93834fe7fe27d42b5f19fccf3" + integrity sha512-woUViG28WKf/kRiv6NFXu4Oc0DvAPeX4+fT4coDVt2OqndnfJZTXwkkys23uVsBpKSIflRyjPvmcVBHQvcunZw== + "@nestjs/platform-express@^10.2.7": version "10.2.7" resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.2.7.tgz#b2ef2df01c0c757a3d356659460563a5246e7d0f" @@ -1139,6 +1199,17 @@ jsonc-parser "3.2.0" pluralize "8.0.0" +"@nestjs/swagger@^7.1.14": + version "7.1.14" + resolved "https://registry.yarnpkg.com/@nestjs/swagger/-/swagger-7.1.14.tgz#492b3816308264472b3619f5c0336f378f1c9995" + integrity sha512-2Ol4S6qHeYVVmkshkWBM8E/qkmEqEOUj2QIewr0jLSyo30H7f3v81pJyks6pTLy4PK0LGUXojMvIfFIE3mmGQQ== + dependencies: + "@nestjs/mapped-types" "2.0.2" + js-yaml "4.1.0" + lodash "4.17.21" + path-to-regexp "3.2.0" + swagger-ui-dist "5.9.0" + "@nestjs/testing@^10.2.7": version "10.2.7" resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-10.2.7.tgz#50408ccb4c809d216a12d60ac7932fd6ad7fedf4" @@ -1373,6 +1444,13 @@ dependencies: "@babel/types" "^7.20.7" +"@types/bcrypt@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-5.0.1.tgz#50a6a662ad6a14c44ae7b25633cfadddf7a85f45" + integrity sha512-dIIrEsLV1/v0AUNI8oHMaRRTSeVjoy5ID8oclJavtPj8CwPJoD1eFoNXEypuu6k091brEzBeOo3LlxeAH9zRZg== + dependencies: + "@types/node" "*" + "@types/cache-manager@^4.0.3": version "4.0.3" resolved "https://registry.yarnpkg.com/@types/cache-manager/-/cache-manager-4.0.3.tgz#1baef7fffe2c9f73ababdac21a0d9e732909be72" @@ -1544,6 +1622,24 @@ dependencies: "@types/superagent" "*" +"@types/validator@^13.7.10": + version "13.11.5" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.11.5.tgz#1911964fd5556b08d3479d1ded977c06f89a44a7" + integrity sha512-xW4qsT4UIYILu+7ZrBnfQdBYniZrMLYYK3wN9M/NdeIHgBN5pZI2/8Q7UfdWIcr5RLJv/OGENsx91JIpUUoC7Q== + +"@types/webidl-conversions@*": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.2.tgz#d703e2bf61d8b77a7669adcd8fdf98108155d594" + integrity sha512-uNv6b/uGRLlCVmelat2rA8bcVd3k/42mV2EmjhPh6JLkd35T5bgwR/t6xy7a9MWhd9sixIeBUzhBenvk3NO+DQ== + +"@types/whatwg-url@^8.2.1": + version "8.2.2" + resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz#749d5b3873e845897ada99be4448041d4cc39e63" + integrity sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA== + dependencies: + "@types/node" "*" + "@types/webidl-conversions" "*" + "@types/ws@^8.0.0": version "8.5.7" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.7.tgz#1ca585074fe5d2c81dec7a3d451f244a2a6d83cb" @@ -1873,6 +1969,11 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -1913,6 +2014,13 @@ acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + ajv-formats@2.1.1, ajv-formats@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" @@ -2004,6 +2112,11 @@ append-field@^1.0.0: resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" integrity sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw== +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + archy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" @@ -2014,6 +2127,14 @@ are-docs-informative@^0.0.2: resolved "https://registry.yarnpkg.com/are-docs-informative/-/are-docs-informative-0.0.2.tgz#387f0e93f5d45280373d387a59d34c96db321963" integrity sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig== +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -2310,6 +2431,14 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bcrypt@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.1.1.tgz#0f732c6dcb4e12e5b70a25e326a72965879ba6e2" + integrity sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.11" + node-addon-api "^5.0.0" + big-integer@^1.6.44: version "1.6.51" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" @@ -2423,6 +2552,11 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" +bson@^5.5.0: + version "5.5.1" + resolved "https://registry.yarnpkg.com/bson/-/bson-5.5.1.tgz#f5849d405711a7f23acdda9a442375df858e6833" + integrity sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g== + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" @@ -2563,6 +2697,11 @@ chokidar@3.5.3, "chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + chrome-trace-event@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" @@ -2578,6 +2717,20 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== +class-transformer@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" + integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== + +class-validator@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.0.tgz#40ed0ecf3c83b2a8a6a320f4edb607be0f0df159" + integrity sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A== + dependencies: + "@types/validator" "^13.7.10" + libphonenumber-js "^1.10.14" + validator "^13.7.0" + clean-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clean-regexp/-/clean-regexp-1.0.0.tgz#8df7c7aae51fd36874e8f8d05b9180bc11a3fed7" @@ -2669,6 +2822,11 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -2727,7 +2885,12 @@ consola@^2.15.0: resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550" integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw== -content-disposition@0.5.4: +console-control-strings@^1.0.0, console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + +content-disposition@0.5.4, content-disposition@^0.5.3: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== @@ -2859,6 +3022,13 @@ debug@2.6.9: dependencies: ms "2.0.0" +debug@4, debug@4.x, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -2866,13 +3036,6 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - dedent@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" @@ -2941,6 +3104,11 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + denque@^1.1.0: version "1.5.1" resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" @@ -2961,6 +3129,11 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== +detect-libc@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d" + integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw== + detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -4175,6 +4348,13 @@ fs-extra@^10.0.0: jsonfile "^6.0.1" universalify "^2.0.0" +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs-monkey@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.5.tgz#fe450175f0db0d7ea758102e1d84096acb925788" @@ -4210,6 +4390,21 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -4321,6 +4516,17 @@ glob@^7.0.0, glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^8.0.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + glob@^9.2.0: version "9.3.5" resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" @@ -4457,6 +4663,11 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + has@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" @@ -4488,6 +4699,14 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -4642,6 +4861,11 @@ ioredis@^4.14.1: redis-parser "^3.0.0" standard-as-callback "^2.1.0" +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -5411,6 +5635,13 @@ js-types@^1.0.0: resolved "https://registry.yarnpkg.com/js-types/-/js-types-1.0.0.tgz#d242e6494ed572ad3c92809fc8bed7f7687cbf03" integrity sha512-bfwqBW9cC/Lp7xcRpug7YrXm0IVw+T9e3g4mCYnv0Pjr3zIzU9PCQElYU9oSGAWzXlbdl9X5SAMPejO9sxkeUw== +js-yaml@4.1.0, js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + js-yaml@^3.13.1: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" @@ -5419,13 +5650,6 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - jsdoc-type-pratt-parser@~4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz#136f0571a99c184d84ec84662c45c29ceff71114" @@ -5554,6 +5778,11 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" +kareem@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.5.1.tgz#7b8203e11819a8e77a34b3517d3ead206764d15d" + integrity sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA== + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -5619,6 +5848,11 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +libphonenumber-js@^1.10.14: + version "1.10.49" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.49.tgz#c871661c62452348d228c96425f75ddf7e10f05a" + integrity sha512-gvLtyC3tIuqfPzjvYLH9BmVdqzGDiSi4VjtWe2fAgSdBf0yt8yPmbNnRIHNbR5IdtVkm0ayGuzwQKTWmU0hdjQ== + light-my-request@5.11.0, light-my-request@^5.9.1: version "5.11.0" resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-5.11.0.tgz#90e446c303b3a47b59df38406d5f5c2cf224f2d1" @@ -5760,6 +5994,13 @@ magic-string@0.30.1: dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" +make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + make-dir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" @@ -5791,6 +6032,11 @@ memfs@^3.4.1: dependencies: fs-monkey "^1.0.4" +memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -5851,6 +6097,11 @@ mime@2.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== +mime@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -5880,6 +6131,13 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + minimatch@^8.0.2: version "8.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" @@ -5899,16 +6157,36 @@ minimist@^1.2.0, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + minipass@^4.2.4: version "4.2.8" resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + "minipass@^5.0.0 || ^6.0.2 || ^7.0.0": version "7.0.4" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + mkdirp@^0.5.4: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -5916,6 +6194,11 @@ mkdirp@^0.5.4: dependencies: minimist "^1.2.6" +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mnemonist@0.39.5: version "0.39.5" resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.39.5.tgz#5850d9b30d1b2bc57cc8787e5caa40f6c3420477" @@ -5923,6 +6206,50 @@ mnemonist@0.39.5: dependencies: obliterator "^2.0.1" +mongodb-connection-string-url@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz#57901bf352372abdde812c81be47b75c6b2ec5cf" + integrity sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ== + dependencies: + "@types/whatwg-url" "^8.2.1" + whatwg-url "^11.0.0" + +mongodb@5.9.0: + version "5.9.0" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-5.9.0.tgz#5a22065fa8cfaf1d58bf2e3c451cd2c4bfa983a2" + integrity sha512-g+GCMHN1CoRUA+wb1Agv0TI4YTSiWr42B5ulkiAfLLHitGK1R+PkSAf3Lr5rPZwi/3F04LiaZEW0Kxro9Fi2TA== + dependencies: + bson "^5.5.0" + mongodb-connection-string-url "^2.6.0" + socks "^2.7.1" + optionalDependencies: + "@mongodb-js/saslprep" "^1.1.0" + +mongoose@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-7.6.3.tgz#b06507dd164ad4426013eeb266d54aa1e5178092" + integrity sha512-moYP2qWCOdWRDeBxqB/zYwQmQnTBsF5DoolX5uPyI218BkiA1ujGY27P0NTd4oWIX+LLkZPw0LDzlc/7oh1plg== + dependencies: + bson "^5.5.0" + kareem "2.5.1" + mongodb "5.9.0" + mpath "0.9.0" + mquery "5.0.0" + ms "2.1.3" + sift "16.0.1" + +mpath@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.9.0.tgz#0c122fe107846e31fc58c75b09c35514b3871904" + integrity sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew== + +mquery@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-5.0.0.tgz#a95be5dfc610b23862df34a47d3e5d60e110695d" + integrity sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg== + dependencies: + debug "4.x" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -6009,6 +6336,11 @@ node-abort-controller@^3.0.1: resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== +node-addon-api@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" + integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== + node-emoji@1.11.0: version "1.11.0" resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c" @@ -6016,7 +6348,7 @@ node-emoji@1.11.0: dependencies: lodash "^4.17.21" -node-fetch@^2.6.1: +node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -6033,6 +6365,13 @@ node-releases@^2.0.13: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -6074,6 +6413,16 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + obj-props@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/obj-props/-/obj-props-1.4.0.tgz#9a9beebb6faf8b287ff7dc1cd133a4247dc85641" @@ -6525,7 +6874,7 @@ punycode@^1.3.2: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.3.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== @@ -6571,6 +6920,11 @@ quick-format-unescaped@^4.0.3: resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== +radash@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/radash/-/radash-11.0.0.tgz#925698e94b554336fc159c253ac33a9a49881835" + integrity sha512-CRWxTFTDff0IELGJ/zz58yY4BDgyI14qSM5OLNKbCItJrff7m7dXbVF0kWYVCXQtPb3SXIVhXvAImH6eT7VLSg== + rambda@^7.4.0: version "7.5.0" resolved "https://registry.yarnpkg.com/rambda/-/rambda-7.5.0.tgz#1865044c59bc0b16f63026c6e5a97e4b1bbe98fe" @@ -6670,7 +7024,7 @@ readable-stream@^2.2.2: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.4.0: +readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -7052,7 +7406,7 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.1.0, semver@^6.3.0, semver@^6.3.1: +semver@^6.0.0, semver@^6.1.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -7100,6 +7454,11 @@ serve-static@1.15.0: parseurl "~1.3.3" send "0.18.0" +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + set-cookie-parser@^2.4.1: version "2.6.0" resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz#131921e50f62ff1a66a461d7d62d7b21d5d15a51" @@ -7149,7 +7508,12 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: +sift@16.0.1: + version "16.0.1" + resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.1.tgz#e9c2ccc72191585008cf3e36fc447b2d2633a053" + integrity sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ== + +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -7169,6 +7533,19 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socks@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" + integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== + dependencies: + ip "^2.0.0" + smart-buffer "^4.2.0" + sonic-boom@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-3.7.0.tgz#b4b7b8049a912986f4a92c51d4660b721b11f2f2" @@ -7207,6 +7584,13 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" + integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ== + dependencies: + memory-pager "^1.0.2" + spdx-correct@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" @@ -7283,7 +7667,7 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7460,6 +7844,11 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +swagger-ui-dist@5.9.0: + version "5.9.0" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.9.0.tgz#d52b6cf52fd0a8e6930866c402aaa793fe4e3f76" + integrity sha512-NUHSYoe5XRTk/Are8jPJ6phzBh3l9l33nEyXosM17QInoV95/jng8+PuSGtbD407QoPf93MH3Bkh773OgesJpA== + symbol-observable@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" @@ -7478,6 +7867,18 @@ tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== +tar@^6.1.11: + version "6.2.0" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73" + integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + terser-webpack-plugin@^5.3.7: version "5.3.9" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" @@ -7564,6 +7965,13 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -7924,6 +8332,11 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +validator@^13.7.0: + version "13.11.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" + integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== + value-or-promise@^1.0.11, value-or-promise@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.12.tgz#0e5abfeec70148c78460a849f6b003ea7986f15c" @@ -8002,6 +8415,11 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + webpack-node-externals@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz#1a3407c158d547a9feb4229a9e3385b7b60c9917" @@ -8042,6 +8460,14 @@ webpack@5.88.2: watchpack "^2.4.0" webpack-sources "^3.2.3" +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -8107,6 +8533,13 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wide-align@^1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + windows-release@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-4.0.0.tgz#4725ec70217d1bf6e02c7772413b29cdde9ec377"