From 90fb47f720a1c79e412f3d948b4e0f5bcf035c2c Mon Sep 17 00:00:00 2001 From: Cali93 <32299095+Cali93@users.noreply.github.com> Date: Wed, 7 Feb 2024 17:23:29 +0700 Subject: [PATCH 1/2] fix(prisma-transaction): remove Promise.all in Prisma transaction --- .env.example | 2 +- .github/workflows/cd.yml | 4 +- docker-compose.yml | 8 +- package-lock.json | 464 +++++++++++++++++++++++-------------- package.json | 28 +-- prisma/schema.prisma | 29 ++- src/handlers/verify.ts | 80 +++---- src/services/prisma.ts | 229 +++++++++--------- terraform/ecs/main.tf | 2 +- terraform/ecs/variables.tf | 2 +- terraform/main.tf | 22 +- terraform/variables.tf | 2 +- tsconfig.json | 1 - 13 files changed, 504 insertions(+), 369 deletions(-) diff --git a/.env.example b/.env.example index 2d9deb7..381b279 100644 --- a/.env.example +++ b/.env.example @@ -9,4 +9,4 @@ DATABASE_URL="postgres://postgres.[YOUR_SUPABASE_PROJECT_ID]:[YOUR_DB_PASSWORD]@ REDIS_PASSWORD="authpassword" REDIS_HOST=redis REDIS_PORT=6379 -INFURA_API_KEY= +WALLETCONNECT_PROJECT_ID= diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 3cf4f5f..0eaf2c2 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -63,7 +63,7 @@ jobs: TF_VAR_redis_host: ${{ secrets.REDIS_HOST }} TF_VAR_redis_port: ${{ secrets.REDIS_PORT }} TF_VAR_redis_password: ${{ secrets.REDIS_PASSWORD }} - TF_VAR_infura_api_key: ${{ secrets.INFURA_API_KEY }} + TF_VAR_walletconnect_project_id: ${{ secrets.WALLETCONNECT_PROJECT_ID }} with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -104,7 +104,7 @@ jobs: TF_VAR_redis_host: ${{ secrets.REDIS_HOST }} TF_VAR_redis_port: ${{ secrets.REDIS_PORT }} TF_VAR_redis_password: ${{ secrets.REDIS_PASSWORD }} - TF_VAR_infura_api_key: ${{ secrets.INFURA_API_KEY }} + TF_VAR_walletconnect_project_id: ${{ secrets.WALLETCONNECT_PROJECT_ID }} with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/docker-compose.yml b/docker-compose.yml index 38d1f4a..bc06d6f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: "3" +version: '3' services: api: build: . @@ -18,7 +18,7 @@ services: REDIS_PASSWORD: ${REDIS_PASSWORD} REDIS_HOST: ${REDIS_HOST} REDIS_PORT: ${REDIS_PORT} - INFURA_API_KEY: ${INFURA_API_KEY} + WALLETCONNECT_PROJECT_ID: ${WALLETCONNECT_PROJECT_ID} depends_on: redis: condition: service_healthy @@ -28,6 +28,6 @@ services: image: redis:6.2.12 command: redis-server --requirepass ${REDIS_PASSWORD} healthcheck: - test: ["CMD", "redis-cli", "ping"] + test: ['CMD', 'redis-cli', 'ping'] ports: - - "6379:6379" + - '6379:6379' diff --git a/package-lock.json b/package-lock.json index c09d8ee..dc7c667 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,41 +9,41 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@prisma/client": "^5.3.1", - "connect-redis": "^7.1.0", + "@prisma/client": "^5.9.1", + "connect-redis": "^7.1.1", "cookie": "^0.5.0", "cors": "^2.8.5", - "dotenv": "^16.3.1", - "ethers": "^6.7.1", + "dotenv": "^16.4.1", + "ethers": "^6.10.0", "express": "^4.18.2", - "express-rate-limit": "^7.0.2", - "express-session": "^1.17.3", + "express-rate-limit": "^7.1.5", + "express-session": "^1.18.0", "ioredis": "^5.3.2", "jsonwebtoken": "^9.0.2", "siwe": "^2.1.4" }, "devDependencies": { - "@types/cookie": "^0.5.2", - "@types/cors": "^2.8.14", - "@types/express": "^4.17.18", - "@types/express-session": "^1.17.8", - "@types/jsonwebtoken": "^9.0.3", - "@types/node": "^18.14.4", + "@types/cookie": "^0.5.4", + "@types/cors": "^2.8.17", + "@types/express": "^4.17.21", + "@types/express-session": "^1.17.10", + "@types/jsonwebtoken": "^9.0.5", + "@types/node": "^18.19.14", "concurrently": "^7.6.0", - "nodemon": "^3.0.1", - "prisma": "^5.3.1", + "nodemon": "^3.0.3", + "prisma": "^5.9.1", "typescript": "^4.9.5" } }, "node_modules/@adraffy/ens-normalize": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz", - "integrity": "sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg==" + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", + "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==" }, "node_modules/@babel/runtime": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz", - "integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -57,36 +57,33 @@ "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" }, - "node_modules/@noble/hashes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", - "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/@noble/secp256k1": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", - "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, "node_modules/@prisma/client": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.3.1.tgz", - "integrity": "sha512-ArOKjHwdFZIe1cGU56oIfy7wRuTn0FfZjGuU/AjgEBOQh+4rDkB6nF+AGHP8KaVpkBIiHGPQh3IpwQ3xDMdO0Q==", + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.9.1.tgz", + "integrity": "sha512-caSOnG4kxcSkhqC/2ShV7rEoWwd3XrftokxJqOCMVvia4NYV/TPtJlS9C2os3Igxw/Qyxumj9GBQzcStzECvtQ==", "hasInstallScript": true, - "dependencies": { - "@prisma/engines-version": "5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59" - }, "engines": { "node": ">=16.13" }, @@ -99,17 +96,50 @@ } } }, + "node_modules/@prisma/debug": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.9.1.tgz", + "integrity": "sha512-yAHFSFCg8KVoL0oRUno3m60GAjsUKYUDkQ+9BA2X2JfVR3kRVSJFc/GpQ2fSORi4pSHZR9orfM4UC9OVXIFFTA==", + "devOptional": true + }, "node_modules/@prisma/engines": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.3.1.tgz", - "integrity": "sha512-6QkILNyfeeN67BNEPEtkgh3Xo2tm6D7V+UhrkBbRHqKw9CTaz/vvTP/ROwYSP/3JT2MtIutZm/EnhxUiuOPVDA==", + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.9.1.tgz", + "integrity": "sha512-gkdXmjxQ5jktxWNdDA5aZZ6R8rH74JkoKq6LD5mACSvxd2vbqWeWIOV0Py5wFC8vofOYShbt6XUeCIUmrOzOnQ==", "devOptional": true, - "hasInstallScript": true + "hasInstallScript": true, + "dependencies": { + "@prisma/debug": "5.9.1", + "@prisma/engines-version": "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64", + "@prisma/fetch-engine": "5.9.1", + "@prisma/get-platform": "5.9.1" + } }, "node_modules/@prisma/engines-version": { - "version": "5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59.tgz", - "integrity": "sha512-y5qbUi3ql2Xg7XraqcXEdMHh0MocBfnBzDn5GbV1xk23S3Mq8MGs+VjacTNiBh3dtEdUERCrUUG7Z3QaJ+h79w==" + "version": "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64.tgz", + "integrity": "sha512-HFl7275yF0FWbdcNvcSRbbu9JCBSLMcurYwvWc8WGDnpu7APxQo2ONtZrUggU3WxLxUJ2uBX+0GOFIcJeVeOOQ==", + "devOptional": true + }, + "node_modules/@prisma/fetch-engine": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.9.1.tgz", + "integrity": "sha512-l0goQOMcNVOJs1kAcwqpKq3ylvkD9F04Ioe1oJoCqmz05mw22bNAKKGWuDd3zTUoUZr97va0c/UfLNru+PDmNA==", + "devOptional": true, + "dependencies": { + "@prisma/debug": "5.9.1", + "@prisma/engines-version": "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64", + "@prisma/get-platform": "5.9.1" + } + }, + "node_modules/@prisma/get-platform": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.9.1.tgz", + "integrity": "sha512-6OQsNxTyhvG+T2Ksr8FPFpuPeL4r9u0JF0OZHUBI/Uy9SS43sPyAIutt4ZEAyqWQt104ERh70EZedkHZKsnNbg==", + "devOptional": true, + "dependencies": { + "@prisma/debug": "5.9.1" + } }, "node_modules/@spruceid/siwe-parser": { "version": "2.0.2", @@ -150,9 +180,9 @@ "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" }, "node_modules/@types/body-parser": { - "version": "1.19.3", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.3.tgz", - "integrity": "sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, "dependencies": { "@types/connect": "*", @@ -160,33 +190,33 @@ } }, "node_modules/@types/connect": { - "version": "3.4.36", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", - "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/cookie": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.2.tgz", - "integrity": "sha512-DBpRoJGKJZn7RY92dPrgoMew8xCWc2P71beqsjyhEI/Ds9mOyVmBwtekyfhpwFIVt1WrxTonFifiOZ62V8CnNA==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.4.tgz", + "integrity": "sha512-7z/eR6O859gyWIAjuvBWFzNURmf2oPBmJlfVWkwehU5nzIyjwBsTh7WMmEEV4JFnHuQ3ex4oyTvfKzcyJVDBNA==", "dev": true }, "node_modules/@types/cors": { - "version": "2.8.14", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz", - "integrity": "sha512-RXHUvNWYICtbP6s18PnOCaqToK8y14DnLd75c6HfyKf228dxy7pHNOQkxPtvXKp/hINFMDjbYzsj63nnpPMSRQ==", + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/express": { - "version": "4.17.18", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.18.tgz", - "integrity": "sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, "dependencies": { "@types/body-parser": "*", @@ -196,9 +226,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.37", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz", - "integrity": "sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==", + "version": "4.17.43", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", + "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", "dev": true, "dependencies": { "@types/node": "*", @@ -208,57 +238,60 @@ } }, "node_modules/@types/express-session": { - "version": "1.17.8", - "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.8.tgz", - "integrity": "sha512-bFF7/3wOldMn+56XyFRGY9ZzCr3JWhNSP2ajMPgTlbZR6BQOCHdAbNA9W5dMBPgMywpIP4zkmhxP6Opm/NRYMQ==", + "version": "1.17.10", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.10.tgz", + "integrity": "sha512-U32bC/s0ejXijw5MAzyaV4tuZopCh/K7fPoUDyNbsRXHvPSeymygYD1RFL99YOLhF5PNOkzswvOTRaVHdL1zMw==", "dev": true, "dependencies": { "@types/express": "*" } }, "node_modules/@types/http-errors": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz", - "integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", "dev": true }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", - "integrity": "sha512-b0jGiOgHtZ2jqdPgPnP6WLCXZk1T8p06A/vPGzUvxpFGgKMbjXJDjC5m52ErqBnIuWZFgGoIJyRdeG5AyreJjA==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz", + "integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/mime": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", - "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true }, "node_modules/@types/node": { - "version": "18.18.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.3.tgz", - "integrity": "sha512-0OVfGupTl3NBFr8+iXpfZ8NR7jfFO+P1Q+IO/q0wbo02wYkP5gy36phojeYWpLQ6WAMjl+VfmqUk2YbUfp0irA==", - "dev": true + "version": "18.19.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.14.tgz", + "integrity": "sha512-EnQ4Us2rmOS64nHDWr0XqAD8DsO6f3XR6lf9UIIrZQpUzPVdN/oPuEzfDWNHSyXLvoGgjuEm/sPwFGSSs35Wtg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/qs": { - "version": "6.9.8", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", - "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==", + "version": "6.9.11", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", + "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", "dev": true }, "node_modules/@types/range-parser": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz", - "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true }, "node_modules/@types/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.2.tgz", - "integrity": "sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw==", + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, "dependencies": { "@types/mime": "^1", @@ -266,9 +299,9 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.3.tgz", - "integrity": "sha512-yVRvFsEMrv7s0lGhzrggJjNOSmZCdgCjw9xWrPr/kNNLp6FaDfMC1KaYl3TSJ0c58bECwNBMoQrZJ8hA8E1eFg==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", "dev": true, "dependencies": { "@types/http-errors": "*", @@ -337,9 +370,9 @@ } }, "node_modules/apg-js": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/apg-js/-/apg-js-4.2.1.tgz", - "integrity": "sha512-S3unf9jb9XrhmZYC27L5yits1p/+HqN6lksrkqKEv1U0Ytu+ENkIkOMV5+iutFjBaY9JTUCDQFS1svHsy3uNZA==" + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/apg-js/-/apg-js-4.3.0.tgz", + "integrity": "sha512-8U8MULS+JocCnm11bfrVS4zxtAcE3uOiCAI21SnjDrV9LNhMSGwTGGeko3QfyK1JLWwT7KebFqJMB2puzfdFMQ==" }, "node_modules/array-flatten": { "version": "1.1.1", @@ -420,12 +453,13 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -560,9 +594,9 @@ } }, "node_modules/connect-redis": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-7.1.0.tgz", - "integrity": "sha512-UaqO1EirWjON2ENsyau7N5lbkrdYBpS6mYlXSeff/OYXsd6EGZ+SXSmNPoljL2PSua8fgjAEaldSA73PMZQ9Eg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-7.1.1.tgz", + "integrity": "sha512-M+z7alnCJiuzKa8/1qAYdGUXHYfDnLolOGAUjOioB07pP39qxjG+X9ibsud7qUBc4jMV5Mcy3ugGv8eFcgamJQ==", "engines": { "node": ">=16" }, @@ -638,6 +672,19 @@ "ms": "2.0.0" } }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/denque": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", @@ -664,9 +711,9 @@ } }, "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", + "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==", "engines": { "node": ">=12" }, @@ -701,6 +748,14 @@ "node": ">= 0.8" } }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -724,9 +779,9 @@ } }, "node_modules/ethers": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.7.1.tgz", - "integrity": "sha512-qX5kxIFMfg1i+epfgb0xF4WM7IqapIIu50pOJ17aebkxxa4BacW5jFrQRmCJpDEg2ZK2oNtR5QjrQ1WDBF29dA==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.10.0.tgz", + "integrity": "sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA==", "funding": [ { "type": "individual", @@ -738,9 +793,9 @@ } ], "dependencies": { - "@adraffy/ens-normalize": "1.9.2", - "@noble/hashes": "1.1.2", - "@noble/secp256k1": "1.7.1", + "@adraffy/ens-normalize": "1.10.0", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", "@types/node": "18.15.13", "aes-js": "4.0.0-beta.5", "tslib": "2.4.0", @@ -797,23 +852,26 @@ } }, "node_modules/express-rate-limit": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.0.2.tgz", - "integrity": "sha512-EZoojG9civtJ6GRR7vE0JErow5q/ltbIl0RGbYhrNJKwBC9/kp2HckpdAvQkkE0sRAAtFDBvILvwZSR2kQroDw==", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.1.5.tgz", + "integrity": "sha512-/iVogxu7ueadrepw1bS0X0kaRC/U0afwiYRSLg68Ts+p4Dc85Q5QKsOnPS/QUjPMHvOJQtBDrZgvkOzf8ejUYw==", "engines": { "node": ">= 16" }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, "peerDependencies": { - "express": "^4 || ^5" + "express": "4 || 5 || ^5.0.0-beta.1" } }, "node_modules/express-session": { - "version": "1.17.3", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz", - "integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", + "integrity": "sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==", "dependencies": { - "cookie": "0.4.2", - "cookie-signature": "1.0.6", + "cookie": "0.6.0", + "cookie-signature": "1.0.7", "debug": "2.6.9", "depd": "~2.0.0", "on-headers": "~1.0.2", @@ -826,13 +884,18 @@ } }, "node_modules/express-session/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } }, + "node_modules/express-session/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==" + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -893,9 +956,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -907,14 +973,18 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.3.tgz", + "integrity": "sha512-JIcZczvcMVE7AUOP+X72bh8HqHBRxFdz5PDHYtNG/lE3yk9b3KZBJlwFcTyPYjg3L4RLLmZJzvjxhaZVapxFrQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.0.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -932,12 +1002,15 @@ "node": ">= 6" } }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "engines": { - "node": ">= 0.4.0" + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { @@ -949,6 +1022,17 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", @@ -971,6 +1055,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -1295,13 +1390,13 @@ } }, "node_modules/nodemon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", - "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz", + "integrity": "sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==", "dev": true, "dependencies": { "chokidar": "^3.5.2", - "debug": "^3.2.7", + "debug": "^4", "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", @@ -1323,12 +1418,20 @@ } }, "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { - "ms": "^2.1.1" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/nodemon/node_modules/has-flag": { @@ -1341,9 +1444,9 @@ } }, "node_modules/nodemon/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "node_modules/nodemon/node_modules/supports-color": { @@ -1391,9 +1494,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1443,13 +1546,13 @@ } }, "node_modules/prisma": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.3.1.tgz", - "integrity": "sha512-Wp2msQIlMPHe+5k5Od6xnsI/WNG7UJGgFUJgqv/ygc7kOECZapcSz/iU4NIEzISs3H1W9sFLjAPbg/gOqqtB7A==", + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.9.1.tgz", + "integrity": "sha512-Hy/8KJZz0ELtkw4FnG9MS9rNWlXcJhf98Z2QMqi0QiVMoS8PzsBkpla0/Y5hTlob8F3HeECYphBjqmBxrluUrQ==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/engines": "5.3.1" + "@prisma/engines": "5.9.1" }, "bin": { "prisma": "build/index.js" @@ -1477,9 +1580,9 @@ "dev": true }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "engines": { "node": ">=6" } @@ -1560,9 +1663,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "dev": true }, "node_modules/require-directory": { @@ -1663,6 +1766,21 @@ "node": ">= 0.8.0" } }, + "node_modules/set-function-length": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "dependencies": { + "define-data-property": "^1.1.1", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.2", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -1864,6 +1982,12 @@ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", diff --git a/package.json b/package.json index e207833..d072611 100644 --- a/package.json +++ b/package.json @@ -14,29 +14,29 @@ "author": "", "license": "ISC", "dependencies": { - "@prisma/client": "^5.3.1", - "connect-redis": "^7.1.0", + "@prisma/client": "^5.9.1", + "connect-redis": "^7.1.1", "cookie": "^0.5.0", "cors": "^2.8.5", - "dotenv": "^16.3.1", - "ethers": "^6.7.1", + "dotenv": "^16.4.1", + "ethers": "^6.10.0", "express": "^4.18.2", - "express-rate-limit": "^7.0.2", - "express-session": "^1.17.3", + "express-rate-limit": "^7.1.5", + "express-session": "^1.18.0", "ioredis": "^5.3.2", "jsonwebtoken": "^9.0.2", "siwe": "^2.1.4" }, "devDependencies": { - "@types/cookie": "^0.5.2", - "@types/cors": "^2.8.14", - "@types/express": "^4.17.18", - "@types/express-session": "^1.17.8", - "@types/jsonwebtoken": "^9.0.3", - "@types/node": "^18.14.4", + "@types/cookie": "^0.5.4", + "@types/cors": "^2.8.17", + "@types/express": "^4.17.21", + "@types/express-session": "^1.17.10", + "@types/jsonwebtoken": "^9.0.5", + "@types/node": "^18.19.14", "concurrently": "^7.6.0", - "nodemon": "^3.0.1", - "prisma": "^5.3.1", + "nodemon": "^3.0.3", + "prisma": "^5.9.1", "typescript": "^4.9.5" } } diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 08f6d4c..e15acdf 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -69,6 +69,7 @@ model mfa_challenges { ip_address String @db.Inet mfa_factors mfa_factors @relation(fields: [factor_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "mfa_challenges_auth_factor_id_fkey") + @@index([created_at(sort: Desc)], map: "mfa_challenge_created_at_idx") @@schema("auth") } @@ -85,6 +86,7 @@ model mfa_factors { users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction) @@index([user_id, created_at], map: "factor_id_created_at_idx") + @@index([user_id]) @@schema("auth") } @@ -104,7 +106,8 @@ model refresh_tokens { @@index([instance_id, user_id]) @@index([parent]) @@index([session_id, revoked]) - @@index([token]) + @@index([session_id], map: "refresh_token_session_id") + @@index([updated_at(sort: Desc)]) @@schema("auth") } @@ -132,10 +135,13 @@ model saml_relay_states { from_ip_address String? @db.Inet created_at DateTime? @db.Timestamptz(6) updated_at DateTime? @db.Timestamptz(6) + flow_state_id String? @db.Uuid + flow_state flow_state? @relation(fields: [flow_state_id], references: [id], onDelete: Cascade, onUpdate: NoAction) sso_providers sso_providers @relation(fields: [sso_provider_id], references: [id], onDelete: Cascade, onUpdate: NoAction) @@index([for_email]) @@index([sso_provider_id]) + @@index([created_at(sort: Desc)]) @@schema("auth") } @@ -159,6 +165,7 @@ model sessions { @@index([user_id]) @@index([user_id, created_at], map: "user_id_created_at_idx") + @@index([not_after(sort: Desc)]) @@schema("auth") } @@ -229,6 +236,26 @@ model users { @@schema("auth") } +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model flow_state { + id String @id @db.Uuid + user_id String? @db.Uuid + auth_code String + code_challenge String + provider_type String + provider_access_token String? + provider_refresh_token String? + created_at DateTime? @db.Timestamptz(6) + updated_at DateTime? @db.Timestamptz(6) + authentication_method String + saml_relay_states saml_relay_states[] + + @@index([created_at(sort: Desc)]) + @@index([auth_code], map: "idx_auth_code") + @@index([user_id, authentication_method], map: "idx_user_id_auth_method") + @@schema("auth") +} + enum aal_level { aal1 aal2 diff --git a/src/handlers/verify.ts b/src/handlers/verify.ts index dda1dad..b20d5c5 100644 --- a/src/handlers/verify.ts +++ b/src/handlers/verify.ts @@ -1,84 +1,80 @@ -import { ethers } from "ethers"; -import { Request, Response } from "express"; -import { SiweErrorType, SiweMessage } from "siwe"; -import { createOrUpdateUser } from "../services/prisma"; +import { ethers } from 'ethers' +import { Request, Response } from 'express' +import { SiweErrorType, SiweMessage } from 'siwe' +import { createOrUpdateUser } from '../services/prisma' -const provider = new ethers.InfuraProvider( - "mainnet", - process.env.INFURA_API_KEY -); +const provider = new ethers.JsonRpcProvider( + `https://rpc.walletconnect.com/v1?chainId=eip155:1&projectId=${process.env.WALLETCONNECT_PROJECT_ID}` +) export const verifyAndSignIn = async (req: Request, res: Response) => { try { if (!req.body.message) { - res - .status(422) - .json({ message: "Expected prepareMessage object as body." }); - return; + return res.status(422).json({ message: 'Expected prepareMessage object as body.' }) } - const message = new SiweMessage(req.body.message); + const message = new SiweMessage(req.body.message) const fields = await message.verify( { signature: req.body.signature, - nonce: req.session.nonce, + nonce: req.session.nonce }, { - provider, + provider } - ); + ) - req.session.siwe = fields.data; + req.session.siwe = fields.data if (!fields.data.expirationTime) { return res.status(422).json({ - message: "Expected expirationTime to be set.", - }); + message: 'Expected expirationTime to be set.' + }) } - req.session.cookie.expires = new Date(fields.data.expirationTime); + req.session.cookie.expires = new Date(fields.data.expirationTime) - const { accessToken, refreshToken } = await createOrUpdateUser(fields.data); + const { accessToken, refreshToken } = await createOrUpdateUser(fields.data) return req.session.save(() => { return res.status(200).json({ accessToken: accessToken, - refreshToken: refreshToken, - }); - }); + refreshToken: refreshToken + }) + }) } catch (e: any) { - console.error(e); - req.session.siwe = undefined; - req.session.nonce = undefined; + console.error(e) + req.session.siwe = undefined + req.session.nonce = undefined try { switch (e) { case SiweErrorType.EXPIRED_MESSAGE: { - req.session.save(() => res.status(440).json({ message: e.message })); - break; + req.session.save(() => res.status(440).json({ message: e.message })) + break } case SiweErrorType.INVALID_SIGNATURE: { - req.session.save(() => res.status(422).json({ message: e.message })); - break; + req.session.save(() => res.status(422).json({ message: e.message })) + break } case SiweErrorType.INVALID_ADDRESS: { - req.session.save(() => res.status(422).json({ message: e.message })); - break; + req.session.save(() => res.status(422).json({ message: e.message })) + break } case SiweErrorType.NONCE_MISMATCH: { - req.session.save(() => res.status(400).json({ message: e.message })); - break; + req.session.save(() => res.status(400).json({ message: e.message })) + break } case SiweErrorType.DOMAIN_MISMATCH: { - req.session.save(() => res.status(400).json({ message: e.message })); - break; + req.session.save(() => res.status(400).json({ message: e.message })) + break } default: { - req.session.save(() => res.status(500).json({ message: e.message })); - break; + req.session.save(() => res.status(500).json({ message: e.message })) + break } } } catch (sessionError) { - console.error(`Failed to save session, ${JSON.stringify(sessionError)}`); + console.error(`Failed to save session, ${JSON.stringify(sessionError)}`) } - return; + return } -}; +} diff --git a/src/services/prisma.ts b/src/services/prisma.ts index 3fff129..24b1d59 100644 --- a/src/services/prisma.ts +++ b/src/services/prisma.ts @@ -1,14 +1,10 @@ -import { PrismaClient, users } from "@prisma/client"; -import jwt from "jsonwebtoken"; -import { SiweMessage } from "siwe"; -import { - DEFAULT_INSTANCE_ID, - SEVEN_DAYS_IN_SECONDS, - secureToken, -} from "../utils"; -import { GoTrueClaims, TPrismaTransaction } from "../utils/types"; - -const prisma = new PrismaClient(); +import { PrismaClient, users } from '@prisma/client' +import jwt from 'jsonwebtoken' +import { SiweMessage } from 'siwe' +import { DEFAULT_INSTANCE_ID, SEVEN_DAYS_IN_SECONDS, secureToken } from '../utils' +import { GoTrueClaims, TPrismaTransaction } from '../utils/types' + +const prisma = new PrismaClient() export const generateAccessToken = async ( user: users, @@ -19,17 +15,17 @@ export const generateAccessToken = async ( if (sessionId) { const session = await tx.sessions.findUnique({ where: { - id: sessionId, - }, - }); + id: sessionId + } + }) if (!session) { - throw new Error("Session not found"); + throw new Error('Session not found') } } if (!user.aud || !user.role || !sessionId) { - throw new Error("Missing user informations"); + throw new Error('Missing user informations') } const claims: GoTrueClaims = { @@ -40,157 +36,150 @@ export const generateAccessToken = async ( user_metadata: user.raw_user_meta_data, role: user.role, session_id: sessionId, - email: "", - phone: "", - }; + email: '', + phone: '' + } if (!process.env.SUPABASE_JWT_SECRET) { - throw new Error("Missing secret"); + throw new Error('Missing secret') } - const token = jwt.sign(claims, process.env.SUPABASE_JWT_SECRET); - return token; -}; + const token = jwt.sign(claims, process.env.SUPABASE_JWT_SECRET) + return token +} export async function createOrUpdateUser(siweMsg: SiweMessage) { const tokens = await prisma.$transaction(async (tx) => { const existingUser = await tx.users.findFirst({ where: { raw_user_meta_data: { - path: ["address"], - equals: siweMsg.address, + path: ['address'], + equals: siweMsg.address }, AND: { raw_user_meta_data: { - path: ["chain_id"], - equals: siweMsg.chainId.toString(), - }, - }, - }, - }); + path: ['chain_id'], + equals: siweMsg.chainId.toString() + } + } + } + }) if (existingUser) { // Check for an existing session and update the last sign in date - let [existingSession] = await Promise.all([ - tx.sessions.findFirst({ - where: { - user_id: existingUser.id, - }, - }), - tx.users.update({ - where: { - id: existingUser.id, - }, - data: { - last_sign_in_at: siweMsg.issuedAt, - }, - }), - ]); + let existingSession = await tx.sessions.findFirst({ + where: { + user_id: existingUser.id + } + }) + await tx.users.update({ + where: { + id: existingUser.id + }, + data: { + last_sign_in_at: siweMsg.issuedAt + } + }) if (!existingSession) { existingSession = await tx.sessions.create({ data: { - user_id: existingUser.id, - }, - }); + user_id: existingUser.id + } + }) } let existingIdentity = await tx.identities.findFirst({ where: { - user_id: existingUser.id, - }, - }); + user_id: existingUser.id + } + }) if (!existingIdentity) { - existingIdentity = await tx.identities.create({ + await tx.identities.create({ data: { id: existingUser.id, - provider: "eth", + provider: 'eth', user_id: existingUser.id, identity_data: { sub: existingUser.id, - address: siweMsg.address, + address: siweMsg.address }, - last_sign_in_at: siweMsg.issuedAt, - }, - }); + last_sign_in_at: siweMsg.issuedAt + } + }) } // Generate access and refresh tokens - const generatedRefreshToken = secureToken(); - const [refreshToken, accessToken] = await Promise.all([ - tx.refresh_tokens.create({ - data: { - session_id: existingSession.id, - user_id: existingUser.id, - instance_id: DEFAULT_INSTANCE_ID, - parent: "", - token: generatedRefreshToken, - }, - }), - generateAccessToken( - existingUser, - SEVEN_DAYS_IN_SECONDS, - tx, - existingSession.id - ), - ]); - - return { refreshToken: refreshToken.token, accessToken }; + const generatedRefreshToken = secureToken() + + const refreshToken = await tx.refresh_tokens.create({ + data: { + session_id: existingSession.id, + user_id: existingUser.id, + instance_id: DEFAULT_INSTANCE_ID, + parent: '', + token: generatedRefreshToken + } + }) + const accessToken = await generateAccessToken( + existingUser, + SEVEN_DAYS_IN_SECONDS, + tx, + existingSession.id + ) + + return { refreshToken: refreshToken.token, accessToken } } const newUser = await tx.users.create({ data: { - aud: "authenticated", - role: "authenticated", + aud: 'authenticated', + role: 'authenticated', email_confirmed_at: new Date().toISOString(), instance_id: DEFAULT_INSTANCE_ID, last_sign_in_at: siweMsg.issuedAt, - raw_app_meta_data: { provider: "eth", providers: ["eth"] }, + raw_app_meta_data: { provider: 'eth', providers: ['eth'] }, raw_user_meta_data: { address: siweMsg.address, chain_id: siweMsg.chainId.toString(), - namespace: "eip155", - }, - }, - }); + namespace: 'eip155' + } + } + }) - // Create the session and identity at the same time - const [session] = await Promise.all([ - tx.sessions.create({ - data: { - user_id: newUser.id, - }, - }), - tx.identities.create({ - data: { - id: newUser.id, - provider: "eth", - user_id: newUser.id, - identity_data: { - sub: newUser.id, - address: siweMsg.address, - }, - last_sign_in_at: siweMsg.issuedAt, + // Create the session and identity + const session = await tx.sessions.create({ + data: { + user_id: newUser.id + } + }) + await tx.identities.create({ + data: { + id: newUser.id, + provider: 'eth', + user_id: newUser.id, + identity_data: { + sub: newUser.id, + address: siweMsg.address }, - }), - ]); + last_sign_in_at: siweMsg.issuedAt + } + }) // Generate tokens - const generatedRefreshToken = secureToken(); - const [refreshToken, accessToken] = await Promise.all([ - tx.refresh_tokens.create({ - data: { - session_id: session.id, - user_id: newUser.id, - instance_id: DEFAULT_INSTANCE_ID, - parent: "", - token: generatedRefreshToken, - }, - }), - generateAccessToken(newUser, SEVEN_DAYS_IN_SECONDS, tx, session.id), - ]); + const generatedRefreshToken = secureToken() + const refreshToken = await tx.refresh_tokens.create({ + data: { + session_id: session.id, + user_id: newUser.id, + instance_id: DEFAULT_INSTANCE_ID, + parent: '', + token: generatedRefreshToken + } + }) + const accessToken = await generateAccessToken(newUser, SEVEN_DAYS_IN_SECONDS, tx, session.id) - return { refreshToken: refreshToken.token, accessToken }; - }); + return { refreshToken: refreshToken.token, accessToken } + }) - return tokens; + return tokens } diff --git a/terraform/ecs/main.tf b/terraform/ecs/main.tf index 13c438e..a5b5b89 100644 --- a/terraform/ecs/main.tf +++ b/terraform/ecs/main.tf @@ -75,7 +75,7 @@ resource "aws_ecs_task_definition" "app_task_definition" { { name = "REDIS_PASSWORD", value = var.redis_password }, { name = "REDIS_HOST", value = var.redis_host }, { name = "REDIS_PORT", value = var.redis_port }, - { name = "INFURA_API_KEY", value = var.infura_api_key }, + { name = "WALLETCONNECT_PROJECT_ID", value = var.walletconnect_project_id }, ], logConfiguration = { logDriver = "awslogs", diff --git a/terraform/ecs/variables.tf b/terraform/ecs/variables.tf index fc82283..8986c56 100644 --- a/terraform/ecs/variables.tf +++ b/terraform/ecs/variables.tf @@ -114,7 +114,7 @@ variable "redis_password" { sensitive = true } -variable "infura_api_key" { +variable "walletconnect_project_id" { type = string sensitive = true } diff --git a/terraform/main.tf b/terraform/main.tf index cf919e5..4e2a30c 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -84,17 +84,17 @@ module "ecs" { autoscaling_min_capacity = local.environment == "prod" ? 1 : 1 desired_count = local.environment == "prod" ? 1 : 1 - node_env = var.node_env - database_url = var.database_url - direct_url = var.direct_url - cookie_name = var.cookie_name - cookie_secret = var.cookie_secret - hcaptcha_secret = var.hcaptcha_secret - supabase_jwt_secret = var.supabase_jwt_secret - redis_host = var.redis_host - redis_port = var.redis_port - redis_password = var.redis_port - infura_api_key = var.infura_api_key + node_env = var.node_env + database_url = var.database_url + direct_url = var.direct_url + cookie_name = var.cookie_name + cookie_secret = var.cookie_secret + hcaptcha_secret = var.hcaptcha_secret + supabase_jwt_secret = var.supabase_jwt_secret + redis_host = var.redis_host + redis_port = var.redis_port + redis_password = var.redis_port + walletconnect_project_id = var.walletconnect_project_id depends_on = [module.redis_global] } diff --git a/terraform/variables.tf b/terraform/variables.tf index c73de90..3727c8f 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -66,7 +66,7 @@ variable "redis_password" { sensitive = true } -variable "infura_api_key" { +variable "walletconnect_project_id" { type = string sensitive = true } diff --git a/tsconfig.json b/tsconfig.json index 0837839..b8ffc01 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,6 @@ { "compilerOptions": { /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ From dafa309009f3422a173202258c60c8092ef57d6a Mon Sep 17 00:00:00 2001 From: Cali93 <32299095+Cali93@users.noreply.github.com> Date: Wed, 7 Feb 2024 21:31:02 +0700 Subject: [PATCH 2/2] fix(forward-error): forward 500 error and improve health check --- src/handlers/verify.ts | 2 +- src/index.ts | 13 +++++++++++-- src/services/prisma.ts | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/handlers/verify.ts b/src/handlers/verify.ts index b20d5c5..fca6b43 100644 --- a/src/handlers/verify.ts +++ b/src/handlers/verify.ts @@ -67,7 +67,7 @@ export const verifyAndSignIn = async (req: Request, res: Response) => { break } default: { - req.session.save(() => res.status(500).json({ message: e.message })) + req.session.save(() => res.status(500).json({ message: e.message ?? `${e}` })) break } } diff --git a/src/index.ts b/src/index.ts index efd4270..9bbbbb9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,7 @@ import { Redis } from 'ioredis' import { SiweMessage, generateNonce } from 'siwe' import { verifyAndSignIn } from './handlers/verify' import { captchaVerification } from './middlewares/captchaVerification' +import { PrismaClient } from '@prisma/client' dotenv.config() @@ -35,6 +36,8 @@ if (!REDIS_PASSWORD) { throw new ReferenceError('REDIS_PASSWORD missing in environment variables') } +const prismaClient = new PrismaClient() + // Initialize redis client const redisClient = new Redis({ host: REDIS_HOST ?? 'redis', @@ -106,7 +109,13 @@ const limiter = rateLimit({ app.use(limiter) app.get('/health', async function (req, res) { - return res.status(200).json({ status: 'OK' }) + try { + await prismaClient.$queryRaw`SELECT 1;` + return res.status(200).json({ status: 'OK' }) + } catch (error) { + console.error('/health -> DB connection failed') + return res.status(500).json({ status: 'NOT OK' }) + } }) app.get('/nonce', async function (req, res) { @@ -143,7 +152,7 @@ app.use((req, res, next) => { // custom error handler app.use((err: Error, req: Request, res: Response, next: NextFunction) => { - console.error(err.stack) + console.error(err) return res.status(500).json({ error: 'Something went wrong!' }) }) diff --git a/src/services/prisma.ts b/src/services/prisma.ts index 24b1d59..69fc621 100644 --- a/src/services/prisma.ts +++ b/src/services/prisma.ts @@ -25,7 +25,7 @@ export const generateAccessToken = async ( } if (!user.aud || !user.role || !sessionId) { - throw new Error('Missing user informations') + throw new Error('Missing user information') } const claims: GoTrueClaims = {