From ce96537d116e1912deb4113cb00be71f26ed831a Mon Sep 17 00:00:00 2001 From: stringsplit <77242831+nbitzz@users.noreply.github.com> Date: Tue, 21 May 2024 19:51:18 -0700 Subject: [PATCH] access api --- package-lock.json | 580 +----------------- package.json | 14 +- src/server/lib/DiscordAPI/index.ts | 1 - src/server/lib/auth.ts | 52 +- src/server/lib/middleware.ts | 47 +- src/server/lib/package.ts | 6 + src/server/lib/schemas/auth.ts | 43 ++ src/server/lib/schemas/index.ts | 3 +- src/server/routes/api.ts | 10 +- src/server/routes/api/apis.ts | 9 - src/server/routes/api/v0/authRoutes.ts | 4 +- .../routes/api/v0/{api.json => definition.ts} | 6 +- src/server/routes/api/v0/primaryApi.ts | 1 - src/server/routes/api/v1/account/access.ts | 126 ++++ .../api/v1/{account.ts => account/index.ts} | 37 +- .../routes/api/v1/{api.json => definition.ts} | 15 +- src/server/routes/api/v1/file/index.ts | 2 +- src/server/routes/api/v1/file/individual.ts | 7 +- src/server/routes/api/v1/index.ts | 2 +- .../api/web/{api.json => definition.ts} | 6 +- src/server/routes/api/web/go.ts | 1 - src/server/routes/api/web/preview.ts | 2 +- src/server/tools/cli.ts | 2 +- 23 files changed, 311 insertions(+), 665 deletions(-) create mode 100644 src/server/lib/package.ts create mode 100644 src/server/lib/schemas/auth.ts delete mode 100644 src/server/routes/api/apis.ts rename src/server/routes/api/v0/{api.json => definition.ts} (74%) create mode 100644 src/server/routes/api/v1/account/access.ts rename src/server/routes/api/v1/{account.ts => account/index.ts} (91%) rename src/server/routes/api/v1/{api.json => definition.ts} (53%) rename src/server/routes/api/web/{api.json => definition.ts} (53%) diff --git a/package-lock.json b/package-lock.json index c21765a..fae73ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,37 +10,35 @@ "license": "Unlicense", "dependencies": { "@hono/node-server": "^1.8.2", - "@types/body-parser": "^1.19.2", - "@types/express": "^4.17.14", - "@types/multer": "^1.4.7", - "@types/nodemailer": "^6.4.8", "axios": "^0.27.2", - "body-parser": "^1.20.0", "bytes": "^3.1.2", "commander": "^11.1.0", - "cookie-parser": "^1.4.6", "dotenv": "^16.0.2", - "express": "^4.18.1", "formidable": "^3.5.1", "hono": "^4.0.10", "multer": "^1.4.5-lts.1", "node-fetch": "^3.3.2", "nodemailer": "^6.9.3", - "typescript": "^5.2.2", + "range-parser": "^1.2.1", "zod": "^3.23.5" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^2.4.6", "@tsconfig/svelte": "^4.0.1", + "@types/body-parser": "^1.19.2", "@types/bytes": "^3.1.1", "@types/cookie-parser": "^1.4.3", + "@types/express": "^4.17.14", "@types/formidable": "^3.4.5", + "@types/multer": "^1.4.7", + "@types/nodemailer": "^6.4.8", "@types/range-parser": "^1.2.6", "discord-api-types": "^0.37.61", "sass": "^1.57.1", "svelte": "^3.55.1", "svelte-preprocess": "^5.1.3", "tslib": "^2.6.2", + "typescript": "^5.4.5", "vite": "^4.5.0" }, "engines": { @@ -172,6 +170,7 @@ "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -187,6 +186,7 @@ "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, "dependencies": { "@types/node": "*" } @@ -204,6 +204,7 @@ "version": "4.17.14", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "dev": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", @@ -215,6 +216,7 @@ "version": "4.17.31", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "dev": true, "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -233,12 +235,14 @@ "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true }, "node_modules/@types/multer": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, "dependencies": { "@types/express": "*" } @@ -246,12 +250,14 @@ "node_modules/@types/node": { "version": "18.7.23", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==" + "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==", + "dev": true }, "node_modules/@types/nodemailer": { "version": "6.4.8", "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.8.tgz", "integrity": "sha512-oVsJSCkqViCn8/pEu2hfjwVO+Gb3e+eTWjg3PcjeFKRItfKpKwHphQqbYmPQrlMk+op7pNNWPbsJIEthpFN/OQ==", + "dev": true, "dependencies": { "@types/node": "*" } @@ -265,34 +271,25 @@ "node_modules/@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true }, "node_modules/@types/range-parser": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.6.tgz", - "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==" + "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==", + "dev": true }, "node_modules/@types/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, "dependencies": { "@types/mime": "*", "@types/node": "*" } }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -311,11 +308,6 @@ "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -350,29 +342,6 @@ "node": ">=8" } }, - "node_modules/body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -428,18 +397,6 @@ "node": ">= 0.8" } }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -506,58 +463,6 @@ "typedarray": "^0.0.6" } }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", - "dependencies": { - "cookie": "0.4.1", - "cookie-signature": "1.0.6" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/cookie-parser/node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -571,14 +476,6 @@ "node": ">= 12" } }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -596,23 +493,6 @@ "node": ">=0.4.0" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/detect-indent": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", @@ -645,19 +525,6 @@ "node": ">=12" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/es6-promise": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", @@ -701,60 +568,6 @@ "@esbuild/win32-x64": "0.18.20" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.0", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.10.3", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -789,23 +602,6 @@ "node": ">=8" } }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -862,49 +658,12 @@ "url": "https://ko-fi.com/tunnckoCore/commissions" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -943,28 +702,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/hexoid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", @@ -981,32 +718,6 @@ "node": ">=16.0.0" } }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/immutable": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.2.tgz", @@ -1028,14 +739,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1112,30 +815,6 @@ "node": ">= 0.6" } }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -1192,11 +871,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/multer": { "version": "1.4.5-lts.1", "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", @@ -1232,14 +906,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -1300,25 +966,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1327,14 +974,6 @@ "wrappy": "1" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -1344,11 +983,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -1400,32 +1034,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -1434,20 +1042,6 @@ "node": ">= 0.6" } }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -1507,30 +1101,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "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/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, "node_modules/sander": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", @@ -1560,66 +1130,6 @@ "node": ">=12.0.0" } }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/sorcery": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", @@ -1644,14 +1154,6 @@ "node": ">=0.10.0" } }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -1781,14 +1283,6 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -1813,9 +1307,11 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -1824,35 +1320,11 @@ "node": ">=14.17" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, "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", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/vite": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", diff --git a/package.json b/package.json index af8bc38..2561648 100644 --- a/package.json +++ b/package.json @@ -19,37 +19,35 @@ }, "dependencies": { "@hono/node-server": "^1.8.2", - "@types/body-parser": "^1.19.2", - "@types/express": "^4.17.14", - "@types/multer": "^1.4.7", - "@types/nodemailer": "^6.4.8", "axios": "^0.27.2", - "body-parser": "^1.20.0", "bytes": "^3.1.2", "commander": "^11.1.0", - "cookie-parser": "^1.4.6", "dotenv": "^16.0.2", - "express": "^4.18.1", "formidable": "^3.5.1", "hono": "^4.0.10", "multer": "^1.4.5-lts.1", "node-fetch": "^3.3.2", "nodemailer": "^6.9.3", - "typescript": "^5.2.2", + "range-parser": "^1.2.1", "zod": "^3.23.5" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^2.4.6", "@tsconfig/svelte": "^4.0.1", + "@types/body-parser": "^1.19.2", "@types/bytes": "^3.1.1", "@types/cookie-parser": "^1.4.3", + "@types/express": "^4.17.14", "@types/formidable": "^3.4.5", + "@types/multer": "^1.4.7", + "@types/nodemailer": "^6.4.8", "@types/range-parser": "^1.2.6", "discord-api-types": "^0.37.61", "sass": "^1.57.1", "svelte": "^3.55.1", "svelte-preprocess": "^5.1.3", "tslib": "^2.6.2", + "typescript": "^5.4.5", "vite": "^4.5.0" } } diff --git a/src/server/lib/DiscordAPI/index.ts b/src/server/lib/DiscordAPI/index.ts index 1694da5..c6e2052 100644 --- a/src/server/lib/DiscordAPI/index.ts +++ b/src/server/lib/DiscordAPI/index.ts @@ -1,6 +1,5 @@ import { REST } from "./DiscordRequests.js" import type { APIMessage } from "discord-api-types/v10" -import FormData from "form-data" import { Transform, type Readable } from "node:stream" import type { Configuration } from "../config.js" diff --git a/src/server/lib/auth.ts b/src/server/lib/auth.ts index 783144e..a36bd3c 100644 --- a/src/server/lib/auth.ts +++ b/src/server/lib/auth.ts @@ -2,48 +2,31 @@ import crypto from "crypto" import { getCookie } from "hono/cookie" import type { Context } from "hono" import { readFile, writeFile } from "fs/promises" +import { z } from "zod" +import { AuthSchemas } from "./schemas/index.js" export let AuthTokens: AuthToken[] = [] export let AuthTokenTO: { [key: string]: NodeJS.Timeout } = {} -export const ValidTokenPermissions = [ - "user", // permissions to /auth/me, with email docked - "email", // adds email back to /auth/me - "private", // allows app to read private files - "upload", // allows an app to upload under an account - "manage", // allows an app to manage an account's files - "customize", // allows an app to change customization settings - "admin", // only available for accounts with admin - // gives an app access to all admin tools -] as const - -export type TokenType = "User" | "App" -export type TokenPermission = (typeof ValidTokenPermissions)[number] - -export interface AuthToken { - account: string - token: string - expire: number - - type?: TokenType // if !type, assume User - tokenPermissions?: TokenPermission[] // default to user if type is App, - // give full permissions if type is User -} +export type TokenPermission = z.infer +export type TokenType = z.infer +export type AuthToken = z.infer export function create( id: string, - expire: number = 24 * 60 * 60 * 1000, + expire: number | null = 24 * 60 * 60 * 1000, type: TokenType = "User", - tokenPermissions?: TokenPermission[] + tokenPermissions?: TokenPermission[], + issuer?: string ) { - let token = { + let token = AuthSchemas.AuthToken.parse({ account: id, token: crypto.randomBytes(36).toString("hex"), - expire: expire ? Date.now() + expire : 0, - + expire: typeof expire == "number" ? Date.now() + expire : null, + issuer, type, tokenPermissions: - type == "App" ? tokenPermissions || ["user"] : undefined, - } + type != "User" ? tokenPermissions || ["user"] : undefined, + }) AuthTokens.push(token) tokenTimer(token) @@ -64,7 +47,7 @@ export function tokenFor(ctx: Context) { function getToken(token: string) { return AuthTokens.find( - (e) => e.token == token && (e.expire == 0 || Date.now() < e.expire) + (e) => e.token == token && (e.expire == null || Date.now() < e.expire) ) } @@ -77,11 +60,14 @@ export function getType(token: string): TokenType | undefined { } export function getPermissions(token: string): TokenPermission[] | undefined { - return getToken(token)?.tokenPermissions + let tok = getToken(token) + if (tok && "tokenPermissions" in tok) + return tok.tokenPermissions } export function tokenTimer(token: AuthToken) { - if (!token.expire) return // justincase + if (!token.expire) return + if (Date.now() >= token.expire) { invalidate(token.token) return diff --git a/src/server/lib/middleware.ts b/src/server/lib/middleware.ts index 195ad92..51b817e 100644 --- a/src/server/lib/middleware.ts +++ b/src/server/lib/middleware.ts @@ -16,6 +16,26 @@ export const getAccount: RequestHandler = function (ctx, next) { return next() } +/** + * @description use :user param to get a target for this route + */ + +export const getTarget: RequestHandler = async (ctx, next) => { + let acc = + ctx.req.param("user") == "me" + ? ctx.get("account") + : ctx.req.param("user").startsWith("@") + ? Accounts.getFromUsername(ctx.req.param("user").slice(1)) + : Accounts.getFromId(ctx.req.param("user")) + if (acc != ctx.get("account") && !ctx.get("account")?.admin) + return ServeError(ctx, 403, "you cannot manage this user") + if (!acc) return ServeError(ctx, 404, "account does not exist") + + ctx.set("target", acc) + + return next() +} + /** * @description Middleware which blocks requests which do not have ctx.get("account") set */ @@ -48,7 +68,7 @@ export const requiresPermissions = function ( let token = auth.tokenFor(ctx)! let type = auth.getType(token) - if (type == "App") { + if (type != "User") { let permissions = auth.getPermissions(token) if (!permissions) return ServeError(ctx, 403, "insufficient permissions") @@ -100,20 +120,25 @@ export const issuesToMessage = function(issues: z.ZodIssue[]) { return issues.map(e => `${e.path}: ${e.code} :: ${e.message}`).join("; ") } -export const scheme = function(scheme: z.ZodTypeAny): RequestHandler { +export function scheme(scheme: z.ZodTypeAny, transformer: (ctx: Context) => Promise|any = c => c.req.json()): RequestHandler { return async function(ctx, next) { - let chk = scheme.safeParse(await ctx.req.json()) + let data = transformer(ctx) + let chk = await scheme.safeParse(data instanceof Promise ? await data : data) ctx.set("parsedScheme", chk.data) - if (chk.success) return next() - else return ServeError(ctx, 400, issuesToMessage(chk.error.issues)) + + if (chk.success) + return next() + else + return ServeError(ctx, 400, issuesToMessage(chk.error.issues)) } } // Not really middleware but a utility -export const login = (ctx: Context, account: string) => setCookie(ctx, "auth", auth.create(account, 3 * 24 * 60 * 60 * 1000), { - path: "/", - sameSite: "Strict", - secure: true, - httpOnly: true -}) \ No newline at end of file +export const login = (ctx: Context, account: string) => + setCookie(ctx, "auth", auth.create(account, 3 * 24 * 60 * 60 * 1000), { + path: "/", + sameSite: "Strict", + secure: true, + httpOnly: true + }) \ No newline at end of file diff --git a/src/server/lib/package.ts b/src/server/lib/package.ts new file mode 100644 index 0000000..8ab7a05 --- /dev/null +++ b/src/server/lib/package.ts @@ -0,0 +1,6 @@ +// bad but works for now +import {readFile} from "fs/promises" +export default JSON.parse( + (await readFile("./package.json")) + .toString() +) satisfies { version: string } \ No newline at end of file diff --git a/src/server/lib/schemas/auth.ts b/src/server/lib/schemas/auth.ts new file mode 100644 index 0000000..82e3cdc --- /dev/null +++ b/src/server/lib/schemas/auth.ts @@ -0,0 +1,43 @@ +import { z } from "zod"; + +export const Scope = z.enum([ + "user", // permissions to /auth/me, with email docked + "email", // adds email back to /auth/me + "private", // allows app to read private files + "upload", // allows an app to upload under an account + "manage", // allows an app to manage an account's files + "customize", // allows an app to change customization settings + "admin", // only available for accounts with admin + // gives an app access to all admin tools +]) + +export const TokenType = z.enum([ + "User", + "ApiKey", + "App" +]) + +const BaseAuthToken = z.object({ + account: z.string(), + token: z.string(), + expire: z.number() + .nullable() + .refine(e => e == null || e > Date.now(), "expiration must be after now"), + + type: TokenType +}) + +export const AuthToken = z.discriminatedUnion("type",[ + BaseAuthToken.extend({ + type: z.literal("User") + }), + BaseAuthToken.extend({ + type: z.literal("ApiKey"), + tokenPermissions: z.array(Scope).default(["user"]) + }), + BaseAuthToken.extend({ + type: z.literal("App"), + tokenPermissions: z.array(Scope).default(["user"]), + issuer: z.string() + }) +]) \ No newline at end of file diff --git a/src/server/lib/schemas/index.ts b/src/server/lib/schemas/index.ts index 4d030ab..5689486 100644 --- a/src/server/lib/schemas/index.ts +++ b/src/server/lib/schemas/index.ts @@ -1,2 +1,3 @@ export * as AccountSchemas from "./accounts.js" -export * as FileSchemas from "./files.js" \ No newline at end of file +export * as FileSchemas from "./files.js" +export * as AuthSchemas from "./auth.js" \ No newline at end of file diff --git a/src/server/routes/api.ts b/src/server/routes/api.ts index eec22f5..cfba678 100644 --- a/src/server/routes/api.ts +++ b/src/server/routes/api.ts @@ -2,7 +2,7 @@ import { Hono } from "hono" import Files from "../lib/files.js" import { fileURLToPath } from "url" import { dirname } from "path" -import apis from "./api/apis.js" +import { readdir } from "fs/promises" const APIDirectory = dirname(fileURLToPath(import.meta.url)) + "/api" @@ -13,7 +13,7 @@ interface APIMount { type APIMountResolvable = string | APIMount -interface APIDefinition { +export interface APIDefinition { name: string baseURL: string mount: APIMountResolvable[] @@ -73,8 +73,10 @@ export default class APIRouter { } async loadAPIMethods() { - for (let api of apis) { - await this.mount(api as APIDefinition) + let files = await readdir(APIDirectory) + for (let version of files) { + let def = (await import(`${APIDirectory}/${version}/definition.js`)).default + await this.mount(def) } } } diff --git a/src/server/routes/api/apis.ts b/src/server/routes/api/apis.ts deleted file mode 100644 index 571c156..0000000 --- a/src/server/routes/api/apis.ts +++ /dev/null @@ -1,9 +0,0 @@ -// EXTREME BANDAID SOLUTION -// -// SHOULD BE FIXED IN SVELTEKIT REWRITE - -import web from "./web/api.json" assert { type: "json" } -import v0 from "./v0/api.json" assert { type: "json" } -import v1 from "./v1/api.json" assert { type: "json" } - -export default [web, v0, v1] diff --git a/src/server/routes/api/v0/authRoutes.ts b/src/server/routes/api/v0/authRoutes.ts index cb09122..c29af29 100644 --- a/src/server/routes/api/v0/authRoutes.ts +++ b/src/server/routes/api/v0/authRoutes.ts @@ -537,9 +537,9 @@ export default function (files: Files) { ...acc, sessionCount: auth.AuthTokens.filter( (e) => - e.type != "App" && + e.type == "User" && e.account == accId && - (e.expire > Date.now() || !e.expire) + (e.expire == null || e.expire > Date.now()) ).length, sessionExpires: auth.AuthTokens.find( (e) => e.token == sessionToken diff --git a/src/server/routes/api/v0/api.json b/src/server/routes/api/v0/definition.ts similarity index 74% rename from src/server/routes/api/v0/api.json rename to src/server/routes/api/v0/definition.ts index 2a35e07..6290ac8 100644 --- a/src/server/routes/api/v0/api.json +++ b/src/server/routes/api/v0/definition.ts @@ -1,4 +1,6 @@ -{ +import { APIDefinition } from "../../api.js"; + +export default { "name": "v0", "baseURL": "/", "mount": [ @@ -7,4 +9,4 @@ { "file": "authRoutes", "to": "/auth" }, { "file": "fileApiRoutes", "to": "/files" } ] -} +} satisfies APIDefinition \ No newline at end of file diff --git a/src/server/routes/api/v0/primaryApi.ts b/src/server/routes/api/v0/primaryApi.ts index a17e56e..1581880 100644 --- a/src/server/routes/api/v0/primaryApi.ts +++ b/src/server/routes/api/v0/primaryApi.ts @@ -9,7 +9,6 @@ import {Readable} from "node:stream" import type {ReadableStream as StreamWebReadable} from "node:stream/web" import formidable from "formidable" import { HttpBindings } from "@hono/node-server" -import pkg from "../../../../../package.json" assert {type: "json"} import { type StatusCode } from "hono/utils/http-status" export let primaryApi = new Hono<{ Variables: { diff --git a/src/server/routes/api/v1/account/access.ts b/src/server/routes/api/v1/account/access.ts new file mode 100644 index 0000000..ce45081 --- /dev/null +++ b/src/server/routes/api/v1/account/access.ts @@ -0,0 +1,126 @@ +// Modules + +import { type Context, Hono } from "hono" +import { getCookie, setCookie } from "hono/cookie" + +// Libs + +import Files from "../../../../lib/files.js" +import * as Accounts from "../../../../lib/accounts.js" +import * as auth from "../../../../lib/auth.js" +import { + assertAPI, + getAccount, + getTarget, + issuesToMessage, + login, + noAPIAccess, + requiresAccount, + requiresPermissions, + scheme, +} from "../../../../lib/middleware.js" +import ServeError from "../../../../lib/errors.js" +import { CodeMgr, sendMail } from "../../../../lib/mail.js" + +import Configuration from "../../../../lib/config.js" +import { AccountSchemas, AuthSchemas, FileSchemas } from "../../../../lib/schemas/index.js" +import { z } from "zod" +import { BlankInput } from "hono/types" + +type HonoEnv = { + Variables: { + account: Accounts.Account + target: Accounts.Account + targetToken: auth.AuthToken + parsedScheme: any + } +} + +const router = new Hono() + +function getTargetToken(ctx: Context) { + return auth.AuthTokens.find( + e => + e.account == ctx.get("target").id + && e.token == ctx.req.param("token") + ) +} + +router.use(getAccount, requiresAccount, noAPIAccess) +router.all("/", getTarget) // idk if this is redundant but just in case +router.all("/:token", (ctx,next) => { + let tok = getTargetToken(ctx) + if (!tok) + return ServeError(ctx, 404, "token not found") + ctx.set("targetToken", tok) + return next() +}) + +export default function (files: Files) { + + router.get("/", async (ctx) => { + return ctx.json( + auth.AuthTokens.filter(e => e.account == ctx.get("target").id) + ) + }) + + router.delete( + "/", + scheme( + z.array(AuthSchemas.TokenType) + .nonempty() + .default(["User"]) + .transform(e => new Set(e)), + (c) => c.req.query("type")?.split(",") + ), + async (ctx) => { + let targets = auth.AuthTokens.filter( + e => + e.account == ctx.get("target").id + && ctx.get("parsedScheme").has(e.type) + ) + + targets.forEach(e => auth.invalidate(e.token)) + + return ctx.text(`deleted ${targets.length} tokens`) + } + ) + + router.get("/:token", async (ctx) => { + return ctx.json(ctx.get("targetToken")) + }) + + router.delete("/:token", async (ctx) => { + auth.invalidate(ctx.get("targetToken").token) + return ctx.text(`deleted token ${ctx.req.param("token")}`) + }) + + const CreateTokenScheme = + z.object({ + expire: z.number().positive().nullable(), + scopes: z.union([ + z.literal("all"), + z.array(AuthSchemas.Scope).nonempty().default(["user"]) + ]) + }) + + router.post( + "/", + scheme(CreateTokenScheme), + async (ctx) => { + let params = ctx.get("parsedScheme") as z.infer + let token = auth.create( + ctx.get("target").id, + params.expire, + "ApiKey", + params.scopes == "all" + ? AuthSchemas.Scope.options + : Array.from(new Set(params.scopes)), + "monofile" + ) + return ctx.text(token) + } + ) + + return router +} diff --git a/src/server/routes/api/v1/account.ts b/src/server/routes/api/v1/account/index.ts similarity index 91% rename from src/server/routes/api/v1/account.ts rename to src/server/routes/api/v1/account/index.ts index c183964..89e7eb3 100644 --- a/src/server/routes/api/v1/account.ts +++ b/src/server/routes/api/v1/account/index.ts @@ -5,24 +5,25 @@ import { getCookie, setCookie } from "hono/cookie" // Libs -import Files from "../../../lib/files.js" -import * as Accounts from "../../../lib/accounts.js" -import * as auth from "../../../lib/auth.js" +import Files from "../../../../lib/files.js" +import * as Accounts from "../../../../lib/accounts.js" +import * as auth from "../../../../lib/auth.js" import { assertAPI, getAccount, + getTarget, issuesToMessage, login, noAPIAccess, requiresAccount, requiresPermissions, scheme, -} from "../../../lib/middleware.js" -import ServeError from "../../../lib/errors.js" -import { CodeMgr, sendMail } from "../../../lib/mail.js" +} from "../../../../lib/middleware.js" +import ServeError from "../../../../lib/errors.js" +import { CodeMgr, sendMail } from "../../../../lib/mail.js" -import Configuration from "../../../lib/config.js" -import { AccountSchemas, FileSchemas } from "../../../lib/schemas/index.js" +import Configuration from "../../../../lib/config.js" +import { AccountSchemas, FileSchemas } from "../../../../lib/schemas/index.js" import { z } from "zod" const router = new Hono<{ @@ -216,21 +217,7 @@ const validators: { } router.use(getAccount) -router.all("/:user", async (ctx, next) => { - let acc = - ctx.req.param("user") == "me" - ? ctx.get("account") - : ctx.req.param("user").startsWith("@") - ? Accounts.getFromUsername(ctx.req.param("user").slice(1)) - : Accounts.getFromId(ctx.req.param("user")) - if (acc != ctx.get("account") && !ctx.get("account")?.admin) - return ServeError(ctx, 403, "you cannot manage this user") - if (!acc) return ServeError(ctx, 404, "account does not exist") - - ctx.set("target", acc) - - return next() -}) +router.all("/:user", getTarget) function isMessage(object: any): object is Message { return ( @@ -370,9 +357,9 @@ export default function (files: Files) { : undefined, activeSessions: auth.AuthTokens.filter( (e) => - e.type != "App" && + e.type == "User" && e.account == acc.id && - (e.expire > Date.now() || !e.expire) + (e.expire == null || e.expire > Date.now()) ).length, }) }) diff --git a/src/server/routes/api/v1/api.json b/src/server/routes/api/v1/definition.ts similarity index 53% rename from src/server/routes/api/v1/api.json rename to src/server/routes/api/v1/definition.ts index 25318b7..8c6c220 100644 --- a/src/server/routes/api/v1/api.json +++ b/src/server/routes/api/v1/definition.ts @@ -1,8 +1,17 @@ -{ +import { APIDefinition } from "../../api.js"; + +export default { "name": "v1", "baseURL": "/api/v1", "mount": [ - "account", + { + "file": "account/index", + "to": "/account" + }, + { + "file": "account/access", + "to": "/account/:user/access" + }, "session", { "file": "index", @@ -17,4 +26,4 @@ "to": "/file" } ] -} +} satisfies APIDefinition diff --git a/src/server/routes/api/v1/file/index.ts b/src/server/routes/api/v1/file/index.ts index 0bc47cb..e5fd996 100644 --- a/src/server/routes/api/v1/file/index.ts +++ b/src/server/routes/api/v1/file/index.ts @@ -9,7 +9,7 @@ import {Readable} from "node:stream" import type {ReadableStream as StreamWebReadable} from "node:stream/web" import formidable from "formidable" import { HttpBindings } from "@hono/node-server" -import pkg from "../../../../../../package.json" assert {type: "json"} +import pkg from "../../../../lib/package.js" import { type StatusCode } from "hono/utils/http-status" import { z } from "zod" import { FileSchemas } from "../../../../lib/schemas/index.js" diff --git a/src/server/routes/api/v1/file/individual.ts b/src/server/routes/api/v1/file/individual.ts index 05621af..1d49a57 100644 --- a/src/server/routes/api/v1/file/individual.ts +++ b/src/server/routes/api/v1/file/individual.ts @@ -9,7 +9,6 @@ import {Readable} from "node:stream" import type {ReadableStream as StreamWebReadable} from "node:stream/web" import formidable from "formidable" import { HttpBindings } from "@hono/node-server" -import pkg from "../../../../../../package.json" assert {type: "json"} import { type StatusCode } from "hono/utils/http-status" const router = new Hono<{ @@ -52,10 +51,10 @@ export default function(files: Files, apiRoot: Hono) { } if ( - auth.getType(auth.tokenFor(ctx)!) == "App" && + auth.getType(auth.tokenFor(ctx)!) != "User" && auth - .getPermissions(auth.tokenFor(ctx)!) - ?.includes("private") + .getPermissions(auth.tokenFor(ctx)!)! + .includes("private") ) { return ServeError(ctx, 403, "insufficient permissions") } diff --git a/src/server/routes/api/v1/index.ts b/src/server/routes/api/v1/index.ts index 72606bd..77ec13c 100644 --- a/src/server/routes/api/v1/index.ts +++ b/src/server/routes/api/v1/index.ts @@ -1,9 +1,9 @@ import { Hono } from "hono" import * as Accounts from "../../../lib/accounts.js" import { HttpBindings } from "@hono/node-server" -import pkg from "../../../../../package.json" assert {type: "json"} import config, { ClientConfiguration } from "../../../lib/config.js" import type Files from "../../../lib/files.js" +import pkg from "../../../lib/package.js" const router = new Hono<{ Variables: { diff --git a/src/server/routes/api/web/api.json b/src/server/routes/api/web/definition.ts similarity index 53% rename from src/server/routes/api/web/api.json rename to src/server/routes/api/web/definition.ts index a8e17c3..02564eb 100644 --- a/src/server/routes/api/web/api.json +++ b/src/server/routes/api/web/definition.ts @@ -1,5 +1,7 @@ -{ +import { APIDefinition } from "../../api.js"; + +export default { "name": "web", "baseURL": "/", "mount": [{ "file": "preview", "to": "/download" }, "go"] -} +} satisfies APIDefinition \ No newline at end of file diff --git a/src/server/routes/api/web/go.ts b/src/server/routes/api/web/go.ts index b05345f..06c6933 100644 --- a/src/server/routes/api/web/go.ts +++ b/src/server/routes/api/web/go.ts @@ -3,7 +3,6 @@ import bytes from "bytes" import ServeError from "../../../lib/errors.js" import * as Accounts from "../../../lib/accounts.js" import type Files from "../../../lib/files.js" -import pkg from "../../../../../package.json" assert {type:"json"} import { CodeMgr } from "../../../lib/mail.js" import { Hono } from "hono" import { getAccount, login } from "../../../lib/middleware.js" diff --git a/src/server/routes/api/web/preview.ts b/src/server/routes/api/web/preview.ts index 38d12ad..44010f5 100644 --- a/src/server/routes/api/web/preview.ts +++ b/src/server/routes/api/web/preview.ts @@ -3,7 +3,7 @@ import bytes from "bytes" import ServeError from "../../../lib/errors.js" import * as Accounts from "../../../lib/accounts.js" import type Files from "../../../lib/files.js" -import pkg from "../../../../../package.json" assert {type:"json"} +import pkg from "../../../lib/package.js" import { Hono } from "hono" import { getAccount } from "../../../lib/middleware.js" export let router = new Hono<{ diff --git a/src/server/tools/cli.ts b/src/server/tools/cli.ts index 6a7fca0..12c7fac 100644 --- a/src/server/tools/cli.ts +++ b/src/server/tools/cli.ts @@ -5,7 +5,7 @@ import { program } from "commander" import { basename } from "path" import { Writable } from "node:stream" import config from "../lib/config.js" -import pkg from "../../../package.json" assert { type: "json" } +import pkg from "../lib/package.js" import { fileURLToPath } from "url" import { dirname } from "path"