mirror of https://github.com/MaxLeiter/Drift
Added celebreate validation
parent
c9f84fe69c
commit
7b2baad782
@ -1,85 +1,104 @@
|
|||||||
import { Router } from 'express'
|
import { Router } from "express";
|
||||||
import { genSalt, hash, compare } from "bcrypt"
|
import { genSalt, hash, compare } from "bcrypt";
|
||||||
import { User } from '../../lib/models/User'
|
import { User } from "../../lib/models/User";
|
||||||
import { sign } from 'jsonwebtoken'
|
import { sign } from "jsonwebtoken";
|
||||||
import config from '../../lib/config'
|
import config from "../../lib/config";
|
||||||
import jwt from '../../lib/middleware/jwt'
|
import jwt from "../../lib/middleware/jwt";
|
||||||
|
import { celebrate, Joi } from "celebrate";
|
||||||
|
|
||||||
const NO_EMPTY_SPACE_REGEX = /^\S*$/
|
const NO_EMPTY_SPACE_REGEX = /^\S*$/;
|
||||||
|
|
||||||
export const auth = Router()
|
export const auth = Router();
|
||||||
|
|
||||||
const validateAuthPayload = (username: string, password: string): void => {
|
const validateAuthPayload = (username: string, password: string): void => {
|
||||||
if (!NO_EMPTY_SPACE_REGEX.test(username) || password.length < 6) {
|
if (!NO_EMPTY_SPACE_REGEX.test(username) || password.length < 6) {
|
||||||
throw new Error("Authentication data does not fulfill requirements")
|
throw new Error("Authentication data does not fulfill requirements");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
auth.post('/signup', async (req, res, next) => {
|
auth.post(
|
||||||
|
"/signup",
|
||||||
|
celebrate({
|
||||||
|
params: {
|
||||||
|
username: Joi.string().required(),
|
||||||
|
password: Joi.string().required(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
validateAuthPayload(req.body.username, req.body.password)
|
validateAuthPayload(req.body.username, req.body.password);
|
||||||
|
|
||||||
const username = req.body.username.toLowerCase();
|
const username = req.body.username.toLowerCase();
|
||||||
|
|
||||||
const existingUser = await User.findOne({ where: { username: username } })
|
const existingUser = await User.findOne({
|
||||||
if (existingUser) {
|
where: { username: username },
|
||||||
throw new Error("Username already exists")
|
});
|
||||||
}
|
if (existingUser) {
|
||||||
|
throw new Error("Username already exists");
|
||||||
|
}
|
||||||
|
|
||||||
const salt = await genSalt(10)
|
const salt = await genSalt(10);
|
||||||
const user = {
|
const user = {
|
||||||
username: username as string,
|
username: username as string,
|
||||||
password: await hash(req.body.password, salt)
|
password: await hash(req.body.password, salt),
|
||||||
}
|
};
|
||||||
|
|
||||||
const created_user = await User.create(user);
|
const created_user = await User.create(user);
|
||||||
|
|
||||||
const token = generateAccessToken(created_user.id);
|
const token = generateAccessToken(created_user.id);
|
||||||
|
|
||||||
res.status(201).json({ token: token, userId: created_user.id })
|
res.status(201).json({ token: token, userId: created_user.id });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
next(e);
|
next(e);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
auth.post('/signin', async (req, res, next) => {
|
|
||||||
const error = "User does not exist or password is incorrect"
|
auth.post(
|
||||||
|
"/signin",
|
||||||
|
celebrate({
|
||||||
|
params: {
|
||||||
|
username: Joi.string().required(),
|
||||||
|
password: Joi.string().required(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (req, res, next) => {
|
||||||
|
const error = "User does not exist or password is incorrect";
|
||||||
const errorToThrow = new Error(error);
|
const errorToThrow = new Error(error);
|
||||||
try {
|
try {
|
||||||
if (!req.body.username || !req.body.password) {
|
if (!req.body.username || !req.body.password) {
|
||||||
throw errorToThrow
|
throw errorToThrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
const username = req.body.username.toLowerCase();
|
const username = req.body.username.toLowerCase();
|
||||||
const user = await User.findOne({ where: { username: username } });
|
const user = await User.findOne({ where: { username: username } });
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw errorToThrow
|
throw errorToThrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
const password_valid = await compare(req.body.password, user.password);
|
const password_valid = await compare(req.body.password, user.password);
|
||||||
if (password_valid) {
|
if (password_valid) {
|
||||||
const token = generateAccessToken(user.id);
|
const token = generateAccessToken(user.id);
|
||||||
res.status(200).json({ token: token, userId: user.id });
|
res.status(200).json({ token: token, userId: user.id });
|
||||||
} else {
|
} else {
|
||||||
throw errorToThrow
|
throw errorToThrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
next(e);
|
next(e);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function generateAccessToken(id: string) {
|
function generateAccessToken(id: string) {
|
||||||
return sign({ id: id }, config.jwt_secret, { expiresIn: '2d' });
|
return sign({ id: id }, config.jwt_secret, { expiresIn: "2d" });
|
||||||
}
|
}
|
||||||
|
|
||||||
auth.get("/verify-token", jwt, async (req, res, next) => {
|
auth.get("/verify-token", jwt, async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
message: "You are authenticated"
|
message: "You are authenticated",
|
||||||
})
|
});
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
next(e);
|
||||||
next(e);
|
}
|
||||||
}
|
});
|
||||||
})
|
|
||||||
|
|||||||
@ -1,29 +1,36 @@
|
|||||||
import { Router } from 'express'
|
import { celebrate, Joi } from "celebrate";
|
||||||
|
import { Router } from "express";
|
||||||
// import { Movie } from '../models/Post'
|
// import { Movie } from '../models/Post'
|
||||||
import { File } from '../../lib/models/File'
|
import { File } from "../../lib/models/File";
|
||||||
|
|
||||||
export const files = Router()
|
export const files = Router();
|
||||||
|
|
||||||
files.get("/raw/:id", async (req, res, next) => {
|
files.get(
|
||||||
|
"/raw/:id",
|
||||||
|
celebrate({
|
||||||
|
params: {
|
||||||
|
id: Joi.string().required(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const file = await File.findOne({
|
const file = await File.findOne({
|
||||||
where: {
|
where: {
|
||||||
id: req.params.id
|
id: req.params.id,
|
||||||
},
|
},
|
||||||
attributes: ["title", "content"],
|
attributes: ["title", "content"],
|
||||||
})
|
});
|
||||||
// TODO: fix post inclusion
|
// TODO: fix post inclusion
|
||||||
// if (file?.post.visibility === 'public' || file?.post.visibility === 'unlisted') {
|
// if (file?.post.visibility === 'public' || file?.post.visibility === 'unlisted') {
|
||||||
res.setHeader("Cache-Control", "public, max-age=86400");
|
res.setHeader("Cache-Control", "public, max-age=86400");
|
||||||
res.json(file);
|
res.json(file);
|
||||||
// } else {
|
// } else {
|
||||||
// TODO: should this be `private, `?
|
// TODO: should this be `private, `?
|
||||||
// res.setHeader("Cache-Control", "max-age=86400");
|
// res.setHeader("Cache-Control", "max-age=86400");
|
||||||
// res.json(file);
|
// res.json(file);
|
||||||
// }
|
// }
|
||||||
|
} catch (e) {
|
||||||
|
next(e);
|
||||||
}
|
}
|
||||||
catch (e) {
|
}
|
||||||
next(e);
|
);
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export { auth } from './auth';
|
export { auth } from "./auth";
|
||||||
export { posts } from './posts';
|
export { posts } from "./posts";
|
||||||
export { users } from './users';
|
export { users } from "./users";
|
||||||
export { files } from './files';
|
export { files } from "./files";
|
||||||
|
|||||||
@ -1,97 +1,116 @@
|
|||||||
import { Router } from 'express'
|
import { Router } from "express";
|
||||||
// import { Movie } from '../models/Post'
|
// import { Movie } from '../models/Post'
|
||||||
import { File } from '../../lib/models/File'
|
import { File } from "../../lib/models/File";
|
||||||
import { Post } from '../../lib/models/Post';
|
import { Post } from "../../lib/models/Post";
|
||||||
import jwt, { UserJwtRequest } from '../../lib/middleware/jwt';
|
import jwt, { UserJwtRequest } from "../../lib/middleware/jwt";
|
||||||
import * as crypto from "crypto";
|
import * as crypto from "crypto";
|
||||||
import { User } from '../../lib/models/User';
|
import { User } from "../../lib/models/User";
|
||||||
|
import { celebrate, Joi } from "celebrate";
|
||||||
|
|
||||||
export const posts = Router()
|
export const posts = Router();
|
||||||
|
|
||||||
posts.post('/create', jwt, async (req, res, next) => {
|
posts.post(
|
||||||
|
"/create",
|
||||||
|
jwt,
|
||||||
|
celebrate({
|
||||||
|
body: {
|
||||||
|
title: Joi.string().required(),
|
||||||
|
files: Joi.any().required(),
|
||||||
|
visibility: Joi.string().required(),
|
||||||
|
userId: Joi.string().required(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (req, res, next) => {
|
||||||
|
console.log(req.body);
|
||||||
try {
|
try {
|
||||||
if (!req.body.files) {
|
// Create the "post" object
|
||||||
throw new Error("Please provide files.")
|
const newPost = new Post({
|
||||||
}
|
title: req.body.title,
|
||||||
|
visibility: req.body.visibility,
|
||||||
|
});
|
||||||
|
|
||||||
if (!req.body.title) {
|
await newPost.save();
|
||||||
throw new Error("Please provide a title.")
|
await newPost.$add("users", req.body.userId);
|
||||||
}
|
const newFiles = await Promise.all(
|
||||||
|
req.body.files.map(async (file) => {
|
||||||
|
// Establish a "file" for each file in the request
|
||||||
|
const newFile = new File({
|
||||||
|
title: file.title,
|
||||||
|
content: file.content,
|
||||||
|
sha: crypto
|
||||||
|
.createHash("sha256")
|
||||||
|
.update(file.content)
|
||||||
|
.digest("hex")
|
||||||
|
.toString(),
|
||||||
|
});
|
||||||
|
|
||||||
if (!req.body.userId) {
|
await newFile.$set("user", req.body.userId);
|
||||||
throw new Error("No user id provided.")
|
await newFile.$set("post", newPost.id);
|
||||||
}
|
await newFile.save();
|
||||||
|
return newFile;
|
||||||
if (!req.body.visibility) {
|
|
||||||
throw new Error("Please provide a visibility.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the "post" object
|
|
||||||
const newPost = new Post({
|
|
||||||
title: req.body.title,
|
|
||||||
visibility: req.body.visibility,
|
|
||||||
})
|
})
|
||||||
|
);
|
||||||
|
|
||||||
await newPost.save()
|
await Promise.all(
|
||||||
await newPost.$add('users', req.body.userId);
|
newFiles.map((file) => {
|
||||||
const newFiles = await Promise.all(req.body.files.map(async (file) => {
|
newPost.$add("files", file.id);
|
||||||
// Establish a "file" for each file in the request
|
newPost.save();
|
||||||
const newFile = new File({
|
})
|
||||||
title: file.title,
|
);
|
||||||
content: file.content,
|
|
||||||
sha: crypto.createHash('sha256').update(file.content).digest('hex').toString(),
|
|
||||||
})
|
|
||||||
|
|
||||||
await newFile.$set("user", req.body.userId);
|
|
||||||
await newFile.$set("post", newPost.id);
|
|
||||||
await newFile.save();
|
|
||||||
return newFile;
|
|
||||||
}))
|
|
||||||
|
|
||||||
await Promise.all(newFiles.map((file) => {
|
|
||||||
newPost.$add("files", file.id);
|
|
||||||
newPost.save();
|
|
||||||
}))
|
|
||||||
|
|
||||||
res.json(newPost);
|
res.json(newPost);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
next(e);
|
next(e);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
posts.get("/:id", async (req: UserJwtRequest, res, next) => {
|
posts.get(
|
||||||
|
"/:id",
|
||||||
|
celebrate({
|
||||||
|
params: {
|
||||||
|
id: Joi.string().required(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (req: UserJwtRequest, res, next) => {
|
||||||
try {
|
try {
|
||||||
const post = await Post.findOne({
|
const post = await Post.findOne({
|
||||||
where: {
|
where: {
|
||||||
id: req.params.id
|
id: req.params.id,
|
||||||
},
|
},
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: File,
|
model: File,
|
||||||
as: "files",
|
as: "files",
|
||||||
attributes: ["id", "title", "content", "sha", "createdAt", "updatedAt"],
|
attributes: [
|
||||||
},
|
"id",
|
||||||
{
|
"title",
|
||||||
model: User,
|
"content",
|
||||||
as: "users",
|
"sha",
|
||||||
attributes: ["id", "username"],
|
"createdAt",
|
||||||
},
|
"updatedAt",
|
||||||
]
|
],
|
||||||
})
|
},
|
||||||
|
{
|
||||||
|
model: User,
|
||||||
|
as: "users",
|
||||||
|
attributes: ["id", "username"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
if (post?.visibility === 'public' || post?.visibility === 'unlisted') {
|
if (post?.visibility === "public" || post?.visibility === "unlisted") {
|
||||||
res.setHeader("Cache-Control", "public, max-age=86400");
|
res.setHeader("Cache-Control", "public, max-age=86400");
|
||||||
res.json(post);
|
res.json(post);
|
||||||
} else {
|
} else {
|
||||||
// TODO: should this be `private, `?
|
// TODO: should this be `private, `?
|
||||||
res.setHeader("Cache-Control", "max-age=86400");
|
res.setHeader("Cache-Control", "max-age=86400");
|
||||||
jwt(req, res, () => {
|
jwt(req, res, () => {
|
||||||
res.json(post);
|
res.json(post);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
} catch (e) {
|
||||||
catch (e) {
|
next(e);
|
||||||
next(e);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|||||||
@ -1,46 +1,47 @@
|
|||||||
import { Router } from 'express'
|
import { Router } from "express";
|
||||||
// import { Movie } from '../models/Post'
|
import { User } from "../../lib/models/User";
|
||||||
import { User } from '../../lib/models/User'
|
import { File } from "../../lib/models/File";
|
||||||
import { File } from '../../lib/models/File'
|
import jwt, { UserJwtRequest } from "../../lib/middleware/jwt";
|
||||||
import jwt, { UserJwtRequest } from '../../lib/middleware/jwt'
|
import { Post } from "../../lib/models/Post";
|
||||||
import { Post } from '../../lib/models/Post'
|
|
||||||
|
|
||||||
export const users = Router()
|
export const users = Router();
|
||||||
|
|
||||||
users.get('/', jwt, async (req, res, next) => {
|
users.get("/", jwt, async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const allUsers = await User.findAll()
|
const allUsers = await User.findAll();
|
||||||
res.json(allUsers)
|
res.json(allUsers);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error)
|
next(error);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
users.get("/mine", jwt, async (req: UserJwtRequest, res, next) => {
|
users.get("/mine", jwt, async (req: UserJwtRequest, res, next) => {
|
||||||
if (!req.user) {
|
if (!req.user) {
|
||||||
return res.status(401).json({ error: "Unauthorized" })
|
return res.status(401).json({ error: "Unauthorized" });
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const user = await User.findByPk(req.user.id, {
|
const user = await User.findByPk(req.user.id, {
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: Post,
|
model: Post,
|
||||||
as: "posts",
|
as: "posts",
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: File,
|
model: File,
|
||||||
as: "files"
|
as: "files",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
});
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return res.status(404).json({ error: "User not found" })
|
return res.status(404).json({ error: "User not found" });
|
||||||
}
|
|
||||||
return res.json(user.posts?.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()))
|
|
||||||
} catch (error) {
|
|
||||||
next(error)
|
|
||||||
}
|
}
|
||||||
})
|
return res.json(
|
||||||
|
user.posts?.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue