From e028afeb3f7c6dd1f541ca53bbed10345018e4b1 Mon Sep 17 00:00:00 2001 From: dicedtomatoreal Date: Tue, 6 Oct 2020 20:01:55 -0700 Subject: [PATCH] typeorm & formatting --- .prettierignore | 4 + .prettierrc.json | 1 + next-env.d.ts | 2 +- package-lock.json | 6 + package.json | 1 + src/components/UI.tsx | 83 +++++------ src/components/UIPlaceholder.tsx | 68 +++++----- src/controllers/RootController.ts | 23 ++-- src/controllers/UserController.ts | 219 ++++++++++++++++++------------ src/entities/User.ts | 10 +- src/index.ts | 60 ++++---- src/lib/Config.ts | 12 +- src/lib/ConsoleFormatter.ts | 11 +- src/lib/Data.ts | 2 +- src/lib/Encryption.ts | 30 ++-- src/lib/api/APIErrors.ts | 12 +- src/lib/logger/Console.ts | 5 +- src/lib/logger/Formatter.ts | 23 +++- src/lib/logger/index.ts | 4 +- src/lib/reducer.ts | 7 +- src/lib/store.ts | 25 ++-- src/lib/theme.ts | 12 +- src/pages/_app.tsx | 27 ++-- src/pages/_document.tsx | 13 +- src/pages/index.tsx | 141 ++++++++++++------- src/pages/login.tsx | 146 ++++++++++++-------- src/pages/statistics.tsx | 8 +- tsconfig.json | 18 +-- 28 files changed, 577 insertions(+), 396 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc.json diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..3ab54ec5 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +.next +dist +node_modules +Zipline.toml diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/next-env.d.ts b/next-env.d.ts index 24d1f49f..7b7aa2c7 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,2 +1,2 @@ /// -/// \ No newline at end of file +/// diff --git a/package-lock.json b/package-lock.json index 966c0eba..6c08340a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5761,6 +5761,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": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", diff --git a/package.json b/package.json index 2aabe40d..ca8fdb36 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@types/react-redux": "^7.1.9", "mongodb": "^3.6.2", "pg": "^8.4.0", + "prettier": "2.1.2", "ts-node": "^9.0.0", "typescript": "^4.0.3" } diff --git a/src/components/UI.tsx b/src/components/UI.tsx index 6b22de1d..ff8b4bd4 100644 --- a/src/components/UI.tsx +++ b/src/components/UI.tsx @@ -1,49 +1,48 @@ -import React from 'react'; -import Link from 'next/link'; -import PropTypes from 'prop-types'; -import AppBar from '@material-ui/core/AppBar'; -import CssBaseline from '@material-ui/core/CssBaseline'; -import Divider from '@material-ui/core/Divider'; -import Drawer from '@material-ui/core/Drawer'; -import Hidden from '@material-ui/core/Hidden'; -import IconButton from '@material-ui/core/IconButton'; -import HomeIcon from '@material-ui/icons/Home'; -import DataUsageIcon from '@material-ui/icons/DataUsage'; -import PhotoIcon from '@material-ui/icons/Photo'; -import LinkIcon from '@material-ui/icons/Link'; -import List from '@material-ui/core/List'; -import ListItem from '@material-ui/core/ListItem'; -import ListItemIcon from '@material-ui/core/ListItemIcon'; -import ListItemText from '@material-ui/core/ListItemText'; -import MailIcon from '@material-ui/icons/Mail'; -import MenuIcon from '@material-ui/icons/Menu'; -import Toolbar from '@material-ui/core/Toolbar'; -import Typography from '@material-ui/core/Typography'; -import { makeStyles, useTheme } from '@material-ui/core/styles'; - +import React from "react"; +import Link from "next/link"; +import PropTypes from "prop-types"; +import AppBar from "@material-ui/core/AppBar"; +import CssBaseline from "@material-ui/core/CssBaseline"; +import Divider from "@material-ui/core/Divider"; +import Drawer from "@material-ui/core/Drawer"; +import Hidden from "@material-ui/core/Hidden"; +import IconButton from "@material-ui/core/IconButton"; +import HomeIcon from "@material-ui/icons/Home"; +import DataUsageIcon from "@material-ui/icons/DataUsage"; +import PhotoIcon from "@material-ui/icons/Photo"; +import LinkIcon from "@material-ui/icons/Link"; +import List from "@material-ui/core/List"; +import ListItem from "@material-ui/core/ListItem"; +import ListItemIcon from "@material-ui/core/ListItemIcon"; +import ListItemText from "@material-ui/core/ListItemText"; +import MailIcon from "@material-ui/icons/Mail"; +import MenuIcon from "@material-ui/icons/Menu"; +import Toolbar from "@material-ui/core/Toolbar"; +import Typography from "@material-ui/core/Typography"; +import { makeStyles, useTheme } from "@material-ui/core/styles"; const drawerWidth = 240; const useStyles = makeStyles((theme) => ({ root: { - display: 'flex', + display: "flex", }, drawer: { - [theme.breakpoints.up('sm')]: { + [theme.breakpoints.up("sm")]: { width: drawerWidth, flexShrink: 0, }, }, appBar: { - [theme.breakpoints.up('sm')]: { + [theme.breakpoints.up("sm")]: { width: `calc(100%)`, marginLeft: drawerWidth, }, }, menuButton: { marginRight: theme.spacing(2), - [theme.breakpoints.up('sm')]: { - display: 'none', + [theme.breakpoints.up("sm")]: { + display: "none", }, }, // necessary for content to be below app bar @@ -83,7 +82,7 @@ export default function UI(props) { Zipline - + @@ -91,36 +90,44 @@ export default function UI(props) { - + + + - + + + - + + + - + + + - + ); - const container = window !== undefined ? () => window().document.body : undefined; + const container = + window !== undefined ? () => window().document.body : undefined; return ( -
@@ -143,7 +150,7 @@ export default function UI(props) {
); -} \ No newline at end of file +} diff --git a/src/components/UIPlaceholder.tsx b/src/components/UIPlaceholder.tsx index 18c77e19..8d02fcc5 100644 --- a/src/components/UIPlaceholder.tsx +++ b/src/components/UIPlaceholder.tsx @@ -1,43 +1,42 @@ -import React from 'react'; -import Link from 'next/link'; -import AppBar from '@material-ui/core/AppBar'; -import Drawer from '@material-ui/core/Drawer'; -import Hidden from '@material-ui/core/Hidden'; -import IconButton from '@material-ui/core/IconButton'; -import List from '@material-ui/core/List'; -import ListItem from '@material-ui/core/ListItem'; -import Box from '@material-ui/core/Box'; -import MenuIcon from '@material-ui/icons/Menu'; -import Toolbar from '@material-ui/core/Toolbar'; -import Typography from '@material-ui/core/Typography'; -import CircularProgress from '@material-ui/core/CircularProgress'; -import Grid from '@material-ui/core/Grid'; -import Skeleton from '@material-ui/lab/Skeleton'; -import { makeStyles, useTheme } from '@material-ui/core/styles'; - +import React from "react"; +import Link from "next/link"; +import AppBar from "@material-ui/core/AppBar"; +import Drawer from "@material-ui/core/Drawer"; +import Hidden from "@material-ui/core/Hidden"; +import IconButton from "@material-ui/core/IconButton"; +import List from "@material-ui/core/List"; +import ListItem from "@material-ui/core/ListItem"; +import Box from "@material-ui/core/Box"; +import MenuIcon from "@material-ui/icons/Menu"; +import Toolbar from "@material-ui/core/Toolbar"; +import Typography from "@material-ui/core/Typography"; +import CircularProgress from "@material-ui/core/CircularProgress"; +import Grid from "@material-ui/core/Grid"; +import Skeleton from "@material-ui/lab/Skeleton"; +import { makeStyles, useTheme } from "@material-ui/core/styles"; const drawerWidth = 240; const useStyles = makeStyles((theme) => ({ root: { - display: 'flex', + display: "flex", }, drawer: { - [theme.breakpoints.up('sm')]: { + [theme.breakpoints.up("sm")]: { width: drawerWidth, flexShrink: 0, }, }, appBar: { - [theme.breakpoints.up('sm')]: { + [theme.breakpoints.up("sm")]: { width: `calc(100%)`, marginLeft: drawerWidth, }, }, menuButton: { marginRight: theme.spacing(2), - [theme.breakpoints.up('sm')]: { - display: 'none', + [theme.breakpoints.up("sm")]: { + display: "none", }, }, // necessary for content to be below app bar @@ -50,8 +49,8 @@ const useStyles = makeStyles((theme) => ({ padding: theme.spacing(3), }, fullWidth: { - width: '100%' - } + width: "100%", + }, })); export default function UIPlaceholder(props) { @@ -80,7 +79,7 @@ export default function UIPlaceholder(props) { Zipline - + @@ -99,13 +98,13 @@ export default function UIPlaceholder(props) { - + ); - const container = window !== undefined ? () => window().document.body : undefined; + const container = + window !== undefined ? () => window().document.body : undefined; return ( -
@@ -128,7 +127,7 @@ export default function UIPlaceholder(props) {
- + @@ -164,4 +170,4 @@ export default function UIPlaceholder(props) {
); -} \ No newline at end of file +} diff --git a/src/controllers/RootController.ts b/src/controllers/RootController.ts index 3911a0af..770354d4 100644 --- a/src/controllers/RootController.ts +++ b/src/controllers/RootController.ts @@ -1,14 +1,19 @@ -import { FastifyReply, FastifyRequest, FastifyInstance } from 'fastify'; -import { Controller, GET, POST, FastifyInstanceToken, Inject, Hook } from 'fastify-decorators'; -import { User } from '../entities/User'; +import { FastifyReply, FastifyRequest, FastifyInstance } from "fastify"; +import { + Controller, + GET, + POST, + FastifyInstanceToken, + Inject, + Hook, +} from "fastify-decorators"; +import { User } from "../entities/User"; -@Controller('/api') +@Controller("/api") export class RootController { @Inject(FastifyInstanceToken) private instance!: FastifyInstance; - @POST('/upload') - async loginStatus(req: FastifyRequest, reply: FastifyReply) { - - } -} \ No newline at end of file + @POST("/upload") + async loginStatus(req: FastifyRequest, reply: FastifyReply) {} +} diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 6ac3a517..9d66fb0c 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -1,105 +1,150 @@ -// import { FastifyReply, FastifyRequest, FastifyInstance } from 'fastify'; -// import { Controller, GET, POST, FastifyInstanceToken, Inject, Hook } from 'fastify-decorators'; -// import { UserNotFoundError, MissingBodyData, LoginError, UserExistsError, NotAdministratorError } from '../lib/api/APIErrors'; -// import { User } from '../lib/Data'; -// import { checkPassword, createToken, encryptPassword } from '../lib/Encryption'; +import { FastifyReply, FastifyRequest, FastifyInstance } from "fastify"; +import { + Controller, + GET, + POST, + FastifyInstanceToken, + Inject, + Hook, +} from "fastify-decorators"; +import { Repository } from "typeorm"; +import { User } from "../entities/User"; +import { + UserNotFoundError, + MissingBodyData, + LoginError, + UserExistsError, + NotAdministratorError, +} from "../lib/api/APIErrors"; +import { + checkPassword, + createBaseCookie, + createToken, + encryptPassword, + readBaseCookie, +} from "../lib/Encryption"; -// @Controller('/api/user') -// export class UserController { -// @Inject(FastifyInstanceToken) -// private instance!: FastifyInstance; +@Controller("/api/user") +export class UserController { + @Inject(FastifyInstanceToken) + private instance!: FastifyInstance; -// @GET('/login-status') -// async loginStatus(req: FastifyRequest, reply: FastifyReply) { -// return reply.send({ user: !!req.cookies.zipline }); -// } + private users: Repository = this.instance.orm.getRepository(User); -// @GET('/current') -// async currentUser(req: FastifyRequest, reply: FastifyReply) { -// if (!req.cookies.zipline) throw new LoginError(`Not logged in.`); -// const user = await this.instance.mongo.db.collection('zipline_users').findOne({ _id: new this.instance.mongo.ObjectId(req.cookies.zipline) }); -// if (!user) throw new UserExistsError(`User doesn't exist`); -// delete user.password; -// return reply.send(user); -// } + @GET("/login-status") + async loginStatus(req: FastifyRequest, reply: FastifyReply) { + return reply.send({ + user: !!req.cookies.zipline, + }); + } -// @POST('/login') -// async login(req: FastifyRequest<{ Body: { username: string, password: string } }>, reply: FastifyReply) { -// if (req.cookies.zipline) throw new LoginError(`Already logged in.`) -// if (!req.body.username) throw new MissingBodyData(`Missing username.`); -// if (!req.body.password) throw new MissingBodyData(`Missing uassword.`); + @GET("/current") + async currentUser(req: FastifyRequest, reply: FastifyReply) { + if (!req.cookies.zipline) throw new LoginError(`Not logged in.`); + const user = await this.users.findOne({ + where: { + id: readBaseCookie(req.cookies.zipline), + }, + }); + if (!user) throw new UserExistsError(`User doesn't exist`); + delete user.password; + return reply.send(user); + } -// const user: User = await this.instance.mongo.db.collection('zipline_users').findOne({ -// username: req.body.username -// }); + @POST("/login") + async login( + req: FastifyRequest<{ Body: { username: string; password: string } }>, + reply: FastifyReply + ) { + if (req.cookies.zipline) throw new LoginError(`Already logged in.`); + if (!req.body.username) throw new MissingBodyData(`Missing username.`); + if (!req.body.password) throw new MissingBodyData(`Missing uassword.`); -// if (!user) throw new UserNotFoundError(`User "${req.body.username}" was not found.`); -// if (!checkPassword(req.body.password, user.password)) throw new LoginError(`Wrong credentials!`); -// delete user.password; -// return reply -// .setCookie("zipline", user._id, { path: '/' }) -// .send(user); -// } + const user = await this.users.findOne({ + where: { + id: readBaseCookie(req.cookies.zipline), + }, + }); -// @POST('/logout') -// async logout(req: FastifyRequest, reply: FastifyReply) { -// if (!req.cookies.zipline) throw new LoginError(`Not logged in.`); -// try { -// reply.clearCookie('zipline', { path: '/' }).send({ clearStore: true }) -// } catch (e) { -// reply.send({ clearStore: false }); -// } -// } + if (!user) + throw new UserNotFoundError(`User "${req.body.username}" was not found.`); + if (!checkPassword(req.body.password, user.password)) + throw new LoginError(`Wrong credentials!`); + delete user.password; -// @POST('/reset-token') -// async resetToken(req: FastifyRequest, reply: FastifyReply) { -// if (!req.cookies.zipline) throw new LoginError(`Not logged in.`); + return reply + .setCookie("zipline", createBaseCookie(user.id), { path: "/" }) + .send(user); + } -// const users = this.instance.mongo.db.collection('zipline_users'); -// const user: User = await users.findOne({ _id: new this.instance.mongo.ObjectId(req.cookies.zipline) }); -// if (!user) throw new UserNotFoundError(`User was not found.`); + @POST("/logout") + async logout(req: FastifyRequest, reply: FastifyReply) { + if (!req.cookies.zipline) throw new LoginError(`Not logged in.`); + try { + reply.clearCookie("zipline", { path: "/" }).send({ clearStore: true }); + } catch (e) { + reply.send({ clearStore: false }); + } + } -// users.updateOne({ _id: new this.instance.mongo.ObjectId(req.cookies.zipline) }, { $set: { token: createToken() } }); -// return reply.send({ updated: true }); -// } + @POST("/reset-token") + async resetToken(req: FastifyRequest, reply: FastifyReply) { + if (!req.cookies.zipline) throw new LoginError(`Not logged in.`); -// @POST('/create') -// async create(req: FastifyRequest<{ Body: { username: string, password: string, administrator: boolean } }>, reply: FastifyReply) { -// if (!req.body.username) throw new MissingBodyData(`Missing username.`); -// if (!req.body.password) throw new MissingBodyData(`Missing uassword.`); + const user = await this.users.findOne({ + where: { + id: readBaseCookie(req.cookies.zipline), + }, + }); -// const users = this.instance.mongo.db.collection('zipline_users'); + if (!user) throw new UserNotFoundError(`User was not found.`); -// const existingUser = await users.findOne({ username: req.body.username }); -// if (existingUser) throw new UserExistsError('User exists already'); + user.token = createToken(); + this.users.save(user); -// const newUser: User = { -// username: req.body.username, -// password: encryptPassword(req.body.password), -// token: createToken(), -// administrator: req.body.administrator -// }; + return reply.send({ updated: true }); + } -// try { -// users.insertOne(newUser); -// } catch (e) { -// throw new Error(`Could not create user: ${e.message}`); -// } + @POST("/create") + async create( + req: FastifyRequest<{ + Body: { username: string; password: string; administrator: boolean }; + }>, + reply: FastifyReply + ) { + if (!req.body.username) throw new MissingBodyData(`Missing username.`); + if (!req.body.password) throw new MissingBodyData(`Missing uassword.`); -// return reply.send(newUser); -// } + const existing = await this.users.findOne({ + where: { username: req.body.username }, + }); + if (existing) throw new UserExistsError("User exists already"); -// @Hook('preValidation') -// public async preValidation(req: FastifyRequest, reply: FastifyReply) { -// const adminRoutes = ['/api/user/create']; + try { + const user = await this.users.save( + new User( + req.body.username, + req.body.password, + createToken(), + req.body.administrator || false + ) + ); + delete user.password; + return reply.send(user); + } catch (e) { + throw new Error(`Could not create user: ${e.message}`); + } + } -// if (adminRoutes.includes(req.routerPath)) { -// if (!req.cookies.zipline) return reply.send({ error: "You are not logged in" }); - -// const admin = await this.instance.mongo.db.collection('zipline_users').findOne({ _id: req.cookies.zipline }); -// if (!admin) return reply.send({ error: "You are not an administrator" }); -// return; -// } -// return; -// } -// } \ No newline at end of file + @Hook("preValidation") + public async preValidation(req: FastifyRequest, reply: FastifyReply) { + // const adminRoutes = ['/api/user/create']; + // if (adminRoutes.includes(req.routerPath)) { + // if (!req.cookies.zipline) return reply.send({ error: "You are not logged in" }); + // const admin = await this.instance.mongo.db.collection('zipline_users').findOne({ _id: req.cookies.zipline }); + // if (!admin) return reply.send({ error: "You are not an administrator" }); + // return; + // } + // return; + } +} diff --git a/src/entities/User.ts b/src/entities/User.ts index d1a23f1d..be63827f 100644 --- a/src/entities/User.ts +++ b/src/entities/User.ts @@ -2,7 +2,6 @@ import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"; @Entity() export class User { - @PrimaryGeneratedColumn() public id: number; @@ -18,10 +17,15 @@ export class User { @Column("text") public token: string; - public constructor(username: string, password: string, token: string, administrator: boolean = false) { + public constructor( + username: string, + password: string, + token: string, + administrator: boolean = false + ) { this.username = username; this.password = password; this.administrator = administrator; this.token = token; } -} \ No newline at end of file +} diff --git a/src/index.ts b/src/index.ts index 5cc3f8c4..6b300fe6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,55 +1,55 @@ -import next from 'next'; -import fastify from 'fastify'; -import fastifyTypeorm from 'fastify-typeorm-plugin'; -import fastifyCookies from 'fastify-cookie'; -import fastifyMultipart from 'fastify-multipart'; -import { bootstrap } from 'fastify-decorators'; -import { RootController } from './controllers/RootController'; -import { Console } from './lib/logger'; -import { AddressInfo } from 'net'; -import { ConsoleFormatter } from './lib/ConsoleFormatter'; -import { bold, green, reset } from '@dicedtomato/colors'; -import { Configuration } from './lib/Config'; +import next from "next"; +import fastify from "fastify"; +import fastifyTypeorm from "fastify-typeorm-plugin"; +import fastifyCookies from "fastify-cookie"; +import fastifyMultipart from "fastify-multipart"; +import { bootstrap } from "fastify-decorators"; +import { RootController } from "./controllers/RootController"; +import { Console } from "./lib/logger"; +import { AddressInfo } from "net"; +import { ConsoleFormatter } from "./lib/ConsoleFormatter"; +import { bold, green, reset } from "@dicedtomato/colors"; +import { Configuration } from "./lib/Config"; // import { UserController } from './controllers/UserController'; - Console.setFormatter(new ConsoleFormatter()); const config = Configuration.readConfig(); if (!config) process.exit(0); const server = fastify({}); -const dev = process.env.NODE_ENV !== 'production'; +const dev = process.env.NODE_ENV !== "production"; const app = next({ dev, quiet: dev }); const handle = app.getRequestHandler(); Console.logger("Next").info(`Preparing app`); app.prepare(); -if (dev) server.get('/_next/*', (req, reply) => { - return handle(req.raw, reply.raw).then(() => reply.sent = true); -}); +if (dev) + server.get("/_next/*", (req, reply) => { + return handle(req.raw, reply.raw).then(() => (reply.sent = true)); + }); -server.all('/*', (req, reply) => { - return handle(req.raw, reply.raw).then(() => reply.sent = true); +server.all("/*", (req, reply) => { + return handle(req.raw, reply.raw).then(() => (reply.sent = true)); }); server.setNotFoundHandler((req, reply) => { - return app.render404(req.raw, reply.raw).then(() => reply.sent = true); -}) + return app.render404(req.raw, reply.raw).then(() => (reply.sent = true)); +}); server.register(fastifyMultipart); server.register(fastifyTypeorm, { ...config.database, - entities: [dev ? './src/entities/**/*.ts' : './dist/entities/**/*.js'], + entities: [dev ? "./src/entities/**/*.ts" : "./dist/entities/**/*.js"], synchronize: true, - logging: false + logging: false, }); server.register(bootstrap, { controllers: [ // UserController, - RootController + RootController, ], }); @@ -60,11 +60,15 @@ server.register(bootstrap, { // }); server.register(fastifyCookies, { - secret: config.core.secret + secret: config.core.secret, }); -server.listen(config.core.port, err => { +server.listen(config.core.port, (err) => { if (err) throw err; const info = server.server.address() as AddressInfo; - Console.logger("Server").info(`server listening on ${bold(`${green(info.address)}${reset(":")}${bold(green(info.port.toString()))}`)}`) -}) + Console.logger("Server").info( + `server listening on ${bold( + `${green(info.address)}${reset(":")}${bold(green(info.port.toString()))}` + )}` + ); +}); diff --git a/src/lib/Config.ts b/src/lib/Config.ts index 595b02ce..9a69ccb5 100644 --- a/src/lib/Config.ts +++ b/src/lib/Config.ts @@ -1,7 +1,7 @@ -import { readFileSync } from 'fs'; -import { resolve } from 'path'; -import { parse } from 'toml'; -import { ConnectionOptions } from 'typeorm'; +import { readFileSync } from "fs"; +import { resolve } from "path"; +import { parse } from "toml"; +import { ConnectionOptions } from "typeorm"; export interface Config { database: ConnectionOptions; @@ -21,11 +21,11 @@ export interface ConfigCore { export class Configuration { static readConfig(): Config { try { - const data = readFileSync(resolve(process.cwd(), "Zipline.toml"), 'utf8'); + const data = readFileSync(resolve(process.cwd(), "Zipline.toml"), "utf8"); return parse(data) as Config; } catch (e) { console.log(e); return null; } } -} \ No newline at end of file +} diff --git a/src/lib/ConsoleFormatter.ts b/src/lib/ConsoleFormatter.ts index 3deaa16b..67d61478 100644 --- a/src/lib/ConsoleFormatter.ts +++ b/src/lib/ConsoleFormatter.ts @@ -2,7 +2,12 @@ import { bold, magenta, reset } from "@dicedtomato/colors"; import { ConsoleLevel, Formatter } from "./logger"; export class ConsoleFormatter implements Formatter { - format(message: string, origin: string, level: ConsoleLevel, time: Date): string { - return `${bold(magenta(origin))} ${bold(">")} ${reset(message)}` + format( + message: string, + origin: string, + level: ConsoleLevel, + time: Date + ): string { + return `${bold(magenta(origin))} ${bold(">")} ${reset(message)}`; } -} \ No newline at end of file +} diff --git a/src/lib/Data.ts b/src/lib/Data.ts index 102dcd20..20ffdb6d 100644 --- a/src/lib/Data.ts +++ b/src/lib/Data.ts @@ -11,4 +11,4 @@ export interface Image { user: any; views: number; _id?: any; -} \ No newline at end of file +} diff --git a/src/lib/Encryption.ts b/src/lib/Encryption.ts index 0bf1ec75..b3c805f4 100644 --- a/src/lib/Encryption.ts +++ b/src/lib/Encryption.ts @@ -1,18 +1,24 @@ -import aes from 'crypto-js/aes' -import { compareSync, hashSync } from 'bcrypt'; -import { Configuration } from './Config'; +import aes from "crypto-js/aes"; +import { compareSync, hashSync } from "bcrypt"; +import { Configuration } from "./Config"; const config = Configuration.readConfig(); if (!config) process.exit(0); -export function createRandomId(length: number, charset: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') { - let result = ''; - for (let i = 0; i < length; i++) result += charset.charAt(Math.floor(Math.random() * charset.length)); +export function createRandomId( + length: number, + charset: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" +) { + let result = ""; + for (let i = 0; i < length; i++) + result += charset.charAt(Math.floor(Math.random() * charset.length)); return result; } export function createToken() { - return aes.encrypt(`${createRandomId(10)}.${Date.now()}`, config.core.secret).toString(); + return aes + .encrypt(`${createRandomId(10)}.${Date.now()}`, config.core.secret) + .toString(); } export function encryptPassword(pass: string) { @@ -21,4 +27,12 @@ export function encryptPassword(pass: string) { export function checkPassword(will: string, equal: string) { return compareSync(will, equal); -} \ No newline at end of file +} + +export function createBaseCookie(id: number) { + return Buffer.from(id.toString()).toString("base64"); +} + +export function readBaseCookie(data: string) { + return Buffer.from(data, "base64").toString(); +} diff --git a/src/lib/api/APIErrors.ts b/src/lib/api/APIErrors.ts index f54e3618..52cc93a3 100644 --- a/src/lib/api/APIErrors.ts +++ b/src/lib/api/APIErrors.ts @@ -1,6 +1,6 @@ -export class MissingBodyData extends Error { }; -export class LoginError extends Error { }; -export class NotAdministratorError extends Error { }; -export class UserExistsError extends Error { }; -export class UserNotFoundError extends Error { }; -export class UserCredentialsError extends Error { }; \ No newline at end of file +export class MissingBodyData extends Error {} +export class LoginError extends Error {} +export class NotAdministratorError extends Error {} +export class UserExistsError extends Error {} +export class UserNotFoundError extends Error {} +export class UserCredentialsError extends Error {} diff --git a/src/lib/logger/Console.ts b/src/lib/logger/Console.ts index b239ca08..c25f6772 100644 --- a/src/lib/logger/Console.ts +++ b/src/lib/logger/Console.ts @@ -15,10 +15,9 @@ export enum ConsoleLevel { ERROR, INFO, TRACE, - WARN + WARN, } - export class Console { public name: string; @@ -59,4 +58,4 @@ export class Console { const name = o instanceof Function ? o.name : o; return new Console(name); } -} \ No newline at end of file +} diff --git a/src/lib/logger/Formatter.ts b/src/lib/logger/Formatter.ts index 8a76c2dd..ba9cb9cd 100644 --- a/src/lib/logger/Formatter.ts +++ b/src/lib/logger/Formatter.ts @@ -1,13 +1,24 @@ import { ConsoleLevel } from "./Console"; -import { brightGreen, blue } from '@dicedtomato/colors'; - +import { brightGreen, blue } from "@dicedtomato/colors"; export interface Formatter { - format(message: string, origin: string, level: ConsoleLevel, time: Date): string; + format( + message: string, + origin: string, + level: ConsoleLevel, + time: Date + ): string; } export class DefaultFormatter implements Formatter { - public format(message: string, origin: string, level: ConsoleLevel, time: Date) { - return `[${time.toLocaleString()}] ${brightGreen(origin)} - ${blue(ConsoleLevel[level])}: ${message}` + public format( + message: string, + origin: string, + level: ConsoleLevel, + time: Date + ) { + return `[${time.toLocaleString()}] ${brightGreen(origin)} - ${blue( + ConsoleLevel[level] + )}: ${message}`; } -} \ No newline at end of file +} diff --git a/src/lib/logger/index.ts b/src/lib/logger/index.ts index a18892ea..277e8688 100644 --- a/src/lib/logger/index.ts +++ b/src/lib/logger/index.ts @@ -1,2 +1,2 @@ -export * from './Console'; -export * from './Formatter'; \ No newline at end of file +export * from "./Console"; +export * from "./Formatter"; diff --git a/src/lib/reducer.ts b/src/lib/reducer.ts index 167eecdd..8a61cda7 100644 --- a/src/lib/reducer.ts +++ b/src/lib/reducer.ts @@ -6,13 +6,12 @@ export const LOGOUT = "LOGOUT"; export const UPDATE_USER = "UPDATE_USER"; export interface State { loggedIn: boolean; - user: User + user: User; } - const initialState: State = { loggedIn: false, - user: null + user: null, }; export function reducer(state: State = initialState, action) { @@ -26,4 +25,4 @@ export function reducer(state: State = initialState, action) { default: return state; } -} \ No newline at end of file +} diff --git a/src/lib/store.ts b/src/lib/store.ts index 43fc598f..924cca6b 100644 --- a/src/lib/store.ts +++ b/src/lib/store.ts @@ -1,15 +1,18 @@ -import { createStore } from 'redux'; -import { persistStore, persistReducer } from 'redux-persist'; -import storage from 'redux-persist/lib/storage'; +import { createStore } from "redux"; +import { persistStore, persistReducer } from "redux-persist"; +import storage from "redux-persist/lib/storage"; -import { reducer } from './reducer' +import { reducer } from "./reducer"; -const persistedReducer = persistReducer({ - key: 'root', - storage, -}, reducer); +const persistedReducer = persistReducer( + { + key: "root", + storage, + }, + reducer +); -let store = createStore(persistedReducer) -let persistor = persistStore(store) +let store = createStore(persistedReducer); +let persistor = persistStore(store); -export { store, persistor }; \ No newline at end of file +export { store, persistor }; diff --git a/src/lib/theme.ts b/src/lib/theme.ts index 6a00444f..042fa4b0 100644 --- a/src/lib/theme.ts +++ b/src/lib/theme.ts @@ -1,21 +1,21 @@ -import { createMuiTheme } from '@material-ui/core/styles'; -import { red } from '@material-ui/core/colors'; +import { createMuiTheme } from "@material-ui/core/styles"; +import { red } from "@material-ui/core/colors"; // Create a theme instance. const theme = createMuiTheme({ palette: { - type: 'dark', + type: "dark", primary: { - main: '#556cd6', + main: "#556cd6", }, secondary: { - main: '#19857b', + main: "#19857b", }, error: { main: red.A100, }, background: { - default: '#121212', + default: "#121212", }, }, }); diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index e255e6a6..f4a55c02 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,18 +1,18 @@ -import React, { useEffect } from 'react'; -import PropTypes from 'prop-types'; -import Head from 'next/head'; -import { ThemeProvider } from '@material-ui/core/styles'; -import CssBaseline from '@material-ui/core/CssBaseline'; -import { Provider } from 'react-redux'; -import { PersistGate } from 'redux-persist/integration/react' -import theme from '../lib/theme'; -import { store, persistor } from '../lib/store'; -import UIPlaceholder from '../components/UIPlaceholder'; +import React, { useEffect } from "react"; +import PropTypes from "prop-types"; +import Head from "next/head"; +import { ThemeProvider } from "@material-ui/core/styles"; +import CssBaseline from "@material-ui/core/CssBaseline"; +import { Provider } from "react-redux"; +import { PersistGate } from "redux-persist/integration/react"; +import theme from "../lib/theme"; +import { store, persistor } from "../lib/store"; +import UIPlaceholder from "../components/UIPlaceholder"; export default function MyApp(props) { const { Component, pageProps } = props; useEffect(() => { - const jssStyles = document.querySelector('#jss-server-side'); + const jssStyles = document.querySelector("#jss-server-side"); if (jssStyles) { jssStyles.parentElement.removeChild(jssStyles); } @@ -24,7 +24,10 @@ export default function MyApp(props) { } persistor={persistor}> Zipline - + diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx index 3cdb3827..b624b523 100644 --- a/src/pages/_document.tsx +++ b/src/pages/_document.tsx @@ -1,7 +1,7 @@ -import React from 'react'; -import Document, { Html, Head, Main, NextScript } from 'next/document'; -import { ServerStyleSheets } from '@material-ui/core/styles'; -import theme from '../lib/theme'; +import React from "react"; +import Document, { Html, Head, Main, NextScript } from "next/document"; +import { ServerStyleSheets } from "@material-ui/core/styles"; +import theme from "../lib/theme"; export default class MyDocument extends Document { render() { @@ -63,6 +63,9 @@ MyDocument.getInitialProps = async (ctx) => { return { ...initialProps, // Styles fragment is rendered after the app and page rendering finish. - styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()], + styles: [ + ...React.Children.toArray(initialProps.styles), + sheets.getStyleElement(), + ], }; }; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index d52b8d3a..3bf68478 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,34 +1,33 @@ -import React, { useState, useEffect } from 'react'; -import { useRouter } from 'next/router'; -import UI from '../components/UI'; -import UIPlaceholder from '../components/UIPlaceholder'; -import Typography from '@material-ui/core/Typography'; -import Paper from '@material-ui/core/Paper'; -import TextField from '@material-ui/core/TextField'; -import Divider from '@material-ui/core/Divider'; -import Button from '@material-ui/core/Button'; -import Grid from '@material-ui/core/Grid'; -import Dialog from '@material-ui/core/Dialog'; -import DialogActions from '@material-ui/core/DialogActions'; -import DialogContent from '@material-ui/core/DialogContent'; -import DialogContentText from '@material-ui/core/DialogContentText'; -import DialogTitle from '@material-ui/core/DialogTitle'; -import Alert from '@material-ui/lab/Alert'; -import Snackbar from '@material-ui/core/Snackbar'; -import copy from 'copy-to-clipboard'; -import { LOGOUT, UPDATE_USER } from '../lib/reducer'; -import { makeStyles } from '@material-ui/core'; -import { store } from '../lib/store'; -import { useDispatch } from 'react-redux'; - +import React, { useState, useEffect } from "react"; +import { useRouter } from "next/router"; +import UI from "../components/UI"; +import UIPlaceholder from "../components/UIPlaceholder"; +import Typography from "@material-ui/core/Typography"; +import Paper from "@material-ui/core/Paper"; +import TextField from "@material-ui/core/TextField"; +import Divider from "@material-ui/core/Divider"; +import Button from "@material-ui/core/Button"; +import Grid from "@material-ui/core/Grid"; +import Dialog from "@material-ui/core/Dialog"; +import DialogActions from "@material-ui/core/DialogActions"; +import DialogContent from "@material-ui/core/DialogContent"; +import DialogContentText from "@material-ui/core/DialogContentText"; +import DialogTitle from "@material-ui/core/DialogTitle"; +import Alert from "@material-ui/lab/Alert"; +import Snackbar from "@material-ui/core/Snackbar"; +import copy from "copy-to-clipboard"; +import { LOGOUT, UPDATE_USER } from "../lib/reducer"; +import { makeStyles } from "@material-ui/core"; +import { store } from "../lib/store"; +import { useDispatch } from "react-redux"; const useStyles = makeStyles({ margin: { - margin: '5px' + margin: "5px", }, padding: { - padding: '10px' - } + padding: "10px", + }, }); export default function IndexPage() { @@ -36,49 +35,53 @@ export default function IndexPage() { const router = useRouter(); const dispatch = useDispatch(); const state = store.getState(); - const [alertMessage, setAlertMessage] = useState('Copied token!'); + const [alertMessage, setAlertMessage] = useState("Copied token!"); const [tokenOpen, setTokenOpen] = useState(false); const [resetToken, setResetToken] = useState(false); const [alertOpen, setAlertOpen] = useState(false); const handleCopyTokenThenClose = async () => { - const data = await (await fetch('/api/user/current')).json(); + const data = await (await fetch("/api/user/current")).json(); if (!data.error) { copy(data.token); - setAlertMessage('Copied token!'); + setAlertMessage("Copied token!"); setTokenOpen(false); setAlertOpen(true); } }; const handleResetTokenThenClose = async () => { - const data = await (await fetch('/api/user/reset-token', { method: 'POST' })).json(); + const data = await ( + await fetch("/api/user/reset-token", { method: "POST" }) + ).json(); if (!data.error && data.updated) { - setAlertMessage('Reset token!'); + setAlertMessage("Reset token!"); setResetToken(false); setAlertOpen(true); } }; const handleLogout = async () => { - const data = await (await fetch('/api/user/logout', { method: 'POST' })).json(); + const data = await ( + await fetch("/api/user/logout", { method: "POST" }) + ).json(); if (!data.error && data.clearStore) { dispatch({ type: LOGOUT }); dispatch({ type: UPDATE_USER, payload: null }); - setAlertMessage('Logged out!'); + setAlertMessage("Logged out!"); setAlertOpen(true); - router.push('/login'); + router.push("/login"); } }; - if (typeof window !== 'undefined' && !state.loggedIn) router.push('/login'); + if (typeof window !== "undefined" && !state.loggedIn) router.push("/login"); else { return ( - Welcome back, {state.user.username} - You have 2 images + + Welcome back, {state.user.username} + + + You have 2 images +
Token - Are you sure? - This token is used to upload images to Zipline, and should not be shared! + This token is used to upload images to Zipline, and should not + be shared! - - Are you sure? - This token is used to upload images to Zipline, resetting your token will cause any uploading actions to not work until you update them your self. + This token is used to upload images to Zipline, resetting your + token will cause any uploading actions to not work until you + update them your self. - @@ -146,23 +174,36 @@ export default function IndexPage() {
User - +
- + - +
- ); } return ; -} \ No newline at end of file +} diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 73710112..7340d94d 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -1,25 +1,25 @@ -import { useState, useEffect } from 'react'; -import Typography from '@material-ui/core/Typography'; -import TextField from '@material-ui/core/TextField'; -import Button from '@material-ui/core/Button'; -import Card from '@material-ui/core/Card'; -import CardContent from '@material-ui/core/CardContent'; -import CardActions from '@material-ui/core/CardActions'; -import Snackbar from '@material-ui/core/Snackbar'; -import Grid from '@material-ui/core/Grid'; -import { makeStyles } from '@material-ui/core'; -import { useDispatch } from 'react-redux'; -import Router from 'next/router'; -import { store, persistor } from '../lib/store'; -import { UPDATE_USER, LOGIN } from '../lib/reducer'; -import UIPlaceholder from '../components/UIPlaceholder'; -import Alert from '@material-ui/lab/Alert'; +import { useState, useEffect } from "react"; +import Typography from "@material-ui/core/Typography"; +import TextField from "@material-ui/core/TextField"; +import Button from "@material-ui/core/Button"; +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import CardActions from "@material-ui/core/CardActions"; +import Snackbar from "@material-ui/core/Snackbar"; +import Grid from "@material-ui/core/Grid"; +import { makeStyles } from "@material-ui/core"; +import { useDispatch } from "react-redux"; +import Router from "next/router"; +import { store, persistor } from "../lib/store"; +import { UPDATE_USER, LOGIN } from "../lib/reducer"; +import UIPlaceholder from "../components/UIPlaceholder"; +import Alert from "@material-ui/lab/Alert"; const useStyles = makeStyles({ field: { - width: '100%' + width: "100%", }, padding: { - padding: '10px' + padding: "10px", }, }); @@ -36,54 +36,84 @@ export default function Index() { }; const handleClose = (event, reason) => { - if (reason === 'clickaway') return; + if (reason === "clickaway") return; setOpen(false); }; const handleLogin = async () => { - const d = await (await fetch('/api/user/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) })).json() + const d = await ( + await fetch("/api/user/login", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ username, password }), + }) + ).json(); if (!d.error) { dispatch({ type: UPDATE_USER, payload: d }); - dispatch({ type: LOGIN }) - Router.push('/'); + dispatch({ type: LOGIN }); + Router.push("/"); } else { setOpen(true); } - } + }; - if (state.loggedIn) Router.push('/'); - else return ( -
- - - Could not login! - - - - - - - - Login - - setUsername(e.target.value)} /> - setPassword(e.target.value)} /> - - - - - + if (state.loggedIn) Router.push("/"); + else + return ( +
+ + + Could not login! + + + + + + + + Login + + setUsername(e.target.value)} + /> + setPassword(e.target.value)} + /> + + + + + + - -
- ) - return -} \ No newline at end of file +
+ ); + return ; +} diff --git a/src/pages/statistics.tsx b/src/pages/statistics.tsx index 663ea27d..b9f481f7 100644 --- a/src/pages/statistics.tsx +++ b/src/pages/statistics.tsx @@ -1,5 +1,5 @@ -import UI from '../components/UI'; -import { Typography } from '@material-ui/core'; +import UI from "../components/UI"; +import { Typography } from "@material-ui/core"; export default function MyApp(props) { return ( @@ -8,5 +8,5 @@ export default function MyApp(props) { stater
- ) -} \ No newline at end of file + ); +} diff --git a/tsconfig.json b/tsconfig.json index 67b50856..27af3143 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { "target": "ES2020", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "outDir": "./dist", "allowJs": true, "skipLibCheck": true, @@ -20,12 +16,6 @@ "experimentalDecorators": true, "noEmit": false }, - "include": [ - "next-env.d.ts", - "src" - ], - "exclude": [ - "node_modules", - ".next" - ] -} \ No newline at end of file + "include": ["next-env.d.ts", "src"], + "exclude": ["node_modules", ".next"] +}