From 338a283a07d2b958ec164a7ecaecede3da19c8d2 Mon Sep 17 00:00:00 2001 From: legonzaur Date: Wed, 9 Aug 2023 23:32:36 +0200 Subject: [PATCH] register match working --- .eslintrc.js | 2 +- .gitignore | 3 +- package-lock.json | 458 +++++++++++++++++++++++++++++++++++++++- package.json | 8 +- src/db | 2 +- src/server/server.ts | 291 ------------------------- src/server/types.ts | 54 +++++ src/serverMain.ts | 6 +- src/templates/server.ts | 142 +++++++++++++ tests/server.test.ts | 198 ++++++++--------- 10 files changed, 758 insertions(+), 406 deletions(-) delete mode 100644 src/server/server.ts create mode 100644 src/server/types.ts create mode 100644 src/templates/server.ts diff --git a/.eslintrc.js b/.eslintrc.js index 05a62aa..0d8c25a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -14,6 +14,6 @@ module.exports = { "@typescript-eslint/strict-boolean-expressions": 0, "@typescript-eslint/explicit-function-return-type": "off", }, - plugins: ["jest"], + plugins: ["jest", { transform: "typia/lib/transform" }], "jest/globals": true, }; diff --git a/.gitignore b/.gitignore index 7d81c88..fb939e4 100644 --- a/.gitignore +++ b/.gitignore @@ -102,4 +102,5 @@ dist # TernJS port file .tern-port -out/ \ No newline at end of file +out/ +src/generated \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2e0ac24..1893875 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "pg": "^8.9.0", "redis": "^4.6.5", "ts-node": "^10.9.1", + "typia": "^4.2.1", "ws": "^8.13.0" }, "devDependencies": { @@ -3251,7 +3252,6 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "devOptional": true, "dependencies": { "type-fest": "^0.21.3" }, @@ -3266,7 +3266,6 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "devOptional": true, "engines": { "node": ">=10" }, @@ -3343,6 +3342,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==" + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -3543,6 +3547,25 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -3559,6 +3582,16 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -3639,6 +3672,29 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3739,6 +3795,11 @@ "node": ">=10" } }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, "node_modules/ci-info": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", @@ -3760,6 +3821,36 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "devOptional": true }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", + "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -3774,6 +3865,14 @@ "node": ">=12" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/cluster-key-slot": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", @@ -3814,6 +3913,29 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, + "node_modules/comment-json": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.3.tgz", + "integrity": "sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3870,6 +3992,11 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -3928,6 +4055,17 @@ "node": ">=0.10.0" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-properties": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", @@ -4017,6 +4155,14 @@ "node": ">=12" } }, + "node_modules/drange": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz", + "integrity": "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==", + "engines": { + "node": ">=4" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4043,8 +4189,7 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "devOptional": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/encodeurl": { "version": "1.0.2", @@ -4588,7 +4733,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "devOptional": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -4752,6 +4896,19 @@ "node": ">= 8.0.0" } }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4810,6 +4967,28 @@ "bser": "2.1.1" } }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -5162,6 +5341,14 @@ "node": ">=8" } }, + "node_modules/has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", @@ -5253,6 +5440,25 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -5317,6 +5523,44 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/internal-slot": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", @@ -5438,7 +5682,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "devOptional": true, "engines": { "node": ">=8" } @@ -5463,6 +5706,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -5595,6 +5846,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -6417,6 +6679,21 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -6547,7 +6824,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "devOptional": true, "engines": { "node": ">=6" } @@ -6577,6 +6853,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -6712,7 +6993,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "devOptional": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -6739,6 +7019,36 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -7160,6 +7470,18 @@ } ] }, + "node_modules/randexp": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.5.3.tgz", + "integrity": "sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==", + "dependencies": { + "drange": "^1.0.2", + "ret": "^0.2.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -7188,6 +7510,19 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "devOptional": true }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/redis": { "version": "4.6.5", "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.5.tgz", @@ -7300,6 +7635,14 @@ "jsesc": "bin/jsesc" } }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7364,6 +7707,26 @@ "node": ">=10" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "engines": { + "node": ">=4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -7387,6 +7750,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -7409,6 +7780,19 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -7543,8 +7927,7 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "devOptional": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/sisteransi": { "version": "1.0.5", @@ -7622,6 +8005,14 @@ "node": ">= 0.8" } }, + "node_modules/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==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -7639,7 +8030,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "devOptional": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -7759,6 +8149,22 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -7935,6 +8341,23 @@ "node": ">=4.2.0" } }, + "node_modules/typia": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/typia/-/typia-4.2.1.tgz", + "integrity": "sha512-X2cp2w+t59wcIO7n5qQRGb0T6N0rsCxF4Dgfy7hy2IqgKL2+GrVUWHG+KvCf5CgcKmDyql+A9CgVwoxJeiZkpg==", + "dependencies": { + "commander": "^10.0.0", + "comment-json": "^4.2.3", + "inquirer": "^8.2.5", + "randexp": "^0.5.3" + }, + "bin": { + "typia": "lib/executable/typia.js" + }, + "peerDependencies": { + "typescript": ">= 4.7.4" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -8032,6 +8455,11 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -8100,6 +8528,14 @@ "makeerror": "1.0.12" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 780bf83..f52515f 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "pg": "^8.9.0", "redis": "^4.6.5", "ts-node": "^10.9.1", + "typia": "^4.2.1", "ws": "^8.13.0" }, "devDependencies": { @@ -33,11 +34,12 @@ }, "main": "out/index.js", "scripts": { - "build": "npx tsc", + "build": "npm run generate && npx tsc", "startServer": "node out/serverMain.js", "startClient": "node out/clientMain.js", "startWebsocket": "node out/websocket.js", "documentation": "redocly build-docs .\\docs\\v2.yml --output=docs\\index.html", - "test": "jest --runInBand" + "test": "jest --runInBand", + "generate": "npx typia generate --input src/templates --output src/generated --project tsconfig.json" } -} +} \ No newline at end of file diff --git a/src/db b/src/db index 4912131..c985feb 160000 --- a/src/db +++ b/src/db @@ -1 +1 @@ -Subproject commit 491213147e0e61ade18b4e4b1cc1d47be0043558 +Subproject commit c985feb7261c36cd4e6a38809f4f461e72a402c7 diff --git a/src/server/server.ts b/src/server/server.ts deleted file mode 100644 index 1e273c6..0000000 --- a/src/server/server.ts +++ /dev/null @@ -1,291 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import { Router } from 'express' -import { body, header } from 'express-validator' -import { /* CreateKillRecord, */ CheckServerToken } from '../db/db' -import { validateErrors } from '../common' - -const router = Router() - -// auth middleware -router.post( - '/*', - header('authorization') - .exists({ checkFalsy: true }) - .withMessage('Missing Authorization Header') - .bail() - .custom((e) => e.split(' ')[0].toLowerCase() === 'bearer') - .withMessage('Authorization Token is not Bearer'), - validateErrors, - (req, res, next) => { - void (async () => { - if (!req) return res.sendStatus(500) - if (!req.headers.authorization) { - console.error('no authorization header') - return res.sendStatus(403) - } - const query = await CheckServerToken( - req.headers.authorization.split(' ')[1] - ) - if (!query?.host_id) { - console.error( - `incorrect token : ${ - req.headers.authorization.split(' ')[1] - } with IP ${ - req.headers['x-forwarded-for']?.toString() ?? - req.socket.remoteAddress?.toString() ?? - '' - }` - ) - return res.sendStatus(403) - } - next() - })() - } -) - -// Route to check auth -router.post('/', (req, res) => { - res.sendStatus(200) -}) - -// const serversCount: Record = {} -// const serversTimeout: Record = {} - -// same rate limiting code as register. max 10 kills per server every 1 sec. should be enough. -/* router.post('/kill', (req, res, next) => { - let host = Number(req.query.serverId) - if (serversCount[serverId] > 2) { - return res.status(429).json({ - error: 'too many requests. Are players really making that much kills ?' - }) - } - clearTimeout(serversTimeout[serverId]) - serversCount[serverId] = - serversCount[serverId] ?? (serversCount[serverId] + 1) | 1 - serversTimeout[serverId] = setTimeout(() => { - serversCount[serverId] = 0 - }, 1000) - next() -}) */ - -router.post( - '/kill', - body([ - 'attacker_current_weapon_mods', - 'attacker_weapon_1_mods', - 'attacker_weapon_2_mods', - 'attacker_weapon_3_mods', - 'attacker_offhand_weapon_1_mods', - 'attacker_offhand_weapon_2_mods', - 'victim_current_weapon_mods', - 'victim_weapon_1_mods', - 'victim_weapon_2_mods', - 'victim_weapon_3_mods', - 'victim_offhand_weapon_1_mods', - 'victim_offhand_weapon_2_mods' - ]).customSanitizer((value) => { - if (isNaN(value) || !value) { - value = 0 - } - return value - }), - body([ - 'attacker_current_weapon_mods', - 'attacker_weapon_1_mods', - 'attacker_weapon_2_mods', - 'attacker_weapon_3_mods', - 'attacker_offhand_weapon_1_mods', - 'attacker_offhand_weapon_2_mods', - 'victim_current_weapon_mods', - 'victim_weapon_1_mods', - 'victim_weapon_2_mods', - 'victim_weapon_3_mods', - 'victim_offhand_weapon_1_mods', - 'victim_offhand_weapon_2_mods' - ]) - .toInt() - .isInt() - .withMessage('must be a valid int'), - body(['distance', 'player_count']) - .toInt() - .isInt() - .withMessage('must be a valid int'), - body(['distance', 'game_time']) - .toFloat() - .isFloat() - .withMessage('must be a valid float'), - body( - [ - 'attacker_id', - 'victim_id', - 'killstat_version', - 'match_id', - 'game_mode', - 'map', - 'attacker_name', - 'attacker_current_weapon', - 'attacker_weapon_1', - 'attacker_weapon_2', - 'attacker_weapon_3', - 'attacker_offhand_weapon_1', - 'attacker_offhand_weapon_2', - 'victim_name', - 'victim_current_weapon', - 'victim_weapon_1', - 'victim_weapon_2', - 'victim_weapon_3', - 'victim_offhand_weapon_1', - 'victim_offhand_weapon_2', - 'cause_of_death', - 'victim_titan', - 'attacker_titan' - ], - 'must be composed of a maximum of 50 valid ascii characters' - ) - .isString() - .isLength({ max: 50 }) - .isAscii(), - body('servername').isString().isLength({ max: 100 }).isAscii(), - body(['distance', 'game_time'], 'must be postitive floats').isFloat({ - min: 0 - }), - body(['cause_of_death', 'victim_id'], 'mandatory').exists().notEmpty(), - // do we need this ? - // body('servername').customSanitizer(e => e.replace(/[^a-z0-9]/gi, '')), - validateErrors, - (req, res) => { - void (async () => { - // Do we check the same thing twice ????? - if (!req.headers.authorization) return res.sendStatus(403) - const headers = req.headers.authorization.split(' ') - if (headers[0].toLowerCase() !== 'bearer') { return res.status(403).send('authorization must be token bearer') } - const query = await CheckServerToken(headers[1]) - if (!query) return res.sendStatus(403) - // const host = query.id - // const { - // servername, - // match_id, - // game_mode, - // map, - // game_time, - // player_count, - // attacker_name, - // attacker_id, - // attacker_current_weapon, - // attacker_current_weapon_mods, - // attacker_weapon_1, - // attacker_weapon_1_mods, - // attacker_weapon_2, - // attacker_weapon_2_mods, - // attacker_weapon_3, - // attacker_weapon_3_mods, - // attacker_offhand_weapon_1, - // attacker_offhand_weapon_1_mods, - // attacker_offhand_weapon_2, - // attacker_offhand_weapon_2_mods, - // victim_name, - // victim_id, - // victim_current_weapon, - // victim_current_weapon_mods, - // victim_weapon_1, - // victim_weapon_1_mods, - // victim_weapon_2, - // victim_weapon_2_mods, - // victim_weapon_3, - // victim_weapon_3_mods, - // victim_offhand_weapon_1, - // victim_offhand_weapon_1_mods, - // victim_offhand_weapon_2, - // victim_offhand_weapon_2_mods, - // cause_of_death, - // distance - // } = req.body - // CreateKillRecord({ - // servername, - // host, - // match_id, - // game_mode, - // map, - // game_time, - // player_count, - // attacker_name, - // attacker_id, - // attacker_current_weapon, - // attacker_current_weapon_mods, - // attacker_weapon_1, - // attacker_weapon_1_mods, - // attacker_weapon_2, - // attacker_weapon_2_mods, - // attacker_weapon_3, - // attacker_weapon_3_mods, - // attacker_offhand_weapon_1, - // attacker_offhand_weapon_1_mods, - // attacker_offhand_weapon_2, - // attacker_offhand_weapon_2_mods, - // victim_name, - // victim_id, - // victim_current_weapon, - // victim_current_weapon_mods, - // victim_weapon_1, - // victim_weapon_1_mods, - // victim_weapon_2, - // victim_weapon_2_mods, - // victim_weapon_3, - // victim_weapon_3_mods, - // victim_offhand_weapon_1, - // victim_offhand_weapon_1_mods, - // victim_offhand_weapon_2, - // victim_offhand_weapon_2_mods, - // cause_of_death, - // distance - // }) - // .then((e) => { - // res.sendStatus(201) - // console.log( - // `[${new Date().toLocaleString()}] Kill submitted for server ${servername}, ${attacker_name} killed ${victim_name}` - // ) - // }) - // .catch((e) => { - // res.sendStatus(500) - // console.error({ - // killstat_version, - // servername, - // host, - // match_id, - // game_mode, - // map, - // game_time, - // player_count, - // attacker_name, - // attacker_id, - // attacker_current_weapon, - // attacker_current_weapon_mods, - // attacker_weapon_1, - // attacker_weapon_1_mods, - // attacker_weapon_2, - // attacker_weapon_2_mods, - // attacker_weapon_3, - // attacker_weapon_3_mods, - // attacker_offhand_weapon_1, - // attacker_offhand_weapon_2, - // victim_name, - // victim_id, - // victim_current_weapon, - // victim_current_weapon_mods, - // victim_weapon_1, - // victim_weapon_1_mods, - // victim_weapon_2, - // victim_weapon_2_mods, - // victim_weapon_3, - // victim_weapon_3_mods, - // victim_offhand_weapon_1, - // victim_offhand_weapon_2, - // cause_of_death, - // distance - // }) - // console.error(e) - // }) - })() - } -) -export default router diff --git a/src/server/types.ts b/src/server/types.ts new file mode 100644 index 0000000..f0f406f --- /dev/null +++ b/src/server/types.ts @@ -0,0 +1,54 @@ +import { RequestHandler, Request } from "express"; +import typia from "typia"; + +type WeaponKillData = { + name: string; + mods: number; +}; + +type PlayerKillData = { + velocity: number; + name: string; + loadout: { + ordnance: WeaponKillData; + secondary: WeaponKillData; + primary: WeaponKillData; + tactical: WeaponKillData; + anti_titan: WeaponKillData; + }; + current_weapon: WeaponKillData; + state: string; + titan: string | null; + id: number | bigint; + cloaked: boolean; +}; + +export type MatchData = { + server_name: string; + game_map: string; + gamemode: string; + air_accel: boolean; +}; + +export type KillData = { + game_time: number; + player_count: number; + match_id: number; + victim: PlayerKillData; + attacker: PlayerKillData; + distance: number; + cause_of_death: string; +}; + +type RequestBody = Request<{}, {}, T>; + +export const validateBody = + (checker: (input: T) => typia.IValidation): RequestHandler => + (req, res, next) => { + const result: typia.IValidation = checker(req.body); + if (!result.success) { + res.status(400).send({ errors: result.errors }); + } else { + next(); + } + }; diff --git a/src/serverMain.ts b/src/serverMain.ts index 4b9693a..9f8d343 100644 --- a/src/serverMain.ts +++ b/src/serverMain.ts @@ -1,8 +1,12 @@ +// Typed routes from https://urosstok.com/blog/typed-routes-in-express + + + import * as dotenv from 'dotenv' import express from 'express' import cors from 'cors' import { dbReady } from './db/db' -import server from './server/server' +import server from './generated/server' dotenv.config() const app = express() diff --git a/src/templates/server.ts b/src/templates/server.ts new file mode 100644 index 0000000..971019c --- /dev/null +++ b/src/templates/server.ts @@ -0,0 +1,142 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { Router, Request, Response } from "express"; +import { header } from "express-validator"; +import db, { /* CreateKillRecord, */ CheckServerToken } from "../db/db"; +import { validateErrors } from "../common"; +import { KillData, MatchData, validateBody } from "../server/types"; +import typia from "typia"; + +const router = Router(); + +// auth middleware +router.post( + "/*", + header("authorization") + .exists({ checkFalsy: true }) + .withMessage("Missing Authorization Header") + .bail() + .custom((e) => e.split(" ")[0].toLowerCase() === "bearer") + .withMessage("Authorization Token is not Bearer"), + validateErrors, + (req, res, next) => { + void (async () => { + if (!req.headers.authorization) { + return res.sendStatus(401); + } + const query = await CheckServerToken( + req.headers.authorization.split(" ")[1] + ); + if (!query?.host_id) { + console.error( + `incorrect token : ${ + req.headers.authorization.split(" ")[1] + } with IP ${ + req.headers["x-forwarded-for"]?.toString() ?? + req.socket.remoteAddress?.toString() ?? + "" + }` + ); + return res.status(401).send({ + errors: [ + { + msg: "Incorrect Token", + param: "authorization", + location: "headers", + }, + ], + }); + } + res.locals.host_id = query.host_id; + next(); + })(); + } +); + +// Route to check auth +router.post("/", (req, res) => { + res.sendStatus(200); +}); + +// const serversCount: Record = {} +// const serversTimeout: Record = {} + +// same rate limiting code as register. max 10 kills per server every 1 sec. should be enough. +/* router.post('/kill', (req, res, next) => { + let host = Number(req.query.serverId) + if (serversCount[serverId] > 2) { + return res.status(429).json({ + error: 'too many requests. Are players really making that much kills ?' + }) + } + clearTimeout(serversTimeout[serverId]) + serversCount[serverId] = + serversCount[serverId] ?? (serversCount[serverId] + 1) | 1 + serversTimeout[serverId] = setTimeout(() => { + serversCount[serverId] = 0 + }, 1000) + next() +}) */ + +type RequestBody = Request<{}, {}, T>; + +router.post( + "/kill", + validateBody(typia.createValidate()), + (req: RequestBody, res: Response) => { + void (async () => { + const host_id = res.locals.host_id; + const { match_id } = req.body; + const match = await db + .selectFrom("ToneAPI_v3.match") + .select(["ToneAPI_v3.match.host_id", "ToneAPI_v3.match.match_id"]) + .where("ToneAPI_v3.match.host_id", "=", host_id) + .where("ToneAPI_v3.match.match_id", "=", match_id) + .executeTakeFirst(); + if (!match) { + res + .status(403) + .send({ + errors: [ + { + msg: "Match does not exists", + param: "match_id", + location: "body", + }, + ], + }); + return; + } + req.body; + })(); + } +); + +router.post( + "/match", + validateBody(typia.createValidate()), + (req: RequestBody, res: Response) => { + void (async () => { + const host_id = res.locals.host_id; + const { air_accel, server_name, game_map, gamemode } = req.body; + const server = await db + .selectFrom("ToneAPI_v3.server") + .selectAll() + .where("ToneAPI_v3.server.host_id", "=", host_id) + .where("ToneAPI_v3.server.server_name", "=", server_name) + .executeTakeFirst(); + if (!server) { + await db + .insertInto("ToneAPI_v3.server") + .values({ host_id, server_name }) + .execute(); + } + const match = await db + .insertInto("ToneAPI_v3.match") + .values({ air_accel, server_name, game_map, gamemode, host_id }) + .executeTakeFirst(); + res.status(201).send({ match: match.insertId }); + })(); + } +); + +export default router; diff --git a/tests/server.test.ts b/tests/server.test.ts index 9eccf27..18e5ed9 100644 --- a/tests/server.test.ts +++ b/tests/server.test.ts @@ -2,10 +2,93 @@ import { afterAll, beforeAll, describe, expect, test } from '@jest/globals' import serverMain from '../src/serverMain' import db from "../src/db/db" import * as dotenv from 'dotenv' +import {type KillData} from '../src/server/types' dotenv.config() let listenServer +const headers = { + "Content-Type": "application/json", + 'Authorization': `Bearer ${Buffer.from(process.env.SERVERAUTH_TOKEN + '').toString('base64')}` +} +const testMatch = { air_accel:false, server_name:Math.floor(Math.random()*100).toString(), game_map:"testMap", gamemode:"test" } +const testKill = { + "game_time": 22.616668701171876, + "player_count": 1, + "match_id": 1, + "victim": { + "velocity": 0.0, + "name": "Legonzaur", + "loadout": { + "ordnance": { + "name": "mp_weapon_satchel", + "mods": 0 + }, + "secondary": { + "name": "mp_weapon_wingman", + "mods": 140 + }, + "primary": { + "name": "mp_weapon_sniper", + "mods": 1168 + }, + "tactical": { + "name": "mp_ability_grapple", + "mods": 8 + }, + "anti_titan": { + "name": "mp_weapon_defender", + "mods": 134 + } + }, + "current_weapon": { + "name": "mp_weapon_sniper", + "mods": 1168 + }, + "state": "OnGround", + "titan": "null", + "id": 1005930844007n, + "cloaked": false + }, + "attacker": { + "velocity": 0.0, + "name": "Legonzaur", + "loadout": { + "ordnance": { + "name": "mp_weapon_satchel", + "mods": 0 + }, + "secondary": { + "name": "mp_weapon_wingman", + "mods": 140 + }, + "primary": { + "name": "mp_weapon_sniper", + "mods": 1168 + }, + "tactical": { + "name": "mp_ability_grapple", + "mods": 8 + }, + "anti_titan": { + "name": "mp_weapon_defender", + "mods": 134 + } + }, + "current_weapon": { + "name": "mp_weapon_sniper", + "mods": 1168 + }, + "state": "OnGround", + "titan": "null", + "id": 1005930844007n, + "cloaked": false + }, + "distance": 0.0, + "cause_of_death": "mp_weapon_satchel" +} as KillData + + beforeAll(async () => { listenServer = await serverMain; }) @@ -46,69 +129,30 @@ describe('server', () => { expect(response2.status).toBe(403) }) - test('good auth prefetch', async () => { const response = await fetch(`http://127.0.0.1:3001/`, { method: "POST", // *GET, POST, PUT, DELETE, etc. credentials: "same-origin", // include, *same-origin, omit - headers: { - "Content-Type": "application/json", - 'Authorization': `Bearer ${Buffer.from('' + process.env.SERVERAUTH_TOKEN).toString('base64')}` - } + headers }); expect(response.status).toBe(200) }) + test('register a match', async () => { + const response = await fetch(`http://127.0.0.1:3001/match`, { + method: "POST", + headers, + body: JSON.stringify(testMatch), + }); + expect(await response.json()).toHaveProperty("match") + expect(response.status).toBe(201) + }) + test('register a kill', async () => { - const data = { - servername: 'testserver', - attacker_weapon_1_mods: 0, - victim_id: '0', - victim_name: 'TestVictim', - victim_offhand_weapon_2: 'offhand_weapon_test', - victim_offhand_weapon_2_mods: 0, - victim_weapon_3_mods: 0, - attacker_weapon_2_mods: 0, - attacker_offhand_weapon_1: 'offhand_weapon_test', - attacker_offhand_weapon_1_mods: 0, - attacker_weapon_3_mods: 0, - attacker_offhand_weapon_2: 'offhand_weapon_test', - attacker_offhand_weapon_2_mods: 0, - victim_offhand_weapon_1: 'offhand_weapon_test', - victim_offhand_weapon_1_mods: 0, - attacker_weapon_3: 'defender', - killstat_version: 'ks_3.0.0', - attacker_weapon_1: 'smr', - match_id: '31b1f34d', - distance: 0, - victim_current_weapon: 'smr', - cause_of_death: 'smr', - victim_weapon_2_mods: 0, - victim_current_weapon_mods: 0, - attacker_current_weapon_mods: 0, - game_time: 377.799, - player_count: 1, - attacker_current_weapon: 'smr', - attacker_id: '1', - game_mode: 'tdm', - map: 'thaw', - attacker_weapon_2: 'autopistol', - victim_weapon_1: 'smr', - victim_weapon_2: 'autopistol', - victim_weapon_1_mods: 0, - victim_weapon_3: 'defender', - attacker_name: 'TestAttacker', - victim_titan: 'null', - attacker_titan: 'null' - } const response = await fetch(`http://127.0.0.1:3001/kill`, { - method: "POST", // *GET, POST, PUT, DELETE, etc. - credentials: "same-origin", // include, *same-origin, omit - headers: { - "Content-Type": "application/json", - 'Authorization': `Bearer ${Buffer.from(process.env.SERVERAUTH_TOKEN + '').toString('base64')}` - }, - body: JSON.stringify(data), // body data type must match "Content-Type" header + method: "POST", + headers, + body: JSON.stringify(testKill), }); console.log(await response.text()) expect(response.status).toBe(201) @@ -116,47 +160,7 @@ describe('server', () => { test('register a kill with missing data', async () => { - const data = { - servername: 'testserver', - attacker_weapon_1_mods: 0, - victim_id: '0', - victim_name: 'TestVictim', - victim_offhand_weapon_2: 'null', - victim_offhand_weapon_2_mods: 0, - victim_weapon_3_mods: 0, - attacker_weapon_2_mods: NaN, - attacker_offhand_weapon_1: 'null', - attacker_offhand_weapon_1_mods: 0, - attacker_weapon_3_mods: NaN, - attacker_offhand_weapon_2: 'null', - attacker_offhand_weapon_2_mods: NaN, - victim_offhand_weapon_1: 'offhand_weapon_test', - victim_offhand_weapon_1_mods: 0, - attacker_weapon_3: 'defender', - killstat_version: 'ks_3.0.0', - attacker_weapon_1: 'smr', - match_id: '31b1f34d', - distance: 0, - victim_current_weapon: 'smr', - cause_of_death: 'smr', - victim_weapon_2_mods: 0, - victim_current_weapon_mods: 0, - attacker_current_weapon_mods: 0, - game_time: 377.799, - player_count: 1, - attacker_current_weapon: 'smr', - attacker_id: '1', - game_mode: 'tdm', - map: 'thaw', - attacker_weapon_2: 'autopistol', - victim_weapon_1: 'null', - victim_weapon_2: 'autopistol', - victim_weapon_1_mods: 0, - victim_weapon_3: 'defender', - attacker_name: 'TestAttacker', - victim_titan: 'null', - attacker_titan: 'null' - } + const data = testKill const response = await fetch(`http://127.0.0.1:3001/kill`, { method: "POST", // *GET, POST, PUT, DELETE, etc. credentials: "same-origin", // include, *same-origin, omit @@ -164,17 +168,17 @@ describe('server', () => { "Content-Type": "application/json", 'Authorization': `Bearer ${Buffer.from(process.env.SERVERAUTH_TOKEN + '').toString('base64')}` }, - body: JSON.stringify(data), // body data type must match "Content-Type" header + body: JSON.stringify(data), }); expect(response.status).toBe(201) }) }) afterAll((done) => { - db.deleteFrom('kill').where('attacker_id', '=', '0').orWhere('attacker_id', '=', '1').execute().then(() => { + // db.deleteFrom('kill').where('attacker_id', '=', 0n).orWhere('attacker_id', '=', 1n).execute().then(() => { listenServer.close(async () => { await db.destroy() done() }) - }) + // }) })