access api

This commit is contained in:
split / May 2024-05-21 19:51:18 -07:00
parent 17db90898f
commit ce96537d11
23 changed files with 311 additions and 665 deletions

580
package-lock.json generated
View file

@ -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",

View file

@ -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"
}
}

View file

@ -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"

View file

@ -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<typeof AuthSchemas.Scope>
export type TokenType = z.infer<typeof AuthSchemas.TokenType>
export type AuthToken = z.infer<typeof AuthSchemas.AuthToken>
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

View file

@ -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,18 +120,23 @@ 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>|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), {
export const login = (ctx: Context, account: string) =>
setCookie(ctx, "auth", auth.create(account, 3 * 24 * 60 * 60 * 1000), {
path: "/",
sameSite: "Strict",
secure: true,

View file

@ -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 }

View file

@ -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()
})
])

View file

@ -1,2 +1,3 @@
export * as AccountSchemas from "./accounts.js"
export * as FileSchemas from "./files.js"
export * as AuthSchemas from "./auth.js"

View file

@ -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)
}
}
}

View file

@ -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]

View file

@ -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

View file

@ -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

View file

@ -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: {

View file

@ -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<HonoEnv>()
function getTargetToken(ctx: Context<HonoEnv, "/:token", BlankInput>) {
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<typeof CreateTokenScheme>
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
}

View file

@ -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,
})
})

View file

@ -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

View file

@ -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"

View file

@ -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")
}

View file

@ -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: {

View file

@ -1,5 +1,7 @@
{
import { APIDefinition } from "../../api.js";
export default {
"name": "web",
"baseURL": "/",
"mount": [{ "file": "preview", "to": "/download" }, "go"]
}
} satisfies APIDefinition

View file

@ -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"

View file

@ -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<{

View file

@ -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"