diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..1f739e6 --- /dev/null +++ b/.env.template @@ -0,0 +1,8 @@ +# Environment variables declared in this file are automatically made available to Prisma. +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema + +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. +# See the documentation for all the connection string options: https://pris.ly/d/connection-strings + +DATABASE_URL= +secret= \ No newline at end of file diff --git a/package.json b/package.json index f843aff..b632f34 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,16 @@ "dependencies": { "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", + "@nestjs/jwt": "^10.2.0", + "@nestjs/passport": "^10.0.2", "@nestjs/platform-express": "^10.0.0", + "@prisma/client": "^5.6.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "passport-local": "^1.0.0", + "prisma": "^5.6.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1" }, @@ -34,6 +43,8 @@ "@types/express": "^4.17.17", "@types/jest": "^29.5.2", "@types/node": "^20.3.1", + "@types/passport-jwt": "^3.0.13", + "@types/passport-local": "^1.0.38", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", diff --git a/prisma/migrations/20231119154116_init/migration.sql b/prisma/migrations/20231119154116_init/migration.sql new file mode 100644 index 0000000..a14be22 --- /dev/null +++ b/prisma/migrations/20231119154116_init/migration.sql @@ -0,0 +1,12 @@ +-- CreateTable +CREATE TABLE "user" ( + "id" TEXT NOT NULL, + "name" VARCHAR(64) NOT NULL, + "email" VARCHAR(64) NOT NULL, + "password" VARCHAR(64) NOT NULL, + + CONSTRAINT "user_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "user_id_key" ON "user"("id"); diff --git a/prisma/migrations/20231119154336_init/migration.sql b/prisma/migrations/20231119154336_init/migration.sql new file mode 100644 index 0000000..bd339f7 --- /dev/null +++ b/prisma/migrations/20231119154336_init/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "user" ADD COLUMN "idx" SERIAL NOT NULL; diff --git a/prisma/migrations/20231119154600_init/migration.sql b/prisma/migrations/20231119154600_init/migration.sql new file mode 100644 index 0000000..1e2a748 --- /dev/null +++ b/prisma/migrations/20231119154600_init/migration.sql @@ -0,0 +1,6 @@ +/* + Warnings: + - You are about to drop the column `idx` on the `user` table. All the data in the column will be lost. +*/ +-- AlterTable +ALTER TABLE "user" DROP COLUMN "idx"; diff --git a/prisma/migrations/20231120003024_init/migration.sql b/prisma/migrations/20231120003024_init/migration.sql new file mode 100644 index 0000000..f0f4ba0 --- /dev/null +++ b/prisma/migrations/20231120003024_init/migration.sql @@ -0,0 +1,19 @@ +/* + Warnings: + - You are about to drop the `user` table. If the table is not empty, all the data it contains will be lost. +*/ +-- DropTable +DROP TABLE "user"; + +-- CreateTable +CREATE TABLE "user1" ( + "id" TEXT NOT NULL, + "name" VARCHAR(64) NOT NULL, + "email" VARCHAR(64) NOT NULL, + "password" VARCHAR(64) NOT NULL, + + CONSTRAINT "user1_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "user1_id_key" ON "user1"("id"); diff --git a/prisma/migrations/20231120003348_init/migration.sql b/prisma/migrations/20231120003348_init/migration.sql new file mode 100644 index 0000000..3d53f33 --- /dev/null +++ b/prisma/migrations/20231120003348_init/migration.sql @@ -0,0 +1,12 @@ +-- CreateTable +CREATE TABLE "user2" ( + "id" TEXT NOT NULL, + "name" VARCHAR(64) NOT NULL, + "email" VARCHAR(64) NOT NULL, + "password" VARCHAR(64) NOT NULL, + + CONSTRAINT "user2_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "user2_id_key" ON "user2"("id"); diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..99e4f20 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..6b46c82 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,17 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model User { + id String @id @unique @default(uuid()) + name String @db.VarChar(64) + email String @unique @db.VarChar(64) + password String @db.VarChar(64) + + @@map("user") +} diff --git a/src/app.module.ts b/src/app.module.ts index b062806..8b191f9 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,10 +1,27 @@ +import { JwtModule } from '@nestjs/jwt'; import { Module } from '@nestjs/common'; -import { UserController } from './user/user.controller'; + import { UserService } from './user/user.service'; +import { PrismaService } from './prisma/prisma.service'; +import { AuthModule } from './auth/auth.module'; +import { UserModule } from './user/user.module'; +import { AuthController } from './auth/auth.controller'; +import { AuthService } from './auth/auth.service'; +import { PassportModule } from '@nestjs/passport'; @Module({ - imports: [], - controllers: [UserController], - providers: [UserService], + imports: [ + AuthModule, + UserModule, + PassportModule.register({ defaultStrategy: 'jwt' }), + JwtModule.register({ + secret: process.env.secret, + signOptions: { + expiresIn: 60 * 60, + }, + }), + ], + controllers: [AuthController], + providers: [UserService, PrismaService, AuthService], }) export class AppModule {} diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts new file mode 100644 index 0000000..d988e21 --- /dev/null +++ b/src/auth/auth.controller.ts @@ -0,0 +1,27 @@ +import { SignupBody, LoginBody } from './dto/auth.dto'; +import { + Body, + Controller, + Get, + Post, + UsePipes, + ValidationPipe, +} from '@nestjs/common'; +import { AuthService } from './auth.service'; + +@Controller('auth') +export class AuthController { + constructor(private readonly authService: AuthService) {} + + @Post('signup') + @UsePipes(ValidationPipe) + signUp(@Body() signupBody: SignupBody) { + return this.authService.signup(signupBody); + } + + @Post('login') + @UsePipes(ValidationPipe) + login(@Body() loginBody: LoginBody) { + return this.authService.login(loginBody); + } +} diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts new file mode 100644 index 0000000..b10d2e0 --- /dev/null +++ b/src/auth/auth.module.ts @@ -0,0 +1,22 @@ +import { PrismaService } from './../prisma/prisma.service'; +import { Module } from '@nestjs/common'; +import { AuthService } from './auth.service'; +import { AuthController } from './auth.controller'; +import { UserService } from 'src/user/user.service'; +import { JwtModule } from '@nestjs/jwt'; +import { PassportModule } from '@nestjs/passport'; + +@Module({ + imports: [ + PassportModule.register({ defaultStrategy: 'jwt' }), + JwtModule.register({ + secret: process.env.secret, + signOptions: { + expiresIn: 60 * 60, + }, + }), + ], + providers: [AuthService, UserService, PrismaService], + controllers: [AuthController], +}) +export class AuthModule {} diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts new file mode 100644 index 0000000..7b41bfc --- /dev/null +++ b/src/auth/auth.service.ts @@ -0,0 +1,44 @@ +import { PrismaService } from './../prisma/prisma.service'; +import { UserService } from 'src/user/user.service'; +import { + BadRequestException, + Injectable, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { Messeges } from 'src/utils/messege.utils'; + +import { LoginBody, SignupBody } from './dto/auth.dto'; +import { JwtService } from '@nestjs/jwt'; + +@Injectable() +export class AuthService { + constructor( + private userService: UserService, + private jwtService: JwtService, + ) {} + + async signup(userData: SignupBody) { + const { password, email, name } = userData; + try { + const response = await this.userService.createOne(userData); + } catch (response) { + if (response.code === 'P2002') { + throw new BadRequestException(Messeges.already.email); + } + } + return { messege: Messeges.success.signup }; + } + + async login(loginData: LoginBody) { + const { email, password } = loginData; + const currentUser = await this.userService.findOne(email); + if (!currentUser) return new NotFoundException(Messeges.notFound.email); + if (currentUser.password !== password) + return new UnauthorizedException(Messeges.correct.password); + + const payload = { email: email }; + const accessToken = await this.jwtService.sign(payload); + return { accessToken: accessToken }; + } +} diff --git a/src/auth/dto/auth.dto.ts b/src/auth/dto/auth.dto.ts new file mode 100644 index 0000000..f6794e1 --- /dev/null +++ b/src/auth/dto/auth.dto.ts @@ -0,0 +1,28 @@ +import { IsEmail, IsNotEmpty, IsString, Length } from 'class-validator'; + +export class SignupBody { + @IsNotEmpty() + @IsString() + @Length(1, 16) + name: string; + + @IsNotEmpty() + @IsEmail() + email: string; + + @IsNotEmpty() + @IsString() + @Length(1, 16) + password: string; +} + +export class LoginBody { + @IsNotEmpty() + @IsEmail() + email: string; + + @IsNotEmpty() + @IsString() + @Length(1, 16) + password: string; +} diff --git a/src/auth/jwt.stratefy.ts b/src/auth/jwt.stratefy.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/auth/jwt/jwt.guard.ts b/src/auth/jwt/jwt.guard.ts new file mode 100644 index 0000000..2155290 --- /dev/null +++ b/src/auth/jwt/jwt.guard.ts @@ -0,0 +1,5 @@ +import { Injectable } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; + +@Injectable() +export class JwtAuthGuard extends AuthGuard('jwt') {} diff --git a/src/auth/jwt/jwt.strategy.ts b/src/auth/jwt/jwt.strategy.ts new file mode 100644 index 0000000..7f1f349 --- /dev/null +++ b/src/auth/jwt/jwt.strategy.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@nestjs/common'; +import { PassportStrategy } from '@nestjs/passport'; +import { Strategy, ExtractJwt } from 'passport-jwt'; + +@Injectable() +export class JwtStrategy extends PassportStrategy(Strategy) { + constructor() { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // 헤더로부터 토큰 추출하는 함수 + secretOrKey: process.env.JWT_SECRET_KEY, + ignoreExpiration: false, + }); + } +} diff --git a/src/auth/pipe/validation.pipe.ts b/src/auth/pipe/validation.pipe.ts new file mode 100644 index 0000000..6cd2153 --- /dev/null +++ b/src/auth/pipe/validation.pipe.ts @@ -0,0 +1,17 @@ +import { ArgumentMetadata, PipeTransform } from '@nestjs/common'; +import { ArgumentOutOfRangeError } from 'rxjs'; + +export class ValidationPipe implements PipeTransform { + transform(value: any, metadata: ArgumentMetadata) { + console.log( + '🚀 ~ file: validation.pipe.ts:6 ~ ValidationPipe ~ transform ~ metadata:', + metadata, + ); + console.log( + '🚀 ~ file: validation.pipe.ts:6 ~ ValidationPipe ~ transform ~ value:', + value, + ); + + return value; + } +} diff --git a/src/model/user.model.ts b/src/model/user.model.ts deleted file mode 100644 index d3bdc4c..0000000 --- a/src/model/user.model.ts +++ /dev/null @@ -1,16 +0,0 @@ -export interface User { - name: string; - email: string; - password: string; -} - -export interface SignupBody { - name: string; - email: string; - password: string; -} - -export interface LoginBody { - email: string; - password: string; -} diff --git a/src/prisma/prisma.service.ts b/src/prisma/prisma.service.ts new file mode 100644 index 0000000..359f950 --- /dev/null +++ b/src/prisma/prisma.service.ts @@ -0,0 +1,9 @@ +import { Injectable, OnModuleInit } from '@nestjs/common'; +import { PrismaClient } from '@prisma/client'; + +@Injectable() +export class PrismaService extends PrismaClient implements OnModuleInit { + async onModuleInit() { + await this.$connect(); + } +} diff --git a/src/user/user.controller.ts b/src/user/user.controller.ts deleted file mode 100644 index 8927617..0000000 --- a/src/user/user.controller.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { UserService } from './user.service'; -import { Body, Controller, Get, Post } from '@nestjs/common'; -import { User } from '../model/user.model'; - -@Controller('user') -export class UserController { - constructor(private readonly userService: UserService) {} - - @Get() - getRoot() { - return this.userService.getRoot(); - } - - @Post('signup') - signup(@Body() userData: User) { - return this.userService.signup(userData); - } - - @Post('login') - login(@Body() loginData: User) { - return this.userService.login(loginData); - } -} diff --git a/src/user/user.module.ts b/src/user/user.module.ts new file mode 100644 index 0000000..48d83a5 --- /dev/null +++ b/src/user/user.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { UserService } from './user.service'; +import { PrismaService } from 'src/prisma/prisma.service'; + +@Module({ + providers: [UserService, PrismaService], + exports: [UserService], +}) +export class UserModule {} diff --git a/src/user/user.service.ts b/src/user/user.service.ts index d8c33d4..abe4bf3 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -1,42 +1,46 @@ +import { PrismaService } from './../prisma/prisma.service'; import { BadRequestException, Injectable, NotFoundException, UnauthorizedException, } from '@nestjs/common'; -import { - validateEmail, - validatePassword, - validateName, -} from './validation.utils'; -import { LoginBody, SignupBody, User } from 'src/model/user.model'; + +import { LoginBody, SignupBody } from '../auth/dto/auth.dto'; +import { Messeges } from 'src/utils/messege.utils'; @Injectable() export class UserService { - private users: User[] = []; + constructor(private prismaService: PrismaService) {} + + async createOne(userData: SignupBody) { + try { + await this.prismaService.user.create({ data: userData }); + } catch (error) { + throw error; + } + return { messege: Messeges.success.signup }; + } + + async findOne(email: string) { + const currentUser = await this.prismaService.user.findUnique({ + where: { email: String(email) }, + }); + if (!currentUser) { + return null; + } + return currentUser; + } - signup(signupData: SignupBody) { - const { password, email, name } = signupData; - if (!validateEmail(email)) - throw new BadRequestException('please enter a valid email address.'); - if (!validatePassword(password)) - throw new BadRequestException('please enter a valid password.'); - if (!validateName(name)) - throw new BadRequestException('please enter a valid name.'); - this.users.push(signupData); - return { message: 'signup success' }; + async getAll() { + return await this.prismaService.user.findMany(); } - login(loginData: LoginBody) { - const { email, password } = loginData; - const currentUser = this.users.find((user) => user.email === email); - if (!currentUser) return new NotFoundException('email not found.'); - if (currentUser.password !== password) - return new UnauthorizedException('password is not correct'); - return { message: 'login success' }; + async deleteOne(id: string) { + return await this.prismaService.user.delete({ where: { id: String(id) } }); } - getRoot(): string { + getRoot() { return 'root'; } } diff --git a/src/user/validation.utils.ts b/src/user/validation.utils.ts deleted file mode 100644 index 63fc383..0000000 --- a/src/user/validation.utils.ts +++ /dev/null @@ -1,20 +0,0 @@ -export const reg = { - hasUpperCase: new RegExp(/[A-Z]/), - hasNumber: new RegExp(/\d/), - hasSpecialCharacter: new RegExp(/[!@#$%^&*(),.?":{}|<>]/), - emailCheck: new RegExp(/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/), -}; - -export const validateEmail = (email: string): boolean => { - return reg.emailCheck.test(email); -}; - -export const validatePassword = (password: string) => { - const { hasNumber, hasSpecialCharacter, hasUpperCase } = reg; - const regTests = [hasNumber, hasSpecialCharacter, hasUpperCase]; - return regTests.every((reg) => reg.test(password)); -}; - -export const validateName = (name: string) => { - return name.length < 16 && name.length > 0; -}; diff --git a/src/utils/messege.utils.ts b/src/utils/messege.utils.ts new file mode 100644 index 0000000..8333e9c --- /dev/null +++ b/src/utils/messege.utils.ts @@ -0,0 +1,21 @@ +export const Messeges = { + invaildError: { + invalidEmail: 'please enter a valid email address.', + invalidPassword: 'please enter a valid password.', + invalidName: 'please enter a valid name.', + }, + success: { + login: 'login success', + signup: 'signup success', + }, + already: { + email: 'email already exists.', + nickname: 'nickname already exists.', + }, + notFound: { + email: 'email not found', + }, + correct: { + password: 'password is not correct', + }, +} as const; diff --git a/src/utils/messeges.json b/src/utils/messeges.json new file mode 100644 index 0000000..d3b1d7b --- /dev/null +++ b/src/utils/messeges.json @@ -0,0 +1,21 @@ +{ + "invaildError": { + "invalidEmail": "please enter a valid email address.", + "invalidPassword": "please enter a valid password.", + "invalidName": "please enter a valid name." + }, + "success": { + "login": "login success", + "signup": "signup success" + }, + "already": { + "email": "email already exists.", + "nickname": "nickname already exists." + }, + "notFound": { + "email": "email not found" + }, + "correct": { + "password": "password is not correct" + } +} diff --git a/yarn.lock b/yarn.lock index 55905db..997c340 100644 --- a/yarn.lock +++ b/yarn.lock @@ -723,6 +723,19 @@ path-to-regexp "3.2.0" tslib "2.6.2" +"@nestjs/jwt@^10.2.0": + version "10.2.0" + resolved "https://registry.yarnpkg.com/@nestjs/jwt/-/jwt-10.2.0.tgz#6aa35a04922d19c6426efced4671620f92e6dbd0" + integrity sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g== + dependencies: + "@types/jsonwebtoken" "9.0.5" + jsonwebtoken "9.0.2" + +"@nestjs/passport@^10.0.2": + version "10.0.2" + resolved "https://registry.yarnpkg.com/@nestjs/passport/-/passport-10.0.2.tgz#42ad193bccec3c332ac8b5e04cf6897bd57500fb" + integrity sha512-od31vfB2z3y05IDB5dWSbCGE2+pAf2k2WCBinNuTTOxN0O0+wtO1L3kawj/aCW3YR9uxsTOVbTDwtwgpNNsnjQ== + "@nestjs/platform-express@^10.0.0": version "10.2.8" resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.2.8.tgz#c5af1fe3afb6e9858fc5610fd11a247635187eff" @@ -799,6 +812,23 @@ picocolors "^1.0.0" tslib "^2.6.0" +"@prisma/client@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.6.0.tgz#1c15932250d5658fe0127e62faf4ecd96a877259" + integrity sha512-mUDefQFa1wWqk4+JhKPYq8BdVoFk9NFMBXUI8jAkBfQTtgx8WPx02U2HB/XbAz3GSUJpeJOKJQtNvaAIDs6sug== + dependencies: + "@prisma/engines-version" "5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee" + +"@prisma/engines-version@5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee": + version "5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee.tgz#57b003ab5e1ea1523b5cdd7f06b24ebcf5c7fd8c" + integrity sha512-UoFgbV1awGL/3wXuUK3GDaX2SolqczeeJ5b4FVec9tzeGbSWJboPSbT0psSrmgYAKiKnkOPFSLlH6+b+IyOwAw== + +"@prisma/engines@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.6.0.tgz#82c445aa10633bbc0388aa2d6e411a0bd94c9439" + integrity sha512-Mt2q+GNJpU2vFn6kif24oRSBQv1KOkYaterQsi0k2/lA+dLvhRX6Lm26gon6PYHwUM8/h8KRgXIUMU0PCLB6bw== + "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -922,7 +952,7 @@ "@types/range-parser" "*" "@types/send" "*" -"@types/express@^4.17.17": +"@types/express@*", "@types/express@^4.17.17": version "4.17.21" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== @@ -976,6 +1006,13 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== +"@types/jsonwebtoken@*", "@types/jsonwebtoken@9.0.5": + version "9.0.5" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz#0bd9b841c9e6c5a937c17656e2368f65da025588" + integrity sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA== + dependencies: + "@types/node" "*" + "@types/mime@*": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45" @@ -993,6 +1030,39 @@ dependencies: undici-types "~5.26.4" +"@types/passport-jwt@^3.0.13": + version "3.0.13" + resolved "https://registry.yarnpkg.com/@types/passport-jwt/-/passport-jwt-3.0.13.tgz#119267d2fc1af7d274a512731146183de5f2b53f" + integrity sha512-fjHaC6Bv8EpMMqzTnHP32SXlZGaNfBPC/Po5dmRGYi2Ky7ljXPbGnOy+SxZqa6iZvFgVhoJ1915Re3m93zmcfA== + dependencies: + "@types/express" "*" + "@types/jsonwebtoken" "*" + "@types/passport-strategy" "*" + +"@types/passport-local@^1.0.38": + version "1.0.38" + resolved "https://registry.yarnpkg.com/@types/passport-local/-/passport-local-1.0.38.tgz#8073758188645dde3515808999b1c218a6fe7141" + integrity sha512-nsrW4A963lYE7lNTv9cr5WmiUD1ibYJvWrpE13oxApFsRt77b0RdtZvKbCdNIY4v/QZ6TRQWaDDEwV1kCTmcXg== + dependencies: + "@types/express" "*" + "@types/passport" "*" + "@types/passport-strategy" "*" + +"@types/passport-strategy@*": + version "0.2.38" + resolved "https://registry.yarnpkg.com/@types/passport-strategy/-/passport-strategy-0.2.38.tgz#482abba0b165cd4553ec8b748f30b022bd6c04d3" + integrity sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA== + dependencies: + "@types/express" "*" + "@types/passport" "*" + +"@types/passport@*": + version "1.0.16" + resolved "https://registry.yarnpkg.com/@types/passport/-/passport-1.0.16.tgz#5a2918b180a16924c4d75c31254c31cdca5ce6cf" + integrity sha512-FD0qD5hbPWQzaM0wHUnJ/T0BBCJBxCeemtnCwc/ThhTg3x9jfrAcRUmj5Dopza+MfFS9acTe3wk7rcVnRIp/0A== + dependencies: + "@types/express" "*" + "@types/qs@*": version "6.9.10" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.10.tgz#0af26845b5067e1c9a622658a51f60a3934d51e8" @@ -1045,6 +1115,11 @@ dependencies: "@types/superagent" "*" +"@types/validator@^13.7.10": + version "13.11.7" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.11.7.tgz#99e19760297667ae46b7069ec8b96cbfe0a08b98" + integrity sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q== + "@types/yargs-parser@*": version "21.0.3" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" @@ -1617,6 +1692,11 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" +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" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -1735,6 +1815,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" + cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -2069,6 +2163,13 @@ eastasianwidth@^0.2.0: resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -3503,6 +3604,39 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsonwebtoken@9.0.2, jsonwebtoken@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -3528,6 +3662,11 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +libphonenumber-js@^1.10.14: + version "1.10.51" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.51.tgz#a3b8c15db2721c3e5f7fe6759e2a524712b578e6" + integrity sha512-vY2I+rQwrDQzoPds0JeTEpeWzbUJgqoV0O4v31PauHBb/e+1KCXKylHcDnBMgJZ9fH9mErsEbROJY3Z3JtqEmg== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -3552,6 +3691,36 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + lodash.memoize@4.x: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -3562,6 +3731,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -3752,7 +3926,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@2.1.3, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3981,6 +4155,35 @@ parseurl@~1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +passport-jwt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.1.tgz#c443795eff322c38d173faa0a3c481479646ec3d" + integrity sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ== + dependencies: + jsonwebtoken "^9.0.0" + passport-strategy "^1.0.0" + +passport-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee" + integrity sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow== + dependencies: + passport-strategy "1.x.x" + +passport-strategy@1.x.x, passport-strategy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" + integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA== + +passport@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.7.0.tgz#3688415a59a48cf8068417a8a8092d4492ca3a05" + integrity sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ== + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + utils-merge "^1.0.1" + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -4029,6 +4232,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pause@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -4082,6 +4290,13 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" +prisma@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.6.0.tgz#ae2c27fdfb4d53be7f7dafb50d6b8b7f55c93aa5" + integrity sha512-EEaccku4ZGshdr2cthYHhf7iyvCcXqwJDvnoQRAJg5ge2Tzpv0e2BaMCp+CbbDUwoVTzwgOap9Zp+d4jFa2O9A== + dependencies: + "@prisma/engines" "5.6.0" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -4317,7 +4532,7 @@ rxjs@7.8.1, rxjs@^7.5.5, rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-buffer@5.2.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -4892,7 +5107,7 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -utils-merge@1.0.1: +utils-merge@1.0.1, utils-merge@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== @@ -4911,6 +5126,11 @@ v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^2.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== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"