From 5c79aa18f4e914d2f25120d85d1bea72d5fd407d Mon Sep 17 00:00:00 2001 From: Hyang-Dan Date: Sun, 30 Nov 2025 18:19:39 +0900 Subject: [PATCH] =?UTF-8?q?issue=20#39=20-=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=EC=9D=B4=ED=9B=84=20access/refresh=20token=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20=EB=B0=98=ED=99=98=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.common | 5 +- .env.dev | 2 + .env.local | 11 +- .env.prod | 2 + nest-cli.json | 5 +- package.json | 17 +- src/config/config.module.ts | 5 +- src/main.ts | 5 +- src/middleware/auth/auth.module.ts | 24 ++ src/middleware/auth/auth.service.ts | 23 ++ src/middleware/auth/jwt.guard.ts | 5 + src/middleware/auth/jwt.strategy.ts | 27 ++ src/modules/account/account.controller.ts | 8 +- src/modules/account/account.module.ts | 5 +- src/modules/account/account.repo.ts | 35 ++- src/modules/account/account.service.ts | 39 +++ .../account/dto/login/login-response.dto.ts | 2 + tsconfig.build.json | 6 +- tsconfig.json | 5 +- yarn.lock | 238 +++++++++++++++++- 20 files changed, 435 insertions(+), 34 deletions(-) create mode 100644 src/middleware/auth/auth.module.ts create mode 100644 src/middleware/auth/auth.service.ts create mode 100644 src/middleware/auth/jwt.guard.ts create mode 100644 src/middleware/auth/jwt.strategy.ts diff --git a/.env.common b/.env.common index ebe5ea8..ac9df40 100644 --- a/.env.common +++ b/.env.common @@ -1,6 +1,3 @@ -# Nestjs 서버 포트 -PORT=3000 - # Gmail SMTP 설정 GMAIL_USER=bkd.scheduler@gmail.com GMAIL_PASS= # 앱 비밀번호 또는 OAuth2 토큰 @@ -13,3 +10,5 @@ SMTP_AUTH=true SMTP_STARTTLS_ENABLE=true SMTP_STARTTLS_REQUIRED=true SMTP_AUTH_MECHANISMS=XOAUTH2 + +JWT_SECRET=96612b08364bbd9f275f29f86d39c18225e3cb3f31551434d5a84a88f5b01e627b5aafac902e0769bda4f1574b2f84ffb26e659b1a672182015a180c086cb911 diff --git a/.env.dev b/.env.dev index d010852..a30d3fa 100644 --- a/.env.dev +++ b/.env.dev @@ -1,3 +1,5 @@ +PORT=8088 + # PostgreSQL 설정 PGHOST=bkdhome.p-e.kr PGPORT=15454 diff --git a/.env.local b/.env.local index 20bf4ec..d88e4d5 100644 --- a/.env.local +++ b/.env.local @@ -1,12 +1,11 @@ +PORT=3000 + # PostgreSQL 설정 -PGHOST=bkdhome.p-e.kr -PGPORT=15454 -PGDATABASE=scheduler PGUSER=baekyangdan PGPASSWORD=qwas745478! -PG_DATABASE_URL=postgres://192.168.219.107:5454/scheduler +PG_DATABASE_URL=postgres://192.168.219.103:5454/scheduler # Redis 설정 -RD_HOST=bkdhome.p-e.kr +RD_HOST=192.168.219.103 RD_PORT=6779 -RD_URL=redis://192.168.219.107:6779 +RD_URL=redis://192.168.219.103:6779 diff --git a/.env.prod b/.env.prod index c83a9f1..92920bb 100644 --- a/.env.prod +++ b/.env.prod @@ -1,3 +1,5 @@ +PORT=3000 + # PostgreSQL 설정 PGHOST=db PGPORT=5454 diff --git a/nest-cli.json b/nest-cli.json index f9aa683..2566481 100644 --- a/nest-cli.json +++ b/nest-cli.json @@ -1,8 +1,5 @@ { "$schema": "https://json.schemastore.org/nest-cli", "collection": "@nestjs/schematics", - "sourceRoot": "src", - "compilerOptions": { - "deleteOutDir": true - } + "sourceRoot": "src" } diff --git a/package.json b/package.json index c482d6c..4b2d83a 100644 --- a/package.json +++ b/package.json @@ -6,13 +6,15 @@ "private": true, "license": "UNLICENSED", "scripts": { - "build": "NODE_ENV=prod nest build", + "build": "cross-env NODE_ENV=prod nest build", + "build:local": "cross-env NODE_ENV=local nest build", + "build:dev": "cross-env NODE_ENV=dev nest build", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "start": "nest start", - "start:local": "NODE_ENV=local nest start --watch", - "start:dev": "NODE_ENV=dev nest start --watch", + "start:local": "cross-env NODE_ENV=local nest start --watch", + "start:dev": "cross-env NODE_ENV=dev nest start --watch", "start:debug": "nest start --debug --watch", - "start:prod": "NODE_ENV=prod node dist/main", + "start:prod": "cross-env NODE_ENV=prod node dist/main", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "test": "jest", "test:watch": "jest --watch", @@ -26,6 +28,8 @@ "@nestjs/common": "^11.0.1", "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.0.1", + "@nestjs/jwt": "^11.0.1", + "@nestjs/passport": "^11.0.5", "@nestjs/platform-express": "^11.0.1", "bcrypt": "^6.0.0", "dotenv": "^17.2.3", @@ -34,6 +38,8 @@ "googleapis": "^166.0.0", "ioredis": "^5.8.2", "nodemailer": "^7.0.10", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", "pg": "^8.16.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" @@ -50,8 +56,11 @@ "@types/jest": "^30.0.0", "@types/node": "^22.10.7", "@types/nodemailer": "^7.0.4", + "@types/passport": "^0", + "@types/passport-jwt": "^4.0.1", "@types/pg": "^8.15.6", "@types/supertest": "^6.0.2", + "cross-env": "^10.1.0", "eslint": "^9.18.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-prettier": "^5.2.2", diff --git a/src/config/config.module.ts b/src/config/config.module.ts index b401e15..d7103fd 100644 --- a/src/config/config.module.ts +++ b/src/config/config.module.ts @@ -1,13 +1,14 @@ import { Module } from "@nestjs/common"; import { ConfigModule } from '@nestjs/config'; +import dotenv from 'dotenv'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, envFilePath: [ - '.env.common', - `.env.${process.env.NODE_ENV}` + `.env.${process.env.NODE_ENV}`, + '.env.common' ] }) ] diff --git a/src/main.ts b/src/main.ts index de0361c..a4bf559 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,5 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; -import dotenv from 'dotenv'; - -dotenv.config(); async function bootstrap() { const app = await NestFactory.create(AppModule); @@ -25,7 +22,7 @@ async function bootstrap() { app.enableShutdownHooks(); - await app.listen(process.env.PORT ?? 3000); + await app.listen(process.env.PORT ?? 3000, () => { process.env.NODE_ENV !== 'prod' && console.log(`servier is running on ${process.env.PORT}`) }); } bootstrap(); diff --git a/src/middleware/auth/auth.module.ts b/src/middleware/auth/auth.module.ts new file mode 100644 index 0000000..ebfdb27 --- /dev/null +++ b/src/middleware/auth/auth.module.ts @@ -0,0 +1,24 @@ +import { forwardRef, Module } from '@nestjs/common'; +import { AuthService } from './auth.service'; +import { JwtStrategy } from './jwt.strategy'; +import { JwtModule } from '@nestjs/jwt'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { AccountModule } from 'src/modules/account/account.module'; + +@Module({ + imports: [ + ConfigModule, + JwtModule.registerAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: (config: ConfigService) => ({ + secret: config.get('JWT_SECRET')!, + signOptions: { expiresIn: '1h' } + }) + }), + forwardRef(() => AccountModule) + ], + providers: [AuthService, JwtStrategy], + exports: [AuthService] +}) +export class AuthModule{} \ No newline at end of file diff --git a/src/middleware/auth/auth.service.ts b/src/middleware/auth/auth.service.ts new file mode 100644 index 0000000..707a659 --- /dev/null +++ b/src/middleware/auth/auth.service.ts @@ -0,0 +1,23 @@ +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { JwtService } from '@nestjs/jwt'; + +@Injectable() +export class AuthService { + constructor(private readonly jwtService: JwtService) {} + + generateTokens(payload: any) { + const accessToken = this.jwtService.sign(payload, { expiresIn: '1h' }); + const refreshToken = this.jwtService.sign(payload, { expiresIn: '7d' }); + + return { accessToken, refreshToken }; + } + + refreshTokens(refreshToken: string) { + try { + const payload = this.jwtService.verify(refreshToken); + return this.generateTokens(payload); + } catch (e) { + throw new UnauthorizedException('Invalid Refresh Token'); + } + } +} \ No newline at end of file diff --git a/src/middleware/auth/jwt.guard.ts b/src/middleware/auth/jwt.guard.ts new file mode 100644 index 0000000..8f3bcfd --- /dev/null +++ b/src/middleware/auth/jwt.guard.ts @@ -0,0 +1,5 @@ +import { Injectable } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; + +@Injectable() +export class JwtGuard extends AuthGuard('jwt') {} \ No newline at end of file diff --git a/src/middleware/auth/jwt.strategy.ts b/src/middleware/auth/jwt.strategy.ts new file mode 100644 index 0000000..d195601 --- /dev/null +++ b/src/middleware/auth/jwt.strategy.ts @@ -0,0 +1,27 @@ +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { JwtService } from '@nestjs/jwt'; +import { PassportStrategy } from '@nestjs/passport'; +import { ExtractJwt, Strategy } from 'passport-jwt'; +import { AccountRepo } from 'src/modules/account/account.repo'; + +@Injectable() +export class JwtStrategy extends PassportStrategy(Strategy) { + constructor( + private readonly accountRepo: AccountRepo + , private readonly configService: ConfigService + , private readonly jwtService: JwtService + ) { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + ignoreExpiration: false, + secretOrKey: configService.get('JWT_SECRET')! + }); + } + + async validate(payload: any) { + const account = await this.accountRepo.findById(payload.id); + if (!account || account.length < 1) throw new UnauthorizedException(); + return account[0]; + } +} \ No newline at end of file diff --git a/src/modules/account/account.controller.ts b/src/modules/account/account.controller.ts index d162eba..3aa8d68 100644 --- a/src/modules/account/account.controller.ts +++ b/src/modules/account/account.controller.ts @@ -36,8 +36,14 @@ export class AccountController { } @Post('signup') - async signup(@Body() body: SignupRequest): Promise { + async signup(@Body() body: SignupRequest): Promise { const result = await this.accountService.signup(body); return result; } + + @Post('login') + async login(@Body() body: LoginRequest): Promise { + const result = await this.accountService.login(body); + return result; + } } \ No newline at end of file diff --git a/src/modules/account/account.module.ts b/src/modules/account/account.module.ts index 62e3171..bb93ff9 100644 --- a/src/modules/account/account.module.ts +++ b/src/modules/account/account.module.ts @@ -1,9 +1,10 @@ -import { Module } from "@nestjs/common"; +import { forwardRef, Module } from "@nestjs/common"; import { AccountController } from "./account.controller"; import { AccountRepo } from "./account.repo"; import { AccountService } from "./account.service"; - +import { AuthModule } from 'src/middleware/auth/auth.module'; @Module({ + imports: [forwardRef(() => AuthModule)], controllers: [AccountController], providers: [AccountService, AccountRepo], exports: [AccountService, AccountRepo] diff --git a/src/modules/account/account.repo.ts b/src/modules/account/account.repo.ts index c385fb0..e8de7b9 100644 --- a/src/modules/account/account.repo.ts +++ b/src/modules/account/account.repo.ts @@ -1,6 +1,6 @@ import { Inject, Injectable } from "@nestjs/common"; import * as schema from "drizzle/schema"; -import { countDistinct, and, eq } from 'drizzle-orm'; +import { countDistinct, and, eq, not } from 'drizzle-orm'; import { NodePgDatabase } from "drizzle-orm/node-postgres"; @Injectable() @@ -38,5 +38,36 @@ export class AccountRepo { }); } - async + async login( + type: 'email' | 'accountId' + , id: string + ) { + const condition = type === 'email' + ? eq(schema.account.email, id) + : eq(schema.account.accountId, id); + return this + .db + .select() + .from(schema.account) + .where( + and( + condition, + eq(schema.account.isDeleted, false), + eq(schema.account.status, 'active') + ) + ); + } + + async findById(id: string) { + return await this + .db + .select() + .from(schema.account) + .where( + and( + eq(schema.account.id, id), + eq(schema.account.isDeleted, false) + ) + ) + } } \ No newline at end of file diff --git a/src/modules/account/account.service.ts b/src/modules/account/account.service.ts index 341130f..9fb6dff 100644 --- a/src/modules/account/account.service.ts +++ b/src/modules/account/account.service.ts @@ -5,12 +5,14 @@ import { MailerService } from "src/util/mailer/mailer.service"; import { Generator } from "src/util/generator"; import Redis from "ioredis"; import { Converter } from "src/util/converter"; +import { AuthService } from "src/middleware/auth/auth.service"; @Injectable() export class AccountService { constructor( private readonly accountRepo: AccountRepo , private readonly mailerService: MailerService + , private readonly authService: AuthService , @Inject("REDIS") private readonly redis: Redis ) {} @@ -70,4 +72,41 @@ export class AccountService { } } + + async login(data: DTO.LoginRequest): Promise { + const { type, id, password } = data; + const queryResult = await this.accountRepo.login(type, id); + const typeValue = type === 'email' ? '이메일' : '아이디'; + console.log(queryResult); + if (!queryResult || (queryResult.length < 1)) { + return { + success: false, + message: `존재하지 않는 ${typeValue} 입니다.` + }; + } + const hashedPassword = queryResult[0].password; + const isPasswordMatch = Converter.comparePassword(password, hashedPassword); + if (!isPasswordMatch) { + return { + success: false, + message: `비밀번호가 맞지 않습니다.` + }; + } + + { + const { id, accountId, name, nickname, email, status, isDeleted, birthday } = queryResult[0]; + + const payload = { + id, accountId, name, nickname, email, status, isDeleted, birthday + }; + + const { accessToken, refreshToken } = this.authService.generateTokens(payload); + + return { + success: true, + accessToken: accessToken, + refreshToken: refreshToken + }; + } + } } \ No newline at end of file diff --git a/src/modules/account/dto/login/login-response.dto.ts b/src/modules/account/dto/login/login-response.dto.ts index 4a53850..f6c909f 100644 --- a/src/modules/account/dto/login/login-response.dto.ts +++ b/src/modules/account/dto/login/login-response.dto.ts @@ -1,5 +1,7 @@ export class LoginResponseDto { success: boolean; + accessToken?: string; + refreshToken?: string; message?: string; error?: string; } \ No newline at end of file diff --git a/tsconfig.build.json b/tsconfig.build.json index 0ddc267..cd09ef1 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -2,8 +2,10 @@ "compilerOptions": { "noEmitOnError": true, "sourceMap": false, - "incremental": true, - "tsBuildInfoFile": ".tsbuildinfo" + "incremental": false, + "noEmit": false, + "tsBuildInfoFile": ".tsbuildinfo", + "outDir": "./dist" }, "extends": "./tsconfig.json", "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] diff --git a/tsconfig.json b/tsconfig.json index 89eb88f..f2efd8b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,12 +14,13 @@ "sourceMap": true, "outDir": "./dist", "baseUrl": "./", - "incremental": true, + "incremental": false, "skipLibCheck": true, "strictNullChecks": true, "forceConsistentCasingInFileNames": true, "noImplicitAny": false, "strictBindCallApply": false, - "noFallthroughCasesInSwitch": false + "noFallthroughCasesInSwitch": false, + "noEmit": false } } diff --git a/yarn.lock b/yarn.lock index 7c35b7b..ad4f98b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1064,6 +1064,13 @@ __metadata: languageName: node linkType: hard +"@epic-web/invariant@npm:^1.0.0": + version: 1.0.0 + resolution: "@epic-web/invariant@npm:1.0.0" + checksum: 10c0/72dbeb026e4e4eb3bc9c65739b91408ca77ab7d603a2494fa2eff3790ec22892c4caba751cffdf30f5ccf0e7ba79c1e9c96cf0a357404b9432bf1365baac23ca + languageName: node + linkType: hard + "@esbuild-kit/core-utils@npm:^3.3.2": version: 3.3.2 resolution: "@esbuild-kit/core-utils@npm:3.3.2" @@ -2341,6 +2348,28 @@ __metadata: languageName: node linkType: hard +"@nestjs/jwt@npm:^11.0.1": + version: 11.0.1 + resolution: "@nestjs/jwt@npm:11.0.1" + dependencies: + "@types/jsonwebtoken": "npm:9.0.10" + jsonwebtoken: "npm:9.0.2" + peerDependencies: + "@nestjs/common": ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 + checksum: 10c0/9514327aefb9570e2526bb68e84180330e751a66646f73f430e89f4980ab4d2c3dcfd6162fc7b2bbc60259a0bc1cba03a00e771799abc2796a8324f233f47b82 + languageName: node + linkType: hard + +"@nestjs/passport@npm:^11.0.5": + version: 11.0.5 + resolution: "@nestjs/passport@npm:11.0.5" + peerDependencies: + "@nestjs/common": ^10.0.0 || ^11.0.0 + passport: ^0.5.0 || ^0.6.0 || ^0.7.0 + checksum: 10c0/24175f6791abf02b70c3c0705ce56fefd3981fdece0da7e58325f790ce71aa6932b31a87a2ceaa52b6d9d8edab3a7c049f6081e4b4d59bcdfcaa00383b64ae02 + languageName: node + linkType: hard + "@nestjs/platform-express@npm:^11.0.1": version: 11.1.9 resolution: "@nestjs/platform-express@npm:11.1.9" @@ -3165,7 +3194,7 @@ __metadata: languageName: node linkType: hard -"@types/express@npm:^5.0.0": +"@types/express@npm:*, @types/express@npm:^5.0.0": version: 5.0.5 resolution: "@types/express@npm:5.0.5" dependencies: @@ -3234,6 +3263,16 @@ __metadata: languageName: node linkType: hard +"@types/jsonwebtoken@npm:*, @types/jsonwebtoken@npm:9.0.10": + version: 9.0.10 + resolution: "@types/jsonwebtoken@npm:9.0.10" + dependencies: + "@types/ms": "npm:*" + "@types/node": "npm:*" + checksum: 10c0/0688ac8fb75f809201cb7e18a12b9d80ce539cb9dd27e1b01e11807cb1a337059e899b8ee3abc3f2c9417f02e363a3069d9eab9ef9724b1da1f0e10713514f94 + languageName: node + linkType: hard + "@types/methods@npm:^1.1.4": version: 1.1.4 resolution: "@types/methods@npm:1.1.4" @@ -3248,6 +3287,13 @@ __metadata: languageName: node linkType: hard +"@types/ms@npm:*": + version: 2.1.0 + resolution: "@types/ms@npm:2.1.0" + checksum: 10c0/5ce692ffe1549e1b827d99ef8ff71187457e0eb44adbae38fdf7b9a74bae8d20642ee963c14516db1d35fa2652e65f47680fdf679dcbde52bbfadd021f497225 + languageName: node + linkType: hard + "@types/node@npm:*": version: 24.10.1 resolution: "@types/node@npm:24.10.1" @@ -3276,6 +3322,44 @@ __metadata: languageName: node linkType: hard +"@types/passport-jwt@npm:^4.0.1": + version: 4.0.1 + resolution: "@types/passport-jwt@npm:4.0.1" + dependencies: + "@types/jsonwebtoken": "npm:*" + "@types/passport-strategy": "npm:*" + checksum: 10c0/0ced0eaa7bb379d674821108d9bc6758223f1a5f2b9790ec78d3eaaccce6a58a424cf8ed22b53d813740ec53d929e21d92cf794ef0fb30c732866750763c0d7a + languageName: node + linkType: hard + +"@types/passport-strategy@npm:*": + version: 0.2.38 + resolution: "@types/passport-strategy@npm:0.2.38" + dependencies: + "@types/express": "npm:*" + "@types/passport": "npm:*" + checksum: 10c0/d7d2b1782a0845bd8914250aa9213a23c8d9c2225db46d854b77f2bf0129a789f46d4a5e9ad336eca277fc7e0a051c0a2942da5c864e7c6710763f102d9d4295 + languageName: node + linkType: hard + +"@types/passport@npm:*": + version: 1.0.17 + resolution: "@types/passport@npm:1.0.17" + dependencies: + "@types/express": "npm:*" + checksum: 10c0/09039429a9178117a80880c4e7d437abc83216eac5e0c97bc6f14a03a59193386cff484931dc880693f8b13a512c366ef7a51ecd8cc1a63f17366be68161f633 + languageName: node + linkType: hard + +"@types/passport@npm:^0": + version: 0.4.7 + resolution: "@types/passport@npm:0.4.7" + dependencies: + "@types/express": "npm:*" + checksum: 10c0/58ca21800b7910385961b7a3dc9071fc9db6223242b96ff88d16c9d004ce7173524e7c17c63363595565af3f85ad932ee301efc8cc3e378bea172eebc9e07703 + languageName: node + linkType: hard + "@types/pg@npm:^8.15.6": version: 8.15.6 resolution: "@types/pg@npm:8.15.6" @@ -4175,6 +4259,8 @@ __metadata: "@nestjs/common": "npm:^11.0.1" "@nestjs/config": "npm:^4.0.2" "@nestjs/core": "npm:^11.0.1" + "@nestjs/jwt": "npm:^11.0.1" + "@nestjs/passport": "npm:^11.0.5" "@nestjs/platform-express": "npm:^11.0.1" "@nestjs/schematics": "npm:^11.0.0" "@nestjs/testing": "npm:^11.0.1" @@ -4184,9 +4270,12 @@ __metadata: "@types/jest": "npm:^30.0.0" "@types/node": "npm:^22.10.7" "@types/nodemailer": "npm:^7.0.4" + "@types/passport": "npm:^0" + "@types/passport-jwt": "npm:^4.0.1" "@types/pg": "npm:^8.15.6" "@types/supertest": "npm:^6.0.2" bcrypt: "npm:^6.0.0" + cross-env: "npm:^10.1.0" dotenv: "npm:^17.2.3" drizzle-kit: "npm:^0.31.7" drizzle-orm: "npm:^0.44.7" @@ -4198,6 +4287,8 @@ __metadata: ioredis: "npm:^5.8.2" jest: "npm:^30.0.0" nodemailer: "npm:^7.0.10" + passport: "npm:^0.7.0" + passport-jwt: "npm:^4.0.1" pg: "npm:^8.16.3" prettier: "npm:^3.4.2" reflect-metadata: "npm:^0.2.2" @@ -4759,6 +4850,19 @@ __metadata: languageName: node linkType: hard +"cross-env@npm:^10.1.0": + version: 10.1.0 + resolution: "cross-env@npm:10.1.0" + dependencies: + "@epic-web/invariant": "npm:^1.0.0" + cross-spawn: "npm:^7.0.6" + bin: + cross-env: dist/bin/cross-env.js + cross-env-shell: dist/bin/cross-env-shell.js + checksum: 10c0/834a862db456ba1fedf6c6da43436b123ae38f514fa286d6f0937c14fa83f13469f77f70f2812db041ae2d84f82bac627040b8686030aca27fbdf113dfa38b63 + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" @@ -7211,6 +7315,35 @@ __metadata: languageName: node linkType: hard +"jsonwebtoken@npm:9.0.2, jsonwebtoken@npm:^9.0.0": + version: 9.0.2 + resolution: "jsonwebtoken@npm:9.0.2" + dependencies: + jws: "npm:^3.2.2" + lodash.includes: "npm:^4.3.0" + lodash.isboolean: "npm:^3.0.3" + lodash.isinteger: "npm:^4.0.4" + lodash.isnumber: "npm:^3.0.3" + lodash.isplainobject: "npm:^4.0.6" + lodash.isstring: "npm:^4.0.1" + lodash.once: "npm:^4.0.0" + ms: "npm:^2.1.1" + semver: "npm:^7.5.4" + checksum: 10c0/d287a29814895e866db2e5a0209ce730cbc158441a0e5a70d5e940eb0d28ab7498c6bf45029cc8b479639bca94056e9a7f254e2cdb92a2f5750c7f358657a131 + languageName: node + linkType: hard + +"jwa@npm:^1.4.1": + version: 1.4.2 + resolution: "jwa@npm:1.4.2" + dependencies: + buffer-equal-constant-time: "npm:^1.0.1" + ecdsa-sig-formatter: "npm:1.0.11" + safe-buffer: "npm:^5.0.1" + checksum: 10c0/210a544a42ca22203e8fc538835205155ba3af6a027753109f9258bdead33086bac3c25295af48ac1981f87f9c5f941bc8f70303670f54ea7dcaafb53993d92c + languageName: node + linkType: hard + "jwa@npm:^2.0.0": version: 2.0.1 resolution: "jwa@npm:2.0.1" @@ -7222,6 +7355,16 @@ __metadata: languageName: node linkType: hard +"jws@npm:^3.2.2": + version: 3.2.2 + resolution: "jws@npm:3.2.2" + dependencies: + jwa: "npm:^1.4.1" + safe-buffer: "npm:^5.0.1" + checksum: 10c0/e770704533d92df358adad7d1261fdecad4d7b66fa153ba80d047e03ca0f1f73007ce5ed3fbc04d2eba09ba6e7e6e645f351e08e5ab51614df1b0aa4f384dfff + languageName: node + linkType: hard + "jws@npm:^4.0.0": version: 4.0.0 resolution: "jws@npm:4.0.0" @@ -7311,6 +7454,13 @@ __metadata: languageName: node linkType: hard +"lodash.includes@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.includes@npm:4.3.0" + checksum: 10c0/7ca498b9b75bf602d04e48c0adb842dfc7d90f77bcb2a91a2b2be34a723ad24bc1c8b3683ec6b2552a90f216c723cdea530ddb11a3320e08fa38265703978f4b + languageName: node + linkType: hard + "lodash.isarguments@npm:^3.1.0": version: 3.1.0 resolution: "lodash.isarguments@npm:3.1.0" @@ -7318,6 +7468,41 @@ __metadata: languageName: node linkType: hard +"lodash.isboolean@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isboolean@npm:3.0.3" + checksum: 10c0/0aac604c1ef7e72f9a6b798e5b676606042401dd58e49f051df3cc1e3adb497b3d7695635a5cbec4ae5f66456b951fdabe7d6b387055f13267cde521f10ec7f7 + languageName: node + linkType: hard + +"lodash.isinteger@npm:^4.0.4": + version: 4.0.4 + resolution: "lodash.isinteger@npm:4.0.4" + checksum: 10c0/4c3e023a2373bf65bf366d3b8605b97ec830bca702a926939bcaa53f8e02789b6a176e7f166b082f9365bfec4121bfeb52e86e9040cb8d450e64c858583f61b7 + languageName: node + linkType: hard + +"lodash.isnumber@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isnumber@npm:3.0.3" + checksum: 10c0/2d01530513a1ee4f72dd79528444db4e6360588adcb0e2ff663db2b3f642d4bb3d687051ae1115751ca9082db4fdef675160071226ca6bbf5f0c123dbf0aa12d + languageName: node + linkType: hard + +"lodash.isplainobject@npm:^4.0.6": + version: 4.0.6 + resolution: "lodash.isplainobject@npm:4.0.6" + checksum: 10c0/afd70b5c450d1e09f32a737bed06ff85b873ecd3d3d3400458725283e3f2e0bb6bf48e67dbe7a309eb371a822b16a26cca4a63c8c52db3fc7dc9d5f9dd324cbb + languageName: node + linkType: hard + +"lodash.isstring@npm:^4.0.1": + version: 4.0.1 + resolution: "lodash.isstring@npm:4.0.1" + checksum: 10c0/09eaf980a283f9eef58ef95b30ec7fee61df4d6bf4aba3b5f096869cc58f24c9da17900febc8ffd67819b4e29de29793190e88dc96983db92d84c95fa85d1c92 + languageName: node + linkType: hard + "lodash.memoize@npm:^4.1.2": version: 4.1.2 resolution: "lodash.memoize@npm:4.1.2" @@ -7332,6 +7517,13 @@ __metadata: languageName: node linkType: hard +"lodash.once@npm:^4.0.0": + version: 4.1.1 + resolution: "lodash.once@npm:4.1.1" + checksum: 10c0/46a9a0a66c45dd812fcc016e46605d85ad599fe87d71a02f6736220554b52ffbe82e79a483ad40f52a8a95755b0d1077fba259da8bfb6694a7abbf4a48f1fc04 + languageName: node + linkType: hard + "lodash@npm:4.17.21, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" @@ -7662,7 +7854,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:^2.1.3": +"ms@npm:^2.1.1, ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 @@ -8000,6 +8192,34 @@ __metadata: languageName: node linkType: hard +"passport-jwt@npm:^4.0.1": + version: 4.0.1 + resolution: "passport-jwt@npm:4.0.1" + dependencies: + jsonwebtoken: "npm:^9.0.0" + passport-strategy: "npm:^1.0.0" + checksum: 10c0/d7e2b472d399f596a1db31310f8e63d10777ab7468b9a378c964156e5f0a772598b007417356ead578cfdaf60dc2bba39a55f0033ca865186fdb2a2b198e2e7e + languageName: node + linkType: hard + +"passport-strategy@npm:1.x.x, passport-strategy@npm:^1.0.0": + version: 1.0.0 + resolution: "passport-strategy@npm:1.0.0" + checksum: 10c0/cf4cd32e1bf2538a239651581292fbb91ccc83973cde47089f00d2014c24bed63d3e65af21da8ddef649a8896e089eb9c3ac9ca639f36c797654ae9ee4ed65e1 + languageName: node + linkType: hard + +"passport@npm:^0.7.0": + version: 0.7.0 + resolution: "passport@npm:0.7.0" + dependencies: + passport-strategy: "npm:1.x.x" + pause: "npm:0.0.1" + utils-merge: "npm:^1.0.1" + checksum: 10c0/08c940b86e4adbfe43e753f8097300a5a9d1ce9a3aa002d7b12d27770943a1a87202c54597c0f04dbfd4117d67de76303433577512fc19c7e364fec37b0d3fc5 + languageName: node + linkType: hard + "path-exists@npm:^4.0.0": version: 4.0.0 resolution: "path-exists@npm:4.0.0" @@ -8055,6 +8275,13 @@ __metadata: languageName: node linkType: hard +"pause@npm:0.0.1": + version: 0.0.1 + resolution: "pause@npm:0.0.1" + checksum: 10c0/f362655dfa7f44b946302c5a033148852ed5d05f744bd848b1c7eae6a543f743e79c7751ee896ba519fd802affdf239a358bb2ea5ca1b1c1e4e916279f83ab75 + languageName: node + linkType: hard + "pg-cloudflare@npm:^1.2.7": version: 1.2.7 resolution: "pg-cloudflare@npm:1.2.7" @@ -9497,6 +9724,13 @@ __metadata: languageName: node linkType: hard +"utils-merge@npm:^1.0.1": + version: 1.0.1 + resolution: "utils-merge@npm:1.0.1" + checksum: 10c0/02ba649de1b7ca8854bfe20a82f1dfbdda3fb57a22ab4a8972a63a34553cf7aa51bc9081cf7e001b035b88186d23689d69e71b510e610a09a4c66f68aa95b672 + languageName: node + linkType: hard + "v8-compile-cache-lib@npm:^3.0.1": version: 3.0.1 resolution: "v8-compile-cache-lib@npm:3.0.1"