mirror of
https://github.com/Infisical/infisical.git
synced 2025-03-25 14:05:03 +00:00
Merge pull request #152 from Zamion101/feat/error-handling
Refactoring backend codebase to use central error handling and logging
This commit is contained in:
2
backend/environment.d.ts
vendored
2
backend/environment.d.ts
vendored
@ -14,6 +14,8 @@ declare global {
|
||||
JWT_SIGNUP_SECRET: string;
|
||||
MONGO_URL: string;
|
||||
NODE_ENV: 'development' | 'staging' | 'testing' | 'production';
|
||||
VERBOSE_ERROR_OUTPUT: string;
|
||||
LOKI_HOST: string;
|
||||
CLIENT_ID_HEROKU: string;
|
||||
CLIENT_ID_VERCEL: string;
|
||||
CLIENT_ID_NETLIFY: string;
|
||||
|
441
backend/package-lock.json
generated
441
backend/package-lock.json
generated
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "infisical-api",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
@ -12957,6 +12957,11 @@
|
||||
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
|
||||
"dev": true
|
||||
},
|
||||
"@colors/colors": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
|
||||
"integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="
|
||||
},
|
||||
"@cspotcode/source-map-support": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||
@ -12966,6 +12971,16 @@
|
||||
"@jridgewell/trace-mapping": "0.3.9"
|
||||
}
|
||||
},
|
||||
"@dabh/diagnostics": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
|
||||
"integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
|
||||
"requires": {
|
||||
"colorspace": "1.1.x",
|
||||
"enabled": "2.0.x",
|
||||
"kuler": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@eslint/eslintrc": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
|
||||
@ -13413,6 +13428,84 @@
|
||||
"maxmind": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"@napi-rs/snappy-android-arm-eabi": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-android-arm-eabi/-/snappy-android-arm-eabi-7.1.1.tgz",
|
||||
"integrity": "sha512-NKd/ztuVEgQaAaNVQ5zZaCB9VV+7+uBXBHqhaE5iSapQhLc41szTlT0s68FCee75OoT3vhqdA6Jp5TrzZ2WOaw==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-android-arm64": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-android-arm64/-/snappy-android-arm64-7.1.1.tgz",
|
||||
"integrity": "sha512-DktruMAO0K0toTnxNHg2GWNIAPJqdvIchCsdsRaKyuEnG101qBg0mYiRCAhxHgbT6RJlOGbUPKkbA9KKRhEJUg==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-darwin-arm64": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-arm64/-/snappy-darwin-arm64-7.1.1.tgz",
|
||||
"integrity": "sha512-3LZyoAw3Qa5F7sCCTkSkhmGlydwUKU6L3Jl46eKHO2Ctm8Gcjxww6T7MfwlwGZ6JqAM6d1d++WLzUZPCGXVmag==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-darwin-x64": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-x64/-/snappy-darwin-x64-7.1.1.tgz",
|
||||
"integrity": "sha512-X1D2F67bQkPwr5iSR29/RnOrLwAkB55YO6t41toABzla3mflLDpzZcakz6FokIukykf7ey31/t73v/4pbgaBkg==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-freebsd-x64": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-freebsd-x64/-/snappy-freebsd-x64-7.1.1.tgz",
|
||||
"integrity": "sha512-vSeuf+An8jFVHPAn5IbWE9hTGU9PFAaZLj/X7rKTQQtZstnDsHgWe6u4g7FHLuOdwQ8TvhcxAEpNlYIXIk4AJg==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-linux-arm-gnueabihf": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm-gnueabihf/-/snappy-linux-arm-gnueabihf-7.1.1.tgz",
|
||||
"integrity": "sha512-/yyN6QsnOs3D1+jI3SfRX+gtnD86rbixdfmgxv9g40+FrDaDTLAu/3VuZIqH02qqq/xiWbDnkO+42RGxXDzTCw==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-linux-arm64-gnu": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm64-gnu/-/snappy-linux-arm64-gnu-7.1.1.tgz",
|
||||
"integrity": "sha512-StEeUCSwUoajgrBtiCQPTkHu+0Q4QlYndghGZNdbN1zJ1ny70YzPpevaFBUyjI/eJ+FN9uICKtwTPtQNSILS5g==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-linux-arm64-musl": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm64-musl/-/snappy-linux-arm64-musl-7.1.1.tgz",
|
||||
"integrity": "sha512-jWEBRzj+lswZVYf0b5eY0fjMlBL9L9yqjmTuv2UIMjJNHPuR282LK/s3Fm9sYIXQtKkiCo5JyhmIcoghZ3v0Eg==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-linux-x64-gnu": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-x64-gnu/-/snappy-linux-x64-gnu-7.1.1.tgz",
|
||||
"integrity": "sha512-41DPoAUFAU9VNrj/96qKfStH2Xq88ZYIsSz8BlITDm2ScoeDGOGbmaWguCXU7I+bC2uKWTmUVMXKqk6tVY6LEg==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-linux-x64-musl": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-x64-musl/-/snappy-linux-x64-musl-7.1.1.tgz",
|
||||
"integrity": "sha512-xR4hzFQqVq6J8Zf6XyUVtFJBaRgDyAQYUoBsCr92tZ7gI/0RlWCV6Q6JMO/wP5CSsvyFJIAtSUXXqlzIpw0GPA==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-win32-arm64-msvc": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-arm64-msvc/-/snappy-win32-arm64-msvc-7.1.1.tgz",
|
||||
"integrity": "sha512-2mHPadctsaYtrfSV5Na8ooTdI5rflPxP1pceY4us6vbjeWrfgB+KQCuEFOHsGXqFNfsi6L9nWH8nB9swnxnSyw==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-win32-ia32-msvc": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-ia32-msvc/-/snappy-win32-ia32-msvc-7.1.1.tgz",
|
||||
"integrity": "sha512-FOMgs9W71hdgjyl3T9F7b/WEIuoryfgBqsyhtHjAaa/98R0BUHl0bOoHg8ka0b5GgnhLBHkX2Yd6VD+Si9Q2ww==",
|
||||
"optional": true
|
||||
},
|
||||
"@napi-rs/snappy-win32-x64-msvc": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-x64-msvc/-/snappy-win32-x64-msvc-7.1.1.tgz",
|
||||
"integrity": "sha512-Mu3yELySvzhBcNTVCq+hYxVh+lH3/KjoQ5HIEb3DDPoX0AGRTm3XZa+usq8pFWjl91Cgp9nWK+9lVSkCCIRaKA==",
|
||||
"optional": true
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@ -13560,6 +13653,60 @@
|
||||
"@maxmind/geoip2-node": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"@protobufjs/aspromise": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
|
||||
},
|
||||
"@protobufjs/base64": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
|
||||
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
|
||||
},
|
||||
"@protobufjs/codegen": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
|
||||
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
|
||||
},
|
||||
"@protobufjs/eventemitter": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
|
||||
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
|
||||
},
|
||||
"@protobufjs/fetch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
|
||||
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
|
||||
"requires": {
|
||||
"@protobufjs/aspromise": "^1.1.1",
|
||||
"@protobufjs/inquire": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"@protobufjs/float": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
||||
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
|
||||
},
|
||||
"@protobufjs/inquire": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
|
||||
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
|
||||
},
|
||||
"@protobufjs/path": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
||||
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
|
||||
},
|
||||
"@protobufjs/pool": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
||||
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
|
||||
},
|
||||
"@protobufjs/utf8": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
||||
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
|
||||
},
|
||||
"@sentry/node": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.19.0.tgz",
|
||||
@ -13852,6 +13999,10 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/long": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
|
||||
"integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="
|
||||
"@types/libsodium-wrappers": {
|
||||
"version": "0.7.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz",
|
||||
@ -13877,6 +14028,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/prettier": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz",
|
||||
"integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/qs": {
|
||||
"version": "6.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||
@ -14098,8 +14255,7 @@
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
||||
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
"dev": true
|
||||
},
|
||||
"acorn-walk": {
|
||||
"version": "8.2.0",
|
||||
@ -14204,6 +14360,16 @@
|
||||
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
|
||||
"dev": true
|
||||
},
|
||||
"async": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
|
||||
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
|
||||
},
|
||||
"async-exit-hook": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz",
|
||||
"integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw=="
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
@ -14414,6 +14580,11 @@
|
||||
"buffer": "^5.6.0"
|
||||
}
|
||||
},
|
||||
"btoa": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
|
||||
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="
|
||||
},
|
||||
"buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
@ -14565,6 +14736,30 @@
|
||||
"integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==",
|
||||
"dev": true
|
||||
},
|
||||
"color": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||
"integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.3",
|
||||
"color-string": "^1.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@ -14577,8 +14772,25 @@
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"color-string": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
||||
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
||||
"requires": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"colorspace": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
|
||||
"integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
|
||||
"requires": {
|
||||
"color": "^3.1.3",
|
||||
"text-hex": "1.0.x"
|
||||
}
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
@ -14846,6 +15058,11 @@
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
},
|
||||
"enabled": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
|
||||
"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
@ -15140,8 +15357,7 @@
|
||||
"express-rate-limit": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz",
|
||||
"integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA==",
|
||||
"requires": {}
|
||||
"integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA=="
|
||||
},
|
||||
"express-validator": {
|
||||
"version": "6.14.2",
|
||||
@ -15233,6 +15449,11 @@
|
||||
"bser": "2.1.1"
|
||||
}
|
||||
},
|
||||
"fecha": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
|
||||
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
|
||||
},
|
||||
"file-entry-cache": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||
@ -15311,6 +15532,11 @@
|
||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"fn.name": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
|
||||
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
@ -15711,8 +15937,7 @@
|
||||
"is-stream": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="
|
||||
},
|
||||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
@ -16018,8 +16243,7 @@
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
|
||||
"integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
"dev": true
|
||||
},
|
||||
"jest-regex-util": {
|
||||
"version": "29.2.0",
|
||||
@ -16129,6 +16353,7 @@
|
||||
"@jest/transform": "^29.3.1",
|
||||
"@jest/types": "^29.3.1",
|
||||
"@types/babel__traverse": "^7.0.6",
|
||||
"@types/prettier": "^2.1.5",
|
||||
"babel-preset-current-node-syntax": "^1.0.0",
|
||||
"chalk": "^4.0.0",
|
||||
"expect": "^29.3.1",
|
||||
@ -16336,6 +16561,11 @@
|
||||
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
|
||||
"dev": true
|
||||
},
|
||||
"kuler": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
||||
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
|
||||
},
|
||||
"leven": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||
@ -16397,10 +16627,27 @@
|
||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"lru_map": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz",
|
||||
"integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ=="
|
||||
"lodash.once": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
|
||||
},
|
||||
"logform": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/logform/-/logform-2.4.2.tgz",
|
||||
"integrity": "sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw==",
|
||||
"requires": {
|
||||
"@colors/colors": "1.5.0",
|
||||
"fecha": "^4.2.0",
|
||||
"ms": "^2.1.1",
|
||||
"safe-stable-stringify": "^2.3.1",
|
||||
"triple-beam": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"long": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
||||
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
@ -16410,6 +16657,11 @@
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"lru_map": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz",
|
||||
"integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ=="
|
||||
},
|
||||
"make-dir": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||
@ -18393,14 +18645,6 @@
|
||||
"minipass": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.3",
|
||||
"bundled": true,
|
||||
@ -18411,6 +18655,14 @@
|
||||
"strip-ansi": "^6.0.1"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"bundled": true,
|
||||
@ -18578,6 +18830,14 @@
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"one-time": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
|
||||
"integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
|
||||
"requires": {
|
||||
"fn.name": "1.x.x"
|
||||
}
|
||||
},
|
||||
"onetime": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
|
||||
@ -18805,6 +19065,26 @@
|
||||
"sisteransi": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"protobufjs": {
|
||||
"version": "6.11.3",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz",
|
||||
"integrity": "sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==",
|
||||
"requires": {
|
||||
"@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.1",
|
||||
"@types/node": ">=13.7.0",
|
||||
"long": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@ -18999,6 +19279,11 @@
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||
},
|
||||
"safe-stable-stringify": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz",
|
||||
"integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
@ -19124,6 +19409,21 @@
|
||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"dev": true
|
||||
},
|
||||
"simple-swizzle": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
|
||||
"requires": {
|
||||
"is-arrayish": "^0.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-arrayish": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"simple-update-notifier": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz",
|
||||
@ -19158,6 +19458,27 @@
|
||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="
|
||||
},
|
||||
"snappy": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/snappy/-/snappy-7.1.1.tgz",
|
||||
"integrity": "sha512-mL7GGPJ+WdsaFT5aR/uEqCq8cPg2VbhyifDEP7AeqIVDsAC8LBGYbZP1Qzoa2Ym84OW7JEQXqIpwqFp1EQw5BA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@napi-rs/snappy-android-arm-eabi": "7.1.1",
|
||||
"@napi-rs/snappy-android-arm64": "7.1.1",
|
||||
"@napi-rs/snappy-darwin-arm64": "7.1.1",
|
||||
"@napi-rs/snappy-darwin-x64": "7.1.1",
|
||||
"@napi-rs/snappy-freebsd-x64": "7.1.1",
|
||||
"@napi-rs/snappy-linux-arm-gnueabihf": "7.1.1",
|
||||
"@napi-rs/snappy-linux-arm64-gnu": "7.1.1",
|
||||
"@napi-rs/snappy-linux-arm64-musl": "7.1.1",
|
||||
"@napi-rs/snappy-linux-x64-gnu": "7.1.1",
|
||||
"@napi-rs/snappy-linux-x64-musl": "7.1.1",
|
||||
"@napi-rs/snappy-win32-arm64-msvc": "7.1.1",
|
||||
"@napi-rs/snappy-win32-ia32-msvc": "7.1.1",
|
||||
"@napi-rs/snappy-win32-x64-msvc": "7.1.1"
|
||||
}
|
||||
},
|
||||
"socks": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz",
|
||||
@ -19202,6 +19523,11 @@
|
||||
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
|
||||
"dev": true
|
||||
},
|
||||
"stack-trace": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
||||
"integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="
|
||||
},
|
||||
"stack-utils": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
|
||||
@ -19234,14 +19560,6 @@
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ=="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"string-length": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
|
||||
@ -19263,6 +19581,14 @@
|
||||
"strip-ansi": "^6.0.1"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
@ -19367,6 +19693,11 @@
|
||||
"minimatch": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"text-hex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
||||
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
|
||||
},
|
||||
"text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
@ -19422,6 +19753,11 @@
|
||||
"punycode": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"triple-beam": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
|
||||
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
|
||||
},
|
||||
"ts-jest": {
|
||||
"version": "29.0.3",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz",
|
||||
@ -19572,8 +19908,7 @@
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
},
|
||||
"v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
@ -19663,6 +19998,46 @@
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"winston": {
|
||||
"version": "3.8.2",
|
||||
"resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz",
|
||||
"integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==",
|
||||
"requires": {
|
||||
"@colors/colors": "1.5.0",
|
||||
"@dabh/diagnostics": "^2.0.2",
|
||||
"async": "^3.2.3",
|
||||
"is-stream": "^2.0.0",
|
||||
"logform": "^2.4.0",
|
||||
"one-time": "^1.0.0",
|
||||
"readable-stream": "^3.4.0",
|
||||
"safe-stable-stringify": "^2.3.1",
|
||||
"stack-trace": "0.0.x",
|
||||
"triple-beam": "^1.3.0",
|
||||
"winston-transport": "^4.5.0"
|
||||
}
|
||||
},
|
||||
"winston-loki": {
|
||||
"version": "6.0.6",
|
||||
"resolved": "https://registry.npmjs.org/winston-loki/-/winston-loki-6.0.6.tgz",
|
||||
"integrity": "sha512-cll+nv5T/b9uJXqca0N2WKL1JJNuJND9E6WOOAuSGkZ44L9VQ/QK9F+/5VKbv6LIP9p0nvPSOYxtACCDb/9iWw==",
|
||||
"requires": {
|
||||
"async-exit-hook": "2.0.1",
|
||||
"btoa": "^1.2.1",
|
||||
"protobufjs": "^6.8.8",
|
||||
"snappy": "7.1.1",
|
||||
"winston-transport": "^4.3.0"
|
||||
}
|
||||
},
|
||||
"winston-transport": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz",
|
||||
"integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==",
|
||||
"requires": {
|
||||
"logform": "^2.3.2",
|
||||
"readable-stream": "^3.6.0",
|
||||
"triple-beam": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"word-wrap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||
|
@ -28,7 +28,9 @@
|
||||
"stripe": "^10.7.0",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"tweetnacl-util": "^0.15.1",
|
||||
"typescript": "^4.9.3"
|
||||
"typescript": "^4.9.3",
|
||||
"winston": "^3.8.2",
|
||||
"winston-loki": "^6.0.6"
|
||||
},
|
||||
"name": "infisical-api",
|
||||
"version": "1.0.0",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import { patchRouterParam } from './utils/patchAsyncRoutes';
|
||||
import express from 'express';
|
||||
import helmet from 'helmet';
|
||||
import cors from 'cors';
|
||||
@ -29,6 +29,12 @@ import {
|
||||
integration as integrationRouter,
|
||||
integrationAuth as integrationAuthRouter
|
||||
} from './routes';
|
||||
import { getLogger } from './utils/logger';
|
||||
import { RouteNotFoundError } from './utils/errors';
|
||||
import { requestErrorHandler } from './middleware/requestErrorHandler';
|
||||
|
||||
//* Patch Async route params to handle Promise Rejections
|
||||
patchRouterParam()
|
||||
|
||||
export const app = express();
|
||||
|
||||
@ -69,6 +75,17 @@ app.use('/api/v1/stripe', stripeRouter);
|
||||
app.use('/api/v1/integration', integrationRouter);
|
||||
app.use('/api/v1/integration-auth', integrationAuthRouter);
|
||||
|
||||
|
||||
//* Handle unrouted requests and respond with proper error message as well as status code
|
||||
app.use((req, res, next)=>{
|
||||
if(res.headersSent) return next();
|
||||
next(RouteNotFoundError({message: `The requested source '(${req.method})${req.url}' was not found`}))
|
||||
})
|
||||
|
||||
//* Error Handling Middleware (must be after all routing logic)
|
||||
app.use(requestErrorHandler)
|
||||
|
||||
|
||||
export const server = app.listen(PORT, () => {
|
||||
console.log(`Listening on PORT ${[PORT]}`);
|
||||
getLogger("backend-main").info(`Server started listening at port ${PORT}`)
|
||||
});
|
||||
|
@ -10,6 +10,8 @@ const JWT_SIGNUP_LIFETIME = process.env.JWT_SIGNUP_LIFETIME! || '15m';
|
||||
const JWT_SIGNUP_SECRET = process.env.JWT_SIGNUP_SECRET!;
|
||||
const MONGO_URL = process.env.MONGO_URL!;
|
||||
const NODE_ENV = process.env.NODE_ENV! || 'production';
|
||||
const VERBOSE_ERROR_OUTPUT = process.env.VERBOSE_ERROR_OUTPUT! === 'true' && true;
|
||||
const LOKI_HOST = process.env.LOKI_HOST || undefined;
|
||||
const CLIENT_SECRET_HEROKU = process.env.CLIENT_SECRET_HEROKU!;
|
||||
const CLIENT_ID_HEROKU = process.env.CLIENT_ID_HEROKU!;
|
||||
const CLIENT_ID_VERCEL = process.env.CLIENT_ID_VERCEL!;
|
||||
@ -53,6 +55,8 @@ export {
|
||||
JWT_SIGNUP_SECRET,
|
||||
MONGO_URL,
|
||||
NODE_ENV,
|
||||
VERBOSE_ERROR_OUTPUT,
|
||||
LOKI_HOST,
|
||||
CLIENT_ID_HEROKU,
|
||||
CLIENT_ID_VERCEL,
|
||||
CLIENT_ID_NETLIFY,
|
||||
|
@ -2,18 +2,18 @@ import * as Sentry from '@sentry/node';
|
||||
import {
|
||||
Bot,
|
||||
Integration,
|
||||
IIntegration,
|
||||
IntegrationAuth,
|
||||
IIntegrationAuth
|
||||
} from '../models';
|
||||
import { exchangeCode, exchangeRefresh, syncSecrets } from '../integrations';
|
||||
import { BotService, IntegrationService } from '../services';
|
||||
import { BotService } from '../services';
|
||||
import {
|
||||
ENV_DEV,
|
||||
EVENT_PUSH_SECRETS,
|
||||
INTEGRATION_VERCEL,
|
||||
INTEGRATION_NETLIFY
|
||||
} from '../variables';
|
||||
import { UnauthorizedRequestError } from '../utils/errors';
|
||||
import RequestError from '../utils/requestError';
|
||||
|
||||
interface Update {
|
||||
workspace: string;
|
||||
@ -176,12 +176,13 @@ const syncIntegrationsHelper = async ({
|
||||
*/
|
||||
const getIntegrationAuthRefreshHelper = async ({ integrationAuthId }: { integrationAuthId: string }) => {
|
||||
let refreshToken;
|
||||
|
||||
try {
|
||||
const integrationAuth = await IntegrationAuth
|
||||
.findById(integrationAuthId)
|
||||
.select('+refreshCiphertext +refreshIV +refreshTag');
|
||||
|
||||
if (!integrationAuth) throw new Error('Failed to find integration auth');
|
||||
if (!integrationAuth) throw UnauthorizedRequestError({message: 'Failed to locate Integration Authentication credentials'});
|
||||
|
||||
refreshToken = await BotService.decryptSymmetric({
|
||||
workspaceId: integrationAuth.workspace.toString(),
|
||||
@ -193,7 +194,10 @@ const syncIntegrationsHelper = async ({
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
throw new Error('Failed to get integration refresh token');
|
||||
if(err instanceof RequestError)
|
||||
throw err
|
||||
else
|
||||
throw new Error('Failed to get integration refresh token');
|
||||
}
|
||||
|
||||
return refreshToken;
|
||||
@ -209,12 +213,13 @@ const syncIntegrationsHelper = async ({
|
||||
*/
|
||||
const getIntegrationAuthAccessHelper = async ({ integrationAuthId }: { integrationAuthId: string }) => {
|
||||
let accessToken;
|
||||
|
||||
try {
|
||||
const integrationAuth = await IntegrationAuth
|
||||
.findById(integrationAuthId)
|
||||
.select('workspace integration +accessCiphertext +accessIV +accessTag +accessExpiresAt + refreshCiphertext');
|
||||
|
||||
if (!integrationAuth) throw new Error('Failed to find integration auth');
|
||||
if (!integrationAuth) throw UnauthorizedRequestError({message: 'Failed to locate Integration Authentication credentials'});
|
||||
|
||||
accessToken = await BotService.decryptSymmetric({
|
||||
workspaceId: integrationAuth.workspace.toString(),
|
||||
@ -240,7 +245,10 @@ const getIntegrationAuthAccessHelper = async ({ integrationAuthId }: { integrati
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
throw new Error('Failed to get integration access token');
|
||||
if(err instanceof RequestError)
|
||||
throw err
|
||||
else
|
||||
throw new Error('Failed to get integration access token');
|
||||
}
|
||||
|
||||
return accessToken;
|
||||
|
@ -21,6 +21,7 @@ const validateMembership = async ({
|
||||
}) => {
|
||||
|
||||
let membership;
|
||||
//TODO: Refactor code to take advantage of using RequestError. It's possible to create new types of errors for more detailed errors
|
||||
try {
|
||||
membership = await Membership.findOne({
|
||||
user: userId,
|
||||
|
@ -53,6 +53,7 @@ const exchangeRefreshHeroku = async ({
|
||||
refreshToken: string;
|
||||
}) => {
|
||||
let accessToken;
|
||||
//TODO: Refactor code to take advantage of using RequestError. It's possible to create new types of errors for more detailed errors
|
||||
try {
|
||||
const res = await axios.post(
|
||||
INTEGRATION_HEROKU_TOKEN_URL,
|
||||
|
29
backend/src/middleware/requestErrorHandler.ts
Normal file
29
backend/src/middleware/requestErrorHandler.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { ErrorRequestHandler } from "express";
|
||||
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { InternalServerError } from "../utils/errors";
|
||||
import { getLogger } from "../utils/logger";
|
||||
import RequestError, { LogLevel } from "../utils/requestError";
|
||||
|
||||
|
||||
export const requestErrorHandler: ErrorRequestHandler = (error: RequestError|Error, req, res, next) => {
|
||||
if(res.headersSent) return next();
|
||||
//TODO: Find better way to type check for error. In current setting you need to cast type to get the functions and variables from RequestError
|
||||
if(!(error instanceof RequestError)){
|
||||
error = InternalServerError({context: {exception: error.message}, stack: error.stack})
|
||||
getLogger('backend-main').log((<RequestError>error).levelName.toLowerCase(), (<RequestError>error).message)
|
||||
}
|
||||
|
||||
//* Set Sentry user identification if req.user is populated
|
||||
if(req.user !== undefined && req.user !== null){
|
||||
Sentry.setUser({ email: req.user.email })
|
||||
}
|
||||
//* Only sent error to Sentry if LogLevel is one of the following level 'ERROR', 'EMERGENCY' or 'CRITICAL'
|
||||
//* with this we will eliminate false-positive errors like 'BadRequestError', 'UnauthorizedRequestError' and so on
|
||||
if([LogLevel.ERROR, LogLevel.EMERGENCY, LogLevel.CRITICAL].includes((<RequestError>error).level)){
|
||||
Sentry.captureException(error)
|
||||
}
|
||||
|
||||
res.status((<RequestError>error).statusCode).json((<RequestError>error).format(req))
|
||||
next()
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { User } from '../models';
|
||||
import { JWT_AUTH_SECRET } from '../config';
|
||||
import { AccountNotFoundError, BadRequestError, UnauthorizedRequestError } from '../utils/errors';
|
||||
|
||||
declare module 'jsonwebtoken' {
|
||||
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
||||
@ -20,32 +20,25 @@ declare module 'jsonwebtoken' {
|
||||
*/
|
||||
const requireAuth = async (req: Request, res: Response, next: NextFunction) => {
|
||||
// JWT authentication middleware
|
||||
try {
|
||||
if (!req.headers?.authorization)
|
||||
throw new Error('Failed to locate authorization header');
|
||||
const [ AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE ] = <[string, string]>req.headers['authorization']?.split(' ', 2) ?? [null, null]
|
||||
if(AUTH_TOKEN_TYPE === null) return next(BadRequestError({message: `Missing Authorization Header in the request header.`}))
|
||||
if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(BadRequestError({message: `The provided authentication type '${AUTH_TOKEN_TYPE}' is not supported.`}))
|
||||
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
|
||||
|
||||
const token = req.headers.authorization.split(' ')[1];
|
||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||
jwt.verify(token, JWT_AUTH_SECRET)
|
||||
);
|
||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||
jwt.verify(AUTH_TOKEN_VALUE, JWT_AUTH_SECRET)
|
||||
);
|
||||
|
||||
const user = await User.findOne({
|
||||
_id: decodedToken.userId
|
||||
}).select('+publicKey');
|
||||
const user = await User.findOne({
|
||||
_id: decodedToken.userId
|
||||
}).select('+publicKey');
|
||||
|
||||
if (!user) throw new Error('Failed to authenticate unfound user');
|
||||
if (!user?.publicKey)
|
||||
throw new Error('Failed to authenticate not fully set up account');
|
||||
if (!user) return next(AccountNotFoundError({message: 'Failed to locate User account'}))
|
||||
if (!user?.publicKey)
|
||||
return next(UnauthorizedRequestError({message: 'Unable to authenticate due to partially set up account'}))
|
||||
|
||||
req.user = user;
|
||||
return next();
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
return res.status(401).send({
|
||||
error: 'Failed to authenticate user. Try logging in'
|
||||
});
|
||||
}
|
||||
req.user = user;
|
||||
return next();
|
||||
};
|
||||
|
||||
export default requireAuth;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { Bot } from '../models';
|
||||
import { validateMembership } from '../helpers/membership';
|
||||
import { AccountNotFoundError } from '../utils/errors';
|
||||
|
||||
type req = 'params' | 'body' | 'query';
|
||||
|
||||
@ -15,30 +15,22 @@ const requireBotAuth = ({
|
||||
location?: req;
|
||||
}) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const bot = await Bot.findOne({ _id: req[location].botId });
|
||||
|
||||
if (!bot) {
|
||||
throw new Error('Failed to find bot');
|
||||
}
|
||||
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: bot.workspace.toString(),
|
||||
acceptedRoles,
|
||||
acceptedStatuses
|
||||
});
|
||||
|
||||
req.bot = bot;
|
||||
|
||||
next();
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
return res.status(401).send({
|
||||
error: 'Failed bot authorization'
|
||||
});
|
||||
const bot = await Bot.findOne({ _id: req[location].botId });
|
||||
|
||||
if (!bot) {
|
||||
return next(AccountNotFoundError({message: 'Failed to locate Bot account'}))
|
||||
}
|
||||
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: bot.workspace.toString(),
|
||||
acceptedRoles,
|
||||
acceptedStatuses
|
||||
});
|
||||
|
||||
req.bot = bot;
|
||||
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { Bot, Integration, IntegrationAuth, Membership } from '../models';
|
||||
import { Integration, IntegrationAuth } from '../models';
|
||||
import { IntegrationService } from '../services';
|
||||
import { validateMembership } from '../helpers/membership';
|
||||
import { IntegrationNotFoundError, UnauthorizedRequestError } from '../utils/errors';
|
||||
|
||||
/**
|
||||
* Validate if user on request is a member of workspace with proper roles associated
|
||||
@ -21,48 +21,40 @@ const requireIntegrationAuth = ({
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
// integration authorization middleware
|
||||
|
||||
try {
|
||||
const { integrationId } = req.params;
|
||||
const { integrationId } = req.params;
|
||||
|
||||
// validate integration accessibility
|
||||
const integration = await Integration.findOne({
|
||||
_id: integrationId
|
||||
});
|
||||
// validate integration accessibility
|
||||
const integration = await Integration.findOne({
|
||||
_id: integrationId
|
||||
});
|
||||
|
||||
if (!integration) {
|
||||
throw new Error('Failed to find integration');
|
||||
}
|
||||
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: integration.workspace.toString(),
|
||||
acceptedRoles,
|
||||
acceptedStatuses
|
||||
});
|
||||
|
||||
const integrationAuth = await IntegrationAuth.findOne({
|
||||
_id: integration.integrationAuth
|
||||
}).select(
|
||||
'+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt'
|
||||
);
|
||||
|
||||
if (!integrationAuth) {
|
||||
throw new Error('Failed to find integration authorization');
|
||||
}
|
||||
|
||||
req.integration = integration;
|
||||
req.accessToken = await IntegrationService.getIntegrationAuthAccess({
|
||||
integrationAuthId: integrationAuth._id.toString()
|
||||
});
|
||||
|
||||
return next();
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
return res.status(401).send({
|
||||
error: 'Failed integration authorization'
|
||||
});
|
||||
if (!integration) {
|
||||
return next(IntegrationNotFoundError({message: 'Failed to locate Integration'}))
|
||||
}
|
||||
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: integration.workspace.toString(),
|
||||
acceptedRoles,
|
||||
acceptedStatuses
|
||||
});
|
||||
|
||||
const integrationAuth = await IntegrationAuth.findOne({
|
||||
_id: integration.integrationAuth
|
||||
}).select(
|
||||
'+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt'
|
||||
);
|
||||
|
||||
if (!integrationAuth) {
|
||||
return next(UnauthorizedRequestError({message: 'Failed to locate Integration Authentication credentials'}))
|
||||
}
|
||||
|
||||
req.integration = integration;
|
||||
req.accessToken = await IntegrationService.getIntegrationAuthAccess({
|
||||
integrationAuthId: integrationAuth._id.toString()
|
||||
});
|
||||
|
||||
return next();
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { Request, Response, NextFunction } from 'express';
|
||||
import { IntegrationAuth } from '../models';
|
||||
import { IntegrationService } from '../services';
|
||||
import { validateMembership } from '../helpers/membership';
|
||||
import { UnauthorizedRequestError } from '../utils/errors';
|
||||
|
||||
/**
|
||||
* Validate if user on request is a member of workspace with proper roles associated
|
||||
@ -22,41 +23,33 @@ const requireIntegrationAuthorizationAuth = ({
|
||||
attachAccessToken?: boolean;
|
||||
}) => {
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const { integrationAuthId } = req.params;
|
||||
const { integrationAuthId } = req.params;
|
||||
|
||||
const integrationAuth = await IntegrationAuth.findOne({
|
||||
_id: integrationAuthId
|
||||
}).select(
|
||||
'+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt'
|
||||
);
|
||||
const integrationAuth = await IntegrationAuth.findOne({
|
||||
_id: integrationAuthId
|
||||
}).select(
|
||||
'+refreshCiphertext +refreshIV +refreshTag +accessCiphertext +accessIV +accessTag +accessExpiresAt'
|
||||
);
|
||||
|
||||
if (!integrationAuth) {
|
||||
throw new Error('Failed to find integration authorization');
|
||||
}
|
||||
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: integrationAuth.workspace.toString(),
|
||||
acceptedRoles,
|
||||
acceptedStatuses
|
||||
});
|
||||
if (!integrationAuth) {
|
||||
return next(UnauthorizedRequestError({message: 'Failed to locate Integration Authorization credentials'}))
|
||||
}
|
||||
|
||||
await validateMembership({
|
||||
userId: req.user._id.toString(),
|
||||
workspaceId: integrationAuth.workspace.toString(),
|
||||
acceptedRoles,
|
||||
acceptedStatuses
|
||||
});
|
||||
|
||||
req.integrationAuth = integrationAuth;
|
||||
if (attachAccessToken) {
|
||||
req.accessToken = await IntegrationService.getIntegrationAuthAccess({
|
||||
integrationAuthId: integrationAuth._id.toString()
|
||||
});
|
||||
}
|
||||
|
||||
return next();
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
return res.status(401).send({
|
||||
error: 'Failed (authorization) integration authorizationt'
|
||||
req.integrationAuth = integrationAuth;
|
||||
if (attachAccessToken) {
|
||||
req.accessToken = await IntegrationService.getIntegrationAuthAccess({
|
||||
integrationAuthId: integrationAuth._id.toString()
|
||||
});
|
||||
}
|
||||
|
||||
return next();
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { IOrganization, MembershipOrg } from '../models';
|
||||
import { UnauthorizedRequestError, ValidationError } from '../utils/errors';
|
||||
|
||||
/**
|
||||
* Validate if user on request is a member with proper roles for organization
|
||||
@ -19,35 +19,28 @@ const requireOrganizationAuth = ({
|
||||
return async (req: Request, res: Response, next: NextFunction) => {
|
||||
// organization authorization middleware
|
||||
|
||||
try {
|
||||
// validate organization membership
|
||||
const membershipOrg = await MembershipOrg.findOne({
|
||||
user: req.user._id,
|
||||
organization: req.params.organizationId
|
||||
}).populate<{ organization: IOrganization }>('organization');
|
||||
// validate organization membership
|
||||
const membershipOrg = await MembershipOrg.findOne({
|
||||
user: req.user._id,
|
||||
organization: req.params.organizationId
|
||||
}).populate<{ organization: IOrganization }>('organization');
|
||||
|
||||
if (!membershipOrg) {
|
||||
throw new Error('Failed to find organization membership');
|
||||
}
|
||||
|
||||
if (!acceptedRoles.includes(membershipOrg.role)) {
|
||||
throw new Error('Failed to validate organization membership role');
|
||||
}
|
||||
|
||||
if (!acceptedStatuses.includes(membershipOrg.status)) {
|
||||
throw new Error('Failed to validate organization membership status');
|
||||
}
|
||||
|
||||
req.membershipOrg = membershipOrg;
|
||||
|
||||
return next();
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
return res.status(401).send({
|
||||
error: 'Failed organization authorization'
|
||||
});
|
||||
if (!membershipOrg) {
|
||||
return next(UnauthorizedRequestError({message: "You're not a member of this Organization."}))
|
||||
}
|
||||
//TODO is this important to validate? I mean is it possible to save wrong role to database or get wrong role from databse? - Zamion101
|
||||
if (!acceptedRoles.includes(membershipOrg.role)) {
|
||||
return next(ValidationError({message: 'Failed to validate Organization Membership Role'}))
|
||||
}
|
||||
|
||||
if (!acceptedStatuses.includes(membershipOrg.status)) {
|
||||
return next(ValidationError({message: 'Failed to validate Organization Membership Status'}))
|
||||
}
|
||||
|
||||
req.membershipOrg = membershipOrg;
|
||||
|
||||
return next();
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { ServiceToken } from '../models';
|
||||
import { JWT_SERVICE_SECRET } from '../config';
|
||||
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
|
||||
|
||||
declare module 'jsonwebtoken' {
|
||||
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
||||
@ -24,33 +24,27 @@ const requireServiceTokenAuth = async (
|
||||
next: NextFunction
|
||||
) => {
|
||||
// JWT service token middleware
|
||||
try {
|
||||
if (!req.headers?.authorization)
|
||||
throw new Error('Failed to locate authorization header');
|
||||
|
||||
const [ AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE ] = <[string, string]>req.headers['authorization']?.split(' ', 2) ?? [null, null]
|
||||
if(AUTH_TOKEN_TYPE === null) return next(BadRequestError({message: `Missing Authorization Header in the request header.`}))
|
||||
//TODO: Determine what is the actual Token Type for Service Token Authentication (ex. Bearer)
|
||||
//if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(UnauthorizedRequestError({message: `The provided authentication type '${AUTH_TOKEN_TYPE}' is not supported.`}))
|
||||
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
|
||||
|
||||
const token = req.headers.authorization.split(' ')[1];
|
||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||
jwt.verify(AUTH_TOKEN_VALUE, JWT_SERVICE_SECRET)
|
||||
);
|
||||
|
||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||
jwt.verify(token, JWT_SERVICE_SECRET)
|
||||
);
|
||||
const serviceToken = await ServiceToken.findOne({
|
||||
_id: decodedToken.serviceTokenId
|
||||
})
|
||||
.populate('user', '+publicKey')
|
||||
.select('+encryptedKey +publicKey +nonce');
|
||||
|
||||
const serviceToken = await ServiceToken.findOne({
|
||||
_id: decodedToken.serviceTokenId
|
||||
})
|
||||
.populate('user', '+publicKey')
|
||||
.select('+encryptedKey +publicKey +nonce');
|
||||
if (!serviceToken) return next(UnauthorizedRequestError({message: 'The service token does not match the record in the database'}))
|
||||
|
||||
if (!serviceToken) throw new Error('Failed to find service token');
|
||||
|
||||
req.serviceToken = serviceToken;
|
||||
return next();
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
return res.status(401).send({
|
||||
error: 'Failed to authenticate service token'
|
||||
});
|
||||
}
|
||||
req.serviceToken = serviceToken;
|
||||
return next();
|
||||
};
|
||||
|
||||
export default requireServiceTokenAuth;
|
||||
|
@ -1,8 +1,8 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { User } from '../models';
|
||||
import { JWT_SIGNUP_SECRET } from '../config';
|
||||
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
|
||||
|
||||
declare module 'jsonwebtoken' {
|
||||
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
||||
@ -21,32 +21,24 @@ const requireSignupAuth = async (
|
||||
) => {
|
||||
// JWT (temporary) authentication middleware for complete signup
|
||||
|
||||
try {
|
||||
if (!req.headers?.authorization)
|
||||
throw new Error('Failed to locate authorization header');
|
||||
const [ AUTH_TOKEN_TYPE, AUTH_TOKEN_VALUE ] = <[string, string]>req.headers['authorization']?.split(' ', 2) ?? [null, null]
|
||||
if(AUTH_TOKEN_TYPE === null) return next(BadRequestError({message: `Missing Authorization Header in the request header.`}))
|
||||
if(AUTH_TOKEN_TYPE.toLowerCase() !== 'bearer') return next(BadRequestError({message: `The provided authentication type '${AUTH_TOKEN_TYPE}' is not supported.`}))
|
||||
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: 'Missing Authorization Body in the request header'}))
|
||||
|
||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||
jwt.verify(AUTH_TOKEN_VALUE, JWT_SIGNUP_SECRET)
|
||||
);
|
||||
|
||||
const token = req.headers.authorization.split(' ')[1];
|
||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||
jwt.verify(token, JWT_SIGNUP_SECRET)
|
||||
);
|
||||
const user = await User.findOne({
|
||||
_id: decodedToken.userId
|
||||
}).select('+publicKey');
|
||||
|
||||
const user = await User.findOne({
|
||||
_id: decodedToken.userId
|
||||
}).select('+publicKey');
|
||||
if (!user)
|
||||
return next(UnauthorizedRequestError({message: 'Unable to authenticate for User account completion. Try logging in again'}))
|
||||
|
||||
if (!user)
|
||||
throw new Error('Failed to temporarily authenticate unfound user');
|
||||
|
||||
req.user = user;
|
||||
return next();
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
return res.status(401).send({
|
||||
error:
|
||||
'Failed to temporarily authenticate user for complete account. Try logging in'
|
||||
});
|
||||
}
|
||||
req.user = user;
|
||||
return next();
|
||||
};
|
||||
|
||||
export default requireSignupAuth;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { validateMembership } from '../helpers/membership';
|
||||
import { UnauthorizedRequestError } from '../utils/errors';
|
||||
|
||||
type req = 'params' | 'body' | 'query';
|
||||
|
||||
@ -36,11 +36,7 @@ const requireWorkspaceAuth = ({
|
||||
|
||||
return next();
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
return res.status(401).send({
|
||||
error: 'Failed workspace authorization'
|
||||
});
|
||||
return next(UnauthorizedRequestError({message: 'Unable to authenticate workspace'}))
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { validationResult } from 'express-validator';
|
||||
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
|
||||
|
||||
/**
|
||||
* Validate intended inputs on [req] via express-validator
|
||||
@ -15,16 +15,12 @@ const validate = (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({ errors: errors.array() });
|
||||
return next(BadRequestError({context: {errors: errors.array}}))
|
||||
}
|
||||
|
||||
return next();
|
||||
} catch (err) {
|
||||
Sentry.setUser(null);
|
||||
Sentry.captureException(err);
|
||||
return res.status(401).send({
|
||||
error: "Looks like you're unauthenticated . Try logging in"
|
||||
});
|
||||
return next(UnauthorizedRequestError({message: 'Unauthenticated requests are not allowed. Try logging in'}))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5,8 +5,16 @@ import {
|
||||
POSTHOG_PROJECT_API_KEY,
|
||||
TELEMETRY_ENABLED
|
||||
} from '../config';
|
||||
import { getLogger } from '../utils/logger';
|
||||
|
||||
console.log('TELEMETRY_ENABLED: ', TELEMETRY_ENABLED);
|
||||
if(TELEMETRY_ENABLED){
|
||||
getLogger("backend-main").info([
|
||||
"",
|
||||
"Infisical collects telemetry data about general usage.",
|
||||
"The data helps us understand how the product is doing and guide our product development to create the best possible platform; it also helps us demonstrate growth for investors as we support Infisical as open-source software.",
|
||||
"To opt out of telemetry, you can set `TELEMETRY_ENABLED=false` within the environment variables",
|
||||
].join('\n'))
|
||||
}
|
||||
|
||||
let postHogClient: any;
|
||||
if (NODE_ENV === 'production' && TELEMETRY_ENABLED) {
|
||||
|
@ -1,10 +1,10 @@
|
||||
/* eslint-disable no-console */
|
||||
import mongoose from 'mongoose';
|
||||
import { getLogger } from '../utils/logger';
|
||||
|
||||
export const initDatabase = (MONGO_URL: string) => {
|
||||
mongoose
|
||||
.connect(MONGO_URL)
|
||||
.then(() => console.log('Successfully connected to DB'))
|
||||
.catch((e) => console.log('Failed to connect to DB ', e));
|
||||
.then(() => getLogger("database").info("Database connection established"))
|
||||
.catch((e) => getLogger("database").error(`Unable to establish Database connection due to the error.\n${e}`));
|
||||
return mongoose.connection;
|
||||
};
|
||||
|
@ -1,10 +1,10 @@
|
||||
/* eslint-disable no-console */
|
||||
import mongoose from 'mongoose';
|
||||
import { createTerminus } from '@godaddy/terminus';
|
||||
import { getLogger } from '../utils/logger';
|
||||
|
||||
export const setUpHealthEndpoint = <T>(server: T) => {
|
||||
const onSignal = () => {
|
||||
console.log('Server is starting clean-up');
|
||||
getLogger('backend-main').info('Server is starting clean-up');
|
||||
return Promise.all([
|
||||
new Promise((resolve) => {
|
||||
if (mongoose.connection && mongoose.connection.readyState == 1) {
|
||||
|
1
backend/src/types/express/index.d.ts
vendored
1
backend/src/types/express/index.d.ts
vendored
@ -1,5 +1,6 @@
|
||||
import * as express from 'express';
|
||||
|
||||
|
||||
// TODO: fix (any) types
|
||||
declare global {
|
||||
namespace Express {
|
||||
|
116
backend/src/utils/errors.ts
Normal file
116
backend/src/utils/errors.ts
Normal file
@ -0,0 +1,116 @@
|
||||
import RequestError, { LogLevel, RequestErrorContext } from "./requestError"
|
||||
|
||||
//* ----->[GENERAL HTTP ERRORS]<-----
|
||||
export const RouteNotFoundError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.INFO,
|
||||
statusCode: error?.statusCode ?? 404,
|
||||
type: error?.type ?? 'route_not_found',
|
||||
message: error?.message ?? 'The requested source was not found',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
export const MethodNotAllowedError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.INFO,
|
||||
statusCode: error?.statusCode ?? 405,
|
||||
type: error?.type ?? 'method_not_allowed',
|
||||
message: error?.message ?? 'The requested method is not allowed for the resource',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
export const UnauthorizedRequestError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.INFO,
|
||||
statusCode: error?.statusCode ?? 401,
|
||||
type: error?.type ?? 'unauthorized',
|
||||
message: error?.message ?? 'You are not authorized to access this resource',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
export const ForbiddenRequestError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.INFO,
|
||||
statusCode: error?.statusCode ?? 403,
|
||||
type: error?.type ?? 'forbidden',
|
||||
message: error?.message ?? 'You are not allowed to access this resource',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
export const BadRequestError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.INFO,
|
||||
statusCode: error?.statusCode ?? 400,
|
||||
type: error?.type ?? 'bad_request',
|
||||
message: error?.message ?? 'The request is invalid or cannot be served',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
export const InternalServerError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.ERROR,
|
||||
statusCode: error?.statusCode ?? 500,
|
||||
type: error?.type ?? 'internal_server_error',
|
||||
message: error?.message ?? 'The server encountered an error while processing the request',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
export const ServiceUnavailableError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.ERROR,
|
||||
statusCode: error?.statusCode ?? 503,
|
||||
type: error?.type ?? 'service_unavailable',
|
||||
message: error?.message ?? 'The service is currently unavailable. Please try again later.',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
export const ValidationError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.ERROR,
|
||||
statusCode: error?.statusCode ?? 400,
|
||||
type: error?.type ?? 'validation_error',
|
||||
message: error?.message ?? 'The request failed validation',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
//* ----->[INTEGRATION ERRORS]<-----
|
||||
export const IntegrationNotFoundError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.ERROR,
|
||||
statusCode: error?.statusCode ?? 404,
|
||||
type: error?.type ?? 'integration_not_found_error',
|
||||
message: error?.message ?? 'The requested integration was not found',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
//* ----->[WORKSPACE ERRORS]<-----
|
||||
export const WorkspaceNotFoundError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.ERROR,
|
||||
statusCode: error?.statusCode ?? 404,
|
||||
type: error?.type ?? 'workspace_not_found_error',
|
||||
message: error?.message ?? 'The requested workspace was not found',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
//* ----->[ORGANIZATION ERRORS]<-----
|
||||
export const OrganizationNotFoundError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.ERROR,
|
||||
statusCode: error?.statusCode ?? 404,
|
||||
type: error?.type ?? 'organization_not_found_error',
|
||||
message: error?.message ?? 'The requested organization was not found',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
//* ----->[ACCOUNT ERRORS]<-----
|
||||
export const AccountNotFoundError = (error?: Partial<RequestErrorContext>) => new RequestError({
|
||||
logLevel: error?.logLevel ?? LogLevel.ERROR,
|
||||
statusCode: error?.statusCode ?? 404,
|
||||
type: error?.type ?? 'account_not_found_error',
|
||||
message: error?.message ?? 'The requested account was not found',
|
||||
context: error?.context,
|
||||
stack: error?.stack
|
||||
})
|
||||
|
||||
//* ----->[MISC ERRORS]<-----
|
65
backend/src/utils/logger.ts
Normal file
65
backend/src/utils/logger.ts
Normal file
@ -0,0 +1,65 @@
|
||||
/* eslint-disable no-console */
|
||||
import { createLogger, format, transports } from 'winston';
|
||||
import LokiTransport from 'winston-loki';
|
||||
import { LOKI_HOST, NODE_ENV } from '../config';
|
||||
|
||||
const { combine, colorize, label, printf, splat, timestamp } = format;
|
||||
|
||||
const logFormat = (prefix: string) => combine(
|
||||
timestamp(),
|
||||
splat(),
|
||||
label({ label: prefix }),
|
||||
printf((info) => `${info.timestamp} ${info.label} ${info.level}: ${info.message}`)
|
||||
);
|
||||
|
||||
const createLoggerWithLabel = (level: string, label: string) => {
|
||||
const _level = level.toLowerCase() || 'info'
|
||||
//* Always add Console output to transports
|
||||
const _transports: any[] = [
|
||||
new transports.Console({
|
||||
format: combine(
|
||||
colorize(),
|
||||
logFormat(label),
|
||||
// format.json()
|
||||
)
|
||||
})
|
||||
]
|
||||
//* Add LokiTransport if it's enabled
|
||||
if(LOKI_HOST !== undefined){
|
||||
_transports.push(
|
||||
new LokiTransport({
|
||||
host: LOKI_HOST,
|
||||
handleExceptions: true,
|
||||
handleRejections: true,
|
||||
batching: true,
|
||||
level: _level,
|
||||
timeout: 30000,
|
||||
format: format.combine(
|
||||
format.json()
|
||||
),
|
||||
labels: {app: process.env.npm_package_name, version: process.env.npm_package_version, environment: NODE_ENV},
|
||||
onConnectionError: (err: Error)=> console.error('Connection error while connecting to Loki Server.\n', err)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
return createLogger({
|
||||
level: _level,
|
||||
transports: _transports,
|
||||
format: format.combine(
|
||||
logFormat(label),
|
||||
format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] })
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
const DEFAULT_LOGGERS = {
|
||||
"backend-main": createLoggerWithLabel('info', '[IFSC:backend-main]'),
|
||||
"database": createLoggerWithLabel('info', '[IFSC:database]'),
|
||||
}
|
||||
type LoggerNames = keyof typeof DEFAULT_LOGGERS
|
||||
|
||||
export const getLogger = (loggerName: LoggerNames) => {
|
||||
return DEFAULT_LOGGERS[loggerName]
|
||||
}
|
65
backend/src/utils/patchAsyncRoutes.js
Normal file
65
backend/src/utils/patchAsyncRoutes.js
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
Original work Copyright (c) 2016, Nikolay Nemshilov <nemshilov@gmail.com>
|
||||
Modified work Copyright (c) 2016, David Banham <david@banham.id.au>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
/* eslint-env node */
|
||||
const Layer = require('express/lib/router/layer');
|
||||
const Router = require('express/lib/router');
|
||||
|
||||
const last = (arr = []) => arr[arr.length - 1];
|
||||
const noop = Function.prototype;
|
||||
|
||||
function copyFnProps(oldFn, newFn) {
|
||||
Object.keys(oldFn).forEach((key) => {
|
||||
newFn[key] = oldFn[key];
|
||||
});
|
||||
return newFn;
|
||||
}
|
||||
|
||||
function wrap(fn) {
|
||||
const newFn = function newFn(...args) {
|
||||
const ret = fn.apply(this, args);
|
||||
const next = (args.length === 5 ? args[2] : last(args)) || noop;
|
||||
if (ret && ret.catch) ret.catch(err => next(err));
|
||||
return ret;
|
||||
};
|
||||
Object.defineProperty(newFn, 'length', {
|
||||
value: fn.length,
|
||||
writable: false,
|
||||
});
|
||||
return copyFnProps(fn, newFn);
|
||||
}
|
||||
|
||||
export function patchRouterParam() {
|
||||
const originalParam = Router.prototype.constructor.param;
|
||||
Router.prototype.constructor.param = function param(name, fn) {
|
||||
fn = wrap(fn);
|
||||
return originalParam.call(this, name, fn);
|
||||
};
|
||||
}
|
||||
|
||||
Object.defineProperty(Layer.prototype, 'handle', {
|
||||
enumerable: true,
|
||||
get() {
|
||||
return this.__handle;
|
||||
},
|
||||
set(fn) {
|
||||
fn = wrap(fn);
|
||||
this.__handle = fn;
|
||||
},
|
||||
});
|
113
backend/src/utils/requestError.ts
Normal file
113
backend/src/utils/requestError.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import { Request } from 'express'
|
||||
import { VERBOSE_ERROR_OUTPUT } from '../config'
|
||||
|
||||
export enum LogLevel {
|
||||
DEBUG = 100,
|
||||
INFO = 200,
|
||||
NOTICE = 250,
|
||||
WARNING = 300,
|
||||
ERROR = 400,
|
||||
CRITICAL = 500,
|
||||
ALERT = 550,
|
||||
EMERGENCY = 600,
|
||||
}
|
||||
|
||||
export type RequestErrorContext = {
|
||||
logLevel?: LogLevel,
|
||||
statusCode: number,
|
||||
type: string,
|
||||
message: string,
|
||||
context?: Record<string, unknown>,
|
||||
stack?: string|undefined
|
||||
}
|
||||
|
||||
export default class RequestError extends Error{
|
||||
|
||||
private _logLevel: LogLevel
|
||||
private _logName: string
|
||||
statusCode: number
|
||||
type: string
|
||||
context: Record<string, unknown>
|
||||
extra: Record<string, string|number|symbol>[]
|
||||
private stacktrace: string|undefined|string[]
|
||||
|
||||
constructor(
|
||||
{logLevel, statusCode, type, message, context, stack} : RequestErrorContext
|
||||
){
|
||||
super(message)
|
||||
this._logLevel = logLevel || LogLevel.INFO
|
||||
this._logName = LogLevel[this._logLevel]
|
||||
this.statusCode = statusCode
|
||||
this.type = type
|
||||
this.context = context || {}
|
||||
this.extra = []
|
||||
|
||||
if(stack) this.stack = stack
|
||||
else Error.captureStackTrace(this, this.constructor)
|
||||
this.stacktrace = this.stack?.split('\n')
|
||||
}
|
||||
|
||||
static convertFrom(error: Error) {
|
||||
//This error was not handled by error handler. Please report this incident to the staff.
|
||||
return new RequestError({
|
||||
logLevel: LogLevel.ERROR,
|
||||
statusCode: 500,
|
||||
type: 'internal_server_error',
|
||||
message: 'This error was not handled by error handler. Please report this incident to the staff',
|
||||
context: {
|
||||
message: error.message,
|
||||
name: error.name
|
||||
},
|
||||
stack: error.stack
|
||||
})
|
||||
}
|
||||
|
||||
get level(){ return this._logLevel }
|
||||
get levelName(){ return this._logName }
|
||||
|
||||
withTags(...tags: string[]|number[]){
|
||||
this.context['tags'] = Object.assign(tags, this.context['tags'])
|
||||
return this
|
||||
}
|
||||
|
||||
withExtras(...extras: Record<string, string|boolean|number>[]){
|
||||
this.extra = Object.assign(extras, this.extra)
|
||||
return this
|
||||
}
|
||||
|
||||
private _omit(obj: any, keys: string[]): typeof obj{
|
||||
const exclude = new Set(keys)
|
||||
obj = Object.fromEntries(Object.entries(obj).filter(e => !exclude.has(e[0])))
|
||||
return obj
|
||||
}
|
||||
|
||||
public format(req: Request){
|
||||
let _context = Object.assign({
|
||||
stacktrace: this.stacktrace
|
||||
}, this.context)
|
||||
|
||||
//* Omit sensitive information from context that can leak internal workings of this program if user is not developer
|
||||
if(!VERBOSE_ERROR_OUTPUT){
|
||||
_context = this._omit(_context, [
|
||||
'stacktrace',
|
||||
'exception',
|
||||
])
|
||||
}
|
||||
|
||||
const formatObject = {
|
||||
type: this.type,
|
||||
message: this.message,
|
||||
context: _context,
|
||||
level: this.level,
|
||||
level_name: this.levelName,
|
||||
status_code: this.statusCode,
|
||||
datetime_iso: new Date().toISOString(),
|
||||
application: process.env.npm_package_name || 'unknown',
|
||||
request_id: req.headers["Request-Id"],
|
||||
extra: this.extra
|
||||
}
|
||||
|
||||
return formatObject
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user