From 06777cca9293ea0dc50fd88c7954dd662f7c02aa Mon Sep 17 00:00:00 2001 From: dicedtomatoreal Date: Mon, 5 Oct 2020 14:50:32 -0700 Subject: [PATCH] #37 format --- .github/ISSUE_TEMPLATE/bug_report.md | 11 +- .github/workflows/node.js.yml | 19 +- .prettierignore | 4 + .prettierrc.json | 1 + CODE_OF_CONDUCT.md | 26 +- OLDREADME.md | 146 ++++---- README.md | 4 + package-lock.json | 8 +- package.json | 3 +- src/controllers/APIController.ts | 524 ++++++++++++++++++++------- src/controllers/IndexController.ts | 112 +++--- src/core/Console.ts | 22 +- src/entities/Image.ts | 30 +- src/entities/Note.ts | 47 +-- src/entities/Shorten.ts | 48 +-- src/entities/User.ts | 18 +- src/index.ts | 53 ++- src/interval.ts | 30 +- src/middleware/cookies.ts | 52 +-- src/middleware/cookiesForAPI.ts | 58 ++- src/server.ts | 77 ++-- src/structures/ConsoleFormatter.ts | 24 +- src/structures/DiscordWebhook.ts | 96 ++--- src/structures/GitHub.ts | 14 +- src/structures/ImageUtil.ts | 62 ++-- src/structures/ShortenUtil.ts | 62 ++-- src/util.ts | 62 ++-- tsconfig.json | 26 +- 28 files changed, 1038 insertions(+), 601 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc.json diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1fd613250..996524368 100755 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,10 +1,9 @@ --- name: Bug report about: Create a report to help us improve -title: '' +title: "" labels: bug assignees: dicedtomatoreal - --- **Describe the bug** @@ -12,6 +11,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -24,9 +24,10 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - - OS: [e.g. Arch] - - Browser [e.g. chrome, firefox, chrome mobile] - - Version [e.g. 2.0.0] + +- OS: [e.g. Arch] +- Browser [e.g. chrome, firefox, chrome mobile] +- Version [e.g. 2.0.0] **Additional context** Add any other context about the problem here. diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 3b8d0553d..314aa0785 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -5,13 +5,12 @@ name: Node.js CI on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] jobs: build: - runs-on: ubuntu-latest strategy: @@ -19,10 +18,10 @@ jobs: node-version: [14.x] steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - run: npm ci - - run: npm run build --if-present + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm run build --if-present diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..ca5be0512 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +dist +scripts +public +views \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 09827eb16..a4ba3a94c 100755 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -14,22 +14,22 @@ appearance, race, religion, or sexual identity and orientation. Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting ## Our Responsibilities diff --git a/OLDREADME.md b/OLDREADME.md index 3f4fb7974..021016a4a 100755 --- a/OLDREADME.md +++ b/OLDREADME.md @@ -155,26 +155,26 @@ Every single configuration option will be listed here | `upload.fileLength` | integer | how long the random id for a file should be | | `upload.tempDir` | string | temporary directory, files are stored here and then deleted. | | `upload.uploadDir` | string | upload directory (where all uploads are stored) | -| `upload.route` | string | Route for uploads, default is /u, ex.`/u/hd27ua.png` | +| `upload.route` | string | Route for uploads, default is /u, ex.`/u/hd27ua.png` | #### User Settings **Config Property:** `user` -| Config Property | Type | Description / Expected Values | -| ------------------- | ------- | ------------------------------------------------------------ | -| `user.tokenLength` | integer | How long the randomly generated user token should be | +| Config Property | Type | Description / Expected Values | +| ------------------ | ------- | ---------------------------------------------------- | +| `user.tokenLength` | integer | How long the randomly generated user token should be | #### Site Settings **Config Property:** `site` -| Config Property | Type | Description / Expected Values | -| --------------- | ------- | ------------------------------------------------------ | -| `site.protocol` | integer | protocol (http or https) | -| `site.serveHTTP` | string | Port to run the web server on with HTTP (can be used with nginx + CloudFlare as a reverse proxy and let CloudFlare take care of SSL) | -| `site.serveHTTPS` | string | Port to run the web server on with HTTPS (only will be used if `site.protocol` is `https`) (you will need SSL certificates! See [this](#site-ssl-settings)) | -| `site.logRoutes` | boolean | Wether or not to log routes when they are requested | +| Config Property | Type | Description / Expected Values | +| ----------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `site.protocol` | integer | protocol (http or https) | +| `site.serveHTTP` | string | Port to run the web server on with HTTP (can be used with nginx + CloudFlare as a reverse proxy and let CloudFlare take care of SSL) | +| `site.serveHTTPS` | string | Port to run the web server on with HTTPS (only will be used if `site.protocol` is `https`) (you will need SSL certificates! See [this](#site-ssl-settings)) | +| `site.logRoutes` | boolean | Wether or not to log routes when they are requested | #### Site SSL Settings @@ -182,16 +182,16 @@ Every single configuration option will be listed here | Config Property | Type | Description / Expected Values | | --------------- | ------ | ----------------------------------------------- | -| `site.ssl.key` | string | path to ssl private key. ex: `./ssl/server.key` | -| `site.ssl.cert` | string | path to ssl certificate. ex: `./ssl/cert.crt` | +| `site.ssl.key` | string | path to ssl private key. ex: `./ssl/server.key` | +| `site.ssl.cert` | string | path to ssl certificate. ex: `./ssl/cert.crt` | #### Administrator User **Config Property:** `administrator` -| Config Property | Type | Description / Expected Values | -| ----------------------------- | ------ | -------------------------------------------------------------------------------------------------------- | -| `administrator.password` | string | password of administrator user (NOT RECOMENDED to use administrator user, set this to a SECURE password) | +| Config Property | Type | Description / Expected Values | +| ------------------------ | ------ | -------------------------------------------------------------------------------------------------------- | +| `administrator.password` | string | password of administrator user (NOT RECOMENDED to use administrator user, set this to a SECURE password) | #### Database Configuration @@ -232,63 +232,60 @@ Particles.JS, can be enabled and it's config can be changed willingly. | `meta.favicon` | string | has to be in /public/assets folder and should be formatted as `"/public/assets/"` | | `meta.title` | string | title of your server shows up like ` - Login` or `<title> - Dashboard` | - ### Example Config ```json { - "upload": { - "fileLength": 6, - "tempDir": "./temp", - "uploadDir": "./uploads", - "route": "/u" - }, - "shorten": { - "idLength": 4, - "route": "/s" - }, - "user": { - "tokenLength": 32 - }, - "site": { - "protocol": "http", - "returnProtocol": "https", - "ssl": { - "key": "./ssl/server.key", - "cert": "./ssl/server.crt" - }, - "serveHTTPS": 8000, - "serveHTTP": 443, - "logRoutes": true + "upload": { + "fileLength": 6, + "tempDir": "./temp", + "uploadDir": "./uploads", + "route": "/u" + }, + "shorten": { + "idLength": 4, + "route": "/s" + }, + "user": { + "tokenLength": 32 + }, + "site": { + "protocol": "http", + "returnProtocol": "https", + "ssl": { + "key": "./ssl/server.key", + "cert": "./ssl/server.crt" }, - "administrator": { - "password": "1234" - }, - "orm": { - "type": "postgres", - "host": "localhost", - "port": 5432, - "username": "user", - "password": "1234", - "database": "typex", - "synchronize": true, - "logging": false, - "entities": [ - "out/src/entities/**/*.js" - ] - }, - "sessionSecret": "1234", - "saltRounds": 10, // You might get an error if its over a certain number, so choose carefully. - "meta": { - "favicon": "/public/assets/typex_small_circle.png", - "title": "TypeX" - }, - "discordWebhook": { - "enabled": true, - "url": "https://canary.discordapp.com/api/webhooks/id/token", - "username": "TypeX Logs", - "avatarURL": "https://domain/public/assets/typex_small_circle.png" - } + "serveHTTPS": 8000, + "serveHTTP": 443, + "logRoutes": true + }, + "administrator": { + "password": "1234" + }, + "orm": { + "type": "postgres", + "host": "localhost", + "port": 5432, + "username": "user", + "password": "1234", + "database": "typex", + "synchronize": true, + "logging": false, + "entities": ["out/src/entities/**/*.js"] + }, + "sessionSecret": "1234", + "saltRounds": 10, // You might get an error if its over a certain number, so choose carefully. + "meta": { + "favicon": "/public/assets/typex_small_circle.png", + "title": "TypeX" + }, + "discordWebhook": { + "enabled": true, + "url": "https://canary.discordapp.com/api/webhooks/id/token", + "username": "TypeX Logs", + "avatarURL": "https://domain/public/assets/typex_small_circle.png" + } } ``` @@ -315,16 +312,17 @@ These are the options you must pass when uploading a url or image/file ### Uploader | Property | Value | -|-----------|-------------------------------------| +| --------- | ----------------------------------- | | URL | `https://<DOMAIN>/api/upload` | | Header | `authorization: <TOKEN>` | | Header | `content-type: multipart/form-data` | | File name | `file` | ### URL Shortener -| Property | Value | -|-----------|-------------------------------------| -| URL | `https://<DOMAIN>/api/shorten` | -| Header | `authorization: <TOKEN>` | -| Header | `content-type: application/json` | -| Data | `{"url": "<URL>"}` | + +| Property | Value | +| -------- | -------------------------------- | +| URL | `https://<DOMAIN>/api/shorten` | +| Header | `authorization: <TOKEN>` | +| Header | `content-type: application/json` | +| Data | `{"url": "<URL>"}` | diff --git a/README.md b/README.md index 9d8fc813b..b2c3d0feb 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # Zipline + Zipline is a Typescript based image/file uploading service & URL shortening service! Simple, and elegant. # Images + ![](https://cdn.diced.wtf/u/F1vtRX.png) ![](https://cdn.diced.wtf/u/a5BTaP.png) ![](https://cdn.diced.wtf/u/bdntjm.png) @@ -11,7 +13,9 @@ Zipline is a Typescript based image/file uploading service & URL shortening serv ![](https://cdn.diced.wtf/u/VTXMbo.png) # Bugs? + Make sure to open an issue if you think you ran into an issue, or need help with anything. # Where is all the old information here? + All configuration options have been moved to the wiki, as the README was getting too long and hard to manage. diff --git a/package-lock.json b/package-lock.json index 606fedfd0..b81033ed7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "typex", - "version": "2.1.3", + "version": "2.1.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1420,6 +1420,12 @@ "xtend": "^4.0.0" } }, + "prettier": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", + "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", + "dev": true + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", diff --git a/package.json b/package.json index 84f900093..c98f6799c 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ }, "devDependencies": { "mongodb": "^3.5.8", - "pg": "^8.0.3" + "pg": "^8.0.3", + "prettier": "2.1.2" } } diff --git a/src/controllers/APIController.ts b/src/controllers/APIController.ts index 5a1bd7d40..b3d8d3077 100755 --- a/src/controllers/APIController.ts +++ b/src/controllers/APIController.ts @@ -1,211 +1,426 @@ -import { BAD_REQUEST, FORBIDDEN } from 'http-status-codes'; -import { Controller, Middleware, Get, Post, Delete, Patch } from '@overnightjs/core'; -import { Request, Response } from 'express'; -import { ORMHandler } from '..'; -import { randomId, getImage, findFile, getShorten, hashPassword } from '../util'; -import { createReadStream, createWriteStream, unlinkSync, existsSync, mkdirSync, readFileSync } from 'fs' -import { User } from '../entities/User'; -import { sep } from 'path'; -import { cookiesForAPI } from '../middleware/cookiesForAPI'; -import { DiscordWebhook } from '../structures/DiscordWebhook'; -import { ImageUtil } from '../structures/ImageUtil'; -import { ShortenUtil } from '../structures/ShortenUtil'; +import { BAD_REQUEST, FORBIDDEN } from "http-status-codes"; +import { + Controller, + Middleware, + Get, + Post, + Delete, + Patch, +} from "@overnightjs/core"; +import { Request, Response } from "express"; +import { ORMHandler } from ".."; +import { + randomId, + getImage, + findFile, + getShorten, + hashPassword, +} from "../util"; +import { + createReadStream, + createWriteStream, + unlinkSync, + existsSync, + mkdirSync, + readFileSync, +} from "fs"; +import { User } from "../entities/User"; +import { sep } from "path"; +import { cookiesForAPI } from "../middleware/cookiesForAPI"; +import { DiscordWebhook } from "../structures/DiscordWebhook"; +import { ImageUtil } from "../structures/ImageUtil"; +import { ShortenUtil } from "../structures/ShortenUtil"; import { Note } from "../entities/Note"; -import Logger from '@ayanaware/logger'; -import multer from 'multer' +import Logger from "@ayanaware/logger"; +import multer from "multer"; -if (!findFile('config.json', process.cwd())) { - Logger.get('FS').error(`No config.json exists in the ${__dirname}, exiting...`) +if (!findFile("config.json", process.cwd())) { + Logger.get("FS").error( + `No config.json exists in the ${__dirname}, exiting...` + ); process.exit(1); } -const config = JSON.parse(readFileSync(findFile('config.json', process.cwd()), 'utf8')) +const config = JSON.parse( + readFileSync(findFile("config.json", process.cwd()), "utf8") +); const upload = multer({ dest: config.uploader.temp }); -@Controller('api') +@Controller("api") export class APIController { public orm: ORMHandler; - @Post('upload') - @Middleware(upload.single('file')) + @Post("upload") + @Middleware(upload.single("file")) private async upload(req: Request, res: Response) { - const users = await this.orm.repos.user.find({ where: { token: req.headers['authorization'] } }); - if (!users[0]) return res.status(FORBIDDEN).json({ code: FORBIDDEN, message: "Unauthorized" }) - if (req.headers['authorization'] !== users[0].token) return res.status(FORBIDDEN).json({ code: FORBIDDEN, message: "Unauthorized" }) + const users = await this.orm.repos.user.find({ + where: { token: req.headers["authorization"] }, + }); + if (!users[0]) + return res + .status(FORBIDDEN) + .json({ code: FORBIDDEN, message: "Unauthorized" }); + if (req.headers["authorization"] !== users[0].token) + return res + .status(FORBIDDEN) + .json({ code: FORBIDDEN, message: "Unauthorized" }); const user = users[0]; const id = randomId(config.uploader.length); - if (config.uploader.blacklistedExt.includes(req.file.originalname.split('.').pop())) return res.status(BAD_REQUEST).json({ code: BAD_REQUEST, message: 'The extension used in this file is blacklisted.' }) + if ( + config.uploader.blacklistedExt.includes( + req.file.originalname.split(".").pop() + ) + ) + return res + .status(BAD_REQUEST) + .json({ + code: BAD_REQUEST, + message: "The extension used in this file is blacklisted.", + }); const source = createReadStream(req.file.path); if (!existsSync(config.uploader.upload)) mkdirSync(config.uploader.upload); - const destination = createWriteStream(`${config.uploader.upload}${sep}${id}.${req.file.originalname.split('.').pop()}`); + const destination = createWriteStream( + `${config.uploader.upload}${sep}${id}.${req.file.originalname + .split(".") + .pop()}` + ); source.pipe(destination, { end: false }); source.on("end", function () { unlinkSync(req.file.path); }); - const img = await getImage(this.orm, `${req.protocol}://${req.headers['host']}${config.uploader.route}/${id}.${req.file.originalname.split('.').pop()}`, user.id) - Logger.get('TypeX.Uploader').info(`New image uploaded ${img.url} (${img.id}) by ${user.username} (${user.id})`) - if (config.discordWebhook.enabled) new DiscordWebhook(config.discordWebhook.url).sendImageUpdate(user, ImageUtil.parseURL(img.url), config); - return res.status(200).send(`${req.protocol}://${req.headers['host']}${config.uploader.route}/${id}.${req.file.originalname.split('.').pop()}`) + const img = await getImage( + this.orm, + `${req.protocol}://${req.headers["host"]}${ + config.uploader.route + }/${id}.${req.file.originalname.split(".").pop()}`, + user.id + ); + Logger.get("TypeX.Uploader").info( + `New image uploaded ${img.url} (${img.id}) by ${user.username} (${user.id})` + ); + if (config.discordWebhook.enabled) + new DiscordWebhook(config.discordWebhook.url).sendImageUpdate( + user, + ImageUtil.parseURL(img.url), + config + ); + return res + .status(200) + .send( + `${req.protocol}://${req.headers["host"]}${ + config.uploader.route + }/${id}.${req.file.originalname.split(".").pop()}` + ); } - @Post('shorten') + @Post("shorten") private async shorten(req: Request, res: Response) { - const users = await this.orm.repos.user.find({ where: { token: req.headers['authorization'] } }); - if (!users[0]) return res.status(FORBIDDEN).json({ code: FORBIDDEN, message: "Unauthorized" }) - if (req.headers['authorization'] !== users[0].token) return res.status(FORBIDDEN).json({ code: FORBIDDEN, message: "Unauthorized" }) + const users = await this.orm.repos.user.find({ + where: { token: req.headers["authorization"] }, + }); + if (!users[0]) + return res + .status(FORBIDDEN) + .json({ code: FORBIDDEN, message: "Unauthorized" }); + if (req.headers["authorization"] !== users[0].token) + return res + .status(FORBIDDEN) + .json({ code: FORBIDDEN, message: "Unauthorized" }); const user = users[0]; - const id = randomId(config.shortener.length) - const shrt = await getShorten(this.orm, id, req.body.url, `${req.protocol}://${req.headers['host']}${config.shortener.route}/${id}`, user.id); - Logger.get('TypeX.Shortener').info(`New url shortened ${shrt.url} (${req.body.url}) (${shrt.id}) by ${user.username} (${user.id})`) - if (config.discordWebhook.enabled) new DiscordWebhook(config.discordWebhook.url).sendShortenUpdate(user, shrt, ShortenUtil.parseURL(shrt.url), config); - return res.status(200).send(`${req.protocol}://${req.headers['host']}${config.shortener.route}/${id}`) + const id = randomId(config.shortener.length); + const shrt = await getShorten( + this.orm, + id, + req.body.url, + `${req.protocol}://${req.headers["host"]}${config.shortener.route}/${id}`, + user.id + ); + Logger.get("TypeX.Shortener").info( + `New url shortened ${shrt.url} (${req.body.url}) (${shrt.id}) by ${user.username} (${user.id})` + ); + if (config.discordWebhook.enabled) + new DiscordWebhook(config.discordWebhook.url).sendShortenUpdate( + user, + shrt, + ShortenUtil.parseURL(shrt.url), + config + ); + return res + .status(200) + .send( + `${req.protocol}://${req.headers["host"]}${config.shortener.route}/${id}` + ); } - @Post('note') + @Post("note") private async note(req: Request, res: Response) { - const users = await this.orm.repos.user.find({ where: { token: req.headers['authorization'] } }); - if (!users[0]) return res.status(FORBIDDEN).json({ code: FORBIDDEN, message: "Unauthorized" }) - if (req.headers['authorization'] !== users[0].token) return res.status(FORBIDDEN).json({ code: FORBIDDEN, message: "Unauthorized" }) + const users = await this.orm.repos.user.find({ + where: { token: req.headers["authorization"] }, + }); + if (!users[0]) + return res + .status(FORBIDDEN) + .json({ code: FORBIDDEN, message: "Unauthorized" }); + if (req.headers["authorization"] !== users[0].token) + return res + .status(FORBIDDEN) + .json({ code: FORBIDDEN, message: "Unauthorized" }); const user = users[0]; - const id = randomId(config.notes.length) - const note = await this.orm.repos.note.save(new Note().set({ - key: id, - user: user.id, - content: req.body.content, - expiration: req.body.expiration ? req.body.expiration : null - })); - Logger.get('TypeX.Notes').info(`New note created ${note.id} and ${note.expriation ? `will expire in ${note.expriation},` : `will not expire,`} by ${user.username} (${user.id})`) + const id = randomId(config.notes.length); + const note = await this.orm.repos.note.save( + new Note().set({ + key: id, + user: user.id, + content: req.body.content, + expiration: req.body.expiration ? req.body.expiration : null, + }) + ); + Logger.get("TypeX.Notes").info( + `New note created ${note.id} and ${ + note.expriation + ? `will expire in ${note.expriation},` + : `will not expire,` + } by ${user.username} (${user.id})` + ); // if (config.discordWebhook.enabled) new DiscordWebhook(config.discordWebhook.url).sendShortenUpdate(user, shrt, ShortenUtil.parseURL(shrt.url), config); - return res.status(200).send(`${req.protocol}://${req.headers['host']}${config.notes.route}/${id}`) + return res + .status(200) + .send( + `${req.protocol}://${req.headers["host"]}${config.notes.route}/${id}` + ); } - @Get('users') + @Get("users") @Middleware(cookiesForAPI) private async getUsers(req: Request, res: Response) { - if (!req.session.user.administrator) return res.status(FORBIDDEN).json({ code: FORBIDDEN, message: 'Unauthorized' }); + if (!req.session.user.administrator) + return res + .status(FORBIDDEN) + .json({ code: FORBIDDEN, message: "Unauthorized" }); try { - let users = await this.orm.repos.user.find({ order: { id: 'ASC' } }) + let users = await this.orm.repos.user.find({ order: { id: "ASC" } }); return res.status(200).json(users); } catch (e) { - return res.status(BAD_REQUEST).json({ error: "Could not create user: " + e.message }) + return res + .status(BAD_REQUEST) + .json({ error: "Could not create user: " + e.message }); } } - @Post('users') + @Post("users") @Middleware(cookiesForAPI) private async createUser(req: Request, res: Response) { - if (!req.session.user.administrator) return res.status(FORBIDDEN).json({ code: FORBIDDEN, message: 'Unauthorized' }); + if (!req.session.user.administrator) + return res + .status(FORBIDDEN) + .json({ code: FORBIDDEN, message: "Unauthorized" }); const data = req.body; try { - let user = await this.orm.repos.user.findOne({ username: data.username }) - if (user) return res.status(BAD_REQUEST).json({ error: "Could not create user: user exists already" }) - user = await this.orm.repos.user.save(new User().set({ username: data.username, password: hashPassword(data.password, config.core.saltRounds), administrator: data.administrator })) - Logger.get('TypeX.User.Create').info(`User ${user.username} (${user.id}) was created`) + let user = await this.orm.repos.user.findOne({ username: data.username }); + if (user) + return res + .status(BAD_REQUEST) + .json({ error: "Could not create user: user exists already" }); + user = await this.orm.repos.user.save( + new User().set({ + username: data.username, + password: hashPassword(data.password, config.core.saltRounds), + administrator: data.administrator, + }) + ); + Logger.get("TypeX.User.Create").info( + `User ${user.username} (${user.id}) was created` + ); return res.status(200).json(user); } catch (e) { - return res.status(BAD_REQUEST).json({ error: "Could not create user: " + e.message }) + return res + .status(BAD_REQUEST) + .json({ error: "Could not create user: " + e.message }); } } - @Post('users/register') + @Post("users/register") private async registerUser(req: Request, res: Response) { const data = req.body; - if (!config.core.public) return res.status(BAD_REQUEST).json({ error: 'This zipline server does not have public enabled, therefore can\'t create a user.' }); + if (!config.core.public) + return res + .status(BAD_REQUEST) + .json({ + error: + "This zipline server does not have public enabled, therefore can't create a user.", + }); try { - let user = await this.orm.repos.user.findOne({ username: data.username }) - if (user) return res.status(BAD_REQUEST).json({ error: "Could not create user: user exists already" }); - user = await this.orm.repos.user.save(new User().set({ username: data.username, password: hashPassword(data.password, config.core.saltRounds), administrator: false })); + let user = await this.orm.repos.user.findOne({ username: data.username }); + if (user) + return res + .status(BAD_REQUEST) + .json({ error: "Could not create user: user exists already" }); + user = await this.orm.repos.user.save( + new User().set({ + username: data.username, + password: hashPassword(data.password, config.core.saltRounds), + administrator: false, + }) + ); return res.status(200).json({ success: true }); } catch (e) { - return res.status(BAD_REQUEST).json({ error: `Couldn't create user: ${e.message}` }) - } + return res + .status(BAD_REQUEST) + .json({ error: `Couldn't create user: ${e.message}` }); + } } - @Patch('users/:id') + @Patch("users/:id") @Middleware(cookiesForAPI) private async patchUser(req: Request, res: Response) { const data = req.body; - if (!data.payload) return res.status(FORBIDDEN).json({ code: BAD_REQUEST, message: 'No payload specified.' }); - if (data.payload === 'USER_EDIT') { - if (Number(req.params.id) !== Number(req.session.user.id)) return res.status(FORBIDDEN).json({ code: FORBIDDEN, message: 'Unauthorized' }); - data.password = hashPassword(data.password, config.core.saltRounds) + if (!data.payload) + return res + .status(FORBIDDEN) + .json({ code: BAD_REQUEST, message: "No payload specified." }); + if (data.payload === "USER_EDIT") { + if (Number(req.params.id) !== Number(req.session.user.id)) + return res + .status(FORBIDDEN) + .json({ code: FORBIDDEN, message: "Unauthorized" }); + data.password = hashPassword(data.password, config.core.saltRounds); try { - let user = await this.orm.repos.user.findOne({ id: Number(req.params.id) }) - if (!user) return res.status(BAD_REQUEST).json({ error: "Could not edit user: user doesnt exist" }) - this.orm.repos.user.update({ id: Number(req.params.id) }, { username: data.username, password: data.password }); - Logger.get('TypeX.User.Edit').info(`User ${user.username} (${user.id}) was edited`) + let user = await this.orm.repos.user.findOne({ + id: Number(req.params.id), + }); + if (!user) + return res + .status(BAD_REQUEST) + .json({ error: "Could not edit user: user doesnt exist" }); + this.orm.repos.user.update( + { id: Number(req.params.id) }, + { username: data.username, password: data.password } + ); + Logger.get("TypeX.User.Edit").info( + `User ${user.username} (${user.id}) was edited` + ); return res.status(200).json(user); } catch (e) { - return res.status(BAD_REQUEST).json({ error: "Could not edit user: " + e.message }) + return res + .status(BAD_REQUEST) + .json({ error: "Could not edit user: " + e.message }); } - } else if (data.payload === 'USER_RESET_PASSWORD') { - data.password = hashPassword(data.password, config.core.saltRounds) + } else if (data.payload === "USER_RESET_PASSWORD") { + data.password = hashPassword(data.password, config.core.saltRounds); try { - let user = await this.orm.repos.user.findOne({ id: Number(req.params.id) }) - if (!user) return res.status(BAD_REQUEST).json({ error: "Could not reset password: user doesnt exist" }) - this.orm.repos.user.update({ id: Number(req.params.id) }, { password: data.password }); - Logger.get('TypeX.User.Edit.ResetPassword').info(`User ${user.username} (${user.id}) had their password reset.`) + let user = await this.orm.repos.user.findOne({ + id: Number(req.params.id), + }); + if (!user) + return res + .status(BAD_REQUEST) + .json({ error: "Could not reset password: user doesnt exist" }); + this.orm.repos.user.update( + { id: Number(req.params.id) }, + { password: data.password } + ); + Logger.get("TypeX.User.Edit.ResetPassword").info( + `User ${user.username} (${user.id}) had their password reset.` + ); return res.status(200).json(user); } catch (e) { - return res.status(BAD_REQUEST).json({ error: "Could not reset password: " + e.message }) + return res + .status(BAD_REQUEST) + .json({ error: "Could not reset password: " + e.message }); } - } else if (data.payload === 'USER_TOKEN_RESET') { + } else if (data.payload === "USER_TOKEN_RESET") { try { - let user = await this.orm.repos.user.findOne({ id: req.session.user.id }) - if (!user) return res.status(BAD_REQUEST).json({ error: "Could not regen token: user doesnt exist" }) + let user = await this.orm.repos.user.findOne({ + id: req.session.user.id, + }); + if (!user) + return res + .status(BAD_REQUEST) + .json({ error: "Could not regen token: user doesnt exist" }); user.token = randomId(config.core.userTokenLength); req.session.user = user; await this.orm.repos.user.save(user); - Logger.get('TypeX.User.Token').info(`User ${user.username} (${user.id}) token was regenerated`) + Logger.get("TypeX.User.Token").info( + `User ${user.username} (${user.id}) token was regenerated` + ); return res.status(200).json(user); } catch (e) { - return res.status(BAD_REQUEST).json({ error: "Could not regen token: " + e.message }) + return res + .status(BAD_REQUEST) + .json({ error: "Could not regen token: " + e.message }); } } else { console.log(data); } } - @Delete('users/:id') + @Delete("users/:id") @Middleware(cookiesForAPI) private async deleteUser(req: Request, res: Response) { - if (!req.session.user.administrator) return res.status(FORBIDDEN).json({ code: FORBIDDEN, message: 'Unauthorized' }); + if (!req.session.user.administrator) + return res + .status(FORBIDDEN) + .json({ code: FORBIDDEN, message: "Unauthorized" }); try { - let user = await this.orm.repos.user.findOne({ id: Number(req.params.id) }) - if (!user) return res.status(BAD_REQUEST).json({ error: "Could not delete user: user doesnt exist" }) + let user = await this.orm.repos.user.findOne({ + id: Number(req.params.id), + }); + if (!user) + return res + .status(BAD_REQUEST) + .json({ error: "Could not delete user: user doesnt exist" }); this.orm.repos.user.delete({ id: Number(req.params.id) }); - Logger.get('TypeX.User.Delete').info(`User ${user.username} (${user.id}) was deleted`) + Logger.get("TypeX.User.Delete").info( + `User ${user.username} (${user.id}) was deleted` + ); return res.status(200).json(user); } catch (e) { - return res.status(BAD_REQUEST).json({ error: "Could not delete user: " + e.message }) + return res + .status(BAD_REQUEST) + .json({ error: "Could not delete user: " + e.message }); } } - @Get('images') + @Get("images") @Middleware(cookiesForAPI) private async allImages(req: Request, res: Response) { - const all = await this.orm.repos.image.find({ where: { user: req.session.user.id }, order: { id: 'ASC' } }); + const all = await this.orm.repos.image.find({ + where: { user: req.session.user.id }, + order: { id: "ASC" }, + }); return res.status(200).json(all); } - @Get('images/statistics') + @Get("images/statistics") @Middleware(cookiesForAPI) private async statistics(req: Request, res: Response) { - const all = await this.orm.repos.image.find({ where: { user: req.session.user.id }, order: { id: 'ASC' } }); - const totalViews = all.map(i => i.views).length !== 0 ? all.map(i => i.views).reduce((a, b) => Number(a) + Number(b)) : 0 + const all = await this.orm.repos.image.find({ + where: { user: req.session.user.id }, + order: { id: "ASC" }, + }); + const totalViews = + all.map((i) => i.views).length !== 0 + ? all.map((i) => i.views).reduce((a, b) => Number(a) + Number(b)) + : 0; const users = await this.orm.repos.user.find(); const images = []; const views = []; for (const user of users) { - const i = await this.orm.repos.image.find({ where: { user: user.id }, order: { views: 'ASC' } }); + const i = await this.orm.repos.image.find({ + where: { user: user.id }, + order: { views: "ASC" }, + }); images.push({ username: user.username, - count: i.length + count: i.length, }); views.push({ username: user.username, - count: i.map(i => i.views).length !== 0 ? i.map(i => i.views).reduce((a, b) => Number(a) + Number(b)) : 0 - }) + count: + i.map((i) => i.views).length !== 0 + ? i.map((i) => i.views).reduce((a, b) => Number(a) + Number(b)) + : 0, + }); } return res.status(200).json({ totalViews, @@ -213,39 +428,57 @@ export class APIController { average: totalViews / all.length, table: { images: images.sort((a, b) => b.count - a.count), - views: views.sort((a, b) => b.count - a.count) - } + views: views.sort((a, b) => b.count - a.count), + }, }); - } - @Delete('images/:id') + @Delete("images/:id") @Middleware(cookiesForAPI) private async deleteImage(req: Request, res: Response) { try { - let image = await this.orm.repos.image.findOne({ id: Number(req.params.id) }) - if (!image) return res.status(BAD_REQUEST).json({ error: "Could not delete image: image doesnt exist in database" }) + let image = await this.orm.repos.image.findOne({ + id: Number(req.params.id), + }); + if (!image) + return res + .status(BAD_REQUEST) + .json({ + error: "Could not delete image: image doesnt exist in database", + }); this.orm.repos.image.delete({ id: Number(req.params.id) }); const url = new URL(image.url); unlinkSync(`${config.uploader.upload}${sep}${url.pathname.slice(3)}`); - Logger.get('TypeX.Images.Delete').info(`Image ${image.url} (${image.id}) was deleted from ${config.uploader.upload}${sep}${url.pathname.slice(3)}`) + Logger.get("TypeX.Images.Delete").info( + `Image ${image.url} (${image.id}) was deleted from ${ + config.uploader.upload + }${sep}${url.pathname.slice(3)}` + ); return res.status(200).json(image); } catch (e) { - return res.status(BAD_REQUEST).json({ error: "Could not delete image: " + e.message }) + return res + .status(BAD_REQUEST) + .json({ error: "Could not delete image: " + e.message }); } } - @Get('images/:id') + @Get("images/:id") @Middleware(cookiesForAPI) private async imagesUser(req: Request, res: Response) { - const all = await this.orm.repos.image.find({ where: { id: req.params.id }, order: { id: 'ASC' } }); + const all = await this.orm.repos.image.find({ + where: { id: req.params.id }, + order: { id: "ASC" }, + }); return res.status(200).json(all); } - @Get('images/user/pages') + @Get("images/user/pages") @Middleware(cookiesForAPI) private async pagedUser(req: Request, res: Response) { - const all = await this.orm.repos.image.find({ where: { user: req.session.user.id }, order: { id: 'ASC' } }); + const all = await this.orm.repos.image.find({ + where: { user: req.session.user.id }, + order: { id: "ASC" }, + }); const paged = []; const pagedNums = []; while (all.length) paged.push(all.splice(0, 25)); @@ -254,59 +487,78 @@ export class APIController { else return res.status(200).json({ page: paged[Number(req.query.page)] }); } - @Get('shortens') + @Get("shortens") @Middleware(cookiesForAPI) private async allShortens(req: Request, res: Response) { - const all = await this.orm.repos.shorten.find({ where: { user: req.session.user.id }, order: { id: 'ASC' } }); + const all = await this.orm.repos.shorten.find({ + where: { user: req.session.user.id }, + order: { id: "ASC" }, + }); return res.status(200).json(all); } - @Get('shortens/:id') + @Get("shortens/:id") @Middleware(cookiesForAPI) private async getShorten(req: Request, res: Response) { - const all = await this.orm.repos.shorten.find({ where: { user: req.session.user.id, id: Number(req.params.id) }, order: { id: 'ASC' } }); + const all = await this.orm.repos.shorten.find({ + where: { user: req.session.user.id, id: Number(req.params.id) }, + order: { id: "ASC" }, + }); return res.status(200).json(all); } - @Get('notes') + @Get("notes") @Middleware(cookiesForAPI) private async allNotes(req: Request, res: Response) { - const all = await this.orm.repos.note.find({ where: { user: req.session.user.id }, order: { id: 'ASC' } }); + const all = await this.orm.repos.note.find({ + where: { user: req.session.user.id }, + order: { id: "ASC" }, + }); return res.status(200).json(all); } - @Get('notes/:id') + @Get("notes/:id") @Middleware(cookiesForAPI) private async getNote(req: Request, res: Response) { - const all = await this.orm.repos.note.find({ where: { user: req.session.user.id, id: Number(req.params.id) }, order: { id: 'ASC' } }); + const all = await this.orm.repos.note.find({ + where: { user: req.session.user.id, id: Number(req.params.id) }, + order: { id: "ASC" }, + }); return res.status(200).json(all); } - @Get('stats') + @Get("stats") private async getStats(req: Request, res: Response) { const memory = process.memoryUsage(); - const views: number = (await this.orm.repos.image.find()).map((a) => a.views).reduce((a, b) => Number(a) + Number(b), 0); - const clicks: number = (await this.orm.repos.shorten.find()).map((a) => a.clicks).reduce((a, b) => Number(a) + Number(b), 0); + const views: number = (await this.orm.repos.image.find()) + .map((a) => a.views) + .reduce((a, b) => Number(a) + Number(b), 0); + const clicks: number = (await this.orm.repos.shorten.find()) + .map((a) => a.clicks) + .reduce((a, b) => Number(a) + Number(b), 0); return res.status(200).json({ memory, uploadedStatistics: { - views, clicks + views, + clicks, }, count: { image: await this.orm.repos.image.count(), note: await this.orm.repos.note.count(), shorten: await this.orm.repos.shorten.count(), - user: await this.orm.repos.user.count() + user: await this.orm.repos.user.count(), }, zipline: { - version: JSON.parse(readFileSync(findFile('package.json', process.cwd()), 'utf8')).version, - database: this.orm.connection.options.type - } - }) + version: JSON.parse( + readFileSync(findFile("package.json", process.cwd()), "utf8") + ).version, + database: this.orm.connection.options.type, + }, + }); } public set(orm: ORMHandler) { this.orm = orm; return this; } -} \ No newline at end of file +} diff --git a/src/controllers/IndexController.ts b/src/controllers/IndexController.ts index 1c7dc705b..a10d230a3 100755 --- a/src/controllers/IndexController.ts +++ b/src/controllers/IndexController.ts @@ -1,84 +1,112 @@ -import { Controller, Middleware, Get, Post } from '@overnightjs/core'; -import { Request, Response } from 'express'; -import { ORMHandler } from '..'; -import { findFile, checkPassword } from '../util'; -import { readFileSync } from 'fs'; -import { cookies } from '../middleware/cookies'; -import Logger from '@ayanaware/logger'; +import { Controller, Middleware, Get, Post } from "@overnightjs/core"; +import { Request, Response } from "express"; +import { ORMHandler } from ".."; +import { findFile, checkPassword } from "../util"; +import { readFileSync } from "fs"; +import { cookies } from "../middleware/cookies"; +import Logger from "@ayanaware/logger"; -if (!findFile('config.json', process.cwd())) { - Logger.get('FS').error(`No config.json exists in the ${__dirname}, exiting...`) +if (!findFile("config.json", process.cwd())) { + Logger.get("FS").error( + `No config.json exists in the ${__dirname}, exiting...` + ); process.exit(1); } -const config = JSON.parse(readFileSync(findFile('config.json', process.cwd()), 'utf8')) +const config = JSON.parse( + readFileSync(findFile("config.json", process.cwd()), "utf8") +); -@Controller('') +@Controller("") export class IndexController { public orm: ORMHandler; - @Get('') + @Get("") @Middleware(cookies) private async index(req: Request, res: Response) { - const images = await this.orm.repos.image.find({ where: { user: req.session.user.id } }); - const users = await this.orm.repos.user.find({ order: { id: 'ASC' } }); + const images = await this.orm.repos.image.find({ + where: { user: req.session.user.id }, + }); + const users = await this.orm.repos.user.find({ order: { id: "ASC" } }); const userImages = []; for (let i = 0; i < users.length; i++) { - userImages[i] = await (await this.orm.repos.image.find({where:{user:users[i].id}})).length + userImages[i] = await ( + await this.orm.repos.image.find({ where: { user: users[i].id } }) + ).length; } - return res.render('index', { user: req.session.user, images, users, userImages, config }) + return res.render("index", { + user: req.session.user, + images, + users, + userImages, + config, + }); } - @Get('login') + @Get("login") private async login(req: Request, res: Response) { - if (req.session.user || req.cookies.typex_user) return res.redirect('/'); - return res.status(200).render('login', { failed: false, config }) + if (req.session.user || req.cookies.typex_user) return res.redirect("/"); + return res.status(200).render("login", { failed: false, config }); } - @Get('logout') + @Get("logout") private async logout(req: Request, res: Response) { - Logger.get('TypeX.Auth').info(`User ${req.session.user?.username} (${req.session.user?.id}) logged out`) + Logger.get("TypeX.Auth").info( + `User ${req.session.user?.username} (${req.session.user?.id}) logged out` + ); req.session.user = null; - res.clearCookie('typex_user'); - res.redirect('/login'); + res.clearCookie("typex_user"); + res.redirect("/login"); } - @Post('login') + @Post("login") private async postLogin(req: Request, res: Response) { - if (req.session.user || req.cookies.typex_user) return res.redirect('/'); - if (req.body.username === 'administrator' && req.body.password === config.core.adminPassword) { + if (req.session.user || req.cookies.typex_user) return res.redirect("/"); + if ( + req.body.username === "administrator" && + req.body.password === config.core.adminPassword + ) { //@ts-ignore req.session.user = { id: 0, - username: 'administrator', + username: "administrator", password: config.core.adminPassword, - administrator: true - } - res.cookie('typex_user', req.session.user.id, { maxAge: 1036800000 }); - Logger.get('TypeX.Auth').info(`Administrator has logged in from IP ${req.headers['x-forwarded-for'] || req.connection.remoteAddress}`) - return res.redirect('/') + administrator: true, + }; + res.cookie("typex_user", req.session.user.id, { maxAge: 1036800000 }); + Logger.get("TypeX.Auth").info( + `Administrator has logged in from IP ${ + req.headers["x-forwarded-for"] || req.connection.remoteAddress + }` + ); + return res.redirect("/"); } - const user = await this.orm.repos.user.findOne({ where: { username: req.body.username } }); - if (!user) return res.status(200).render('login', { failed: true, config }); - if (!checkPassword(req.body.password, user.password)) return res.status(200).render('login', { failed: true, config }) + const user = await this.orm.repos.user.findOne({ + where: { username: req.body.username }, + }); + if (!user) return res.status(200).render("login", { failed: true, config }); + if (!checkPassword(req.body.password, user.password)) + return res.status(200).render("login", { failed: true, config }); req.session.user = user; - res.cookie('typex_user', req.session.user.id, { maxAge: 1036800000 }); - return res.redirect('/'); + res.cookie("typex_user", req.session.user.id, { maxAge: 1036800000 }); + return res.redirect("/"); } @Get(`${config.shortener.route.slice(1)}/:id`) private async getShorten(req: Request, res: Response) { - const shorten = await this.orm.repos.shorten.findOne({ key: req.params.id }); - if (!shorten) return res.render('404'); + const shorten = await this.orm.repos.shorten.findOne({ + key: req.params.id, + }); + if (!shorten) return res.render("404"); shorten.clicks++; this.orm.repos.shorten.save(shorten); - return res.redirect(shorten.origin) + return res.redirect(shorten.origin); } @Get(`${config.notes.route.slice(1)}/:id`) private async getNote(req: Request, res: Response) { const note = await this.orm.repos.note.findOne({ key: req.params.id }); - if (!note) return res.render('404'); + if (!note) return res.render("404"); return res.send(note.content); } @@ -86,4 +114,4 @@ export class IndexController { this.orm = orm; return this; } -} \ No newline at end of file +} diff --git a/src/core/Console.ts b/src/core/Console.ts index becb05bf5..207772ff3 100755 --- a/src/core/Console.ts +++ b/src/core/Console.ts @@ -1,12 +1,16 @@ -import Logger, {ConsoleTransport, DefaultFormatter} from "@ayanaware/logger"; -import {ConsoleFormatter} from "../structures/ConsoleFormatter"; +import Logger, { ConsoleTransport, DefaultFormatter } from "@ayanaware/logger"; +import { ConsoleFormatter } from "../structures/ConsoleFormatter"; -Logger.setFormatter(new DefaultFormatter({ - disableDefaultColors: true -})); +Logger.setFormatter( + new DefaultFormatter({ + disableDefaultColors: true, + }) +); -Logger.addTransport(new ConsoleTransport({ - formatter: new ConsoleFormatter() -})); +Logger.addTransport( + new ConsoleTransport({ + formatter: new ConsoleFormatter(), + }) +); -Logger.disableDefaultTransport(); \ No newline at end of file +Logger.disableDefaultTransport(); diff --git a/src/entities/Image.ts b/src/entities/Image.ts index f422ff42f..232febb07 100755 --- a/src/entities/Image.ts +++ b/src/entities/Image.ts @@ -2,22 +2,22 @@ import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; @Entity() export class Image { - @PrimaryGeneratedColumn({ type: 'bigint' }) - id: number; + @PrimaryGeneratedColumn({ type: "bigint" }) + id: number; - @Column("text") - url: string; + @Column("text") + url: string; - @Column("bigint") - user: number; + @Column("bigint") + user: number; - @Column("bigint", { default: 0 }) - views: number; + @Column("bigint", { default: 0 }) + views: number; - set(options: { url: string, user: number }) { - this.url = options.url; - this.user = options.user; - this.views = 0; - return this; - } -} \ No newline at end of file + set(options: { url: string; user: number }) { + this.url = options.url; + this.user = options.user; + this.views = 0; + return this; + } +} diff --git a/src/entities/Note.ts b/src/entities/Note.ts index f431394ed..1e880584b 100755 --- a/src/entities/Note.ts +++ b/src/entities/Note.ts @@ -2,30 +2,35 @@ import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; @Entity() export class Note { - @PrimaryGeneratedColumn({ type: 'bigint' }) - id: number; + @PrimaryGeneratedColumn({ type: "bigint" }) + id: number; - @Column("bigint") - user: number; + @Column("bigint") + user: number; - @Column("text") - key: string; + @Column("text") + key: string; - @Column("bigint") - creation: number; + @Column("bigint") + creation: number; - @Column("bigint", { nullable: true, default: null }) - expriation: number; + @Column("bigint", { nullable: true, default: null }) + expriation: number; - @Column("text") - content: string; + @Column("text") + content: string; - set(options: { user: number, key: string, content: string, expiration?: number }) { - this.user = options.user; - this.key = options.key; - this.content = options.content; - this.creation = Date.now(); - this.expriation = options.expiration ? options.expiration : null; - return this; - } -} \ No newline at end of file + set(options: { + user: number; + key: string; + content: string; + expiration?: number; + }) { + this.user = options.user; + this.key = options.key; + this.content = options.content; + this.creation = Date.now(); + this.expriation = options.expiration ? options.expiration : null; + return this; + } +} diff --git a/src/entities/Shorten.ts b/src/entities/Shorten.ts index 14e539e21..0d8305598 100755 --- a/src/entities/Shorten.ts +++ b/src/entities/Shorten.ts @@ -2,34 +2,34 @@ import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; @Entity() export class Shorten { - @PrimaryGeneratedColumn({ type: 'bigint' }) - id: number; + @PrimaryGeneratedColumn({ type: "bigint" }) + id: number; - @Column("text") - origin: string; + @Column("text") + origin: string; - @Column("text") - url: string; + @Column("text") + url: string; - @Column("text", { default: "" }) - key: string; + @Column("text", { default: "" }) + key: string; - @Column("bigint") - user: number; + @Column("bigint") + user: number; - @Column("bigint", { default: 0 }) - views: number + @Column("bigint", { default: 0 }) + views: number; - @Column("bigint", { default: 0 }) - clicks: number; + @Column("bigint", { default: 0 }) + clicks: number; - set(options: { key: string, origin: string, url: string, user: number }) { - this.key = options.key; - this.origin = options.origin; - this.url = options.url; - this.user = options.user; - this.views = 0; - this.clicks = 0; - return this; - } -} \ No newline at end of file + set(options: { key: string; origin: string; url: string; user: number }) { + this.key = options.key; + this.origin = options.origin; + this.url = options.url; + this.user = options.user; + this.views = 0; + this.clicks = 0; + return this; + } +} diff --git a/src/entities/User.ts b/src/entities/User.ts index 6ee0b2dd4..d5e756f84 100755 --- a/src/entities/User.ts +++ b/src/entities/User.ts @@ -1,18 +1,22 @@ import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; import { randomId, findFile } from "../util"; import Logger from "@ayanaware/logger"; -import { readFileSync } from 'fs'; +import { readFileSync } from "fs"; -if (!findFile('config.json', process.cwd())) { - Logger.get('FS').error(`No config.json exists in the ${__dirname}, exiting...`) +if (!findFile("config.json", process.cwd())) { + Logger.get("FS").error( + `No config.json exists in the ${__dirname}, exiting...` + ); process.exit(1); } -const config = JSON.parse(readFileSync(findFile('config.json', process.cwd()), 'utf8')) +const config = JSON.parse( + readFileSync(findFile("config.json", process.cwd()), "utf8") +); @Entity() export class User { - @PrimaryGeneratedColumn({ type: 'bigint' }) + @PrimaryGeneratedColumn({ type: "bigint" }) id: number; @Column("text") @@ -27,11 +31,11 @@ export class User { @Column("boolean") administrator: boolean; - set(options: { username: string, password: string, administrator: boolean }) { + set(options: { username: string; password: string; administrator: boolean }) { this.username = options.username; this.password = options.password; this.administrator = options.administrator; - this.token = randomId(config.core.userTokenLength) + this.token = randomId(config.core.userTokenLength); return this; } } diff --git a/src/index.ts b/src/index.ts index 65a32e5ce..0bb0688c6 100755 --- a/src/index.ts +++ b/src/index.ts @@ -1,31 +1,31 @@ import "./core/Console"; -import { - Repository, - Connection, - createConnection -} from "typeorm"; +import { Repository, Connection, createConnection } from "typeorm"; import { User } from "./entities/User"; import { ZiplineServer } from "./server"; import Logger from "@ayanaware/logger"; import { Image } from "./entities/Image"; import { findFile } from "./util"; -import { readFileSync } from 'fs'; +import { readFileSync } from "fs"; import { Shorten } from "./entities/Shorten"; import { Note } from "./entities/Note"; import { notes } from "./interval"; import { GitHub } from "./structures/GitHub"; -import { compare, } from 'semver'; -import chalk from 'chalk'; +import { compare } from "semver"; +import chalk from "chalk"; -if (!findFile('config.json', process.cwd())) { - Logger.get('FS').error(`No config.json exists in ${__dirname}, exiting...`) +if (!findFile("config.json", process.cwd())) { + Logger.get("FS").error(`No config.json exists in ${__dirname}, exiting...`); process.exit(1); } -const config = JSON.parse(readFileSync(findFile('config.json', process.cwd()), 'utf8')) +const config = JSON.parse( + readFileSync(findFile("config.json", process.cwd()), "utf8") +); if (!config.uploader?.route) { - Logger.get('Zipline.Config').error(`Missing needed property on configuration: upload.route`) + Logger.get("Zipline.Config").error( + `Missing needed property on configuration: upload.route` + ); process.exit(1); } @@ -41,12 +41,27 @@ export interface ORMHandler { connection: Connection; } -const pk = JSON.parse(readFileSync(findFile('package.json', process.cwd()), 'utf8')); +const pk = JSON.parse( + readFileSync(findFile("package.json", process.cwd()), "utf8") +); (async () => { - if (compare(JSON.parse(await GitHub.getFile('package.json')).version, pk.version) == 1) Logger.get(`Zipline`).info(`Zipline is ${chalk.bold.redBright('outdated')}, you should run ${chalk.bold.whiteBright('./scripts/update.sh')} to get the best features.`); - Logger.get('Zipline').info(`Starting Zipline ${pk.version}`); - if (!config.database) return Logger.get('Config').error("Database is not found in config.") + if ( + compare( + JSON.parse(await GitHub.getFile("package.json")).version, + pk.version + ) == 1 + ) + Logger.get(`Zipline`).info( + `Zipline is ${chalk.bold.redBright( + "outdated" + )}, you should run ${chalk.bold.whiteBright( + "./scripts/update.sh" + )} to get the best features.` + ); + Logger.get("Zipline").info(`Starting Zipline ${pk.version}`); + if (!config.database) + return Logger.get("Config").error("Database is not found in config."); const connection = await createConnection(config.database); const orm: ORMHandler = { connection, @@ -54,7 +69,7 @@ const pk = JSON.parse(readFileSync(findFile('package.json', process.cwd()), 'utf user: connection.getRepository(User), image: connection.getRepository(Image), shorten: connection.getRepository(Shorten), - note: connection.getRepository(Note) + note: connection.getRepository(Note), }, }; @@ -64,6 +79,6 @@ const pk = JSON.parse(readFileSync(findFile('package.json', process.cwd()), 'utf ); const server = new ZiplineServer(orm); server.start(); - Logger.get('Interval').info('Starting Notes interval'); - const notesInterval = notes(orm); + Logger.get("Interval").info("Starting Notes interval"); + notes(orm); })(); diff --git a/src/interval.ts b/src/interval.ts index 9352f51e3..c0a247128 100755 --- a/src/interval.ts +++ b/src/interval.ts @@ -2,16 +2,22 @@ import { ORMHandler } from "."; import Logger from "@ayanaware/logger"; export function notes(orm: ORMHandler) { - return setInterval(async () => { - const all = await orm.repos.note.find(); - for (const note of all) { - if (note.expriation) { - const expiration = Number(note.creation) + Number(note.expriation); - if (Date.now() > expiration) { - orm.repos.note.delete({ id: note.id }); - Logger.get('TypeX.Notes').info(`Note deleted ${note.id} and ${note.expriation ? `expired in ${note.expriation}` : `never expired`}`) - } - } + return setInterval(async () => { + const all = await orm.repos.note.find(); + for (const note of all) { + if (note.expriation) { + const expiration = Number(note.creation) + Number(note.expriation); + if (Date.now() > expiration) { + orm.repos.note.delete({ id: note.id }); + Logger.get("TypeX.Notes").info( + `Note deleted ${note.id} and ${ + note.expriation + ? `expired in ${note.expriation}` + : `never expired` + }` + ); } - }, 5000) -} \ No newline at end of file + } + } + }, 5000); +} diff --git a/src/middleware/cookies.ts b/src/middleware/cookies.ts index d3495e4a1..c56c25f00 100755 --- a/src/middleware/cookies.ts +++ b/src/middleware/cookies.ts @@ -1,33 +1,41 @@ import Logger from "@ayanaware/logger"; import { Request, Response } from "express"; -import { getConnection } from 'typeorm'; +import { getConnection } from "typeorm"; import { User } from "../entities/User"; import { findFile } from "../util"; -import { readFileSync } from 'fs'; +import { readFileSync } from "fs"; -if (!findFile('config.json', process.cwd())) { - Logger.get('FS').error(`No config.json exists in ${__dirname}, exiting...`) +if (!findFile("config.json", process.cwd())) { + Logger.get("FS").error(`No config.json exists in ${__dirname}, exiting...`); process.exit(1); } -const config = JSON.parse(readFileSync(findFile('config.json', process.cwd()), 'utf8')) +const config = JSON.parse( + readFileSync(findFile("config.json", process.cwd()), "utf8") +); export async function cookies(req: Request, res: Response, next: any) { - if (req.cookies.typex_user) { - if (typeof req.cookies.typex_user !== 'string') return res.send('Please clear your browser cookies and refresh this page.') - if (Number(req.cookies.typex_user) === 0) { - req.session.user = { - id: 0, - username: 'administrator', - password: config.core.adminPassword, - administrator: true - } - } else req.session.user = await getConnection().getRepository(User).findOne({ id: req.cookies.typex_user }); - if (!req.session.user) { - res.clearCookie('typex_user'); - req.session.user = null; - return res.redirect('/login') - } - } else return res.redirect('/login'); - return next(); + if (req.cookies.typex_user) { + if (typeof req.cookies.typex_user !== "string") + return res.send( + "Please clear your browser cookies and refresh this page." + ); + if (Number(req.cookies.typex_user) === 0) { + req.session.user = { + id: 0, + username: "administrator", + password: config.core.adminPassword, + administrator: true, + }; + } else + req.session.user = await getConnection() + .getRepository(User) + .findOne({ id: req.cookies.typex_user }); + if (!req.session.user) { + res.clearCookie("typex_user"); + req.session.user = null; + return res.redirect("/login"); + } + } else return res.redirect("/login"); + return next(); } diff --git a/src/middleware/cookiesForAPI.ts b/src/middleware/cookiesForAPI.ts index 428e278ba..f9673e8d2 100755 --- a/src/middleware/cookiesForAPI.ts +++ b/src/middleware/cookiesForAPI.ts @@ -1,29 +1,51 @@ import Logger from "@ayanaware/logger"; import { Request, Response } from "express"; -import { BAD_REQUEST, INTERNAL_SERVER_ERROR, FORBIDDEN } from 'http-status-codes' -import { getConnection } from 'typeorm'; +import { + BAD_REQUEST, + INTERNAL_SERVER_ERROR, + FORBIDDEN, +} from "http-status-codes"; +import { getConnection } from "typeorm"; import { User } from "../entities/User"; import { findFile } from "../util"; -import { readFileSync } from 'fs'; +import { readFileSync } from "fs"; -if (!findFile('config.json', process.cwd())) { - Logger.get('FS').error(`No config.json exists in ${__dirname}, exiting...`) +if (!findFile("config.json", process.cwd())) { + Logger.get("FS").error(`No config.json exists in ${__dirname}, exiting...`); process.exit(1); } -const config = JSON.parse(readFileSync(findFile('config.json', process.cwd()), 'utf8')) +const config = JSON.parse( + readFileSync(findFile("config.json", process.cwd()), "utf8") +); export async function cookiesForAPI(req: Request, res: Response, next: any) { - if (req.cookies.typex_user) { - if (typeof req.cookies.typex_user !== 'string') return res.status(BAD_REQUEST).send({ code: BAD_REQUEST, message: "Please clear browser cookies." }) - if (Number(req.cookies.typex_user) === 0) req.session.user = { - id: 0, - username: 'administrator', - password: config.core.adminPassword, - administrator: true - } - else req.session.user = await getConnection().getRepository(User).findOne({ id: req.cookies.typex_user }); - if (!req.session.user) return res.status(INTERNAL_SERVER_ERROR).send({ code: INTERNAL_SERVER_ERROR, message: "The user that is logged in does not exist" }) - } else return res.status(FORBIDDEN).send({ code: FORBIDDEN, message: "Unauthorized" }) - return next(); + if (req.cookies.typex_user) { + if (typeof req.cookies.typex_user !== "string") + return res + .status(BAD_REQUEST) + .send({ code: BAD_REQUEST, message: "Please clear browser cookies." }); + if (Number(req.cookies.typex_user) === 0) + req.session.user = { + id: 0, + username: "administrator", + password: config.core.adminPassword, + administrator: true, + }; + else + req.session.user = await getConnection() + .getRepository(User) + .findOne({ id: req.cookies.typex_user }); + if (!req.session.user) + return res + .status(INTERNAL_SERVER_ERROR) + .send({ + code: INTERNAL_SERVER_ERROR, + message: "The user that is logged in does not exist", + }); + } else + return res + .status(FORBIDDEN) + .send({ code: FORBIDDEN, message: "Unauthorized" }); + return next(); } diff --git a/src/server.ts b/src/server.ts index ff2a21407..46fe49b63 100755 --- a/src/server.ts +++ b/src/server.ts @@ -12,22 +12,26 @@ import { APIController } from "./controllers/APIController"; import { IndexController } from "./controllers/IndexController"; import { findFile } from "./util"; -if (!findFile('config.json', process.cwd())) { - Logger.get('FS').error(`No config.json exists in the ${__dirname}, exiting...`) +if (!findFile("config.json", process.cwd())) { + Logger.get("FS").error( + `No config.json exists in the ${__dirname}, exiting...` + ); process.exit(1); } -const config = JSON.parse(fs.readFileSync(findFile('config.json', process.cwd()), 'utf8')) +const config = JSON.parse( + fs.readFileSync(findFile("config.json", process.cwd()), "utf8") +); export class ZiplineServer extends Server { constructor(orm: ORMHandler) { super(); - var p = 'loopback'; + var p = "loopback"; if (config.core.trustedProxy) { - p += ',' + config.core.trustedProxy; + p += "," + config.core.trustedProxy; } this.app.set("trust proxy", p); - this.app.set("view engine", "ejs"); + this.app.set("view engine", "ejs"); this.app.use( session({ secret: config.core.sessionSecret, @@ -37,17 +41,26 @@ export class ZiplineServer extends Server { ); this.app.use(async (req, res, next) => { if (!req.url.startsWith(config.uploader.route)) return next(); - const upload = await orm.repos.image.findOne({ url: `${config.secure ? "https" : "http"}://${req.headers['host']}${req.url}` }); + const upload = await orm.repos.image.findOne({ + url: `${config.secure ? "https" : "http"}://${req.headers["host"]}${ + req.url + }`, + }); if (!upload) return next(); upload.views++; orm.repos.image.save(upload); return next(); - }) + }); this.app.use(cookies()); try { - this.app.use(config.uploader.route, express.static(config.uploader.upload)); + this.app.use( + config.uploader.route, + express.static(config.uploader.upload) + ); } catch (e) { - Logger.get('TypeX.Routes').error(`Could not formulate upload static route`) + Logger.get("TypeX.Routes").error( + `Could not formulate upload static route` + ); process.exit(1); } this.app.use("/public", express.static("public")); @@ -57,9 +70,15 @@ export class ZiplineServer extends Server { if (!config.core.log) return next(); if (req.url.startsWith(config.uploader.route)) return next(); let user = req.session.user; - const users = await orm.repos.user.find({ where: { token: req.headers['authorization'] } }); - if (users[0]) user = users[0] - Logger.get('TypeX.Route').info(`Route ${req.url} was accessed by ${user ? user.username : '<no user found>'}`) + const users = await orm.repos.user.find({ + where: { token: req.headers["authorization"] }, + }); + if (users[0]) user = users[0]; + Logger.get("TypeX.Route").info( + `Route ${req.url} was accessed by ${ + user ? user.username : "<no user found>" + }` + ); return next(); }); @@ -70,12 +89,12 @@ export class ZiplineServer extends Server { const api = new APIController().set(orm); const index = new IndexController().set(orm); super.addControllers([index, api]); - this.app.get('*', (req, res) => { - return res.status(200).render('404'); - }) + this.app.get("*", (req, res) => { + return res.status(200).render("404"); + }); this.app.use((err, req, res, next) => { Logger.get(this.app).error(err); - return res.status(500).render('error'); + return res.status(500).render("error"); }); } @@ -85,19 +104,31 @@ export class ZiplineServer extends Server { try { const creds = { key: fs.readFileSync(config.core.ssl.key, "utf-8"), - cert: fs.readFileSync(config.core.ssl.cert, "utf-8") + cert: fs.readFileSync(config.core.ssl.cert, "utf-8"), }; server = https.createServer(creds, this.app); } catch (e) { - if (e.code === 'ENOENT') { - Logger.get('ZiplineServer.FS').error(`No file/directory found for ${e.path}`); + if (e.code === "ENOENT") { + Logger.get("ZiplineServer.FS").error( + `No file/directory found for ${e.path}` + ); process.exit(1); } } } else server = http.createServer(this.app); - server.listen(config.core.secure ? config.core.port.secure : config.core.port.unsecure, () => { - Logger.get(ZiplineServer).info('Started server on port ' + String(config.core.secure ? config.core.port.secure : config.core.port.unsecure)); - }) + server.listen( + config.core.secure ? config.core.port.secure : config.core.port.unsecure, + () => { + Logger.get(ZiplineServer).info( + "Started server on port " + + String( + config.core.secure + ? config.core.port.secure + : config.core.port.unsecure + ) + ); + } + ); } } diff --git a/src/structures/ConsoleFormatter.ts b/src/structures/ConsoleFormatter.ts index de86cae8c..04b40d957 100755 --- a/src/structures/ConsoleFormatter.ts +++ b/src/structures/ConsoleFormatter.ts @@ -1,5 +1,5 @@ import { Formatter, LogLevel, LogMeta } from "@ayanaware/logger"; -import chalk from 'chalk'; +import chalk from "chalk"; export class ConsoleFormatter extends Formatter { public formatError(meta: Readonly<LogMeta>, error: Error): string { @@ -7,31 +7,33 @@ export class ConsoleFormatter extends Formatter { } public formatMessage(meta: Readonly<LogMeta>, message: string): string { - return `${this.formatTimestamp()} ${this.formatLevel(meta.level)} ${this.formatName(meta.origin.name)}: ${message}` + return `${this.formatTimestamp()} ${this.formatLevel( + meta.level + )} ${this.formatName(meta.origin.name)}: ${message}`; } public formatName(name: string): string { - return `${chalk.greenBright(name)}` + return `${chalk.greenBright(name)}`; } public formatTimestamp(): string { - return new Date().toLocaleString().split(', ').join(' '); + return new Date().toLocaleString().split(", ").join(" "); } public formatLevel(level: LogLevel): string { switch (level) { case LogLevel.DEBUG: - return `${chalk.yellowBright('debug')}`; + return `${chalk.yellowBright("debug")}`; case LogLevel.ERROR: - return `${chalk.redBright('err')} `; + return `${chalk.redBright("err")} `; case LogLevel.INFO: - return `${chalk.blue('info')} `; + return `${chalk.blue("info")} `; case LogLevel.OFF: - return `${chalk.white('off')} `; + return `${chalk.white("off")} `; case LogLevel.TRACE: - return `${chalk.magenta('trace')} `; + return `${chalk.magenta("trace")} `; case LogLevel.WARN: - return `${chalk.yellow('warn')} `; + return `${chalk.yellow("warn")} `; } } -} \ No newline at end of file +} diff --git a/src/structures/DiscordWebhook.ts b/src/structures/DiscordWebhook.ts index 174e36a70..1967f8d17 100755 --- a/src/structures/DiscordWebhook.ts +++ b/src/structures/DiscordWebhook.ts @@ -1,48 +1,56 @@ -import req from 'centra'; -import { User } from '../entities/User'; -import { Shorten } from '../entities/Shorten'; -import { Imaged } from './ImageUtil'; -import { Shortened } from './ShortenUtil'; +import req from "centra"; +import { User } from "../entities/User"; +import { Shorten } from "../entities/Shorten"; +import { Imaged } from "./ImageUtil"; +import { Shortened } from "./ShortenUtil"; export class DiscordWebhook { - public url: string; - constructor(url: string) { - this.url = url; - this.checkExists(); - } - async checkExists(): Promise<boolean> { - const json = await (await req(this.url).send()).json(); - if (json.code === 10015) throw new Error('Unknown Webhook') - else if (json.code === 50027) throw new Error('Invalid Webhook Token') - else if (json.code) throw new Error(`DiscordAPIError[${json.code}]: ${json.message}`); - return json.code ? false : true; - } - async sendImageUpdate(user: User, image: Imaged, config: any) { - const res = await req(this.url, 'POST') - .header({ - 'Content-Type': 'application/json' - }) - .body({ - user: config.discordWebhook.username, - avatar_url: config.discordWebhook.avatarURL, - content: `New image uploaded to <${image.origin}> by ${user.username} (${user.id}). ${image.url})` - }) - .send(); + public url: string; + constructor(url: string) { + this.url = url; + this.checkExists(); + } + async checkExists(): Promise<boolean> { + const json = await (await req(this.url).send()).json(); + if (json.code === 10015) throw new Error("Unknown Webhook"); + else if (json.code === 50027) throw new Error("Invalid Webhook Token"); + else if (json.code) + throw new Error(`DiscordAPIError[${json.code}]: ${json.message}`); + return json.code ? false : true; + } + async sendImageUpdate(user: User, image: Imaged, config: any) { + const res = await req(this.url, "POST") + .header({ + "Content-Type": "application/json", + }) + .body({ + user: config.discordWebhook.username, + avatar_url: config.discordWebhook.avatarURL, + content: `New image uploaded to <${image.origin}> by ${user.username} (${user.id}). ${image.url})`, + }) + .send(); - if (res.statusCode !== 200) throw new Error(`Couldn't send webhook. (Status: ${res.statusCode})`); - } - async sendShortenUpdate(user: User, shorten: Shorten, ex: Shortened, config: any) { - const res = await req(this.url, 'POST') - .header({ - 'Content-Type': 'application/json' - }) - .body({ - user: config.discordWebhook.username, - avatar_url: config.discordWebhook.avatarURL, - content: `New shortened url added to <${ex.origin}> by ${user.username} (${user.id}). <${shorten.origin}> -> <${shorten.url}>` - }) - .send(); + if (res.statusCode !== 200) + throw new Error(`Couldn't send webhook. (Status: ${res.statusCode})`); + } + async sendShortenUpdate( + user: User, + shorten: Shorten, + ex: Shortened, + config: any + ) { + const res = await req(this.url, "POST") + .header({ + "Content-Type": "application/json", + }) + .body({ + user: config.discordWebhook.username, + avatar_url: config.discordWebhook.avatarURL, + content: `New shortened url added to <${ex.origin}> by ${user.username} (${user.id}). <${shorten.origin}> -> <${shorten.url}>`, + }) + .send(); - if (res.statusCode !== 200) throw new Error(`Couldn't send webhook. (Status: ${res.statusCode})`); - } -} \ No newline at end of file + if (res.statusCode !== 200) + throw new Error(`Couldn't send webhook. (Status: ${res.statusCode})`); + } +} diff --git a/src/structures/GitHub.ts b/src/structures/GitHub.ts index 1adf473a5..8aa6ce65a 100755 --- a/src/structures/GitHub.ts +++ b/src/structures/GitHub.ts @@ -1,8 +1,10 @@ -import req from 'centra'; +import req from "centra"; export class GitHub { - public static async getFile(filePath: string) { - const res = await req(`https://raw.githubusercontent.com/ZiplineProject/Zipline/master/${filePath}`).send(); - return res.text(); - } -} \ No newline at end of file + public static async getFile(filePath: string) { + const res = await req( + `https://raw.githubusercontent.com/ZiplineProject/Zipline/master/${filePath}` + ).send(); + return res.text(); + } +} diff --git a/src/structures/ImageUtil.ts b/src/structures/ImageUtil.ts index 902881a35..c7dbf77e1 100755 --- a/src/structures/ImageUtil.ts +++ b/src/structures/ImageUtil.ts @@ -1,34 +1,44 @@ -import { getType } from 'mime'; -import { findFile } from '../util'; -import Logger from '@ayanaware/logger'; -import { readFileSync } from 'fs'; +import { getType } from "mime"; +import { findFile } from "../util"; +import Logger from "@ayanaware/logger"; +import { readFileSync } from "fs"; -if (!findFile('config.json', process.cwd())) { - Logger.get('FS').error(`No config.json exists in the ${__dirname}, exiting...`) - process.exit(1); +if (!findFile("config.json", process.cwd())) { + Logger.get("FS").error( + `No config.json exists in the ${__dirname}, exiting...` + ); + process.exit(1); } -const config = JSON.parse(readFileSync(findFile('config.json', process.cwd()), 'utf8')) +const config = JSON.parse( + readFileSync(findFile("config.json", process.cwd()), "utf8") +); export interface Imaged { - url: string; - origin: string; - protocol: string; - key: string; - extension: string; - mime: string; + url: string; + origin: string; + protocol: string; + key: string; + extension: string; + mime: string; } export class ImageUtil { - static parseURL(url: string): Imaged { - const parsed = new URL(url); - return { - url: parsed.href, - origin: parsed.origin, - protocol: parsed.protocol.slice(0, -1), - key: parsed.pathname.startsWith(config.upload.route) ? parsed.pathname.slice(3).split('.')[0] : null, - extension: parsed.pathname.startsWith(config.upload.route) ? parsed.pathname.slice(3).split('.')[1] : null, - mime: parsed.pathname.startsWith(config.upload.route) ? getType(parsed.pathname.slice(3).split('.')[1]) : null - } - } -} \ No newline at end of file + static parseURL(url: string): Imaged { + const parsed = new URL(url); + return { + url: parsed.href, + origin: parsed.origin, + protocol: parsed.protocol.slice(0, -1), + key: parsed.pathname.startsWith(config.upload.route) + ? parsed.pathname.slice(3).split(".")[0] + : null, + extension: parsed.pathname.startsWith(config.upload.route) + ? parsed.pathname.slice(3).split(".")[1] + : null, + mime: parsed.pathname.startsWith(config.upload.route) + ? getType(parsed.pathname.slice(3).split(".")[1]) + : null, + }; + } +} diff --git a/src/structures/ShortenUtil.ts b/src/structures/ShortenUtil.ts index 6ea31a78d..d78201505 100755 --- a/src/structures/ShortenUtil.ts +++ b/src/structures/ShortenUtil.ts @@ -1,34 +1,44 @@ -import { getType } from 'mime'; -import { findFile } from '../util'; -import Logger from '@ayanaware/logger'; -import { readFileSync } from 'fs'; +import { getType } from "mime"; +import { findFile } from "../util"; +import Logger from "@ayanaware/logger"; +import { readFileSync } from "fs"; -if (!findFile('config.json', process.cwd())) { - Logger.get('FS').error(`No config.json exists in the ${__dirname}, exiting...`) - process.exit(1); +if (!findFile("config.json", process.cwd())) { + Logger.get("FS").error( + `No config.json exists in the ${__dirname}, exiting...` + ); + process.exit(1); } -const config = JSON.parse(readFileSync(findFile('config.json', process.cwd()), 'utf8')) +const config = JSON.parse( + readFileSync(findFile("config.json", process.cwd()), "utf8") +); export interface Shortened { - url: string; - origin: string; - protocol: string; - key: string; - extension: string; - mime: string; + url: string; + origin: string; + protocol: string; + key: string; + extension: string; + mime: string; } export class ShortenUtil { - static parseURL(url: string): Shortened { - const parsed = new URL(url); - return { - url: parsed.href, - origin: parsed.origin, - protocol: parsed.protocol.slice(0, -1), - key: parsed.pathname.startsWith(config.shorten.route) ? parsed.pathname.slice(3).split('.')[0] : null, - extension: parsed.pathname.startsWith(config.shorten.route) ? parsed.pathname.slice(3).split('.')[1] : null, - mime: parsed.pathname.startsWith(config.shorten.route) ? getType(parsed.pathname.slice(3).split('.')[1]) : null - } - } -} \ No newline at end of file + static parseURL(url: string): Shortened { + const parsed = new URL(url); + return { + url: parsed.href, + origin: parsed.origin, + protocol: parsed.protocol.slice(0, -1), + key: parsed.pathname.startsWith(config.shorten.route) + ? parsed.pathname.slice(3).split(".")[0] + : null, + extension: parsed.pathname.startsWith(config.shorten.route) + ? parsed.pathname.slice(3).split(".")[1] + : null, + mime: parsed.pathname.startsWith(config.shorten.route) + ? getType(parsed.pathname.slice(3).split(".")[1]) + : null, + }; + } +} diff --git a/src/util.ts b/src/util.ts index 21bcbe381..979901c5f 100755 --- a/src/util.ts +++ b/src/util.ts @@ -1,33 +1,41 @@ -import bcrypt from 'bcrypt'; -import { ORMHandler } from '.'; -import { User } from './entities/User'; -import { Image } from './entities/Image'; -import { statSync, readdirSync } from 'fs'; -import { join, basename } from 'path'; -import { Shorten } from './entities/Shorten'; - +import bcrypt from "bcrypt"; +import { ORMHandler } from "."; +import { User } from "./entities/User"; +import { Image } from "./entities/Image"; +import { statSync, readdirSync } from "fs"; +import { join, basename } from "path"; +import { Shorten } from "./entities/Shorten"; export function randomId(length) { - var result = ''; - var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + var result = ""; + var characters = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; var charactersLength = characters.length; - for (var i = 0; i < length; i++) result += characters.charAt(Math.floor(Math.random() * charactersLength)); + for (var i = 0; i < length; i++) + result += characters.charAt(Math.floor(Math.random() * charactersLength)); return result; } - export function renderTemplate(res, req, template, data = {}) { const baseData = { path: req.path, user: req.isAuthenticated() ? req.user : null, - auth: req.isAuthenticated() + auth: req.isAuthenticated(), }; res.render(template, Object.assign(baseData, data)); } -export async function getUser(orm: ORMHandler, username: string, password: string, administrator: boolean = false) { +export async function getUser( + orm: ORMHandler, + username: string, + password: string, + administrator: boolean = false +) { const user = await orm.repos.user.findOne({ username }); - if (!user) return orm.repos.user.save(new User().set({ username, password, administrator })); + if (!user) + return orm.repos.user.save( + new User().set({ username, password, administrator }) + ); return user; } @@ -37,9 +45,18 @@ export async function getImage(orm: ORMHandler, url: string, user: number) { return image; } -export async function getShorten(orm: ORMHandler, key: string, origin: string, url: string, user: number) { +export async function getShorten( + orm: ORMHandler, + key: string, + origin: string, + url: string, + user: number +) { const image = await orm.repos.shorten.findOne({ key }); - if (!image) return orm.repos.shorten.save(new Shorten().set({ key, origin, url, user })); + if (!image) + return orm.repos.shorten.save( + new Shorten().set({ key, origin, url, user }) + ); return image; } @@ -49,13 +66,17 @@ export function findFile(file, directory) { const files = readdirSync(dir); for (const file of files) { const filepath = join(dir, file); - if (file !== '.git' && file !== 'node_modules' && statSync(filepath).isDirectory()) { + if ( + file !== ".git" && + file !== "node_modules" && + statSync(filepath).isDirectory() + ) { read(filepath); } else { result.push(filepath); } } - }(directory)); + })(directory); for (const f of result) { const base = basename(f); if (base === file) return f; @@ -63,7 +84,6 @@ export function findFile(file, directory) { return null; } - export function checkPassword(pass: string, hash: string): boolean { return bcrypt.compareSync(pass, hash); } @@ -71,4 +91,4 @@ export function checkPassword(pass: string, hash: string): boolean { export function hashPassword(pass: string, saltRounds: number): string { // console.log(bcrypt.hashSync(pass,saltRounds)); return bcrypt.hashSync(pass, saltRounds); -} \ No newline at end of file +} diff --git a/tsconfig.json b/tsconfig.json index 5b7499765..362072758 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,12 @@ { - "compilerOptions": { - "experimentalDecorators": true, - "module": "commonjs", - "target": "esnext", - "resolveJsonModule": true, - "outDir": "./out", - "esModuleInterop": true - }, - "exclude": [ - "node_modules" - ], - "include": [ - "src" - ] -} \ No newline at end of file + "compilerOptions": { + "experimentalDecorators": true, + "module": "commonjs", + "target": "esnext", + "resolveJsonModule": true, + "outDir": "./out", + "esModuleInterop": true + }, + "exclude": ["node_modules"], + "include": ["src"] +}