From 30848a299dec580a3209f56036894852bd9adf4c Mon Sep 17 00:00:00 2001 From: Raymond <73725736+raymondanythings@users.noreply.github.com> Date: Fri, 3 Feb 2023 19:02:27 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=A7=AAtest=20:=20jwt=20module=20rsa?= =?UTF-8?q?=20=EC=8B=9C=EB=8F=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/app.module.ts b/src/app.module.ts index b0d3578..45bcd80 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -5,6 +5,7 @@ import { EventsModule } from './events/events.module' import { LoggerModule } from './logger/logger.module' import joi from 'joi' import { WorkspacesModule } from './workspaces/workspaces.module' +import { JwtModule } from './jwt/jwt.module' @Module({ imports: [ @@ -20,11 +21,18 @@ import { WorkspacesModule } from './workspaces/workspaces.module' REDIS_HOST: joi.string().required(), REDIS_PORT: joi.string().required(), REDIS_PASSWORD: joi.string().required(), + JWT_PRIVATE_KEY: joi.string().required(), + JWT_PUBLIC_KEY: joi.string().required(), }), }), LoggerModule, WorkspacesModule, EventsModule, + JwtModule.forRoot({ + isRSA: true, + priveKey: process.env.JWT_PRIVATE_KEY, + pubkey: process.env.JWT_PUBLIC_KEY, + }), ], controllers: [], providers: [], @@ -32,5 +40,10 @@ import { WorkspacesModule } from './workspaces/workspaces.module' export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(LoggerMiddleware).forRoutes('*') + consumer + .apply(LoggerMiddleware) + .exclude('/login') + .exclude('/') + .forRoutes('*') } } From a39b141324d6f1dae4a458143580823aa381e16f Mon Sep 17 00:00:00 2001 From: Raymond <73725736+raymondanythings@users.noreply.github.com> Date: Fri, 3 Feb 2023 19:02:43 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=A7=AAtest=20:=20jwt=20module=20rsa?= =?UTF-8?q?=20=EC=8B=9C=EB=8F=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 + src/common/common.constants.ts | 1 + src/events/events.gateway.ts | 1 - src/jwt/jwt.interface.ts | 7 ++ src/jwt/jwt.module.ts | 31 ++++++++ src/jwt/jwt.service.ts | 4 + src/key/private.key.key | 15 ++++ src/key/public.key.pub | 6 ++ src/main.ts | 4 +- src/sockets/socket.adapter.ts | 38 ++++++++++ src/workspaces/workspaces.gateway.ts | 6 -- yarn.lock | 109 ++++++++++++--------------- 12 files changed, 156 insertions(+), 68 deletions(-) create mode 100644 src/common/common.constants.ts create mode 100644 src/jwt/jwt.interface.ts create mode 100644 src/jwt/jwt.module.ts create mode 100644 src/jwt/jwt.service.ts create mode 100644 src/key/private.key.key create mode 100644 src/key/public.key.pub create mode 100644 src/sockets/socket.adapter.ts diff --git a/package.json b/package.json index 288ad95..54b853d 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,9 @@ "@nestjs/swagger": "^6.1.4", "@nestjs/websockets": "^9.2.1", "@socket.io/redis-adapter": "^8.0.1", + "@types/jsonwebtoken": "^9.0.1", "@types/socket.io": "^3.0.2", + "jsonwebtoken": "^9.0.0", "redis": "^4.6.4", "reflect-metadata": "^0.1.13", "rxjs": "^7.2.0" diff --git a/src/common/common.constants.ts b/src/common/common.constants.ts new file mode 100644 index 0000000..b511a41 --- /dev/null +++ b/src/common/common.constants.ts @@ -0,0 +1 @@ +export const JWT_PROVIDER = 'jwt_provider' diff --git a/src/events/events.gateway.ts b/src/events/events.gateway.ts index 7706a01..bcb9e6b 100644 --- a/src/events/events.gateway.ts +++ b/src/events/events.gateway.ts @@ -95,7 +95,6 @@ export class EventsGateway @MessageBody('ice') ice: any, @MessageBody('roomName') roomName: string, ) { - console.log(ice, 'ice') client.to(roomName).emit('ice', ice) } diff --git a/src/jwt/jwt.interface.ts b/src/jwt/jwt.interface.ts new file mode 100644 index 0000000..9aa1176 --- /dev/null +++ b/src/jwt/jwt.interface.ts @@ -0,0 +1,7 @@ +import { Secret } from 'jsonwebtoken' + +export interface JwtModuleOptions { + isRSA?: boolean + priveKey: Secret + pubkey?: Secret +} diff --git a/src/jwt/jwt.module.ts b/src/jwt/jwt.module.ts new file mode 100644 index 0000000..1d7e2f9 --- /dev/null +++ b/src/jwt/jwt.module.ts @@ -0,0 +1,31 @@ +import { DynamicModule, Global, Module } from '@nestjs/common' +// import { JwtModuleOptions } from './jwt.interface' +// import { JwtService } from './jwt.service' +import { Secret } from 'jsonwebtoken' +import { JWT_PROVIDER } from 'src/common/common.constants' +import { JwtModuleOptions } from './jwt.interface' +import { JwtService } from './jwt.service' +@Module({}) +@Global() +export class JwtModule { + static forRoot(options: JwtModuleOptions): DynamicModule { + const { priveKey, isRSA, pubkey } = options || {} + let key: Secret + if (!isRSA) { + key = priveKey + } else { + key = priveKey + } + return { + module: JwtModule, + providers: [ + { + provide: JWT_PROVIDER, + useValue: { ...options, priveKey: key, pubkey }, + }, + JwtService, + ], + exports: [JwtService], + } + } +} diff --git a/src/jwt/jwt.service.ts b/src/jwt/jwt.service.ts new file mode 100644 index 0000000..827a000 --- /dev/null +++ b/src/jwt/jwt.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class JwtService {} diff --git a/src/key/private.key.key b/src/key/private.key.key new file mode 100644 index 0000000..6188ce3 --- /dev/null +++ b/src/key/private.key.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgGaZO6z2wbOsZreRwKgfcVVNEWC27qrQY4nC6Z29Dp/Piofrf2U4 +Xjm1mUPE+ZO/ZaWWFXvb08Ht38jxwQZJBekJ1hq4k22hDHfQ9AtWsLfoDwsbAen3 +yVUDBGytKioBFQGK6dFrDCefPTkuXTSHhgSe6cPziAp3WparpIi4cll7AgMBAAEC +gYAE0MRgReSpjjnz+79TJMao/kkGhQ+GrOk/GgrlAG6jSZZy8ra0BYVGqCNdbu1X +5e/bacPwYEz8GTIbuF0a8mp4iinj/V/uOhfVZKuPU1nxQmnPdGTYwv9rWGzARuO6 +nrPiBAzjpCg2qjKmKsob6WmSBSQTLoFAKes82ZsIDt4rQQJBAMKJSrmErIsepFvJ +VK4p/fWbe+KjzjN/VhpHVSqI8mBVcEmybldaty2nan8U/filrSSyWcpvBcqCEOsC +MNWj1kMCQQCHA7prQbiYQRf+PgWlbLWW+zolszwSLCwyTS3YLz1q8XFNSriLjJXc +VjFvrNtiJPdgaKgyt0GqO38GOFe6VyhpAkEAivBxfTSj4yy8aI3PvCBjsIIfJgym +HiOpBFXEHv/2VBVRgGE+64bv41x59E+y4F673cS/2pQWx77DhIVpCXzdbwJAEDva +hlr4nxX0lJVQiHtxuh2q+C1845J8HfA5uuyzLdCqFukNF3pn6n5So2LdXgej1uu+ +jZqLQrS0qULNCZLBQQJAVvK7soayZN+Bbqz5nzubZz93wsmnFPm+X20yaMLlmV2d +5eTgMFipQXPOQSQD30oDPjNvm3DTlHQI8ct2wlAjtw== +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/src/key/public.key.pub b/src/key/public.key.pub new file mode 100644 index 0000000..b8c6991 --- /dev/null +++ b/src/key/public.key.pub @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGaZO6z2wbOsZreRwKgfcVVNEWC2 +7qrQY4nC6Z29Dp/Piofrf2U4Xjm1mUPE+ZO/ZaWWFXvb08Ht38jxwQZJBekJ1hq4 +k22hDHfQ9AtWsLfoDwsbAen3yVUDBGytKioBFQGK6dFrDCefPTkuXTSHhgSe6cPz +iAp3WparpIi4cll7AgMBAAE= +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index c29da25..ee0bed3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,4 @@ +import { SocketIOAdapter } from './sockets/socket.adapter' import { Logger } from '@nestjs/common' import { NestFactory } from '@nestjs/core' import { SwaggerModule } from '@nestjs/swagger' @@ -19,8 +20,9 @@ async function bootstrap() { const redisIoAdapter = new RedisIoAdapter(app) await redisIoAdapter.connectToRedis() app.useWebSocketAdapter(redisIoAdapter) - + app.useWebSocketAdapter(new SocketIOAdapter(app)) await app.listen(PORT) + // new Logger().localInstance.log(`app listen on port : ${PORT}`) new Logger().localInstance.log(`app listen on port : ${PORT}`) } bootstrap() diff --git a/src/sockets/socket.adapter.ts b/src/sockets/socket.adapter.ts new file mode 100644 index 0000000..c96a6c9 --- /dev/null +++ b/src/sockets/socket.adapter.ts @@ -0,0 +1,38 @@ +import { INestApplicationContext } from '@nestjs/common' +import { IoAdapter } from '@nestjs/platform-socket.io' +import { Server, ServerOptions } from 'socket.io' + +export class SocketIOAdapter extends IoAdapter { + constructor(private app: INestApplicationContext) { + super(app) + } + + createIOServer(port: number, options?: ServerOptions) { + const server: Server = super.createIOServer(port, options) + server.use((socket, next) => { + console.log('connected socket id : ', socket.id) + next() + }) + return server + } +} + +// const createTokenMiddleware = +// (jwtService: JwtService, logger: Logger) => +// (socket: SocketWithAuth, next) => { +// // for Postman testing support, fallback to token header +// const token = +// socket.handshake.auth.token || socket.handshake.headers['token'] + +// logger.debug(`Validating auth token before connection: ${token}`) + +// try { +// const payload = jwtService.verify(token) +// socket.userID = payload.sub +// socket.pollID = payload.pollID +// socket.name = payload.name +// next() +// } catch { +// next(new Error('FORBIDDEN')) +// } +// } diff --git a/src/workspaces/workspaces.gateway.ts b/src/workspaces/workspaces.gateway.ts index 61a7b50..1337f70 100644 --- a/src/workspaces/workspaces.gateway.ts +++ b/src/workspaces/workspaces.gateway.ts @@ -27,12 +27,6 @@ export class WorkspacesGateway this.logger.setContext('WorkspaceGateway') } - /** - * TODO: Socket Handler return value를 통해 클라이언트 내에서 이벤트 핸들링 가능 - * ex) client-side -> socket.emit('join_room' , 'myRoomName' , data => console.log(data)) - * 일단 ws방식으로 구현 후 socket io 방식으로 변경하는게 좋을듯 - */ - @SubscribeMessage('join_room') async joinRoom( @ConnectedSocket() client: Socket, diff --git a/yarn.lock b/yarn.lock index 24443d3..829ec53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -551,11 +551,6 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@ioredis/commands@^1.1.1": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" - integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== - "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -820,11 +815,6 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@nestjs-modules/ioredis@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@nestjs-modules/ioredis/-/ioredis-1.0.1.tgz#bd73daf90d04047612bc93532fa177abc23186e5" - integrity sha512-UhIOqL5pXeJlCucHMkJONwqecvLFySW/95uw34Umh0ld7v+6tvYRK3JHQYcJqzlmNiq52bfNxf7CUpuHCSdA3A== - "@nestjs/cli@^9.0.0": version "9.1.9" resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-9.1.9.tgz#f696b79e1e6478e9fff3bc90c70253720d19f03f" @@ -1231,6 +1221,13 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== +"@types/jsonwebtoken@^9.0.1": + version "9.0.1" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz#29b1369c4774200d6d6f63135bf3d1ba3ef997a4" + integrity sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw== + dependencies: + "@types/node" "*" + "@types/mime@*": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" @@ -1885,6 +1882,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" @@ -2078,7 +2080,7 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== -cluster-key-slot@1.1.2, cluster-key-slot@^1.1.0: +cluster-key-slot@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== @@ -2406,11 +2408,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -denque@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" - integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== - depd@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -2490,6 +2487,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" @@ -3439,21 +3443,6 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== -ioredis@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.3.0.tgz#b5469f0fd374648ef074840c00c1d8eed42fca3f" - integrity sha512-Id9jKHhsILuIZpHc61QkagfVdUj2Rag5GzG1TGEvRNeM7dtTOjICgjC+tvqYxi//PuX2wjQ+Xjva2ONBuf92Pw== - dependencies: - "@ioredis/commands" "^1.1.1" - cluster-key-slot "^1.1.0" - debug "^4.3.4" - denque "^2.1.0" - lodash.defaults "^4.2.0" - lodash.isarguments "^3.1.0" - redis-errors "^1.2.0" - redis-parser "^3.0.0" - standard-as-callback "^2.1.0" - ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -4075,6 +4064,33 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== +jsonwebtoken@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" + integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== + dependencies: + jws "^3.2.2" + lodash "^4.17.21" + ms "^2.1.1" + semver "^7.3.8" + +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" + kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -4165,16 +4181,6 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== -lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== - -lodash.isarguments@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== - lodash.isfunction@^3.0.9: version "3.0.9" resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" @@ -4450,7 +4456,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== @@ -4960,18 +4966,6 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -redis-errors@^1.0.0, redis-errors@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" - integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== - -redis-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" - integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== - dependencies: - redis-errors "^1.0.0" - redis@^4.6.4: version "4.6.4" resolved "https://registry.yarnpkg.com/redis/-/redis-4.6.4.tgz#fe84169de000b247009c70c2740f22d1f85bc2de" @@ -5101,7 +5095,7 @@ rxjs@^7.2.0, rxjs@^7.5.5, rxjs@^7.8.0: 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== @@ -5367,11 +5361,6 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" -standard-as-callback@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" - integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== - statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" From 92ccb912d4751b177701ced29acfe757dfcb29ff Mon Sep 17 00:00:00 2001 From: raymond Date: Sun, 5 Feb 2023 04:06:15 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=8E=A8feat=20:=20DB-ORM=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20JWT=EC=9D=B8=EC=A6=9D=EB=B0=A9=EC=8B=9D=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 닉네임 설정로직 필요하여 로그인 로직 추가 - GQL방식 auth 로직 구현 - TODO: RSA key 저장방식 생각해봐야함 --- package.json | 10 + prisma/schema.prisma | 21 + src/app.module.ts | 21 +- src/auth/auth.guard.ts | 20 + src/auth/auth.module.ts | 13 + src/auth/role.decorator.ts | 6 + src/common/common.type.ts | 7 + src/common/dtos/core.entites.ts | 27 ++ src/events/events.gateway.ts | 23 +- src/events/events.module.ts | 2 + src/jwt/jwt.middleware.ts | 34 ++ src/jwt/jwt.module.ts | 16 +- src/jwt/jwt.service.ts | 31 +- src/key/private.key.key | 43 +- src/key/public.key.pub | 11 +- src/main.ts | 19 +- src/prisma/prisma.module.ts | 10 + src/prisma/prisma.service.ts | 60 +++ src/redis/redis.adapter.ts | 16 +- src/sockets/socket.adapter.ts | 38 -- src/users/dtos/login.dto.ts | 13 + src/users/dtos/user-profile.dto.ts | 10 + src/users/entities/user.entity.ts | 19 + src/users/users.module.ts | 9 + src/users/users.resolver.ts | 18 + src/users/users.service.ts | 51 +++ src/workspaces/workspaces.gateway.ts | 2 +- yarn.lock | 652 ++++++++++++++++++++++++++- 28 files changed, 1106 insertions(+), 96 deletions(-) create mode 100644 prisma/schema.prisma create mode 100644 src/auth/auth.guard.ts create mode 100644 src/auth/auth.module.ts create mode 100644 src/auth/role.decorator.ts create mode 100644 src/common/common.type.ts create mode 100644 src/common/dtos/core.entites.ts create mode 100644 src/jwt/jwt.middleware.ts create mode 100644 src/prisma/prisma.module.ts create mode 100644 src/prisma/prisma.service.ts delete mode 100644 src/sockets/socket.adapter.ts create mode 100644 src/users/dtos/login.dto.ts create mode 100644 src/users/dtos/user-profile.dto.ts create mode 100644 src/users/entities/user.entity.ts create mode 100644 src/users/users.module.ts create mode 100644 src/users/users.resolver.ts create mode 100644 src/users/users.service.ts diff --git a/package.json b/package.json index 54b853d..4717bbd 100644 --- a/package.json +++ b/package.json @@ -18,19 +18,27 @@ "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "jest --config ./test/jest-e2e.json", + "db:push" : "dotenv -e .env.development -- npx prisma db push", "prepare": "husky install" }, "dependencies": { + "@nestjs/apollo": "^10.1.7", "@nestjs/common": "^9.0.0", "@nestjs/config": "^2.2.0", "@nestjs/core": "^9.0.0", + "@nestjs/graphql": "^10.1.7", "@nestjs/platform-express": "^9.0.0", "@nestjs/platform-socket.io": "^9.2.1", "@nestjs/swagger": "^6.1.4", "@nestjs/websockets": "^9.2.1", + "@prisma/client": "^4.9.0", "@socket.io/redis-adapter": "^8.0.1", "@types/jsonwebtoken": "^9.0.1", "@types/socket.io": "^3.0.2", + "apollo-server-express": "^3.11.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "graphql": "^16.6.0", "jsonwebtoken": "^9.0.0", "redis": "^4.6.4", "reflect-metadata": "^0.1.13", @@ -50,6 +58,7 @@ "@typescript-eslint/parser": "^5.0.0", "cross-env": "^7.0.3", "cz-conventional-changelog": "^3.3.0", + "dotenv-cli": "^7.0.0", "eslint": "^8.0.1", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^4.0.0", @@ -58,6 +67,7 @@ "joi": "^17.7.0", "lint-staged": "^13.1.0", "prettier": "^2.3.2", + "prisma": "^4.9.0", "source-map-support": "^0.5.20", "supertest": "^6.1.3", "ts-jest": "^29.0.5", diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..01b51fb --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,21 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +model User { + id Int @id @default(autoincrement()) + nickname String @unique + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + role UserRole? +} + +enum UserRole { + Admin + Client +} diff --git a/src/app.module.ts b/src/app.module.ts index 45bcd80..a4ed1f3 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,3 +1,4 @@ +import { JwtMiddleware } from './jwt/jwt.middleware' import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common' import { ConfigModule } from '@nestjs/config' import { LoggerMiddleware } from './logger/logger.middleware' @@ -6,6 +7,11 @@ import { LoggerModule } from './logger/logger.module' import joi from 'joi' import { WorkspacesModule } from './workspaces/workspaces.module' import { JwtModule } from './jwt/jwt.module' +import { GraphQLModule } from '@nestjs/graphql' +import { ApolloDriverConfig, ApolloDriver } from '@nestjs/apollo' +import { PrismaModule } from './prisma/prisma.module' +import { UsersModule } from './users/users.module' +import { AuthModule } from './auth/auth.module' @Module({ imports: [ @@ -19,12 +25,17 @@ import { JwtModule } from './jwt/jwt.module' validationSchema: joi.object({ PORT: joi.string().required(), REDIS_HOST: joi.string().required(), - REDIS_PORT: joi.string().required(), REDIS_PASSWORD: joi.string().required(), JWT_PRIVATE_KEY: joi.string().required(), JWT_PUBLIC_KEY: joi.string().required(), }), }), + PrismaModule, + GraphQLModule.forRoot({ + driver: ApolloDriver, + autoSchemaFile: true, + context: ({ req }) => ({ user: req['user'] }), + }), LoggerModule, WorkspacesModule, EventsModule, @@ -33,6 +44,8 @@ import { JwtModule } from './jwt/jwt.module' priveKey: process.env.JWT_PRIVATE_KEY, pubkey: process.env.JWT_PUBLIC_KEY, }), + UsersModule, + AuthModule, ], controllers: [], providers: [], @@ -40,10 +53,6 @@ import { JwtModule } from './jwt/jwt.module' export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(LoggerMiddleware).forRoutes('*') - consumer - .apply(LoggerMiddleware) - .exclude('/login') - .exclude('/') - .forRoutes('*') + consumer.apply(JwtMiddleware).exclude('/login').exclude('/').forRoutes('*') } } diff --git a/src/auth/auth.guard.ts b/src/auth/auth.guard.ts new file mode 100644 index 0000000..4d975ae --- /dev/null +++ b/src/auth/auth.guard.ts @@ -0,0 +1,20 @@ +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common' +import { Reflector } from '@nestjs/core' +import { Observable } from 'rxjs' +import { GqlExecutionContext } from '@nestjs/graphql' +import { User } from 'src/users/entities/user.entity' +@Injectable() +export class AuthGuard implements CanActivate { + constructor(private readonly relector: Reflector) {} + canActivate( + context: ExecutionContext, + ): boolean | Promise | Observable { + const roles = this.relector.get('roles', context.getHandler()) + if (!roles) { + return true + } + const gqlContext = GqlExecutionContext.create(context).getContext() + const user: User = gqlContext['user'] + return roles.includes('Any') || !!user + } +} diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts new file mode 100644 index 0000000..32c9d97 --- /dev/null +++ b/src/auth/auth.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common' +import { APP_GUARD } from '@nestjs/core' +import { AuthGuard } from './auth.guard' + +@Module({ + providers: [ + { + provide: APP_GUARD, + useClass: AuthGuard, + }, + ], +}) +export class AuthModule {} diff --git a/src/auth/role.decorator.ts b/src/auth/role.decorator.ts new file mode 100644 index 0000000..39c2763 --- /dev/null +++ b/src/auth/role.decorator.ts @@ -0,0 +1,6 @@ +import { SetMetadata } from '@nestjs/common' +import { UserRole } from '@prisma/client' + +export type AllowedRoles = keyof typeof UserRole | 'Any' + +export const Role = (roles: AllowedRoles[]) => SetMetadata('roles', roles) diff --git a/src/common/common.type.ts b/src/common/common.type.ts new file mode 100644 index 0000000..ef1d4dc --- /dev/null +++ b/src/common/common.type.ts @@ -0,0 +1,7 @@ +import { Socket } from 'socket.io' +import { ExtendedError } from 'socket.io/dist/namespace' + +export type SocketMiddleware = ( + socket: Socket, + next: (err?: ExtendedError) => void, +) => void diff --git a/src/common/dtos/core.entites.ts b/src/common/dtos/core.entites.ts new file mode 100644 index 0000000..7159867 --- /dev/null +++ b/src/common/dtos/core.entites.ts @@ -0,0 +1,27 @@ +import { Field, ObjectType } from '@nestjs/graphql' +import { IsNotEmpty, IsNumber, IsDate } from 'class-validator' + +@ObjectType() +export class CoreDTO { + @Field(() => Number) + @IsNotEmpty() + @IsNumber() + id: number + + @Field(() => Date) + @IsDate() + createdAt: Date + + @Field(() => Date) + @IsDate() + updatedAt: Date +} + +@ObjectType() +export class CoreOutput { + @Field(() => String, { nullable: true }) + error?: string + + @Field(() => Boolean) + ok: boolean +} diff --git a/src/events/events.gateway.ts b/src/events/events.gateway.ts index bcb9e6b..fe55498 100644 --- a/src/events/events.gateway.ts +++ b/src/events/events.gateway.ts @@ -1,3 +1,4 @@ +import { Inject } from '@nestjs/common' import { SubscribeMessage, WebSocketGateway } from '@nestjs/websockets' import { ConnectedSocket, @@ -11,6 +12,7 @@ import { } from '@nestjs/websockets/interfaces' import { Namespace, Socket } from 'socket.io' import { LoggerService } from 'src/logger/logger.service' +import { PrismaService } from 'src/prisma/prisma.service' import { getServerRoomDto } from './dtos/gateway.dto' @WebSocketGateway(3050, { @@ -18,12 +20,16 @@ import { getServerRoomDto } from './dtos/gateway.dto' origin: '*', }, namespace: '/', + transports: ['websocket'], }) export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit { @WebSocketServer() public io: Namespace - constructor(private readonly logger: LoggerService) { + constructor( + @Inject(PrismaService) private readonly prismaService: PrismaService, + private readonly logger: LoggerService, + ) { this.logger.setContext('EventsGateway') } @@ -33,12 +39,25 @@ export class EventsGateway * 일단 ws방식으로 구현 후 socket io 방식으로 변경하는게 좋을듯 */ @SubscribeMessage('set_nickname') - setNickname( + async setNickname( @ConnectedSocket() client: Socket, @MessageBody() nickname: string, ) { const user = this.findCurrentClient(client) user['nickname'] = nickname + const upsertedUser = await this.prismaService.user.upsert({ + where: { + nickname, + }, + update: { + nickname, + }, + create: { + nickname, + }, + }) + console.log(upsertedUser) + this.logger.debug(`${nickname} change`) return nickname } diff --git a/src/events/events.module.ts b/src/events/events.module.ts index 0879df1..cf8424b 100644 --- a/src/events/events.module.ts +++ b/src/events/events.module.ts @@ -1,8 +1,10 @@ import { Module } from '@nestjs/common' +import { PrismaModule } from 'src/prisma/prisma.module' import { EventsGateway } from './events.gateway' @Module({ + imports: [PrismaModule], providers: [EventsGateway], }) export class EventsModule {} diff --git a/src/jwt/jwt.middleware.ts b/src/jwt/jwt.middleware.ts new file mode 100644 index 0000000..d05f02a --- /dev/null +++ b/src/jwt/jwt.middleware.ts @@ -0,0 +1,34 @@ +import { JwtService } from 'src/jwt/jwt.service' +import { Injectable, NestMiddleware } from '@nestjs/common' +import { NextFunction, Request, Response } from 'express' +import { SocketMiddleware } from 'src/common/common.type' +import { UsersService } from 'src/users/users.service' + +@Injectable() +export class JwtMiddleware implements NestMiddleware { + constructor( + private readonly jwtService: JwtService, + private readonly usersService: UsersService, + ) {} + async use(req: Request, res: Response, next: NextFunction) { + if ('_PLUG_AUTH_' in req.headers) { + const token = req.headers['_PLUG_AUTH_'] + const decode = this.jwtService.verify(token.toString()) + if (typeof decode === 'object' && decode.hasOwnProperty('id')) { + try { + const { id } = decode + const { user, ok } = await this.usersService.findById(id) + if (ok) { + req['user'] = user + } + } catch (e) {} + } + } + next() + } +} + +export const jwtSocketMiddleware: SocketMiddleware = (socket, next) => { + console.log(socket.handshake.auth) + next() +} diff --git a/src/jwt/jwt.module.ts b/src/jwt/jwt.module.ts index 1d7e2f9..816d2f8 100644 --- a/src/jwt/jwt.module.ts +++ b/src/jwt/jwt.module.ts @@ -1,6 +1,6 @@ import { DynamicModule, Global, Module } from '@nestjs/common' -// import { JwtModuleOptions } from './jwt.interface' -// import { JwtService } from './jwt.service' +import fs from 'fs' +import path from 'path' import { Secret } from 'jsonwebtoken' import { JWT_PROVIDER } from 'src/common/common.constants' import { JwtModuleOptions } from './jwt.interface' @@ -10,18 +10,24 @@ import { JwtService } from './jwt.service' export class JwtModule { static forRoot(options: JwtModuleOptions): DynamicModule { const { priveKey, isRSA, pubkey } = options || {} - let key: Secret + let key: Secret = priveKey + let pub: Secret = pubkey if (!isRSA) { key = priveKey } else { - key = priveKey + key = fs.readFileSync( + path.resolve(__dirname, '../../src/key/private.key.key'), + ) + pub = fs.readFileSync( + path.resolve(__dirname, '../../src/key/public.key.pub'), + ) } return { module: JwtModule, providers: [ { provide: JWT_PROVIDER, - useValue: { ...options, priveKey: key, pubkey }, + useValue: { ...options, priveKey: key, pubkey: pub }, }, JwtService, ], diff --git a/src/jwt/jwt.service.ts b/src/jwt/jwt.service.ts index 827a000..0e803c0 100644 --- a/src/jwt/jwt.service.ts +++ b/src/jwt/jwt.service.ts @@ -1,4 +1,31 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Inject } from '@nestjs/common' +import { JWT_PROVIDER } from 'src/common/common.constants' +import { JwtModuleOptions } from './jwt.interface' +import jwt, { Algorithm } from 'jsonwebtoken' @Injectable() -export class JwtService {} +export class JwtService { + private readonly algorithm: Algorithm + constructor( + @Inject(JWT_PROVIDER) private readonly options: JwtModuleOptions, + ) { + this.algorithm = this.options.isRSA ? 'RS256' : 'HS256' + } + sign(payload: object | T | any) { + const token = jwt.sign(payload, this.options.priveKey, { + algorithm: this.algorithm, + }) + console.log(token) + return token + } + + verify(token: string) { + return jwt.verify( + token, + this.options.isRSA ? this.options.pubkey : this.options.priveKey, + { + algorithms: [this.algorithm], + }, + ) + } +} diff --git a/src/key/private.key.key b/src/key/private.key.key index 6188ce3..a6d0842 100644 --- a/src/key/private.key.key +++ b/src/key/private.key.key @@ -1,15 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgGaZO6z2wbOsZreRwKgfcVVNEWC27qrQY4nC6Z29Dp/Piofrf2U4 -Xjm1mUPE+ZO/ZaWWFXvb08Ht38jxwQZJBekJ1hq4k22hDHfQ9AtWsLfoDwsbAen3 -yVUDBGytKioBFQGK6dFrDCefPTkuXTSHhgSe6cPziAp3WparpIi4cll7AgMBAAEC -gYAE0MRgReSpjjnz+79TJMao/kkGhQ+GrOk/GgrlAG6jSZZy8ra0BYVGqCNdbu1X -5e/bacPwYEz8GTIbuF0a8mp4iinj/V/uOhfVZKuPU1nxQmnPdGTYwv9rWGzARuO6 -nrPiBAzjpCg2qjKmKsob6WmSBSQTLoFAKes82ZsIDt4rQQJBAMKJSrmErIsepFvJ -VK4p/fWbe+KjzjN/VhpHVSqI8mBVcEmybldaty2nan8U/filrSSyWcpvBcqCEOsC -MNWj1kMCQQCHA7prQbiYQRf+PgWlbLWW+zolszwSLCwyTS3YLz1q8XFNSriLjJXc -VjFvrNtiJPdgaKgyt0GqO38GOFe6VyhpAkEAivBxfTSj4yy8aI3PvCBjsIIfJgym -HiOpBFXEHv/2VBVRgGE+64bv41x59E+y4F673cS/2pQWx77DhIVpCXzdbwJAEDva -hlr4nxX0lJVQiHtxuh2q+C1845J8HfA5uuyzLdCqFukNF3pn6n5So2LdXgej1uu+ -jZqLQrS0qULNCZLBQQJAVvK7soayZN+Bbqz5nzubZz93wsmnFPm+X20yaMLlmV2d -5eTgMFipQXPOQSQD30oDPjNvm3DTlHQI8ct2wlAjtw== ------END RSA PRIVATE KEY----- \ No newline at end of file +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDRJ6zwLhsTKQdY +qCIcegegGbIa+eHkFYoRHuUJPCLeC8CtMhHgf2GQttY87wgkGI37LAfnpbanyc8d +98SNF0LL2zd+yMOYkTti4m4Zh4kVnfcufrk3eNmShdb8349XPHTZ3I1Jtu0nYGqR +jTJ2PBLtYebm02dBKPnpQTFv4/wC/ChyaJSQBVVnBh99YY9vxodCoA24WsVe8HK8 +fty9F9inpOSwd+e6MvO+5d2UgZiZSU6a0kjGh/8FJnQVDjjNEoP7kW+PlPhWD0DR +ShHxpLW6eldYFfH6feCqgNyev1cOWUIqbXibL0yALBY+dgAW83bl05nEC3xxtVLv +IoWToJYzAgMBAAECggEAThpryRDeiWwj0yaN/mZPXKjbypkPkpW8hiIsUyOCvbpT +zBlLdbL7owezvvNf7eLBek758LYAHG4PCtjQLAPIrMmC0rRz3hA1xfpaNOxY85qW +iGVIEv/s93tFSg7NvzzTQdvLYwCNVMv7X7kDZAWQ59ZMXFwLTdjYYhM3O9o97HrC +KVGQEMfsGBNtucjZvnoYB/QhDwk3ozIVMHd137VKAw/x7geO/a00hG6xB20WbREm +lQSZMohN56MGB/cjW9uZHmD43i5Ysc2yID8Hzqstw3//sQSN0quj6NwVc2jzcFd1 +i2oPWWsSVo0ACA+FmWY4t/TrHOCvsYaGrK2oeU8UoQKBgQD0RdbMWa8y4drLpnS1 +g3PR4JmQM3R0JJxI2TmlAmSSuy6qhEUfoCXp5srZ2+zRVbutwWCZ08qA5oBL3TXh +Sg/l0mmH6A8Zz5r/WUj8w/fXUqX1Whyu5JCxw+6pIyBc6ZwaO6ILVuLjnE9BOoxU +skAVQFyR0Yr8yD2w3sVWBZio0QKBgQDbMjtCWyL7+SZfDQ1jbE8gLyd7jQOe3zMi +wif0wmXDgkRnZ3Zl7Wyij5dSh30g814OvudkqrGFcVRkCromQNZmyHfs2gYl0ozc +DgRIeCzWjZgzlCG26Zm5JDmzs9+X39uGJuNU4NtCzq0zBfJgTwSYd88DfkRS6OMX +fc8OqCfPwwKBgGhoYYM+4i+xcb+SClh7M0oF4h1MoP3zmAlbL9RjzXEaKLwhhRob +bZkoWJP9+J8RMgL2oL+fUvL9kuDaUGlXKqxk306D1dCGeA2ksBm5+XlDjkPsnE30 +zBPvV1db+D0+bMaZro2COcBn00hiKhEZj2KF/AsnsWySeivbTCWUhsfBAoGAFeJC +9lIBASUTxqOX9Zgnoi/zAivG88KW6V52/MG3xTgpOiWjNXPpx6UMV4n9XR/PASvg +EDXWeVsiMMa9ZPpOLX7QMk5mFLqbo5CmrtGIsHb8fhHI9+kElu5d8GoB5bjMwuz4 +/01ftqDJu/FZDHJ3I/26JkAh9CEaIwtFc9In/18CgYB/2a8raAm4jt7tGY1z0obq +D7nfB4UifQRZJC00CX9qR4e21oKXvYZHS82IokHv3/KaB3MFxchmy2G8QBuR975P +quPiVmdCJ1zE2gR7z4UGUy2PBoNzhg/qAO4VfFKJx/Y1/cBhSM7dMHJLHJSgXU5Y +hG3fz4atCB357FkrCQr5aw== +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/src/key/public.key.pub b/src/key/public.key.pub index b8c6991..891f4d8 100644 --- a/src/key/public.key.pub +++ b/src/key/public.key.pub @@ -1,6 +1,9 @@ -----BEGIN PUBLIC KEY----- -MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGaZO6z2wbOsZreRwKgfcVVNEWC2 -7qrQY4nC6Z29Dp/Piofrf2U4Xjm1mUPE+ZO/ZaWWFXvb08Ht38jxwQZJBekJ1hq4 -k22hDHfQ9AtWsLfoDwsbAen3yVUDBGytKioBFQGK6dFrDCefPTkuXTSHhgSe6cPz -iAp3WparpIi4cll7AgMBAAE= +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Ses8C4bEykHWKgiHHoH +oBmyGvnh5BWKER7lCTwi3gvArTIR4H9hkLbWPO8IJBiN+ywH56W2p8nPHffEjRdC +y9s3fsjDmJE7YuJuGYeJFZ33Ln65N3jZkoXW/N+PVzx02dyNSbbtJ2BqkY0ydjwS +7WHm5tNnQSj56UExb+P8AvwocmiUkAVVZwYffWGPb8aHQqANuFrFXvByvH7cvRfY +p6TksHfnujLzvuXdlIGYmUlOmtJIxof/BSZ0FQ44zRKD+5Fvj5T4Vg9A0UoR8aS1 +unpXWBXx+n3gqoDcnr9XDllCKm14my9MgCwWPnYAFvN25dOZxAt8cbVS7yKFk6CW +MwIDAQAB -----END PUBLIC KEY----- \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index ee0bed3..c49804c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,4 @@ -import { SocketIOAdapter } from './sockets/socket.adapter' -import { Logger } from '@nestjs/common' +import { Logger, ValidationPipe } from '@nestjs/common' import { NestFactory } from '@nestjs/core' import { SwaggerModule } from '@nestjs/swagger' import { DocumentBuilder } from '@nestjs/swagger/dist' @@ -9,6 +8,11 @@ import { RedisIoAdapter } from './redis/redis.adapter' async function bootstrap() { const PORT = process.env.PORT || 3000 const app = await NestFactory.create(AppModule) + const redisIoAdapter = new RedisIoAdapter(app) + await redisIoAdapter.connectToRedis() + app.useWebSocketAdapter(redisIoAdapter) + app.useGlobalPipes(new ValidationPipe()) + app.setGlobalPrefix('api/v1') const config = new DocumentBuilder() .setTitle('Plug Api') @@ -17,12 +21,9 @@ async function bootstrap() { .build() const documnet = SwaggerModule.createDocument(app, config) SwaggerModule.setup('api', app, documnet) - const redisIoAdapter = new RedisIoAdapter(app) - await redisIoAdapter.connectToRedis() - app.useWebSocketAdapter(redisIoAdapter) - app.useWebSocketAdapter(new SocketIOAdapter(app)) - await app.listen(PORT) - // new Logger().localInstance.log(`app listen on port : ${PORT}`) - new Logger().localInstance.log(`app listen on port : ${PORT}`) + + await app.listen(PORT, () => { + new Logger().localInstance.log(`app listen on port : ${PORT}`) + }) } bootstrap() diff --git a/src/prisma/prisma.module.ts b/src/prisma/prisma.module.ts new file mode 100644 index 0000000..7440fe6 --- /dev/null +++ b/src/prisma/prisma.module.ts @@ -0,0 +1,10 @@ +import { Module, Global } from '@nestjs/common' +import { PrismaService } from './prisma.service' + +@Module({ + imports: [], + providers: [PrismaService], + exports: [PrismaService], +}) +@Global() +export class PrismaModule {} diff --git a/src/prisma/prisma.service.ts b/src/prisma/prisma.service.ts new file mode 100644 index 0000000..9d2f436 --- /dev/null +++ b/src/prisma/prisma.service.ts @@ -0,0 +1,60 @@ +import { + Injectable, + OnModuleInit, + INestApplication, + Logger, +} from '@nestjs/common' +import { Prisma, PrismaClient } from '@prisma/client' + +@Injectable() +export class PrismaService + extends PrismaClient + implements OnModuleInit +{ + private readonly logger + constructor() { + super({ + log: [ + { + emit: 'event', + level: 'query', + }, + { + emit: 'event', + level: 'error', + }, + { + emit: 'stdout', + level: 'info', + }, + { + emit: 'stdout', + level: 'warn', + }, + ], + }) + this.logger = new Logger('PRISMA') + } + + async onModuleInit() { + if (process.env.NODE_ENV === 'development') { + this.$on('query', (event) => { + this.logger.verbose(event.query, event.duration) + }) + this.$on('info', (event) => { + this.logger.verbose(event.timestamp, event.message, event.target) + }) + this.$on('error', (event) => { + this.logger.error(event.target) + }) + } + + await this.$connect() + } + + async enableShutdownHooks(app: INestApplication) { + this.$on('beforeExit', async () => { + await app.close() + }) + } +} diff --git a/src/redis/redis.adapter.ts b/src/redis/redis.adapter.ts index 3da2adf..2bc80d5 100644 --- a/src/redis/redis.adapter.ts +++ b/src/redis/redis.adapter.ts @@ -5,12 +5,17 @@ import { createAdapter } from '@socket.io/redis-adapter' import { createClient } from 'redis' import { INestApplication } from '@nestjs/common/interfaces' import { Server } from 'socket.io' +import { LoggerService } from 'src/logger/logger.service' +import { jwtSocketMiddleware } from 'src/jwt/jwt.middleware' export class RedisIoAdapter extends IoAdapter { private readonly configService: ConfigService + private readonly loggerService: LoggerService + constructor(private readonly app: INestApplication) { super(app) this.configService = app.get(ConfigService) + this.loggerService = app.get(LoggerService) } private adapterConstructor: ReturnType @@ -27,9 +32,16 @@ export class RedisIoAdapter extends IoAdapter { } createIOServer(port: number, options?: ServerOptions): any { - const server: Server = super.createIOServer(port, options) + const server: Server = super.createIOServer(port, { ...options }) + server.use(jwtSocketMiddleware) server.adapter(this.adapterConstructor) - return server } + + // bindClientConnect(server: TServer, callback: Function): void; + // bindClientDisconnect(client: TClient, callback: Function): void; + // close(server: TServer): Promise; + // dispose(): Promise; + // abstract create(port: number, options?: TOptions): TServer; + // abstract bindMessageHandlers(client: TClient, handlers: WsMessageHandler[], transform: (data: any) => Observable): any; } diff --git a/src/sockets/socket.adapter.ts b/src/sockets/socket.adapter.ts deleted file mode 100644 index c96a6c9..0000000 --- a/src/sockets/socket.adapter.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { INestApplicationContext } from '@nestjs/common' -import { IoAdapter } from '@nestjs/platform-socket.io' -import { Server, ServerOptions } from 'socket.io' - -export class SocketIOAdapter extends IoAdapter { - constructor(private app: INestApplicationContext) { - super(app) - } - - createIOServer(port: number, options?: ServerOptions) { - const server: Server = super.createIOServer(port, options) - server.use((socket, next) => { - console.log('connected socket id : ', socket.id) - next() - }) - return server - } -} - -// const createTokenMiddleware = -// (jwtService: JwtService, logger: Logger) => -// (socket: SocketWithAuth, next) => { -// // for Postman testing support, fallback to token header -// const token = -// socket.handshake.auth.token || socket.handshake.headers['token'] - -// logger.debug(`Validating auth token before connection: ${token}`) - -// try { -// const payload = jwtService.verify(token) -// socket.userID = payload.sub -// socket.pollID = payload.pollID -// socket.name = payload.name -// next() -// } catch { -// next(new Error('FORBIDDEN')) -// } -// } diff --git a/src/users/dtos/login.dto.ts b/src/users/dtos/login.dto.ts new file mode 100644 index 0000000..a9ae2da --- /dev/null +++ b/src/users/dtos/login.dto.ts @@ -0,0 +1,13 @@ +import { PickType, Field, InputType, ObjectType } from '@nestjs/graphql' +import { CoreOutput } from 'src/common/dtos/core.entites' +import { User } from '../entities/user.entity' + +@InputType() +export class LoginInput extends PickType(User, ['nickname']) {} +@ObjectType() +export class LoginOutput extends CoreOutput { + @Field(() => String, { nullable: true }) + token?: string + @Field(() => User, { nullable: true }) + user?: User +} diff --git a/src/users/dtos/user-profile.dto.ts b/src/users/dtos/user-profile.dto.ts new file mode 100644 index 0000000..328a3d4 --- /dev/null +++ b/src/users/dtos/user-profile.dto.ts @@ -0,0 +1,10 @@ +import { Field, ObjectType } from '@nestjs/graphql' + +import { CoreOutput } from 'src/common/dtos/core.entites' +import { User } from '../entities/user.entity' + +@ObjectType() +export class UserProfileOutput extends CoreOutput { + @Field(() => User, { nullable: true }) + user?: User +} diff --git a/src/users/entities/user.entity.ts b/src/users/entities/user.entity.ts new file mode 100644 index 0000000..249e69d --- /dev/null +++ b/src/users/entities/user.entity.ts @@ -0,0 +1,19 @@ +import { CoreDTO } from '../../common/dtos/core.entites' +import { User as PrismaUser, UserRole } from '@prisma/client' +import { InputType, ObjectType, Field, registerEnumType } from '@nestjs/graphql' +import { IsString, IsEnum, IsOptional } from 'class-validator' + +registerEnumType(UserRole, { name: 'UserRole' }) + +@InputType('UserInputType', { isAbstract: true }) +@ObjectType() +export class User extends CoreDTO implements PrismaUser { + @Field(() => String) + @IsString() + nickname: string + + @Field(() => UserRole, { nullable: true }) + @IsEnum(UserRole) + @IsOptional() + role: UserRole | null +} diff --git a/src/users/users.module.ts b/src/users/users.module.ts new file mode 100644 index 0000000..37fb7f3 --- /dev/null +++ b/src/users/users.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common' +import { UsersResolver } from './users.resolver' +import { UsersService } from './users.service' + +@Module({ + providers: [UsersResolver, UsersService], + exports: [UsersService], +}) +export class UsersModule {} diff --git a/src/users/users.resolver.ts b/src/users/users.resolver.ts new file mode 100644 index 0000000..c4045f6 --- /dev/null +++ b/src/users/users.resolver.ts @@ -0,0 +1,18 @@ +import { UsersService } from 'src/users/users.service' + +import { Query, Mutation, Resolver, Args } from '@nestjs/graphql' +import { LoginInput, LoginOutput } from './dtos/login.dto' + +@Resolver() +export class UsersResolver { + constructor(private readonly usersService: UsersService) {} + + @Query(() => Boolean) + test() { + return true + } + @Mutation(() => LoginOutput) + async login(@Args('input') loginInput: LoginInput) { + return this.usersService.login(loginInput) + } +} diff --git a/src/users/users.service.ts b/src/users/users.service.ts new file mode 100644 index 0000000..54298ac --- /dev/null +++ b/src/users/users.service.ts @@ -0,0 +1,51 @@ +import { JwtService } from './../jwt/jwt.service' +import { LoginInput, LoginOutput } from './dtos/login.dto' +import { Injectable } from '@nestjs/common' +import { PrismaService } from 'src/prisma/prisma.service' +import { UserProfileOutput } from './dtos/user-profile.dto' + +@Injectable() +export class UsersService { + constructor( + private readonly prismaService: PrismaService, + private readonly jwtService: JwtService, + ) {} + + async findById(id: number): Promise { + try { + const user = await this.prismaService.user.findUniqueOrThrow({ + where: { + id, + }, + }) + + return { + ok: true, + user, + } + } catch { + return { ok: false, error: 'User Not Found.' } + } + } + + async login({ nickname }: LoginInput): Promise { + try { + let loginUser = await this.prismaService.user.findUnique({ + where: { + nickname, + }, + }) + if (!loginUser) { + loginUser = await this.prismaService.user.create({ + data: { + nickname, + }, + }) + } + const token = this.jwtService.sign({ id: loginUser.id, nickname }) + return { ok: true, token, user: loginUser } + } catch (error) { + return { ok: false, error } + } + } +} diff --git a/src/workspaces/workspaces.gateway.ts b/src/workspaces/workspaces.gateway.ts index 1337f70..c5a9bd9 100644 --- a/src/workspaces/workspaces.gateway.ts +++ b/src/workspaces/workspaces.gateway.ts @@ -17,7 +17,7 @@ import { LoggerService } from 'src/logger/logger.service' cors: { origin: '*', }, - namespace: '/workspace', + namespace: 'workspace', }) export class WorkspacesGateway implements OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit diff --git a/yarn.lock b/yarn.lock index 829ec53..a4a8804 100644 --- a/yarn.lock +++ b/yarn.lock @@ -44,6 +44,114 @@ ora "5.4.1" rxjs "6.6.7" +"@apollo/protobufjs@1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.2.6.tgz#d601e65211e06ae1432bf5993a1a0105f2862f27" + integrity sha512-Wqo1oSHNUj/jxmsVp4iR3I480p6qdqHikn38lKrFhfzcDJ7lwd7Ck7cHRl4JE81tWNArl77xhnG/OkZhxKBYOw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.0" + "@types/node" "^10.1.0" + long "^4.0.0" + +"@apollo/protobufjs@1.2.7": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.2.7.tgz#3a8675512817e4a046a897e5f4f16415f16a7d8a" + integrity sha512-Lahx5zntHPZia35myYDBRuF58tlwPskwHc5CWBZC/4bMKB6siTBWwtMrkqXcsNwQiFSzSx5hKdRPUmemrEp3Gg== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.0" + long "^4.0.0" + +"@apollo/usage-reporting-protobuf@^4.0.0": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@apollo/usage-reporting-protobuf/-/usage-reporting-protobuf-4.0.2.tgz#a83db2cbb605b631960ebb1a336b4293d4857a02" + integrity sha512-GfE8aDqi/lAFut95pjH9IRvH0zGsQ5G/2lYL0ZLZfML7ArX+A4UVHFANQcPCcUYGE6bI6OPhLekg4Vsjf6B1cw== + dependencies: + "@apollo/protobufjs" "1.2.7" + +"@apollo/utils.dropunuseddefinitions@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@apollo/utils.dropunuseddefinitions/-/utils.dropunuseddefinitions-1.1.0.tgz#02b04006442eaf037f4c4624146b12775d70d929" + integrity sha512-jU1XjMr6ec9pPoL+BFWzEPW7VHHulVdGKMkPAMiCigpVIT11VmCbnij0bWob8uS3ODJ65tZLYKAh/55vLw2rbg== + +"@apollo/utils.keyvaluecache@^1.0.1": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-1.0.2.tgz#2bfe358c4d82f3a0950518451996758c52613f57" + integrity sha512-p7PVdLPMnPzmXSQVEsy27cYEjVON+SH/Wb7COyW3rQN8+wJgT1nv9jZouYtztWW8ZgTkii5T6tC9qfoDREd4mg== + dependencies: + "@apollo/utils.logger" "^1.0.0" + lru-cache "7.10.1 - 7.13.1" + +"@apollo/utils.logger@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.logger/-/utils.logger-1.0.1.tgz#aea0d1bb7ceb237f506c6bbf38f10a555b99a695" + integrity sha512-XdlzoY7fYNK4OIcvMD2G94RoFZbzTQaNP0jozmqqMudmaGo2I/2Jx71xlDJ801mWA/mbYRihyaw6KJii7k5RVA== + +"@apollo/utils.printwithreducedwhitespace@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@apollo/utils.printwithreducedwhitespace/-/utils.printwithreducedwhitespace-1.1.0.tgz#c466299a4766eef8577a2a64c8f27712e8bd7e30" + integrity sha512-GfFSkAv3n1toDZ4V6u2d7L4xMwLA+lv+6hqXicMN9KELSJ9yy9RzuEXaX73c/Ry+GzRsBy/fdSUGayGqdHfT2Q== + +"@apollo/utils.removealiases@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@apollo/utils.removealiases/-/utils.removealiases-1.0.0.tgz#75f6d83098af1fcae2d3beb4f515ad4a8452a8c1" + integrity sha512-6cM8sEOJW2LaGjL/0vHV0GtRaSekrPQR4DiywaApQlL9EdROASZU5PsQibe2MWeZCOhNrPRuHh4wDMwPsWTn8A== + +"@apollo/utils.sortast@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@apollo/utils.sortast/-/utils.sortast-1.1.0.tgz#93218c7008daf3e2a0725196085a33f5aab5ad07" + integrity sha512-VPlTsmUnOwzPK5yGZENN069y6uUHgeiSlpEhRnLFYwYNoJHsuJq2vXVwIaSmts015WTPa2fpz1inkLYByeuRQA== + dependencies: + lodash.sortby "^4.7.0" + +"@apollo/utils.stripsensitiveliterals@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@apollo/utils.stripsensitiveliterals/-/utils.stripsensitiveliterals-1.2.0.tgz#4920651f36beee8e260e12031a0c5863ad0c7b28" + integrity sha512-E41rDUzkz/cdikM5147d8nfCFVKovXxKBcjvLEQ7bjZm/cg9zEcXvS6vFY8ugTubI3fn6zoqo0CyU8zT+BGP9w== + +"@apollo/utils.usagereporting@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@apollo/utils.usagereporting/-/utils.usagereporting-1.0.1.tgz#3c70b49e554771659576fe35381c7a4b321d27fd" + integrity sha512-6dk+0hZlnDbahDBB2mP/PZ5ybrtCJdLMbeNJD+TJpKyZmSY6bA3SjI8Cr2EM9QA+AdziywuWg+SgbWUF3/zQqQ== + dependencies: + "@apollo/usage-reporting-protobuf" "^4.0.0" + "@apollo/utils.dropunuseddefinitions" "^1.1.0" + "@apollo/utils.printwithreducedwhitespace" "^1.1.0" + "@apollo/utils.removealiases" "1.0.0" + "@apollo/utils.sortast" "^1.1.0" + "@apollo/utils.stripsensitiveliterals" "^1.2.0" + +"@apollographql/apollo-tools@^0.5.3": + version "0.5.4" + resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.5.4.tgz#cb3998c6cf12e494b90c733f44dd9935e2d8196c" + integrity sha512-shM3q7rUbNyXVVRkQJQseXv6bnYM3BUma/eZhwXR4xsuM+bqWnJKvW7SAfRjP7LuSCocrexa5AXhjjawNHrIlw== + +"@apollographql/graphql-playground-html@1.6.29": + version "1.6.29" + resolved "https://registry.yarnpkg.com/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.29.tgz#a7a646614a255f62e10dcf64a7f68ead41dec453" + integrity sha512-xCcXpoz52rI4ksJSdOCxeOCn2DLocxwHf9dVT/Q90Pte1LX+LY+91SFtJF3KXVHH8kEin+g1KKCQPKBjZJfWNA== + dependencies: + xss "^1.0.8" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" @@ -520,6 +628,97 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@graphql-tools/merge@8.3.1": + version "8.3.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.3.1.tgz#06121942ad28982a14635dbc87b5d488a041d722" + integrity sha512-BMm99mqdNZbEYeTPK3it9r9S6rsZsQKtlqJsSBknAclXq2pGEfOxjcIZi+kBSkHZKPKCRrYDd5vY0+rUmIHVLg== + dependencies: + "@graphql-tools/utils" "8.9.0" + tslib "^2.4.0" + +"@graphql-tools/merge@8.3.12": + version "8.3.12" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.3.12.tgz#e3f2e5d8a7b34fb689cda66799d845cbc919e464" + integrity sha512-BFL8r4+FrqecPnIW0H8UJCBRQ4Y8Ep60aujw9c/sQuFmQTiqgWgpphswMGfaosP2zUinDE3ojU5wwcS2IJnumA== + dependencies: + "@graphql-tools/utils" "9.1.1" + tslib "^2.4.0" + +"@graphql-tools/merge@8.3.17": + version "8.3.17" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.3.17.tgz#d7e184a296eb455c1550ab95991c5a2f68ea16a4" + integrity sha512-CLzz49lc6BavPhH9gPRm0sJeNA7kC/tF/jLUTQsyef6xj82Jw3rqIJ9PE+bk1cqPCOG01WLOfquBu445OMDO2g== + dependencies: + "@graphql-tools/utils" "9.2.0" + tslib "^2.4.0" + +"@graphql-tools/mock@^8.1.2": + version "8.7.17" + resolved "https://registry.yarnpkg.com/@graphql-tools/mock/-/mock-8.7.17.tgz#1d087724f4cc18cec32f1a4b398e0204e0d82ead" + integrity sha512-yo3o2fxii3lQ+xwht6ZSYukPb+k81WXmfTX+1TTvj2ylSVuAdFpfRDQrACAqXRDPtXqCWvknN1ReRmnrOpUHrg== + dependencies: + "@graphql-tools/schema" "9.0.15" + "@graphql-tools/utils" "9.2.0" + fast-json-stable-stringify "^2.1.0" + tslib "^2.4.0" + +"@graphql-tools/schema@9.0.10": + version "9.0.10" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-9.0.10.tgz#77ba3dfab241f0232dc0d3ba03201663b63714e2" + integrity sha512-lV0o4df9SpPiaeeDAzgdCJ2o2N9Wvsp0SMHlF2qDbh9aFCFQRsXuksgiDm2yTgT3TG5OtUes/t0D6uPjPZFUbQ== + dependencies: + "@graphql-tools/merge" "8.3.12" + "@graphql-tools/utils" "9.1.1" + tslib "^2.4.0" + value-or-promise "1.0.11" + +"@graphql-tools/schema@9.0.15": + version "9.0.15" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-9.0.15.tgz#6632765e0281a6c890c7ea6865f13c10bc98fc1b" + integrity sha512-p2DbpkOBcsi+yCEjwoS+r4pJ5z+3JjlJdhbPkCwC4q8lGf5r93dVYrExOrqGKTU5kxLXI/mxabSxcunjNIsDIg== + dependencies: + "@graphql-tools/merge" "8.3.17" + "@graphql-tools/utils" "9.2.0" + tslib "^2.4.0" + value-or-promise "1.0.12" + +"@graphql-tools/schema@^8.0.0": + version "8.5.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.5.1.tgz#c2f2ff1448380919a330312399c9471db2580b58" + integrity sha512-0Esilsh0P/qYcB5DKQpiKeQs/jevzIadNTaT0jeWklPMwNbT7yMX4EqZany7mbeRRlSRwMzNzL5olyFdffHBZg== + dependencies: + "@graphql-tools/merge" "8.3.1" + "@graphql-tools/utils" "8.9.0" + tslib "^2.4.0" + value-or-promise "1.0.11" + +"@graphql-tools/utils@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.9.0.tgz#c6aa5f651c9c99e1aca55510af21b56ec296cdb7" + integrity sha512-pjJIWH0XOVnYGXCqej8g/u/tsfV4LvLlj0eATKQu5zwnxd/TiTHq7Cg313qUPTFFHZ3PP5wJ15chYVtLDwaymg== + dependencies: + tslib "^2.4.0" + +"@graphql-tools/utils@9.1.1": + version "9.1.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-9.1.1.tgz#b47ea8f0d18c038c5c1c429e72caa5c25039fbab" + integrity sha512-DXKLIEDbihK24fktR2hwp/BNIVwULIHaSTNTNhXS+19vgT50eX9wndx1bPxGwHnVBOONcwjXy0roQac49vdt/w== + dependencies: + tslib "^2.4.0" + +"@graphql-tools/utils@9.2.0": + version "9.2.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-9.2.0.tgz#d74d0376231c0e8bf897a715fafaf53d0f6bf06c" + integrity sha512-s3lEG1iYkyYEnKCWrIFECX3XH2wmZvbg6Ir3udCvIDynq+ydaO7JQXobclpPtwSJtjlS353haF//6V7mnBQ4bg== + dependencies: + "@graphql-typed-document-node/core" "^3.1.1" + tslib "^2.4.0" + +"@graphql-typed-document-node/core@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052" + integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg== + "@hapi/hoek@^9.0.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" @@ -759,6 +958,11 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" +"@josephg/resolvable@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@josephg/resolvable/-/resolvable-1.0.1.tgz#69bc4db754d79e1a2f17a650d3466e038d94a5eb" + integrity sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg== + "@jridgewell/gen-mapping@^0.1.0": version "0.1.1" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" @@ -815,6 +1019,15 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@nestjs/apollo@^10.1.7": + version "10.1.7" + resolved "https://registry.yarnpkg.com/@nestjs/apollo/-/apollo-10.1.7.tgz#deb3639fdcd01f8b7c646f926b1c253e823bf290" + integrity sha512-UQDgUgyJvrj53AcCzws6/854SVibAeyg+RGxMtb9+ENhd8snP6f7RS6mCaFY85UTAc6mo674NIUu9a/JyeYezw== + dependencies: + iterall "1.3.0" + lodash.omit "4.5.0" + tslib "2.4.1" + "@nestjs/cli@^9.0.0": version "9.1.9" resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-9.1.9.tgz#f696b79e1e6478e9fff3bc90c70253720d19f03f" @@ -875,6 +1088,26 @@ tslib "2.4.1" uuid "9.0.0" +"@nestjs/graphql@^10.1.7": + version "10.1.7" + resolved "https://registry.yarnpkg.com/@nestjs/graphql/-/graphql-10.1.7.tgz#233d96e34f2aa98aad4956ebc2e1f9f97f1fa713" + integrity sha512-InWjG3dV8D/1iAHeAQD6tiDg3HyVNkUILTev3DU33Q0xpFzv+PqtKQR35a9xOncLY9ZS68kwkGB5wksfMyGjAg== + dependencies: + "@graphql-tools/merge" "8.3.12" + "@graphql-tools/schema" "9.0.10" + "@graphql-tools/utils" "9.1.1" + "@nestjs/mapped-types" "1.2.0" + chokidar "3.5.3" + fast-glob "3.2.12" + graphql-tag "2.12.6" + graphql-ws "5.5.5" + lodash "4.17.21" + normalize-path "3.0.0" + subscriptions-transport-ws "0.11.0" + tslib "2.4.1" + uuid "9.0.0" + ws "8.11.0" + "@nestjs/mapped-types@1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-1.2.0.tgz#1bbdbb5c956f0adb3fd76add929137bc6ad3183f" @@ -967,6 +1200,76 @@ consola "^2.15.0" node-fetch "^2.6.1" +"@prisma/client@^4.9.0": + version "4.9.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-4.9.0.tgz#4a4068f3540732ea5723c008d49ed684d20f9340" + integrity sha512-bz6QARw54sWcbyR1lLnF2QHvRW5R/Jxnbbmwh3u+969vUKXtBkXgSgjDA85nji31ZBlf7+FrHDy5x+5ydGyQDg== + dependencies: + "@prisma/engines-version" "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5" + +"@prisma/engines-version@4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5": + version "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5.tgz#9d817a5779fc05b107eb02f63d197ad296d60b3c" + integrity sha512-M16aibbxi/FhW7z1sJCX8u+0DriyQYY5AyeTH7plQm9MLnURoiyn3CZBqAyIoQ+Z1pS77usCIibYJWSgleBMBA== + +"@prisma/engines@4.9.0": + version "4.9.0" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.9.0.tgz#05a1411964e047c1bc43f777c7a1c69f86a2a26c" + integrity sha512-t1pt0Gsp+HcgPJrHFc+d/ZSAaKKWar2G/iakrE07yeKPNavDP3iVKPpfXP22OTCHZUWf7OelwKJxQgKAm5hkgw== + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + "@redis/bloom@1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71" @@ -1072,6 +1375,13 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== +"@types/accepts@^1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575" + integrity sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ== + dependencies: + "@types/node" "*" + "@types/babel__core@^7.1.14": version "7.20.0" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.0.tgz#61bc5a4cae505ce98e1e36c5445e4bee060d8891" @@ -1105,7 +1415,7 @@ dependencies: "@babel/types" "^7.3.0" -"@types/body-parser@*": +"@types/body-parser@*", "@types/body-parser@1.19.2": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== @@ -1130,6 +1440,11 @@ resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== +"@types/cors@2.8.12": + version "2.8.12" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" + integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== + "@types/cors@^2.8.12": version "2.8.13" resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94" @@ -1163,7 +1478,16 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== -"@types/express-serve-static-core@^4.17.31": +"@types/express-serve-static-core@4.17.31": + version "4.17.31" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz#a1139efeab4e7323834bb0226e62ac019f474b2f" + integrity sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^4.17.31": version "4.17.33" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543" integrity sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA== @@ -1172,6 +1496,16 @@ "@types/qs" "*" "@types/range-parser" "*" +"@types/express@4.17.14": + version "4.17.14" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.14.tgz#143ea0557249bc1b3b54f15db4c81c3d4eb3569c" + integrity sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.18" + "@types/qs" "*" + "@types/serve-static" "*" + "@types/express@^4.17.13": version "4.17.16" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.16.tgz#986caf0b4b850611254505355daa24e1b8323de8" @@ -1228,6 +1562,11 @@ dependencies: "@types/node" "*" +"@types/long@^4.0.0": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" + integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== + "@types/mime@*": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" @@ -1243,6 +1582,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== +"@types/node@^10.1.0": + version "10.17.60" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" + integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== + "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" @@ -1308,6 +1652,11 @@ dependencies: "@types/superagent" "*" +"@types/validator@^13.7.10": + version "13.7.12" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.12.tgz#a285379b432cc8d103b69d223cbb159a253cf2f7" + integrity sha512-YVtyAPqpefU+Mm/qqnOANW6IkqKpCSrarcyV269C8MA8Ux0dbkEuQwM/4CjL47kVEM2LgBef/ETfkH+c6+moFA== + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" @@ -1542,7 +1891,7 @@ JSONStream@^1.0.4: jsonparse "^1.2.0" through ">=2.2.7 <3" -accepts@~1.3.4, accepts@~1.3.8: +accepts@^1.3.5, accepts@~1.3.4, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== @@ -1674,6 +2023,96 @@ anymatch@^3.0.3, anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +apollo-datasource@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-3.3.2.tgz#5711f8b38d4b7b53fb788cb4dbd4a6a526ea74c8" + integrity sha512-L5TiS8E2Hn/Yz7SSnWIVbZw0ZfEIXZCa5VUiVxD9P53JvSrf4aStvsFDlGWPvpIdCR+aly2CfoB79B9/JjKFqg== + dependencies: + "@apollo/utils.keyvaluecache" "^1.0.1" + apollo-server-env "^4.2.1" + +apollo-reporting-protobuf@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/apollo-reporting-protobuf/-/apollo-reporting-protobuf-3.3.3.tgz#df2b7ff73422cd682af3f1805d32301aefdd9e89" + integrity sha512-L3+DdClhLMaRZWVmMbBcwl4Ic77CnEBPXLW53F7hkYhkaZD88ivbCVB1w/x5gunO6ZHrdzhjq0FHmTsBvPo7aQ== + dependencies: + "@apollo/protobufjs" "1.2.6" + +apollo-server-core@^3.11.1: + version "3.11.1" + resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-3.11.1.tgz#89d83aeaa71a59f760ebfa35bb0cbd31e15474ca" + integrity sha512-t/eCKrRFK1lYZlc5pHD99iG7Np7CEm3SmbDiONA7fckR3EaB/pdsEdIkIwQ5QBBpT5JLp/nwvrZRVwhaWmaRvw== + dependencies: + "@apollo/utils.keyvaluecache" "^1.0.1" + "@apollo/utils.logger" "^1.0.0" + "@apollo/utils.usagereporting" "^1.0.0" + "@apollographql/apollo-tools" "^0.5.3" + "@apollographql/graphql-playground-html" "1.6.29" + "@graphql-tools/mock" "^8.1.2" + "@graphql-tools/schema" "^8.0.0" + "@josephg/resolvable" "^1.0.0" + apollo-datasource "^3.3.2" + apollo-reporting-protobuf "^3.3.3" + apollo-server-env "^4.2.1" + apollo-server-errors "^3.3.1" + apollo-server-plugin-base "^3.7.1" + apollo-server-types "^3.7.1" + async-retry "^1.2.1" + fast-json-stable-stringify "^2.1.0" + graphql-tag "^2.11.0" + loglevel "^1.6.8" + lru-cache "^6.0.0" + node-abort-controller "^3.0.1" + sha.js "^2.4.11" + uuid "^9.0.0" + whatwg-mimetype "^3.0.0" + +apollo-server-env@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/apollo-server-env/-/apollo-server-env-4.2.1.tgz#ea5b1944accdbdba311f179e4dfaeca482c20185" + integrity sha512-vm/7c7ld+zFMxibzqZ7SSa5tBENc4B0uye9LTfjJwGoQFY5xsUPH5FpO5j0bMUDZ8YYNbrF9SNtzc5Cngcr90g== + dependencies: + node-fetch "^2.6.7" + +apollo-server-errors@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-3.3.1.tgz#ba5c00cdaa33d4cbd09779f8cb6f47475d1cd655" + integrity sha512-xnZJ5QWs6FixHICXHxUfm+ZWqqxrNuPlQ+kj5m6RtEgIpekOPssH/SD9gf2B4HuWV0QozorrygwZnux8POvyPA== + +apollo-server-express@^3.11.1: + version "3.11.1" + resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-3.11.1.tgz#f46d2f2f8db3d99ede6c0c144fea02f24b73cb78" + integrity sha512-x9ngcpXbBlt4naCXTwNtBFb/mOd9OU0wtFXvJkObHF26NsRazu3DxDfEuekA6V1NFOocD+A9jmVMQeQWug5MgA== + dependencies: + "@types/accepts" "^1.3.5" + "@types/body-parser" "1.19.2" + "@types/cors" "2.8.12" + "@types/express" "4.17.14" + "@types/express-serve-static-core" "4.17.31" + accepts "^1.3.5" + apollo-server-core "^3.11.1" + apollo-server-types "^3.7.1" + body-parser "^1.19.0" + cors "^2.8.5" + parseurl "^1.3.3" + +apollo-server-plugin-base@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-3.7.1.tgz#aa78ef49bd114e35906ca9cf7493fed2664cbde8" + integrity sha512-g3vJStmQtQvjGI289UkLMfThmOEOddpVgHLHT2bNj0sCD/bbisj4xKbBHETqaURokteqSWyyd4RDTUe0wAUDNQ== + dependencies: + apollo-server-types "^3.7.1" + +apollo-server-types@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-3.7.1.tgz#87adfcb52ec0893999a9cfafd5474bfda7ab0798" + integrity sha512-aE9RDVplmkaOj/OduNmGa+0a1B5RIWI0o3zC1zLvBTVWMKTpo0ifVf11TyMkLCY+T7cnZqVqwyShziOyC3FyUw== + dependencies: + "@apollo/utils.keyvaluecache" "^1.0.1" + "@apollo/utils.logger" "^1.0.0" + apollo-reporting-protobuf "^3.3.3" + apollo-server-env "^4.2.1" + append-field@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" @@ -1726,6 +2165,13 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +async-retry@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1796,6 +2242,11 @@ babel-preset-jest@^29.4.0: babel-plugin-jest-hoist "^29.4.0" babel-preset-current-node-syntax "^1.0.0" +backo2@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -1825,7 +2276,7 @@ bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -body-parser@1.20.1: +body-parser@1.20.1, body-parser@^1.19.0: version "1.20.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== @@ -2019,6 +2470,20 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== +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-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -2136,7 +2601,7 @@ commander@4.1.1: resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== -commander@^2.20.0: +commander@^2.20.0, commander@^2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -2280,7 +2745,7 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cors@2.8.5, cors@~2.8.5: +cors@2.8.5, cors@^2.8.5, cors@~2.8.5: version "2.8.5" resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== @@ -2335,6 +2800,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +cssfilter@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae" + integrity sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw== + cz-conventional-changelog@3.3.0, cz-conventional-changelog@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz#9246947c90404149b3fe2cf7ee91acad3b7d22d2" @@ -2472,16 +2942,36 @@ dot-prop@^5.1.0: dependencies: is-obj "^2.0.0" +dotenv-cli@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/dotenv-cli/-/dotenv-cli-7.0.0.tgz#b24e842a4c00928ec91d051ab152cd927c66ad97" + integrity sha512-XfMzVdpdDTRnlcgvFLg3lSyiLXqFxS4tH7RbK5IxkC4XIUuxPyrGoDufkfLjy/dA28EILzEu+mros6h8aQmyGg== + dependencies: + cross-spawn "^7.0.3" + dotenv "^16.0.0" + dotenv-expand "^10.0.0" + minimist "^1.2.6" + dotenv-expand@8.0.3: version "8.0.3" resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-8.0.3.tgz#29016757455bcc748469c83a19b36aaf2b83dd6e" integrity sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg== +dotenv-expand@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37" + integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A== + dotenv@16.0.1: version "16.0.1" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d" integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== +dotenv@^16.0.0: + version "16.0.3" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" + integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== + eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" @@ -2735,6 +3225,11 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== +eventemitter3@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== + events@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" @@ -2864,7 +3359,7 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== -fast-glob@^3.2.9: +fast-glob@3.2.12, fast-glob@^3.2.9: version "3.2.12" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== @@ -3229,6 +3724,23 @@ grapheme-splitter@^1.0.4: resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== +graphql-tag@2.12.6, graphql-tag@^2.11.0: + version "2.12.6" + resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" + integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== + dependencies: + tslib "^2.1.0" + +graphql-ws@5.5.5: + version "5.5.5" + resolved "https://registry.yarnpkg.com/graphql-ws/-/graphql-ws-5.5.5.tgz#f375486d3f196e2a2527b503644693ae3a8670a9" + integrity sha512-hvyIS71vs4Tu/yUYHPvGXsTgo0t3arU820+lT5VjZS2go0ewp2LqyCgxEN56CzOG7Iys52eRhHBiD1gGRdiQtw== + +graphql@^16.6.0: + version "16.6.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.6.0.tgz#c2dcffa4649db149f6282af726c8c83f1c7c5fdb" + integrity sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw== + hard-rejection@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" @@ -3367,7 +3879,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3603,6 +4115,11 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +iterall@1.3.0, iterall@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" + integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== + iterare@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/iterare/-/iterare-1.2.1.tgz#139c400ff7363690e33abffa33cbba8920f00042" @@ -4114,6 +4631,11 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +libphonenumber-js@^1.10.14: + version "1.10.19" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.19.tgz#e18970c8d566fbfb1f88e688345f0512e126712e" + integrity sha512-MDZ1zLIkfSDZV5xBta3nuvbEOlsnKCPe4z5r3hyup/AXveevkl9A1eSWmLhd2FX4k7pJDe4MrLeQsux0HI/VWg== + lilconfig@2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" @@ -4216,11 +4738,21 @@ lodash.mergewith@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== +lodash.omit@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + integrity sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg== + lodash.snakecase@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw== +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== + lodash.startcase@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8" @@ -4259,11 +4791,26 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" +loglevel@^1.6.8: + version "1.8.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4" + integrity sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg== + +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + longest@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-2.0.1.tgz#781e183296aa94f6d4d916dc335d0d17aefa23f8" integrity sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q== +"lru-cache@7.10.1 - 7.13.1": + version "7.13.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.13.1.tgz#267a81fbd0881327c46a81c5922606a2cfe336c4" + integrity sha512-CHqbAq7NFlW3RSnoWXLJBxCWaZVBrfa9UEHId2M3AW8iEBurbqduNexEUCGc3SHc6iCYXNJCDi903LajSVAEPQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -4518,6 +5065,13 @@ node-fetch@^2.6.1: dependencies: whatwg-url "^5.0.0" +node-fetch@^2.6.7: + version "2.6.9" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" + integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== + dependencies: + whatwg-url "^5.0.0" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -4548,7 +5102,7 @@ normalize-package-data@^3.0.0: semver "^7.3.4" validate-npm-package-license "^3.0.1" -normalize-path@^3.0.0, normalize-path@~3.0.0: +normalize-path@3.0.0, normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== @@ -4717,7 +5271,7 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q== -parseurl@~1.3.3: +parseurl@^1.3.3, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== @@ -4820,6 +5374,13 @@ pretty-format@^29.0.0, pretty-format@^29.4.1: ansi-styles "^5.0.0" react-is "^18.0.0" +prisma@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-4.9.0.tgz#295954b2a89cd35a0e6bcf66b2b036dbf80c75ee" + integrity sha512-bS96oZ5oDFXYgoF2l7PJ3Mp1wWWfLOo8B/jAfbA2Pn0Wm5Z/owBHzaMQKS3i1CzVBDWWPVnOohmbJmjvkcHS5w== + dependencies: + "@prisma/engines" "4.9.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" @@ -5052,6 +5613,11 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +retry@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -5177,6 +5743,14 @@ setprototypeof@1.2.0: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== +sha.js@^2.4.11: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -5462,6 +6036,17 @@ strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1. resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +subscriptions-transport-ws@0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz#baf88f050cba51d52afe781de5e81b3c31f89883" + integrity sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ== + dependencies: + backo2 "^1.0.2" + eventemitter3 "^3.1.0" + iterall "^1.2.1" + symbol-observable "^1.0.4" + ws "^5.2.0 || ^6.0.0 || ^7.0.0" + superagent@^8.0.5: version "8.0.9" resolved "https://registry.yarnpkg.com/superagent/-/superagent-8.0.9.tgz#2c6fda6fadb40516515f93e9098c0eb1602e0535" @@ -5522,6 +6107,11 @@ symbol-observable@4.0.0: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== +symbol-observable@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" @@ -5703,7 +6293,7 @@ tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0: +tslib@^2.1.0, tslib@^2.4.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== @@ -5815,7 +6405,7 @@ uuid@8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@9.0.0: +uuid@9.0.0, uuid@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== @@ -5842,6 +6432,21 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +validator@^13.7.0: + version "13.9.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855" + integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA== + +value-or-promise@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" + integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg== + +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" + integrity sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -5914,6 +6519,11 @@ webpack@5.75.0: watchpack "^2.4.0" webpack-sources "^3.2.3" +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -5979,11 +6589,29 @@ write-file-atomic@^5.0.0: imurmurhash "^0.1.4" signal-exit "^3.0.7" +ws@8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" + integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== + +"ws@^5.2.0 || ^6.0.0 || ^7.0.0": + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + ws@~8.2.3: version "8.2.3" resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== +xss@^1.0.8: + version "1.0.14" + resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.14.tgz#4f3efbde75ad0d82e9921cc3c95e6590dd336694" + integrity sha512-og7TEJhXvn1a7kzZGQ7ETjdQVS2UfZyTlsEdDOqvQF7GoxNfY+0YLCzBy1kPdsDDx4QuNAonQPddpsn6Xl/7sw== + dependencies: + commander "^2.20.3" + cssfilter "0.0.10" + xtend@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" From 7734732161a094a6601f2952df5f81145377c261 Mon Sep 17 00:00:00 2001 From: raymond Date: Mon, 6 Feb 2023 00:36:39 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=8E=A8feat=20:=20=EC=9C=A0=EC=A0=80?= =?UTF-8?q?=20=EA=B6=8C=ED=95=9C=20=EB=B0=8F=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - jwt RSA 인증 로직 추가 - socket , gql middleware 추가 --- .gitignore | 2 +- commitlint.config.js | 2 - package.json | 9 ++- src/app.module.ts | 33 ++++++-- src/auth/auth-exception.filter.ts | 7 ++ src/auth/auth-user.decorator.ts | 10 +++ src/auth/auth.guard.ts | 30 +++++-- src/auth/auth.module.ts | 9 ++- src/common/common.type.ts | 3 +- src/events/events.gateway.ts | 33 ++++---- src/events/events.module.ts | 3 +- src/jwt/jwt.middleware.ts | 11 +-- src/jwt/jwt.module.ts | 18 +---- src/jwt/jwt.service.ts | 19 +++-- src/key/private.key.key | 28 ------- src/key/public.key.pub | 9 --- src/main.ts | 7 ++ src/redis/redis.adapter.ts | 13 +-- src/sockets/socket.middleware.ts | 0 src/sockets/sockets-exception.filter.ts | 8 ++ src/sockets/sockets.middleware.ts | 41 ++++++++++ src/sockets/sockets.module.ts | 4 + src/users/users.resolver.ts | 15 ++-- src/workspaces/workspaces.gateway.ts | 100 +++++------------------- src/workspaces/workspaces.module.ts | 2 + webpack-hmr.config.js | 25 ++++++ yarn.lock | 28 ++++++- 27 files changed, 268 insertions(+), 201 deletions(-) create mode 100644 src/auth/auth-exception.filter.ts create mode 100644 src/auth/auth-user.decorator.ts delete mode 100644 src/key/private.key.key delete mode 100644 src/key/public.key.pub delete mode 100644 src/sockets/socket.middleware.ts create mode 100644 src/sockets/sockets-exception.filter.ts create mode 100644 src/sockets/sockets.middleware.ts create mode 100644 src/sockets/sockets.module.ts create mode 100644 webpack-hmr.config.js diff --git a/.gitignore b/.gitignore index 1687838..94bb936 100644 --- a/.gitignore +++ b/.gitignore @@ -83,7 +83,7 @@ web_modules/ .env.test.local .env.production.local .env.local - +/key # parcel-bundler cache (https://parceljs.org/) .cache .parcel-cache diff --git a/commitlint.config.js b/commitlint.config.js index 00909e8..2d39486 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -22,8 +22,6 @@ module.exports = { ] }, 'body-max-line-length': ({ body }) => { - console.log(body) - console.log(body.length) const isBodyMatch = body && body.length <= 72 return [!body, isBodyMatch, '본문은 72자 이하로 작성해주세요'] }, diff --git a/package.json b/package.json index 4717bbd..8caf357 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "start": "cross-env NODE_ENV=production nest start", "start:dev": "cross-env NODE_ENV=development nest start --watch", + "start:watch": "cross-env NODE_ENV=development nest build --webpack --webpackPath webpack-hmr.config.js --watch", "start:debug": "nest start --debug --watch", "start:prod": "node dist/main", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", @@ -18,7 +19,7 @@ "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "jest --config ./test/jest-e2e.json", - "db:push" : "dotenv -e .env.development -- npx prisma db push", + "db:push": "dotenv -e .env.development -- npx prisma db push", "prepare": "husky install" }, "dependencies": { @@ -32,6 +33,7 @@ "@nestjs/swagger": "^6.1.4", "@nestjs/websockets": "^9.2.1", "@prisma/client": "^4.9.0", + "@socket.io/admin-ui": "^0.5.1", "@socket.io/redis-adapter": "^8.0.1", "@types/jsonwebtoken": "^9.0.1", "@types/socket.io": "^3.0.2", @@ -68,13 +70,16 @@ "lint-staged": "^13.1.0", "prettier": "^2.3.2", "prisma": "^4.9.0", + "run-script-webpack-plugin": "^0.1.1", "source-map-support": "^0.5.20", "supertest": "^6.1.3", "ts-jest": "^29.0.5", "ts-loader": "^9.2.3", "ts-node": "^10.0.0", "tsconfig-paths": "4.1.1", - "typescript": "^4.7.4" + "typescript": "^4.7.4", + "webpack": "^5.75.0", + "webpack-node-externals": "^3.0.0" }, "jest": { "moduleFileExtensions": [ diff --git a/src/app.module.ts b/src/app.module.ts index a4ed1f3..635046c 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,5 +1,10 @@ import { JwtMiddleware } from './jwt/jwt.middleware' -import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common' +import { + Module, + NestModule, + MiddlewareConsumer, + RequestMethod, +} from '@nestjs/common' import { ConfigModule } from '@nestjs/config' import { LoggerMiddleware } from './logger/logger.middleware' import { EventsModule } from './events/events.module' @@ -12,6 +17,7 @@ import { ApolloDriverConfig, ApolloDriver } from '@nestjs/apollo' import { PrismaModule } from './prisma/prisma.module' import { UsersModule } from './users/users.module' import { AuthModule } from './auth/auth.module' +import { SocketsModule } from './sockets/sockets.module' @Module({ imports: [ @@ -24,6 +30,7 @@ import { AuthModule } from './auth/auth.module' ignoreEnvFile: process.env.NODE_ENV === 'production', validationSchema: joi.object({ PORT: joi.string().required(), + AUTH_KEY: joi.string().required(), REDIS_HOST: joi.string().required(), REDIS_PASSWORD: joi.string().required(), JWT_PRIVATE_KEY: joi.string().required(), @@ -34,18 +41,29 @@ import { AuthModule } from './auth/auth.module' GraphQLModule.forRoot({ driver: ApolloDriver, autoSchemaFile: true, - context: ({ req }) => ({ user: req['user'] }), + context: ({ req, connection }) => { + return { + token: req + ? req.headers[process.env.AUTH_KEY] + : connection.context[process.env.AUTH_KEY], + } + }, }), LoggerModule, - WorkspacesModule, EventsModule, + WorkspacesModule, JwtModule.forRoot({ isRSA: true, - priveKey: process.env.JWT_PRIVATE_KEY, - pubkey: process.env.JWT_PUBLIC_KEY, + priveKey: Buffer.from(process.env.JWT_PRIVATE_KEY, 'base64').toString( + 'ascii', + ), + pubkey: Buffer.from(process.env.JWT_PUBLIC_KEY, 'base64').toString( + 'ascii', + ), }), UsersModule, AuthModule, + SocketsModule, ], controllers: [], providers: [], @@ -53,6 +71,9 @@ import { AuthModule } from './auth/auth.module' export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(LoggerMiddleware).forRoutes('*') - consumer.apply(JwtMiddleware).exclude('/login').exclude('/').forRoutes('*') + consumer.apply(JwtMiddleware).forRoutes({ + path: '/graphql', + method: RequestMethod.POST, + }) } } diff --git a/src/auth/auth-exception.filter.ts b/src/auth/auth-exception.filter.ts new file mode 100644 index 0000000..cf626bb --- /dev/null +++ b/src/auth/auth-exception.filter.ts @@ -0,0 +1,7 @@ +import { ExceptionFilter } from '@nestjs/common' + +export class RoleException implements ExceptionFilter { + async catch() { + return { ok: false, error: '권한이 없습니다' } + } +} diff --git a/src/auth/auth-user.decorator.ts b/src/auth/auth-user.decorator.ts new file mode 100644 index 0000000..07aa64f --- /dev/null +++ b/src/auth/auth-user.decorator.ts @@ -0,0 +1,10 @@ +import { GqlExecutionContext } from '@nestjs/graphql' +import { createParamDecorator, ExecutionContext } from '@nestjs/common' + +export const AuthUser = createParamDecorator( + (data: unknown, ctx: ExecutionContext) => { + const gqlContext = GqlExecutionContext.create(ctx).getContext() + const user = gqlContext['user'] + return user + }, +) diff --git a/src/auth/auth.guard.ts b/src/auth/auth.guard.ts index 4d975ae..c24d5bf 100644 --- a/src/auth/auth.guard.ts +++ b/src/auth/auth.guard.ts @@ -1,20 +1,34 @@ +import { UsersService } from 'src/users/users.service' import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common' import { Reflector } from '@nestjs/core' -import { Observable } from 'rxjs' import { GqlExecutionContext } from '@nestjs/graphql' -import { User } from 'src/users/entities/user.entity' +import { JwtService } from 'src/jwt/jwt.service' +import { RoleException } from './auth-exception.filter' @Injectable() export class AuthGuard implements CanActivate { - constructor(private readonly relector: Reflector) {} - canActivate( - context: ExecutionContext, - ): boolean | Promise | Observable { + constructor( + private readonly relector: Reflector, + private readonly jwtService: JwtService, + private readonly usersService: UsersService, + ) {} + async canActivate(context: ExecutionContext): Promise { const roles = this.relector.get('roles', context.getHandler()) if (!roles) { return true } const gqlContext = GqlExecutionContext.create(context).getContext() - const user: User = gqlContext['user'] - return roles.includes('Any') || !!user + const token = gqlContext.token + if (token) { + const decode = this.jwtService.verify(token) + if (typeof decode === 'object' && decode.hasOwnProperty('id')) { + const { user } = await this.usersService.findById(decode.id) + if (user) { + gqlContext['user'] = user + return roles.includes('Any') || roles.includes(user.role) + } + } + } + + throw new RoleException() } } diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 32c9d97..56f63ae 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -1,13 +1,20 @@ +import { UsersModule } from './../users/users.module' import { Module } from '@nestjs/common' -import { APP_GUARD } from '@nestjs/core' +import { APP_GUARD, APP_FILTER } from '@nestjs/core' import { AuthGuard } from './auth.guard' +import { RoleException } from './auth-exception.filter' @Module({ + imports: [UsersModule], providers: [ { provide: APP_GUARD, useClass: AuthGuard, }, + { + provide: APP_FILTER, + useClass: RoleException, + }, ], }) export class AuthModule {} diff --git a/src/common/common.type.ts b/src/common/common.type.ts index ef1d4dc..c33903b 100644 --- a/src/common/common.type.ts +++ b/src/common/common.type.ts @@ -1,7 +1,6 @@ import { Socket } from 'socket.io' -import { ExtendedError } from 'socket.io/dist/namespace' export type SocketMiddleware = ( socket: Socket, - next: (err?: ExtendedError) => void, + next: (err?: Error) => void, ) => void diff --git a/src/events/events.gateway.ts b/src/events/events.gateway.ts index fe55498..5b34dde 100644 --- a/src/events/events.gateway.ts +++ b/src/events/events.gateway.ts @@ -1,4 +1,5 @@ -import { Inject } from '@nestjs/common' +import { WsExceptionFilter } from './../sockets/sockets-exception.filter' +import { Inject, UseFilters, Logger } from '@nestjs/common' import { SubscribeMessage, WebSocketGateway } from '@nestjs/websockets' import { ConnectedSocket, @@ -11,11 +12,14 @@ import { OnGatewayInit, } from '@nestjs/websockets/interfaces' import { Namespace, Socket } from 'socket.io' -import { LoggerService } from 'src/logger/logger.service' import { PrismaService } from 'src/prisma/prisma.service' import { getServerRoomDto } from './dtos/gateway.dto' +import { AuthSocket, WSAuthMiddleware } from 'src/sockets/sockets.middleware' +import { UsersService } from 'src/users/users.service' +import { JwtService } from 'src/jwt/jwt.service' -@WebSocketGateway(3050, { +@UseFilters(new WsExceptionFilter()) +@WebSocketGateway({ cors: { origin: '*', }, @@ -25,19 +29,15 @@ import { getServerRoomDto } from './dtos/gateway.dto' export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit { - @WebSocketServer() public io: Namespace + private readonly logger = new Logger(EventsGateway.name) constructor( @Inject(PrismaService) private readonly prismaService: PrismaService, - private readonly logger: LoggerService, - ) { - this.logger.setContext('EventsGateway') - } + private readonly usersService: UsersService, + private readonly jwtService: JwtService, + ) {} + + @WebSocketServer() public io: Namespace - /** - * TODO: Socket Handler return value를 통해 클라이언트 내에서 이벤트 핸들링 가능 - * ex) client-side -> socket.emit('join_room' , 'myRoomName' , data => console.log(data)) - * 일단 ws방식으로 구현 후 socket io 방식으로 변경하는게 좋을듯 - */ @SubscribeMessage('set_nickname') async setNickname( @ConnectedSocket() client: Socket, @@ -56,17 +56,15 @@ export class EventsGateway nickname, }, }) - console.log(upsertedUser) this.logger.debug(`${nickname} change`) return nickname } - @SubscribeMessage('join_room') async joinRoom( @ConnectedSocket() client: Socket, @MessageBody() roomName: string, ) { - const { nickname } = this.findCurrentClient(client) + const { nickname } = this.findCurrentClient(client) || {} if (!nickname) { return { ok: false } } @@ -117,7 +115,7 @@ export class EventsGateway client.to(roomName).emit('ice', ice) } - handleConnection(@ConnectedSocket() client: Socket) { + handleConnection(@ConnectedSocket() client: AuthSocket) { this.logger.debug(`connected : ${client.id}`) this.logger.debug(`namespace : ${client.nsp.name}`) this.serverRoomChange() @@ -129,6 +127,7 @@ export class EventsGateway } async afterInit(io: Namespace) { + io.use(WSAuthMiddleware(this.jwtService, this.usersService)) const serverCount = await io.server.sockets.adapter.serverCount() this.logger.log(`serverCount : ${serverCount}`) } diff --git a/src/events/events.module.ts b/src/events/events.module.ts index cf8424b..837161d 100644 --- a/src/events/events.module.ts +++ b/src/events/events.module.ts @@ -1,10 +1,11 @@ +import { UsersModule } from './../users/users.module' import { Module } from '@nestjs/common' import { PrismaModule } from 'src/prisma/prisma.module' import { EventsGateway } from './events.gateway' @Module({ - imports: [PrismaModule], + imports: [PrismaModule, UsersModule], providers: [EventsGateway], }) export class EventsModule {} diff --git a/src/jwt/jwt.middleware.ts b/src/jwt/jwt.middleware.ts index d05f02a..3bee833 100644 --- a/src/jwt/jwt.middleware.ts +++ b/src/jwt/jwt.middleware.ts @@ -1,7 +1,6 @@ import { JwtService } from 'src/jwt/jwt.service' import { Injectable, NestMiddleware } from '@nestjs/common' import { NextFunction, Request, Response } from 'express' -import { SocketMiddleware } from 'src/common/common.type' import { UsersService } from 'src/users/users.service' @Injectable() @@ -11,8 +10,9 @@ export class JwtMiddleware implements NestMiddleware { private readonly usersService: UsersService, ) {} async use(req: Request, res: Response, next: NextFunction) { - if ('_PLUG_AUTH_' in req.headers) { - const token = req.headers['_PLUG_AUTH_'] + const tokenKey = process.env.AUTH_KEY + if (tokenKey in req.headers) { + const token = req.headers[tokenKey] const decode = this.jwtService.verify(token.toString()) if (typeof decode === 'object' && decode.hasOwnProperty('id')) { try { @@ -27,8 +27,3 @@ export class JwtMiddleware implements NestMiddleware { next() } } - -export const jwtSocketMiddleware: SocketMiddleware = (socket, next) => { - console.log(socket.handshake.auth) - next() -} diff --git a/src/jwt/jwt.module.ts b/src/jwt/jwt.module.ts index 816d2f8..d41d7d1 100644 --- a/src/jwt/jwt.module.ts +++ b/src/jwt/jwt.module.ts @@ -1,6 +1,4 @@ import { DynamicModule, Global, Module } from '@nestjs/common' -import fs from 'fs' -import path from 'path' import { Secret } from 'jsonwebtoken' import { JWT_PROVIDER } from 'src/common/common.constants' import { JwtModuleOptions } from './jwt.interface' @@ -9,19 +7,9 @@ import { JwtService } from './jwt.service' @Global() export class JwtModule { static forRoot(options: JwtModuleOptions): DynamicModule { - const { priveKey, isRSA, pubkey } = options || {} - let key: Secret = priveKey - let pub: Secret = pubkey - if (!isRSA) { - key = priveKey - } else { - key = fs.readFileSync( - path.resolve(__dirname, '../../src/key/private.key.key'), - ) - pub = fs.readFileSync( - path.resolve(__dirname, '../../src/key/public.key.pub'), - ) - } + const { priveKey, pubkey } = options || {} + const key: Secret = priveKey + const pub: Secret = pubkey return { module: JwtModule, providers: [ diff --git a/src/jwt/jwt.service.ts b/src/jwt/jwt.service.ts index 0e803c0..b54d8a7 100644 --- a/src/jwt/jwt.service.ts +++ b/src/jwt/jwt.service.ts @@ -15,17 +15,20 @@ export class JwtService { const token = jwt.sign(payload, this.options.priveKey, { algorithm: this.algorithm, }) - console.log(token) return token } verify(token: string) { - return jwt.verify( - token, - this.options.isRSA ? this.options.pubkey : this.options.priveKey, - { - algorithms: [this.algorithm], - }, - ) + try { + return jwt.verify( + token, + this.options.isRSA ? this.options.pubkey : this.options.priveKey, + { + algorithms: [this.algorithm], + }, + ) + } catch { + return false + } } } diff --git a/src/key/private.key.key b/src/key/private.key.key deleted file mode 100644 index a6d0842..0000000 --- a/src/key/private.key.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDRJ6zwLhsTKQdY -qCIcegegGbIa+eHkFYoRHuUJPCLeC8CtMhHgf2GQttY87wgkGI37LAfnpbanyc8d -98SNF0LL2zd+yMOYkTti4m4Zh4kVnfcufrk3eNmShdb8349XPHTZ3I1Jtu0nYGqR -jTJ2PBLtYebm02dBKPnpQTFv4/wC/ChyaJSQBVVnBh99YY9vxodCoA24WsVe8HK8 -fty9F9inpOSwd+e6MvO+5d2UgZiZSU6a0kjGh/8FJnQVDjjNEoP7kW+PlPhWD0DR -ShHxpLW6eldYFfH6feCqgNyev1cOWUIqbXibL0yALBY+dgAW83bl05nEC3xxtVLv -IoWToJYzAgMBAAECggEAThpryRDeiWwj0yaN/mZPXKjbypkPkpW8hiIsUyOCvbpT -zBlLdbL7owezvvNf7eLBek758LYAHG4PCtjQLAPIrMmC0rRz3hA1xfpaNOxY85qW -iGVIEv/s93tFSg7NvzzTQdvLYwCNVMv7X7kDZAWQ59ZMXFwLTdjYYhM3O9o97HrC -KVGQEMfsGBNtucjZvnoYB/QhDwk3ozIVMHd137VKAw/x7geO/a00hG6xB20WbREm -lQSZMohN56MGB/cjW9uZHmD43i5Ysc2yID8Hzqstw3//sQSN0quj6NwVc2jzcFd1 -i2oPWWsSVo0ACA+FmWY4t/TrHOCvsYaGrK2oeU8UoQKBgQD0RdbMWa8y4drLpnS1 -g3PR4JmQM3R0JJxI2TmlAmSSuy6qhEUfoCXp5srZ2+zRVbutwWCZ08qA5oBL3TXh -Sg/l0mmH6A8Zz5r/WUj8w/fXUqX1Whyu5JCxw+6pIyBc6ZwaO6ILVuLjnE9BOoxU -skAVQFyR0Yr8yD2w3sVWBZio0QKBgQDbMjtCWyL7+SZfDQ1jbE8gLyd7jQOe3zMi -wif0wmXDgkRnZ3Zl7Wyij5dSh30g814OvudkqrGFcVRkCromQNZmyHfs2gYl0ozc -DgRIeCzWjZgzlCG26Zm5JDmzs9+X39uGJuNU4NtCzq0zBfJgTwSYd88DfkRS6OMX -fc8OqCfPwwKBgGhoYYM+4i+xcb+SClh7M0oF4h1MoP3zmAlbL9RjzXEaKLwhhRob -bZkoWJP9+J8RMgL2oL+fUvL9kuDaUGlXKqxk306D1dCGeA2ksBm5+XlDjkPsnE30 -zBPvV1db+D0+bMaZro2COcBn00hiKhEZj2KF/AsnsWySeivbTCWUhsfBAoGAFeJC -9lIBASUTxqOX9Zgnoi/zAivG88KW6V52/MG3xTgpOiWjNXPpx6UMV4n9XR/PASvg -EDXWeVsiMMa9ZPpOLX7QMk5mFLqbo5CmrtGIsHb8fhHI9+kElu5d8GoB5bjMwuz4 -/01ftqDJu/FZDHJ3I/26JkAh9CEaIwtFc9In/18CgYB/2a8raAm4jt7tGY1z0obq -D7nfB4UifQRZJC00CX9qR4e21oKXvYZHS82IokHv3/KaB3MFxchmy2G8QBuR975P -quPiVmdCJ1zE2gR7z4UGUy2PBoNzhg/qAO4VfFKJx/Y1/cBhSM7dMHJLHJSgXU5Y -hG3fz4atCB357FkrCQr5aw== ------END PRIVATE KEY----- \ No newline at end of file diff --git a/src/key/public.key.pub b/src/key/public.key.pub deleted file mode 100644 index 891f4d8..0000000 --- a/src/key/public.key.pub +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Ses8C4bEykHWKgiHHoH -oBmyGvnh5BWKER7lCTwi3gvArTIR4H9hkLbWPO8IJBiN+ywH56W2p8nPHffEjRdC -y9s3fsjDmJE7YuJuGYeJFZ33Ln65N3jZkoXW/N+PVzx02dyNSbbtJ2BqkY0ydjwS -7WHm5tNnQSj56UExb+P8AvwocmiUkAVVZwYffWGPb8aHQqANuFrFXvByvH7cvRfY -p6TksHfnujLzvuXdlIGYmUlOmtJIxof/BSZ0FQ44zRKD+5Fvj5T4Vg9A0UoR8aS1 -unpXWBXx+n3gqoDcnr9XDllCKm14my9MgCwWPnYAFvN25dOZxAt8cbVS7yKFk6CW -MwIDAQAB ------END PUBLIC KEY----- \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index c49804c..194a9ca 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,6 +5,8 @@ import { DocumentBuilder } from '@nestjs/swagger/dist' import { AppModule } from './app.module' import { RedisIoAdapter } from './redis/redis.adapter' +declare const module: any + async function bootstrap() { const PORT = process.env.PORT || 3000 const app = await NestFactory.create(AppModule) @@ -25,5 +27,10 @@ async function bootstrap() { await app.listen(PORT, () => { new Logger().localInstance.log(`app listen on port : ${PORT}`) }) + + if (module.hot) { + module.hot.accept() + module.hot.dispose(() => app.close()) + } } bootstrap() diff --git a/src/redis/redis.adapter.ts b/src/redis/redis.adapter.ts index 2bc80d5..1e4b4d2 100644 --- a/src/redis/redis.adapter.ts +++ b/src/redis/redis.adapter.ts @@ -5,17 +5,13 @@ import { createAdapter } from '@socket.io/redis-adapter' import { createClient } from 'redis' import { INestApplication } from '@nestjs/common/interfaces' import { Server } from 'socket.io' -import { LoggerService } from 'src/logger/logger.service' -import { jwtSocketMiddleware } from 'src/jwt/jwt.middleware' export class RedisIoAdapter extends IoAdapter { private readonly configService: ConfigService - private readonly loggerService: LoggerService constructor(private readonly app: INestApplication) { super(app) this.configService = app.get(ConfigService) - this.loggerService = app.get(LoggerService) } private adapterConstructor: ReturnType @@ -33,12 +29,17 @@ export class RedisIoAdapter extends IoAdapter { createIOServer(port: number, options?: ServerOptions): any { const server: Server = super.createIOServer(port, { ...options }) - server.use(jwtSocketMiddleware) server.adapter(this.adapterConstructor) return server } - // bindClientConnect(server: TServer, callback: Function): void; + // bindClientConnect(server: any, callback) { + // // console.log(server) + // console.log(callback()) + // // if (callback) { + // // callback() + // // } + // } // bindClientDisconnect(client: TClient, callback: Function): void; // close(server: TServer): Promise; // dispose(): Promise; diff --git a/src/sockets/socket.middleware.ts b/src/sockets/socket.middleware.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/sockets/sockets-exception.filter.ts b/src/sockets/sockets-exception.filter.ts new file mode 100644 index 0000000..98f7eb5 --- /dev/null +++ b/src/sockets/sockets-exception.filter.ts @@ -0,0 +1,8 @@ +import { Catch, ArgumentsHost } from '@nestjs/common' +import { BaseWsExceptionFilter, WsException } from '@nestjs/websockets' +@Catch(WsException) +export class WsExceptionFilter extends BaseWsExceptionFilter { + catch(exception: unknown, host: ArgumentsHost) { + super.catch(exception, host) + } +} diff --git a/src/sockets/sockets.middleware.ts b/src/sockets/sockets.middleware.ts new file mode 100644 index 0000000..8478b6d --- /dev/null +++ b/src/sockets/sockets.middleware.ts @@ -0,0 +1,41 @@ +import { Socket } from 'socket.io' +import { SocketMiddleware } from 'src/common/common.type' +import { JwtService } from 'src/jwt/jwt.service' +import { User } from 'src/users/entities/user.entity' +import { UsersService } from 'src/users/users.service' + +export class AuthSocket extends Socket { + user: User +} +export const WSAuthMiddleware = ( + jwtService: JwtService, + userService: UsersService, +): SocketMiddleware => { + return async (socket: AuthSocket, next) => { + const { + handshake: { + auth: { token }, + }, + } = socket + const isValidated = jwtService.verify(token) as { + id: number + } + if (isValidated.id) { + const userResult = await userService.findById(isValidated.id) + if (userResult) { + socket.user = userResult.user + next() + } else { + next({ + name: 'Unauthorizaed', + message: 'Unauthorizaed', + }) + } + } else { + next({ + name: 'Unauthorizaed', + message: 'Unauthorizaed', + }) + } + } +} diff --git a/src/sockets/sockets.module.ts b/src/sockets/sockets.module.ts new file mode 100644 index 0000000..83fe730 --- /dev/null +++ b/src/sockets/sockets.module.ts @@ -0,0 +1,4 @@ +import { Module } from '@nestjs/common' + +@Module({}) +export class SocketsModule {} diff --git a/src/users/users.resolver.ts b/src/users/users.resolver.ts index c4045f6..04618fb 100644 --- a/src/users/users.resolver.ts +++ b/src/users/users.resolver.ts @@ -1,16 +1,21 @@ import { UsersService } from 'src/users/users.service' - import { Query, Mutation, Resolver, Args } from '@nestjs/graphql' import { LoginInput, LoginOutput } from './dtos/login.dto' +import { AuthUser } from 'src/auth/auth-user.decorator' +import { User } from './entities/user.entity' +import { Role } from 'src/auth/role.decorator' +import { UserProfileOutput } from './dtos/user-profile.dto' -@Resolver() +@Resolver(() => User) export class UsersResolver { constructor(private readonly usersService: UsersService) {} - @Query(() => Boolean) - test() { - return true + @Query(() => UserProfileOutput) + @Role(['Any']) + getMe(@AuthUser() user: User): UserProfileOutput { + return { ok: true, user } } + @Mutation(() => LoginOutput) async login(@Args('input') loginInput: LoginInput) { return this.usersService.login(loginInput) diff --git a/src/workspaces/workspaces.gateway.ts b/src/workspaces/workspaces.gateway.ts index c5a9bd9..bb1a2bf 100644 --- a/src/workspaces/workspaces.gateway.ts +++ b/src/workspaces/workspaces.gateway.ts @@ -1,7 +1,11 @@ -import { SubscribeMessage, WebSocketGateway } from '@nestjs/websockets' +import { JwtService } from 'src/jwt/jwt.service' +import { UsersService } from 'src/users/users.service' +import { WSAuthMiddleware } from 'src/sockets/sockets.middleware' +import { UseFilters, Logger } from '@nestjs/common' +import { WebSocketGateway } from '@nestjs/websockets' import { ConnectedSocket, - MessageBody, + SubscribeMessage, WebSocketServer, } from '@nestjs/websockets/decorators' import { @@ -11,82 +15,30 @@ import { } from '@nestjs/websockets/interfaces' import { Namespace, Socket } from 'socket.io' import { getServerRoomDto } from 'src/events/dtos/gateway.dto' -import { LoggerService } from 'src/logger/logger.service' -@WebSocketGateway(3050, { +import { WsExceptionFilter } from 'src/sockets/sockets-exception.filter' + +@UseFilters(new WsExceptionFilter()) +@WebSocketGateway({ cors: { origin: '*', }, - namespace: 'workspace', + namespace: '/workspace', + transports: ['websocket'], }) export class WorkspacesGateway implements OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit { + private readonly logger = new Logger(WorkspacesGateway.name) + constructor( + private readonly usersService: UsersService, + private readonly jwtService: JwtService, + ) {} @WebSocketServer() public io: Namespace - constructor(private readonly logger: LoggerService) { - this.logger.setContext('WorkspaceGateway') - } - - @SubscribeMessage('join_room') - async joinRoom( - @ConnectedSocket() client: Socket, - @MessageBody() roomName: string, - ) { - const { nickname } = this.findCurrentClient(client) || {} - console.log(nickname) - if (!nickname) { - return { ok: false } - } - client.join(roomName) - const userList = await this.findJoinedUsers(roomName) - client.to(roomName).emit('welcome', { nickname, userList }) - this.serverRoomChange() - return { nickname, userList, ok: true } - } - - @SubscribeMessage('leave_room') - async leaveRoom( - @ConnectedSocket() client: Socket, - @MessageBody() roomName: string, - ) { - await client.leave(roomName) - const userList = await this.findJoinedUsers(roomName) - client.nsp.to(roomName).emit('leave', { userList }) - this.serverRoomChange() - return roomName - } - - @SubscribeMessage('offer') - requestRTCOffer( - @ConnectedSocket() client: Socket, - // TODO : Offer Type assertion - @MessageBody('offer') offer: any, - @MessageBody('roomName') roomName: string, - ) { - client.to(roomName).emit('offer', offer) - } - - @SubscribeMessage('answer') - sendRTCanswer( - @ConnectedSocket() client: Socket, - @MessageBody('answer') answer: string, - @MessageBody('roomName') roomName: string, - ) { - client.to(roomName).emit('answer', answer) - } - - @SubscribeMessage('ice') - requestRTCICECandidate( - @ConnectedSocket() client: Socket, - @MessageBody('ice') ice: any, - @MessageBody('roomName') roomName: string, - ) { - client.to(roomName).emit('ice', ice) - } handleConnection(@ConnectedSocket() client: Socket) { - this.logger.debug(`connected : ${client.id}`) - this.logger.debug(`namespace : ${client.nsp.name}`) + this.logger.debug(`workspace connected : ${client.id}`) + this.logger.debug(`workspace namespace : ${client.nsp.name}`) this.serverRoomChange() } @@ -96,23 +48,11 @@ export class WorkspacesGateway } async afterInit(io: Namespace) { + io.use(WSAuthMiddleware(this.jwtService, this.usersService)) const serverCount = await io.server.sockets.adapter.serverCount() this.logger.log(`serverCount : ${serverCount}`) } - private async findJoinedUsers(roomName: string) { - const socketsInCurrentRoom = await this.io.server.sockets - .in(roomName) - .fetchSockets() - return socketsInCurrentRoom.map((socket) => socket['nickname']) - } - - private findCurrentClient(client: Socket) { - return this.io.server.sockets.sockets.get(client.id) as Socket & { - nickname: string - } - } - private serverRoomChange(roomChangeArgs?: Partial) { const { isEmit } = roomChangeArgs || { isEmit: true } const { diff --git a/src/workspaces/workspaces.module.ts b/src/workspaces/workspaces.module.ts index db6ca46..2525f4b 100644 --- a/src/workspaces/workspaces.module.ts +++ b/src/workspaces/workspaces.module.ts @@ -1,7 +1,9 @@ +import { UsersModule } from './../users/users.module' import { Module } from '@nestjs/common' import { WorkspacesGateway } from './workspaces.gateway' @Module({ + imports: [UsersModule], providers: [WorkspacesGateway], }) export class WorkspacesModule {} diff --git a/webpack-hmr.config.js b/webpack-hmr.config.js new file mode 100644 index 0000000..9b08917 --- /dev/null +++ b/webpack-hmr.config.js @@ -0,0 +1,25 @@ +const nodeExternals = require('webpack-node-externals') +const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin') + +module.exports = function (options, webpack) { + return { + ...options, + entry: ['webpack/hot/poll?100', options.entry], + externals: [ + nodeExternals({ + allowlist: ['webpack/hot/poll?100'], + }), + ], + plugins: [ + ...options.plugins, + new webpack.HotModuleReplacementPlugin(), + new webpack.WatchIgnorePlugin({ + paths: [/\.js$/, /\.d\.ts$/], + }), + new RunScriptWebpackPlugin({ + name: options.output.filename, + autoRestart: false, + }), + ], + } +} diff --git a/yarn.lock b/yarn.lock index a4a8804..7194ed2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1340,6 +1340,15 @@ dependencies: "@sinonjs/commons" "^2.0.0" +"@socket.io/admin-ui@^0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@socket.io/admin-ui/-/admin-ui-0.5.1.tgz#8091ba571a5262de214b58522a3c03541de1f274" + integrity sha512-1dlGL2FGm6T+uL1e6iDvbo2eCINwvW7iVbjIblwh5kPPRM1SP8lmZrbFZf4QNJ/cqQ+JLcx49eXGM9WAB4TK7w== + dependencies: + "@types/bcryptjs" "^2.4.2" + bcryptjs "^2.4.3" + debug "~4.3.1" + "@socket.io/component-emitter@~3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" @@ -1415,6 +1424,11 @@ dependencies: "@babel/types" "^7.3.0" +"@types/bcryptjs@^2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@types/bcryptjs/-/bcryptjs-2.4.2.tgz#e3530eac9dd136bfdfb0e43df2c4c5ce1f77dfae" + integrity sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ== + "@types/body-parser@*", "@types/body-parser@1.19.2": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" @@ -2262,6 +2276,11 @@ base64id@2.0.0, base64id@~2.0.0: resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== +bcryptjs@^2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" + integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -5647,6 +5666,11 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +run-script-webpack-plugin@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/run-script-webpack-plugin/-/run-script-webpack-plugin-0.1.1.tgz#dad3114be32eb864d2160306e4d9c52a2c1cfd59" + integrity sha512-PrxBRLv1K9itDKMlootSCyGhdTU+KbKGJ2wF6/k0eyo6M0YGPC58HYbS/J/QsDiwM0t7G99WcuCqto0J7omOXA== + rxjs@6.6.7, rxjs@^6.6.0: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" @@ -6479,7 +6503,7 @@ 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== -webpack-node-externals@3.0.0: +webpack-node-externals@3.0.0, 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" integrity sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ== @@ -6489,7 +6513,7 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@5.75.0: +webpack@5.75.0, webpack@^5.75.0: version "5.75.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.75.0.tgz#1e440468647b2505860e94c9ff3e44d5b582c152" integrity sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==