diff options
| -rw-r--r-- | .gitignore | 7 | ||||
| -rw-r--r-- | README.md | 56 | ||||
| -rw-r--r-- | index.ts | 123 | ||||
| -rw-r--r-- | package-lock.json | 717 | ||||
| -rw-r--r-- | package.json | 51 | ||||
| -rw-r--r-- | prisma/schema.prisma | 36 | ||||
| -rw-r--r-- | router.ts | 120 | ||||
| -rw-r--r-- | src/CLI.ts | 31 | ||||
| -rw-r--r-- | src/Main.ts | 84 | ||||
| -rw-r--r-- | src/clients/Multer.ts | 68 | ||||
| -rw-r--r-- | src/clients/Prisma.ts | 19 | ||||
| -rw-r--r-- | src/routers/Auth.ts | 100 | ||||
| -rw-r--r-- | src/routers/Image.ts | 107 | ||||
| -rw-r--r-- | src/routers/Profile.ts | 58 | ||||
| -rw-r--r-- | static/css/style.css | 331 | ||||
| -rw-r--r-- | static/ejs/pages/home.ejs | 81 | ||||
| -rw-r--r-- | static/ejs/pages/me.ejs | 88 | ||||
| -rw-r--r-- | static/ejs/partials/bar.ejs | 7 | ||||
| -rw-r--r-- | static/ejs/partials/meta.ejs | 1 | ||||
| -rw-r--r-- | static/html/index.html | 62 | ||||
| -rw-r--r-- | static/img/favicon.png (renamed from static/webimg/favicon.png) | bin | 70631 -> 70631 bytes | |||
| -rw-r--r-- | static/img/twitch.png | bin | 0 -> 6800 bytes | |||
| -rw-r--r-- | tsconfig.json | 6 |
23 files changed, 1621 insertions, 532 deletions
@@ -129,5 +129,8 @@ dist .yarn/install-state.gz .pnp.* -static/i -options.json
\ No newline at end of file +# Picturebin +*.ini +static/images +prisma/migrations +*.db
\ No newline at end of file @@ -16,7 +16,7 @@ <div align="center"> <h1> - <img src="./static/webimg/favicon.png" width=32> File Hoster! + <img src="./static/img/favicon.png" width=32> <b>Pic</b>ture<b>Bin</b> <i>(formerly Dank File Hoster)</i> <br> <a href="https://wakatime.com/badge/user/09f67b1c-0691-482a-a1d4-e4751e6962de/project/eda75115-4dad-4ada-995a-f1379687f257"><img src="https://wakatime.com/badge/user/09f67b1c-0691-482a-a1d4-e4751e6962de/project/eda75115-4dad-4ada-995a-f1379687f257.svg?style=plastic" alt="wakatime"></a> </h1> @@ -24,28 +24,48 @@ </div> A small file hoster on ExpressJS. +## Dependencies: +1. Node.js +2. NPM +3. Typescript + ## Installation: -1. Use the script... - 1. as a standalone app: - ```bash - $ git clone https://github.com/notdankenough/fh.git - $ cd fh - $ npm install - $ npm run start - ``` - 2. as a module for your project: - ```bash - $ git submodule add https://github.com/notdankenough/fh.git - ``` - and you can import it as: `import SRouter from "./fh/router";` +1. Install from Git repository: +```bash +$ git clone https://github.com/notdankenough/picbin +$ cd picbin +``` +2. Install the Node.js modules: +```bash +$ npm install +``` +3. Run Prisma migrations. This will create the database: +```bash +$ npx prisma migrate dev +``` +4. Build the app: +```bash +$ npm run build +``` +5. Generate the configuration files. The program will create a `config.ini` file and you will need to insert the necessary values into their fields: +```bash +$ npm run init +``` +6. Run the app: +```bash +$ npm run start +``` +7. ??? +8. PROFIT! Now you have your own dank image hoster. ## Use in other tools: -1. [ <img src="https://camo.githubusercontent.com/6ca305d42786c9dbd0b76f5ade013601b080d71a598e881b4349dff2eafae6c7/68747470733a2f2f666f757274662e636f6d2f696d672f63686174746572696e6f2d69636f6e2d36342e706e67" width=24> Chatterino 2 (by fourtf, pajlada, and more...)](https://github.com/chatterino/chatterino2): +1. [ <img src="https://camo.githubusercontent.com/6ca305d42786c9dbd0b76f5ade013601b080d71a598e881b4349dff2eafae6c7/68747470733a2f2f666f757274662e636f6d2f696d672f63686174746572696e6f2d69636f6e2d36342e706e67" width=24> Chatterino (by fourtf, pajlada, and more...)](https://github.com/chatterino/chatterino2): 1. Go to `Settings -> External Tools -> Image Uploader` and paste the values in the relevant fields: | Field | Value | Example | | ---- | ------ | ------- | - | Request URL: | `<YOUR_DOMAIN>`/dank_upload | https://hmmtodayiwill.ru/i/dank_upload + | Request URL: | `<YOUR_DOMAIN>`/upload | https://i.hmmtodayiwill.ru/upload | Form field: | file | - | Extra Headers: | no-redirect: true | - | Image Link: | `<YOUR_DOMAIN>`/i/{name} | https://hmmtodayiwill.ru/i/{name} + | Extra Headers: | `Authorization: <some Base64 shit>` | Authorization: SUZZT1VTRUVUSElTVklWT05aVUxVTA== + +> * If you want to upload pictures under your account, you need to log in with your Twitch account [here](https://i.hmmtodayiwill.ru/).
\ No newline at end of file @@ -1,4 +1,4 @@ -// Copyright 2022 ilotterytea +// Copyright 2022 NotDankEnough (ilotterytea) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,99 +12,38 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Command } from "commander"; -import chalk from "chalk"; -import express from "express"; - -import pck from "./package.json"; -import SRouter from "./router"; -import { existsSync, mkdirSync, writeFileSync } from "fs"; - -main(); - -/** - * The "web server" script. - */ -function main() { - // Obtaining the options that have been provided in the command line interface: - const cli = CLI(); - const opts = cli.opts(); - - try { - // Create the necessary files if the script was started with the --init option: - if (opts.init) { - if (!(existsSync("./options.json"))) { - writeFileSync("./options.json", JSON.stringify({ - allowedMIMETypes: [ - "image/jpeg", - "image/png", - "image/svg+xml", - "image/tiff", - "image/webp", - "image/gif", - "video/mp4"], - maxFileSizeInBytes: 13107200 - }, null, 2), {encoding: "utf-8"}); - console.debug(chalk.green("The options file created!")); - } - return; - } - - // Run the server if the script was started with the --standalone option: - if (opts.standalone) { - // ExpressJS instance: - const App = express(); - - // Using an image loader with custom route (--route <value>) on the server: - App.use(opts.route, SRouter); - - // Using a static folder. Also, this will be used when viewing uploaded pictures. - App.use(express.static(`${__dirname}/static`)); - - // Starting the server on the specified port: - App.listen(opts.port, () => { - console.debug(chalk.bgGreen("Server (Image hoster) running on port ", opts.port)); - }); +import CLI from "./src/CLI"; +import Main from "./src/Main"; +import Ini from "ini"; +import { readFileSync, writeFileSync } from "fs"; +import { Logger } from "tslog"; + +const log: Logger = new Logger({name: "init"}); +const cli: Record<string, string | boolean> = CLI(); + +if (cli.init) { + const cfg_template = { + Auth: { + ClientID: "", + ClientSecret: "", + RedirectURI: "" + }, + Certificate: { + Key: "", + Cert: "", + Ca: "" + }, + Ports: { + HTTP: "80", + HTTPS: "443" } - } catch (err: any) { - console.log(chalk.bgRed(err)); } -} -/** - * Silly command-line interface. - */ -function CLI() { - // New Command instance: - const Program = new Command(); + writeFileSync("config.ini", Ini.stringify(cfg_template), {encoding: "utf-8"}); + log.debug("Config file is generated! Exiting..."); + process.exit(0); +} - // Setting the information about Program: - Program - .name(pck.displayName) - .description(pck.description) - .version(pck.version); - - // Create an option to run this script as a web app: - Program - .option("--standalone", "Run the script as a web app.", false) - .alias("-s"); - - // The option to be specified as the port in the web app: - Program - .option("--port <value>", "Set the port for standalone app.", "8080") - .alias("-p"); - - // The route for our image uploader: - Program - .option("--route <value>", "Set the route for standalone app.", "/") - .alias("-r"); - - // Initialize the first setup of image uploader: - Program - .option("--init", "Create the necessary files for image uploader.", false); - - // Parse the process arguments: - Program.parse(process.argv); +const config: {[key: string]: any} = Ini.parse(readFileSync("./config.ini", {encoding: "utf-8"})); - return Program; -}
\ No newline at end of file +Main(__dirname, config, cli);
\ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8a1e040..2f5bb7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,53 +1,110 @@ { - "name": "imaimagehoster", - "version": "1.0.0", + "name": "@notdankenough/picbin", + "version": "1.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "imaimagehoster", - "version": "1.0.0", + "name": "@notdankenough/picbin", + "version": "1.1.0", "license": "Apache-2.0", "dependencies": { - "chalk": "^4.1.2", - "commander": "^9.3.0", + "@prisma/client": "^4.2.1", + "@types/multer": "^1.4.7", + "axios": "^0.27.2", + "body-parser": "^1.20.0", + "commander": "^9.4.0", + "cookie-parser": "^1.4.6", + "ejs": "^3.1.8", "express": "^4.18.1", "fs": "^0.0.1-security", - "mime": "^1.4.1", + "ini": "^3.0.0", + "jquery": "^3.6.0", + "mime": "^3.0.0", "multer": "^1.4.5-lts.1", - "serve-favicon": "^2.5.0" + "tslog": "^3.3.3" }, "devDependencies": { + "@types/body-parser": "^1.19.2", + "@types/commander": "^2.12.2", + "@types/cookie-parser": "^1.4.3", "@types/express": "^4.17.13", - "@types/multer": "^1.4.7", - "@types/node": "^18.0.1", - "@types/serve-favicon": "^2.5.3" + "@types/ini": "^1.3.31", + "prisma": "^4.2.1" } }, + "node_modules/@prisma/client": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.2.1.tgz", + "integrity": "sha512-PZBkY60+k5oix+e6IUfl3ub8TbRLNsPLdfWrdy2eh80WcHTaT+/UfvXf/B7gXedH7FRtbPFHZXk1hZenJiJZFQ==", + "hasInstallScript": true, + "dependencies": { + "@prisma/engines-version": "4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/engines": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.2.1.tgz", + "integrity": "sha512-0KqBwREUOjBiHwITsQzw2DWfLHjntvbqzGRawj4sBMnIiL5CXwyDUKeHOwXzKMtNr1rEjxEsypM14g0CzLRK3g==", + "devOptional": true, + "hasInstallScript": true + }, + "node_modules/@prisma/engines-version": { + "version": "4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826.tgz", + "integrity": "sha512-tktkqdiwqE4QhmE088boPt+FwPj1Jub/zk+5F6sEfcRHzO5yz9jyMD5HFVtiwxZPLx/8Xg9ElnuTi8E5lWVQFQ==" + }, "node_modules/@types/body-parser": { "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": "*" } }, + "node_modules/@types/commander": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.2.tgz", + "integrity": "sha512-0QEFiR8ljcHp9bAbWxecjVRuAMr16ivPiGOw6KFQBVrVd0RQIcM3xKdRisH2EDWgVWujiYtHwhSkSUoAAGzH7Q==", + "deprecated": "This is a stub types definition for commander (https://github.com/tj/commander.js). commander provides its own type definitions, so you don't need @types/commander installed!", + "dev": true, + "dependencies": { + "commander": "*" + } + }, "node_modules/@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@types/cookie-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.3.tgz", + "integrity": "sha512-CqSKwFwefj4PzZ5n/iwad/bow2hTCh0FlNAeWLtQM3JA/NX/iYagIpWG2cf1bQKQ2c9gU2log5VUCrn7LDOs0w==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/express": { "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "dev": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", @@ -56,65 +113,55 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.29", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz", - "integrity": "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==", - "dev": true, + "version": "4.17.30", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz", + "integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==", "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*" } }, - "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "node_modules/@types/ini": { + "version": "1.3.31", + "resolved": "https://registry.npmjs.org/@types/ini/-/ini-1.3.31.tgz", + "integrity": "sha512-8ecxxaG4AlVEM1k9+BsziMw8UsX0qy3jYI1ad/71RrDZ+rdL6aZB0wLfAuflQiDhkD5o4yJ0uPK3OSUic3fG0w==", "dev": true }, + "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==" + }, "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": "*" } }, "node_modules/@types/node": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.1.tgz", - "integrity": "sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==", - "dev": true + "version": "18.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.4.tgz", + "integrity": "sha512-RzRcw8c0B8LzryWOR4Wj7YOTFXvdYKwvrb6xQQyuDfnlTxwYXGCV5RZ/TEbq5L5kn+w3rliHAUyRcG1RtbmTFg==" }, "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==", - "dev": true + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" }, "node_modules/@types/range-parser": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "node_modules/@types/serve-favicon": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@types/serve-favicon/-/serve-favicon-2.5.3.tgz", - "integrity": "sha512-HirXLRJjLXzwiSnjhE1vMu55X7+qaY+noXsKqi/7eK1uByl3L6TwkcALZuJnQXqOalMdmBz3b662yXvaR+89Vw==", - "dev": true, - "dependencies": { - "@types/express": "*" - } + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "node_modules/@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "dev": true, + "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==", "dependencies": { - "@types/mime": "^1", + "@types/mime": "*", "@types/node": "*" } }, @@ -154,6 +201,30 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, "node_modules/body-parser": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", @@ -177,6 +248,15 @@ "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", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -244,14 +324,30 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", - "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz", + "integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==", "engines": { "node": "^12.20.0 || >=14" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, "node_modules/concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", @@ -293,6 +389,26 @@ "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", @@ -311,6 +427,14 @@ "ms": "2.0.0" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -333,6 +457,20 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/ejs": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -395,6 +533,33 @@ "node": ">= 0.10.0" } }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -412,6 +577,38 @@ "node": ">= 0.8" } }, + "node_modules/follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -512,6 +709,14 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -525,6 +730,28 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, + "node_modules/jake": { + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -547,11 +774,14 @@ } }, "node_modules/mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", "bin": { "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" } }, "node_modules/mime-db": { @@ -573,6 +803,17 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/minimist": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", @@ -659,6 +900,23 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/prisma": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.2.1.tgz", + "integrity": "sha512-HuYqnTDgH8atjPGtYmY0Ql9XrrJnfW7daG1PtAJRW0E6gJxc50lY3vrIDn0yjMR3TvRlypjTcspQX8DT+xD4Sg==", + "devOptional": true, + "hasInstallScript": true, + "dependencies": { + "@prisma/engines": "4.2.1" + }, + "bin": { + "prisma": "build/index.js", + "prisma2": "build/index.js" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -794,31 +1052,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/serve-favicon": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", - "integrity": "sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==", - "dependencies": { - "etag": "~1.8.1", - "fresh": "0.5.2", - "ms": "2.1.1", - "parseurl": "~1.3.2", - "safe-buffer": "5.1.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-favicon/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "node_modules/serve-favicon/node_modules/safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -851,6 +1084,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -899,6 +1149,17 @@ "node": ">=0.6" } }, + "node_modules/tslog": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/tslog/-/tslog-3.3.3.tgz", + "integrity": "sha512-lGrkndwpAohZ9ntQpT+xtUw5k9YFV1DjsksiWQlBSf82TTqsSAWBARPRD9juI730r8o3Awpkjp2aXy9k+6vr+g==", + "dependencies": { + "source-map-support": "^0.5.21" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -955,30 +1216,64 @@ } }, "dependencies": { + "@prisma/client": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.2.1.tgz", + "integrity": "sha512-PZBkY60+k5oix+e6IUfl3ub8TbRLNsPLdfWrdy2eh80WcHTaT+/UfvXf/B7gXedH7FRtbPFHZXk1hZenJiJZFQ==", + "requires": { + "@prisma/engines-version": "4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826" + } + }, + "@prisma/engines": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.2.1.tgz", + "integrity": "sha512-0KqBwREUOjBiHwITsQzw2DWfLHjntvbqzGRawj4sBMnIiL5CXwyDUKeHOwXzKMtNr1rEjxEsypM14g0CzLRK3g==", + "devOptional": true + }, + "@prisma/engines-version": { + "version": "4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826.tgz", + "integrity": "sha512-tktkqdiwqE4QhmE088boPt+FwPj1Jub/zk+5F6sEfcRHzO5yz9jyMD5HFVtiwxZPLx/8Xg9ElnuTi8E5lWVQFQ==" + }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, "requires": { "@types/connect": "*", "@types/node": "*" } }, + "@types/commander": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.2.tgz", + "integrity": "sha512-0QEFiR8ljcHp9bAbWxecjVRuAMr16ivPiGOw6KFQBVrVd0RQIcM3xKdRisH2EDWgVWujiYtHwhSkSUoAAGzH7Q==", + "dev": true, + "requires": { + "commander": "*" + } + }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, "requires": { "@types/node": "*" } }, + "@types/cookie-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.3.tgz", + "integrity": "sha512-CqSKwFwefj4PzZ5n/iwad/bow2hTCh0FlNAeWLtQM3JA/NX/iYagIpWG2cf1bQKQ2c9gU2log5VUCrn7LDOs0w==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/express": { "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "dev": true, "requires": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", @@ -987,65 +1282,55 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.29", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz", - "integrity": "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==", - "dev": true, + "version": "4.17.30", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz", + "integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==", "requires": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*" } }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "@types/ini": { + "version": "1.3.31", + "resolved": "https://registry.npmjs.org/@types/ini/-/ini-1.3.31.tgz", + "integrity": "sha512-8ecxxaG4AlVEM1k9+BsziMw8UsX0qy3jYI1ad/71RrDZ+rdL6aZB0wLfAuflQiDhkD5o4yJ0uPK3OSUic3fG0w==", "dev": true }, + "@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" + }, "@types/multer": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", - "dev": true, "requires": { "@types/express": "*" } }, "@types/node": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.1.tgz", - "integrity": "sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==", - "dev": true + "version": "18.7.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.4.tgz", + "integrity": "sha512-RzRcw8c0B8LzryWOR4Wj7YOTFXvdYKwvrb6xQQyuDfnlTxwYXGCV5RZ/TEbq5L5kn+w3rliHAUyRcG1RtbmTFg==" }, "@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==", - "dev": true + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" }, "@types/range-parser": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "@types/serve-favicon": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@types/serve-favicon/-/serve-favicon-2.5.3.tgz", - "integrity": "sha512-HirXLRJjLXzwiSnjhE1vMu55X7+qaY+noXsKqi/7eK1uByl3L6TwkcALZuJnQXqOalMdmBz3b662yXvaR+89Vw==", - "dev": true, - "requires": { - "@types/express": "*" - } + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "dev": true, + "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==", "requires": { - "@types/mime": "^1", + "@types/mime": "*", "@types/node": "*" } }, @@ -1076,6 +1361,30 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "requires": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, "body-parser": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", @@ -1095,6 +1404,15 @@ "unpipe": "1.0.0" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -1144,10 +1462,23 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", - "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==" + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz", + "integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "concat-stream": { "version": "1.6.2", @@ -1178,6 +1509,22 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, + "cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "requires": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "dependencies": { + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + } + } + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -1196,6 +1543,11 @@ "ms": "2.0.0" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1211,6 +1563,14 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "ejs": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "requires": { + "jake": "^10.8.5" + } + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1264,6 +1624,32 @@ "vary": "~1.1.2" } }, + "filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "requires": { + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -1278,6 +1664,21 @@ "unpipe": "~1.0.0" } }, + "follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1351,6 +1752,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ini": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1361,6 +1767,22 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, + "jake": { + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "requires": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + } + }, + "jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1377,9 +1799,9 @@ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==" }, "mime-db": { "version": "1.52.0", @@ -1394,6 +1816,14 @@ "mime-db": "1.52.0" } }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, "minimist": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", @@ -1459,6 +1889,15 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "prisma": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.2.1.tgz", + "integrity": "sha512-HuYqnTDgH8atjPGtYmY0Ql9XrrJnfW7daG1PtAJRW0E6gJxc50lY3vrIDn0yjMR3TvRlypjTcspQX8DT+xD4Sg==", + "devOptional": true, + "requires": { + "@prisma/engines": "4.2.1" + } + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -1560,30 +1999,6 @@ } } }, - "serve-favicon": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", - "integrity": "sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==", - "requires": { - "etag": "~1.8.1", - "fresh": "0.5.2", - "ms": "2.1.1", - "parseurl": "~1.3.2", - "safe-buffer": "5.1.1" - }, - "dependencies": { - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - } - } - }, "serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -1610,6 +2025,20 @@ "object-inspect": "^1.9.0" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -1648,6 +2077,14 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "tslog": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/tslog/-/tslog-3.3.3.tgz", + "integrity": "sha512-lGrkndwpAohZ9ntQpT+xtUw5k9YFV1DjsksiWQlBSf82TTqsSAWBARPRD9juI730r8o3Awpkjp2aXy9k+6vr+g==", + "requires": { + "source-map-support": "^0.5.21" + } + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", diff --git a/package.json b/package.json index dc3e76c..347e9b9 100644 --- a/package.json +++ b/package.json @@ -1,35 +1,52 @@ { - "name": "imafilehoster", - "displayName": "I'm a File hoster.", - "version": "1.0.0", - "description": "iLotterytea's File hoster using ExpressJS.", - "main": "index.ts", + "name": "@notdankenough/picbin", + "version": "1.1.0", + "description": "Simple web hoster for your pictures and other media files.", + "main": "index.js", "scripts": { - "start": "ts-node ./index.ts --standalone" + "test": "ts-node index.ts --debug", + "build": "tsc", + "init": "node dist/index.js --init", + "start": "node dist/index.js" }, "repository": { "type": "git", - "url": "git+https://github.com/notdankenough/fh.git" + "url": "git+https://github.com/notdankenough/picbin.git" }, - "author": "NotDankEnough <hatesociety@pm.me> (https://hmmtodayiwill.ru)", + "keywords": [ + "hoster", + "web", + "expressjs", + "pictures" + ], + "author": "NotDankEnough <hatesociety@pm.me> (https://hmmtodayiwill.ru/)", "license": "Apache-2.0", "bugs": { - "url": "https://github.com/notdankenough/fh/issues" + "url": "https://github.com/notdankenough/picbin/issues" }, - "homepage": "https://github.com/notdankenough/fh#readme", + "homepage": "https://github.com/notdankenough/picbin#readme", "dependencies": { - "chalk": "^4.1.2", - "commander": "^9.3.0", + "@prisma/client": "^4.2.1", + "@types/multer": "^1.4.7", + "axios": "^0.27.2", + "body-parser": "^1.20.0", + "commander": "^9.4.0", + "cookie-parser": "^1.4.6", + "ejs": "^3.1.8", "express": "^4.18.1", "fs": "^0.0.1-security", - "mime": "^1.4.1", + "ini": "^3.0.0", + "jquery": "^3.6.0", + "mime": "^3.0.0", "multer": "^1.4.5-lts.1", - "serve-favicon": "^2.5.0" + "tslog": "^3.3.3" }, "devDependencies": { + "@types/body-parser": "^1.19.2", + "@types/commander": "^2.12.2", + "@types/cookie-parser": "^1.4.3", "@types/express": "^4.17.13", - "@types/multer": "^1.4.7", - "@types/node": "^18.0.1", - "@types/serve-favicon": "^2.5.3" + "@types/ini": "^1.3.31", + "prisma": "^4.2.1" } } diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..c4d04d2 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,36 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "sqlite" + url = "file:data.db" +} + +model Image { + id String @id @unique @default(cuid()) + storage_id String + description String? + is_hidden Boolean? + burn_after_watched Boolean? + ext String + view_count Int? @default(0) + user User? @relation(fields: [userId], references: [id]) + userId Int? + timestamp DateTime @default(now()) +} + +model User { + id Int @id @default(autoincrement()) + alias_id Int? @unique + key String + name String + desc String? + pic String @default("../img/default_avatar.png") + pswd String? + is_supauser Boolean? + Image Image[] +} diff --git a/router.ts b/router.ts deleted file mode 100644 index 7e8b147..0000000 --- a/router.ts +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2022 ilotterytea -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import express, { - RequestHandler -} from "express"; -import favicon from "serve-favicon"; -import pck from "./package.json"; -import i_opts from "./options.json"; -import multer from "multer"; -import crypto from "crypto"; - -import { existsSync, readdirSync, readFileSync } from "fs"; -import mime from "mime"; - -const router = express.Router(); - -// To store files on local disk: -const storage = multer.diskStorage({ - // File destination: - destination: "./static/i", - // Creation of file name: - filename: (req, file, callback) => { - // Compare file size and limit: - if (file.size > i_opts.maxFileSizeInBytes) { - callback(Error("The file size is larger than the maximum set value."), ""); - return; - } - - // Name pattern: - var pattern = "number/dir"; - - switch (pattern) { - // A name for the file based on where it will be positioned amongst the other files after uploading: - case "number/dir": - const img_id = readdirSync("./static/i").length + 1; - - var maxzero = 5; - var zerostring = ""; - - for (var i = 0; i < maxzero; i++) { zerostring = zerostring + "0"; } - - zerostring = zerostring.slice(img_id.toString().length, zerostring.length); - - callback(null, zerostring + img_id.toString() + "." + mime.extension(file.mimetype)); - break; - // Random byte name: - case "crypto/hex": - crypto.randomBytes(5 /* <-- Character length */, (err, raw) => { - if (err) return callback(err, ""); - callback(null, raw.toString("hex") + "." + mime.extension(file.mimetype)); - }); - break; - default: - break; - } - } -}); - -// Image uploader: -const upload = multer({ - storage: storage, - fileFilter(req, file, callback) { - if (i_opts.allowedMIMETypes.includes(file.mimetype)) { - callback(null, true); - } else { - callback(null, false); - console.debug("The extension of this file isn't allowed."); - } - }, -}) - -// Main page: -router.get("/", async (req, res) => { - var Page: string = readFileSync(`${__dirname}/static/html/index.html`, {encoding: "utf-8"}); - - Page = Page.replace("{{AboutFileHoster}}", `Running on notdankenough/fh@${pck.version}!`); - - res.send(Page); -}); - -// Viewing files. -router.get("/i/:id", async (req, res) => { - if (!(existsSync("./static/i/" + req.params.id))) { - return res.json({ - status: 404, - reason: "The file " + req.params.id + " not found!", - kitty: "https://http.cat/404" - }).status(404); - } - - return res.sendFile(`${__dirname}/static/i/${req.params.id}`); -}); - -// POST request to upload a file and then send its name: -router.post("/dank_upload", upload.single("file"), (req, res) => { - var name = req.file?.filename; - - // Required for some external tools: - if (req.headers["no-redirect"]) { - return res.json({ - name: name - }).status(200); - } - - res.redirect("/i/" + name); -}); - -export default router;
\ No newline at end of file diff --git a/src/CLI.ts b/src/CLI.ts new file mode 100644 index 0000000..f1e4faf --- /dev/null +++ b/src/CLI.ts @@ -0,0 +1,31 @@ +// Copyright 2022 NotDankEnough (ilotterytea) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Command } from "commander"; + +/** + * Silly Command-Line Interface. + * @returns options. + */ +function CLI(): Record<string, string | boolean> { + const Program = new Command(); + + Program.option("--init", "Generate the neccessary files.", false); + Program.option("--no-ssl", "Run application in debug mode. Port for HTTP connection is \"8080\" instead of standard \"80\".", false); + + Program.parse(process.argv); + return Program.opts(); +} + +export default CLI;
\ No newline at end of file diff --git a/src/Main.ts b/src/Main.ts new file mode 100644 index 0000000..bf75f2a --- /dev/null +++ b/src/Main.ts @@ -0,0 +1,84 @@ +// Copyright 2022 NotDankEnough (ilotterytea) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import express from "express"; + +import cookieParser from "cookie-parser"; +import bodyParser from "body-parser"; + +import http from "http"; +import https from "https"; + +import { Logger } from "tslog"; + +import ProfileRouter from "./routers/Profile"; +import AuthRouter from "./routers/Auth"; +import ImageRouter from "./routers/Image"; +import { PrismaClient } from "@prisma/client"; + +const log: Logger = new Logger({name: "main"}); + +function Main(dirPath: string, cfg: {[key: string]: any}, cli_options?: {[key: string]: any}): void { + const App: express.Express = express(); + const prisma: PrismaClient = new PrismaClient(); + + var httpc: http.Server | null = null; + var httpsc: https.Server | null = null; + + App.set("view engine", "ejs"); + App.set("views", `${dirPath}/static/ejs`); + + App.use(cookieParser()); + App.use(bodyParser.urlencoded({extended: false})); + + App.use("/me", ProfileRouter(dirPath, prisma)); + App.use("/auth", AuthRouter(dirPath, cfg, prisma)); + App.use("/", ImageRouter(dirPath, cfg, prisma)); + + App.use(express.static(`${dirPath}/static`)); + + if (cli_options) { + if (!cli_options.noSsl) { + httpc = http.createServer(App); + httpc.listen(parseInt(cfg.Ports.HTTP), () => { + log.info("Image hoster is running on port", cfg.Ports.HTTP); + }); + } else { + if ( + !cfg.Certificate.Key || + !cfg.Certificate.Cert || + !cfg.Certificate.Ca + ) { + log.error("No paths for certificate provided."); + process.exit(1); + } + + const credentials = { + key: cfg.Certificate.Key, + cert: cfg.Certificate.Cert, + ca: cfg.Certificate.Ca + } + + httpsc = https.createServer(credentials, App); + httpsc.listen(parseInt(cfg.Ports.HTTPS), () => { + log.info("Image hoster is running on port", cfg.Ports.HTTPS, "(SSL)"); + }); + } + } else { + log.error("NO CLI OPTIONS PROVIDED!!!") + process.exit(1); + } +} + +export default Main;
\ No newline at end of file diff --git a/src/clients/Multer.ts b/src/clients/Multer.ts new file mode 100644 index 0000000..81f2b0f --- /dev/null +++ b/src/clients/Multer.ts @@ -0,0 +1,68 @@ +// Copyright 2022 NotDankEnough (ilotterytea) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import multer from "multer"; +import mime from "mime"; +import crypto from "crypto"; +import { readdirSync } from "fs"; + +const fileFilter = (req: Express.Request, res: Express.Response, cb: multer.FileFilterCallback) => { + cb(null, true); +} + +const storage = multer.diskStorage({ + destination: "static/images", + filename(req, file, callback) { + if (!req.headers["pattern"]) req.headers["pattern"] = "random"; + + switch (req.headers["pattern"]) { + case "numeration": { + const img_id: number = readdirSync("images").length + 1; + const max_zero: number = 5; + var blank_string: string = ""; + + for (var i = 0; i < max_zero; i++) { blank_string = blank_string + "0"; } + + blank_string = blank_string.slice(img_id.toString().length, blank_string.length); + + callback(null, `${blank_string}${img_id.toString()}.${mime.getExtension(file.mimetype)}`); + break; + } + case "random": { + crypto.randomBytes(5, (err, raw) => { + if (err) return callback(err, ""); + callback(null, `${raw.toString("hex")}.${mime.getExtension(file.mimetype)}`) + }); + break; + } + default: { + crypto.randomBytes(5, (err, raw) => { + if (err) return callback(err, ""); + callback(null, `${raw.toString("hex")}.${mime.getExtension(file.mimetype)}`) + }); + break; + } + } + } +}); + +const Multer = multer({ + fileFilter: fileFilter, + storage: storage, + limits: { + fieldSize: 1.6e+7 + } +}); + +export default Multer;
\ No newline at end of file diff --git a/src/clients/Prisma.ts b/src/clients/Prisma.ts new file mode 100644 index 0000000..1e17fc9 --- /dev/null +++ b/src/clients/Prisma.ts @@ -0,0 +1,19 @@ +// Copyright 2022 NotDankEnough (ilotterytea) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); + +export default prisma;
\ No newline at end of file diff --git a/src/routers/Auth.ts b/src/routers/Auth.ts new file mode 100644 index 0000000..146bafe --- /dev/null +++ b/src/routers/Auth.ts @@ -0,0 +1,100 @@ +// Copyright 2022 NotDankEnough (ilotterytea) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Router, CookieOptions } from "express"; +import { PrismaClient, User } from "@prisma/client"; +import { randomBytes } from "crypto"; +import axios from "axios"; +import { Logger } from "tslog"; + +const log: Logger = new Logger({name: "authlog"}); + +function AuthRouter(dirPath: string, cfg: {[key: string]: any}, prisma: PrismaClient): Router { + const router: Router = Router(); + + router.get("/twitch", async (req, res) => { + if (!("code" in req.query)) { + return res.json({ + status: 400, + reason: "\"code\" query not found." + }).status(400); + } + + try { + const req_token = await axios.post("https://id.twitch.tv/oauth2/token", `client_id=${cfg.Auth.ClientID}&client_secret=${cfg.Auth.ClientSecret}&code=${req.query.code}&grant_type=authorization_code&redirect_uri=${cfg.Auth.RedirectURI}`, {headers: {"Content-Type": "application/x-www-form-urlencoded"}}); + + const ttv_user = await axios.get("https://api.twitch.tv/helix/users", { + responseType: "json", + headers: { + "Authorization": `Bearer ${req_token.data.access_token}`, + "Client-Id": cfg.Auth.ClientID + } + }); + + const user_data = ttv_user.data.data[0]; + + const user: User | null = await prisma.user.findFirst({ + where: { + alias_id: parseInt(user_data.id) + } + }); + + const key: string = randomBytes(16).toString("hex"); + const cookie_opts: CookieOptions = { + httpOnly: false, + secure: true, + sameSite: "lax" + }; + + if (!user) { + await prisma.user.create({ + data: { + alias_id: parseInt(user_data.id), + name: user_data.login, + desc: user_data.description, + pic: user_data.profile_image_url, + key: key + } + }); + + res.cookie("key", key, cookie_opts); + res.cookie("id", user_data.id, cookie_opts); + } else { + await prisma.user.update({ + where: {id: user.id}, + data: { + name: user_data.login, + desc: user_data.description, + pic: user_data.profile_image_url, + key: key + } + }); + + res.cookie("key", key, cookie_opts); + res.cookie("id", user_data.id, cookie_opts); + } + + res.redirect("/me"); + } catch (err: any) { + res.json({ + status: (err.response.data.status) ? err.response.data.status : 400, + message: (err.response.data.message) ? err.response.data.message : "Bad request." + }).status((err.response.data.status) ? err.response.data.status : 400); + } + }); + + return router; +} + +export default AuthRouter;
\ No newline at end of file diff --git a/src/routers/Image.ts b/src/routers/Image.ts new file mode 100644 index 0000000..dfd6a16 --- /dev/null +++ b/src/routers/Image.ts @@ -0,0 +1,107 @@ +// Copyright 2022 NotDankEnough (ilotterytea) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { PrismaClient, User, Image } from "@prisma/client"; +import express from "express"; +import mime from "mime"; +import multer from "../clients/Multer"; + +function ImageRouter(dirPath: string, cfg: {[key: string]: any}, prisma: PrismaClient): express.Router { + const router: express.Router = express.Router(); + + router.get("/", async (req, res) => { + const user: User | null = await prisma.user.findFirst({ + where: { + alias_id: (req.cookies.id) ? parseInt(req.cookies.id) : null, + key: (req.cookies.key) ? req.cookies.key : "" + } + }); + + return res.render("pages/home", { + user: user, + cid: cfg.Auth.ClientID, + uri: cfg.Auth.RedirectURI + }); + }); + + router.post("/upload", multer.single("file"), async (req, res) => { + const auth: string[] | undefined = (req.headers["authorization"]) ? new Buffer(req.headers["authorization"], "base64").toString("utf-8").split(':') : undefined; + + var user: User | null = await prisma.user.findFirst({ + where: { + alias_id: (auth) ? parseInt(auth[1]) : (req.cookies.id) ? parseInt(req.cookies["id"]) : null, + key: (auth) ? auth[2] : (req.cookies.key) ? req.cookies["key"] : "" + } + }); + + const image: Image = await prisma.image.create({ + data: { + storage_id: req.file!.filename!, + ext: mime.getExtension(req.file!.mimetype)!, + userId: (user) ? user.id : null + } + }); + + return res.send(`https://i.hmmtodayiwill.ru/${image.id}`).status(200); + }); + + + router.get("/:imageId", async (req, res) => { + const auth: string[] | undefined = (req.headers["authorization"]) ? new Buffer(req.headers["authorization"], "base64").toString("utf-8").split(':') : undefined; + + var user: User | null = await prisma.user.findFirst({ + where: { + alias_id: (auth) ? parseInt(auth[0]) : (req.cookies.id) ? parseInt(req.cookies["id"]) : null, + key: (auth) ? auth[1] : (req.cookies.key) ? req.cookies["key"] : "" + } + }); + + const image: Image | null = await prisma.image.findFirst({ + where: { + id: req.params.imageId + } + }); + + if (!image) { + return res.json({ + status: 404, + reason: "Image ID " + req.params.imageId + " not found in database!" + }).status(404); + } + + if (image.is_hidden) { + if (user) { + if (image.userId !== user.id) { + return res.json({ + status: 401, + reason: "Image ID " + req.params.imageId + " have a hide flag." + }).status(401); + } else { + return res.sendFile(`${__dirname}/static/images/${image.storage_id}`); + } + } else { + return res.json({ + status: 401, + reason: "Image ID " + req.params.imageId + " have a hide flag." + }).status(401); + } + } + + return res.sendFile(`${dirPath}/static/images/${image.storage_id}`); + }); + + return router; +} + +export default ImageRouter;
\ No newline at end of file diff --git a/src/routers/Profile.ts b/src/routers/Profile.ts new file mode 100644 index 0000000..afc5e5d --- /dev/null +++ b/src/routers/Profile.ts @@ -0,0 +1,58 @@ +// Copyright 2022 NotDankEnough (ilotterytea) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { PrismaClient, User, Image } from "@prisma/client"; +import { Router } from "express"; + +function ProfileRouter(dirPath: string, prisma: PrismaClient): Router { + const router: Router = Router(); + + router.get("/", async (req, res) => { + if (!req.cookies.id || !req.cookies.key) { + return res.redirect("/"); + } + + const user: User | null = await prisma.user.findFirst({ + where: { + alias_id: parseInt(req.cookies.id), + key: req.cookies.key + } + }); + + if (!user) { + return res.redirect("/"); + } + + var images: Image[] = await prisma.image.findMany({ + where: { + userId: user.id + }, + orderBy: { + timestamp: "desc" + } + }); + + const keyNotEncoded: string = `${user.id}:${user.alias_id}:${user.key}`; + + return res.render("pages/me", { + user: user, + images: images, + authKey: Buffer.alloc(keyNotEncoded.length, keyNotEncoded).toString("base64") + }); + }); + + return router; +} + +export default ProfileRouter;
\ No newline at end of file diff --git a/static/css/style.css b/static/css/style.css index bbdd598..ee92164 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -13,114 +13,289 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&family=Manrope:wght@500;600;700&display=swap'); + @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&family=Manrope:wght@500;600;700&family=SourceCodePro:wght@500,600,700&display=swap'); + @import url('https://use.fontawesome.com/releases/v6.1.2/css/all.css'); + :root { - --bg-color-main: #0f0f0f; - --text-color: #ddd; - - --bg-color-submit-button: #649b44; - --bg-color-sec-submit-button: #75b450; - --bg-color-submit-button-na: #555; - --bg-color-submit-button-na-2: #333; - --border-color-submit-button: #a5df84; - --border-color-submit-button-highlight: #d3f3c0; - --border-color-submit-button-na: #888; - --text-color-submit-button: #ddd; - --text-color-submit-button-na: #aaa; - --text-color-submit-button-highlight: #fff; -} -html, body { + --text-black: #151515; + --text-white: #fff; + --button-0: #7aa751; + --button-1: #84b458; + --button-border: #63a62f; + --button-text-shadow: #4c9021; + } + + html, body, h1, h2, h3, p { margin: 0; padding: 0; - min-height: 100vh; -} -body { - background: var(--bg-color-main); - color: var(--text-color); + } + + body { font-family: "Inter", sans-serif; + font-size: 14px; + background: var(--text-black); + color: var(--text-white); + } + + h1,h2,h3 { + font-family: "Manrope", sans-serif; + } + + .container { + width: 100%; + min-height: 100vh; display: flex; - flex-direction: column; justify-content: center; align-items: center; -} + } -.container { - margin: 0 30px; + .wrapper { display: flex; - flex-grow: 1; flex-direction: column; justify-content: center; - padding: 40px 0; -} + align-items: center; + } -.content { - display: flex; - flex-direction: column; - justify-content: center; + .wrapper section { + margin: 8px 0; + padding: 8px; + min-width: 384px; + } +/* NAVIGATION */ +nav { + width: 100%; + margin: 0; + padding: 0; + display: flex; + flex-direction: row; } -.content section { - padding: 14px; -} -h1,h2,h3 { - font-family: "Manrope", sans-serif; +nav a.button img { + width: 16px; + height: auto; + border-radius: 4px; + margin-right: 8px; } -input[type=submit] { - background: linear-gradient(0deg, var(--bg-color-sec-submit-button), var(--bg-color-submit-button)); - padding: 2px 12px; - border-radius: 5px; - border: 1px solid var(--border-color-submit-button); - color: var(--text-color-submit-button); +/* MAIN PAGE */ +section#brand { + display: flex; + flex-direction: row; + justify-content: center; } - -input[type=submit]:hover { - background: linear-gradient(0deg, var(--bg-color-submit-button), var(--bg-color-sec-submit-button)); - border: 1px solid var(--border-color-submit-button-highlight); - color: var(--text-color-submit-button-highlight); - cursor: pointer; +section#brand #logo img { + width: 64px; + height: 64px; + transform: rotate(-45deg); } -input[type=submit]:disabled { - background: linear-gradient(0deg, var(--bg-color-submit-button-na-2), var(--bg-color-submit-button-na)); - color: var(--text-color-submit-button-na); - border: 1px solid var(--border-color-submit-button-na); +section#brand #summary { + margin: 0 16px; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; } - -input[type=submit]:disabled:hover { - cursor: not-allowed; +section#brand #summary p#name { + font-size: 32px; + line-height: 0px; + margin: 0; } -input[type=file]::file-selector-button { - background: linear-gradient(0deg, var(--bg-color-sec-submit-button), var(--bg-color-submit-button)); - padding: 2px 12px; - border-radius: 5px; - border: 1px solid var(--border-color-submit-button); - color: var(--text-color-submit-button); +form#uploadform { + } -input[type=file]::file-selector-button:hover { - background: linear-gradient(0deg, var(--bg-color-submit-button), var(--bg-color-sec-submit-button)); - border: 1px solid var(--border-color-submit-button-highlight); - color: var(--text-color-submit-button-highlight); - cursor: pointer; +form#uploadform button#submit { + float:right; +} +form#uploadform input[type="file"]::file-selector-button { + background: linear-gradient(0deg, var(--button-0), var(--button-1)); + border: var(--button-border) solid 1px; + font-family: "Source Code Pro", monospace; + color: var(--text-white); + text-shadow: 0 -1px 0 var(--button-text-shadow); + text-align: center; + text-decoration: none; + border-radius: 5px; + padding: 2px 6px; } -a img:hover { - opacity: 0.75; +form#uploadform input[type="file"]::file-selector-button:hover { + background: linear-gradient(180deg, var(--button-0), var(--button-1)); + cursor: pointer; } -#i_preview { - padding: 16px 0; +/* LINK SECTION */ +.link { + display: flex; + flex-direction: row; } -#preview { - display: block; - margin-left: auto; - margin-right: auto; +.link #link { + background: #ddd; + overflow-x: scroll; + text-overflow: ellipsis; + display: table; + margin: 0 auto; + max-width: 50%; } + /* ME SECTION */ + .infoblock { + background: linear-gradient(0deg, #000, #222); + border: #222 solid 1px; + display: flex; + flex-direction: column; + vertical-align: middle; + border-radius: 5px; + width: 512px; + } -#footer { - align-items: center; + .infoblock .user_summary { + display: flex; + flex-direction: row; + } + + .summary p#desc { + text-align: justify; + } + + .summary #name { + margin: 12px 0; + } + + .infoblock .user_summary div { + margin: 5px; + } + + .infoblock .user_summary .pfp { + display: flex; justify-content: center; - justify-items: center; + } + + .pfp img { + width: auto; + height: 64px; + border-radius: 5px; + } + + .infoblock .action_buttons { + display: flex; + flex-direction: row-reverse; + } + + .infoblock .action_buttons a.button { + margin: 0 4px; + } + + /* ME/IMAGES SECTION! */ + + #images h2#name { + padding: 6px; + } + + .items { + display: flex; + flex-direction: column; + overflow-y: scroll; + max-height: 512px; + background: #222; + border: #444 solid 1px; + border-radius: 4px; + } + + .item { + background: #525252; + border-radius: 4px; + padding: 5px; + margin: 5px; + display: flex; + flex-direction: column; + } + + .item #info { + display: flex; + flex-direction: row; + } + + .item #info div { + margin: 5px; + } + + .item #info #numeration { + display: flex; + justify-content: center; + align-items: center; + font-family: "Manrope", sans-serif; + font-weight: 800; + font-size: 18px; + } + + .item #info #summary { + display: flex; + flex-direction: column; + justify-content: center; + } + + .item #info #summary #timestamp { + color: #d7ccff; + } + + .item #info #thumbnail img { + width: 64px; + height: auto; + } + + .item #info #actions { + display: flex; + flex-direction: column; + justify-content: center; + align-content: center; + } + + /* AUTHENTICATION SECTION */ + .infoblock#authk .action_buttons { + display: flex; + flex-direction: row; + } + .infoblock#authk .action_buttons button { + flex-grow: 1; + margin: 2px; + } + /* BUTTONS */ + .button { + background: linear-gradient(0deg, var(--button-0), var(--button-1)); + border: var(--button-border) solid 1px; + font-family: "Source Code Pro", monospace; + color: var(--text-white); + text-shadow: 0 -1px 0 var(--button-text-shadow); + text-align: center; + text-decoration: none; + border-radius: 5px; + padding: 2px 6px; + } + + .button:hover { + background: linear-gradient(180deg, var(--button-0), var(--button-1)); + cursor: pointer; + } + .button.twitch { + font-family: "Inter", sans-serif; + padding: 6px; + margin: 8px; + vertical-align: middle; + display: flex; + flex-direction: row; + background: linear-gradient(0deg, #5f1481, #821ab3); + border: #66158b solid 1px; + text-shadow: 0 -1px 0 #691591; +} +.button.twitch:hover { + background: linear-gradient(180deg, #5f1481, #821ab3); +} + +/* SOON (tm) */ +soontm { + color: #444; + text-decoration: wavy; + font-style: italic; }
\ No newline at end of file diff --git a/static/ejs/pages/home.ejs b/static/ejs/pages/home.ejs new file mode 100644 index 0000000..340c563 --- /dev/null +++ b/static/ejs/pages/home.ejs @@ -0,0 +1,81 @@ +<!-- + Copyright 2022 NotDankEnough (ilotterytea) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!DOCTYPE html> +<html> + <head> + <title>Picbin</title> + <%- include("../partials/meta") %> + + </head> + <body> + <nav> + <% if (!user) {%> + <a href="https://id.twitch.tv/oauth2/authorize?response_type=code&redirect_uri=<%= uri %>&client_id=<%= cid %>" class="button twitch"> + <span class="fa-brands fa-twitch" style="margin-right:8px;"></span> + <p>Log in with Twitch</p> + </a> + <% } else { %> + <a href="/me" class="button twitch"> + <img src="<%= user.pic %>"> + <p><%= user.name %></p> + </a> + <button onclick="logout()" class="button twitch"> + <span class="fa-solid fa-arrow-right-from-bracket"></span> + </button> + <% } %> + + <a href="https://github.com/notdankenough/picbin" class="button twitch"> + <span class="fa-brands fa-github"></span> + </a> + </nav> + <div class="container"> + <div class="wrapper"> + <section id="brand"> + <div id="logo"> + <img src="../img/favicon.png"> + </div> + <div id="summary"> + <p id="name"><span style="font-weight:800;font-family:'Manrope', sans-serif;">Pic</span>ture<span style="font-weight:800;font-family:'Manrope',sans-serif;">Bin</span></p> + </div> + </section> + <section id="form"> + <form action="/upload" method="post" id="uploadform"> + <label>Select file to upload:</label><br> + <input accept="image/*" type="file" name="file" id="file"> + <button type="submit" id="submit" class="button">Upload!</button> + </form> + </section> + </div> + </div> + </body> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> + <script src="https://malsup.github.io/jquery.form.js"></script> + <script type="text/javascript"> + function logout() { + document.cookie = "id=;Max-Age=-999999"; + document.cookie = "key=;Max-Age=-999999"; + window.location.reload(); + } + + $("#uploadform").ajaxForm({ + dataType: "text", + success: (response) => { + window.location.replace(response.split('/')[response.split('/').length - 1]); + } + }); + </script> +</html>
\ No newline at end of file diff --git a/static/ejs/pages/me.ejs b/static/ejs/pages/me.ejs new file mode 100644 index 0000000..0c69ef5 --- /dev/null +++ b/static/ejs/pages/me.ejs @@ -0,0 +1,88 @@ +<!-- + Copyright 2022 NotDankEnough (ilotterytea) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!DOCTYPE html> +<html> + <head> + <title><%= user.name %> - Image Hoster</title> + <%- include("../partials/meta") %> + </head> + <body> + <div class="container"> + <div class="wrapper"> + <section class="infoblock"> + <a href="/" class="button">Go back...</a> + </section> + <section class="infoblock"> + <div class="user_summary"> + <div class="pfp"> + <img src="<%= user.pic %>"> + </div> + <div class="summary"> + <h2 id="name"><%= user.name%> (<%= user.alias_id %>)</h2> + <p id="desc"><%= user.desc %></p> + </div> + </div> + <div class="action_buttons"> + + </div> + </section> + <section class="infoblock" id="authk"> + <h2 id="name"> + <span class="fa-solid fa-key"></span> Authentication Key + </h2> + <p>An authentication key is required if you want to upload images under your account <soontm>and be able to delete them.</soontm></p> + <div class="action_buttons"> + <button value="<%= authKey %>" id="authkey" class="button" onclick="copyAuthkey()">Copy to Clipboard</button> + </div> + </section> + <section class="infoblock"> + <h2 id="name"> + Files (<%= images.length %>) + </h2> + <div class="items"> + <% images.forEach((image, index) => { %> + <div class="item"> + <div id="info"> + <div id="numeration"> + <p><%= index + 1 %></p> + </div> + <div id="thumbnail"> + <img src="../images/<%= image.storage_id %>"> + </div> + <div id="summary"> + <!--<p id="desc"><% if (!image.description) {%> No description provided. <% } else { %> <%= image.description %> <%}%></p>--> + <p id="timestamp" title="Timestamp"><span class="fa-solid fa-stamp"></span> <%= image.timestamp %></p> + </div> + <div id="actions"> + <a href="/<%= image.id %>" class="button">View</a> + </div> + </div> + </div> + <%})%> + </div> + </section> + </div> + </div> + </body> + <script> + function copyAuthkey() { + var text = document.getElementById("authkey"); + navigator.clipboard.writeText(text.value); + alert("Copied the authentication key!"); + } + </script> +</html>
\ No newline at end of file diff --git a/static/ejs/partials/bar.ejs b/static/ejs/partials/bar.ejs new file mode 100644 index 0000000..550d9e2 --- /dev/null +++ b/static/ejs/partials/bar.ejs @@ -0,0 +1,7 @@ +<nav> + <div class="content"> + <a href="#"> + API + </a> + </div> +</nav>
\ No newline at end of file diff --git a/static/ejs/partials/meta.ejs b/static/ejs/partials/meta.ejs new file mode 100644 index 0000000..38aa1df --- /dev/null +++ b/static/ejs/partials/meta.ejs @@ -0,0 +1 @@ +<link rel="stylesheet" href="../css/style.css">
\ No newline at end of file diff --git a/static/html/index.html b/static/html/index.html deleted file mode 100644 index 212b1aa..0000000 --- a/static/html/index.html +++ /dev/null @@ -1,62 +0,0 @@ -<!-- - Copyright 2022 ilotterytea - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<!DOCTYPE html> -<html> - <head> - <title>file hoster</title> - <link rel="stylesheet" href="css/style.css"> - <meta property="og:title" content="iLotterytea's file hoster"> - <meta property="og:description" content="iLotterytea's file hoster. Powered by notdankenough/fh. "> - <meta property="og:image" content="webimg/favicon.png"> - </head> - <body> - <div class="container"> - <div class="content"> - <section id="brand"> - <a href="/"> - <img src="webimg/favicon.png" width="64" title="{{AboutFileHoster}}"> - </a> - </section> - - <section id="uploadform"> - <form action="dank_upload" method="post" enctype="multipart/form-data"> - <p>Select file to upload: </p> - <input accept="image/*" name="file" id="fileu" type="file" onchange="loadFile(event)"> - <input value="Upload" name="submit" type="submit" id="submitbtn" disabled="true"> - </form> - </section> - - </div> - - </div> - <section id="i_preview"> - <img id="preview" src="#" alt=""> - </section> - - </body> - <script> - var loadFile = function(event) { - var out = document.getElementById("preview"); - var btn = document.getElementById("submitbtn"); - out.src = URL.createObjectURL(event.target.files[0]); - btn.disabled = false; - out.onload = function() { - URL.revokeObjectURL(out.src); - } - } - </script> -</html>
\ No newline at end of file diff --git a/static/webimg/favicon.png b/static/img/favicon.png Binary files differindex 4b165b8..4b165b8 100644 --- a/static/webimg/favicon.png +++ b/static/img/favicon.png diff --git a/static/img/twitch.png b/static/img/twitch.png Binary files differnew file mode 100644 index 0000000..d7b64a1 --- /dev/null +++ b/static/img/twitch.png diff --git a/tsconfig.json b/tsconfig.json index 1b7a608..03dfc11 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,7 +27,7 @@ /* Modules */ "module": "commonjs", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ @@ -35,7 +35,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - "resolveJsonModule": true, /* Enable importing .json files. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ @@ -49,7 +49,7 @@ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./dist", /* Specify an output folder for all emitted files. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ |
