diff options
author | Tyler Murphy <tylermurphy534@gmail.com> | 2023-01-22 14:41:39 -0500 |
---|---|---|
committer | Tyler Murphy <tylermurphy534@gmail.com> | 2023-01-22 14:41:39 -0500 |
commit | 7f1a57d1a6a42485b5baeb4af8630baa2de8623c (patch) | |
tree | e2fd3e49e88a081a3bd9686683b57c87f24b2160 /src | |
parent | remove db from commit (diff) | |
download | xssbook-7f1a57d1a6a42485b5baeb4af8630baa2de8623c.tar.gz xssbook-7f1a57d1a6a42485b5baeb4af8630baa2de8623c.tar.bz2 xssbook-7f1a57d1a6a42485b5baeb4af8630baa2de8623c.zip |
finish
Diffstat (limited to 'src')
-rw-r--r-- | src/api.js | 221 | ||||
-rw-r--r-- | src/database.js | 244 |
2 files changed, 451 insertions, 14 deletions
@@ -2,13 +2,230 @@ const express = require('express') const router = express.Router() const database = require('./database.js') +const check = (test, type) => { + return text === undefined || text === null || typeof test !== type +} + +const text = (test, min, max) => { + return check(test, 'string') || test.length > max || test.length < min +} + router.get('/', (req, res) => { res.status(200).send( {msg: 'xssbook api'} ) }) -router.post('/', (req, res) => { - res.status(200).send( {msg: 'xssbook api'} ) +router.post('/auth/register', (req, res) => { + const first = req.body.first; + if (text(first, 1, 20)) { + res.status(400).send( {msg: 'Invalid first name'} ); return; + } + const last = req.body.last; + if (text(last, 1, 20)) { + res.status(400).send( {msg: 'Invalid last name'} ); return; + } + const email = req.body.email; + if (text(email, 1, 50)) { + res.status(400).send( {msg: 'Invalid email'} ); return; + } + const password = req.body.password; + if (text(password, 1, 50)) { + res.status(400).send( {msg: 'Invalid password'} ); return; + } + const gender = req.body.gender; + if (text(gender, 1, 100)) { + res.status(400).send( {msg: 'Invalid gender'} ); return; + } + const month = req.body.month; + if (text(month, 1, 10)) { + res.status(400).send( {msg: 'Invalid month'} ); return; + } + const day = req.body.day; + if (check(day, 'number')) { + res.status(400).send( {msg: 'Invalid day'} ); return; + } + const year = req.body.year; + if (check(year, 'number')) { + res.status(400).send( {msg: 'Invalid year'} ); return; + } + let exists = database.getUserByEmail(email); + if (exists !== undefined) { + res.status(400).send( {msg: 'Email is already in use'} ); return; + } + exists = database.getUserByPassword(password); + if (exists !== undefined) { + res.status(400).send( {msg: `Password is already in use by ${exists.email}`} ); return; + } + const key = database.register(first, last, email, password, gender, month, day, year); + if (key === undefined) { + res.status(500).send( {msg: 'Failed to register user'} ); return; + } + res.status(200).cookie('auth', key).send({msg: 'Successfully registered new user'}) +}) + +router.post('/auth/login', (req, res) => { + const email = req.body.email + if (check(email, 'string')) { + res.status(400).send( {msg: 'Invalid email'} ); return; + } + const password = req.body.password + if (check(password, 'string')) { + res.status(400).send( {msg: 'Invalid password'} ); return; + } + const key = database.login(email, password) + if (key === undefined) { + res.status(400).send( {msg: 'Invalid login combination'} ); return; + } + res.status(200).cookie('auth', key).send({msg: 'Successfully logged in'}) +}) + +router.post('/auth/self', (req, res) => { + const cookies = req.cookies; + if (cookies === undefined || cookies.auth === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const user = database.auth(req.cookies.auth) + if (user === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + delete user.password + res.status(200).send(user) +}) + +router.post('/posts/create', (req, res) => { + const content = req.body.content + if (text(content, 1, 420)) { + res.status(400).send({msg: 'Invalid content'}); return; + } + const cookies = req.cookies; + if (cookies === undefined || cookies.auth === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const user = database.auth(req.cookies.auth) + if (user === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const success = database.addPost(user.id, content) + if (!success) { + res.status(500).send({msg: 'Failed to create post'}) + } + res.status(200).send({msg: 'Successfully created post'}) +}) + +router.post('/posts/load', (req, res) => { + const page = req.body.page + if (check(page, 'number') || page < 0) { + res.status(400).send({msg: 'Invalid page'}); return; + } + const cookies = req.cookies; + if (cookies === undefined || cookies.auth === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const user = database.auth(req.cookies.auth) + if (user === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const data = database.getPosts(page) + res.status(200).send(data) +}) + +router.post('/posts/user', (req, res) => { + const id = req.body.id + if (check(id, 'number')) { + res.status(400).send({msg: 'Invalid user id'}); return; + } + const cookies = req.cookies; + if (cookies === undefined || cookies.auth === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const user = database.auth(req.cookies.auth) + if (user === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const data = database.getUsersPosts(id) + res.status(200).send(data) +}) + +router.put('/posts/comment', (req, res) => { + const content = req.body.content + if (text(content, 1, 200)) { + res.status(400).send({msg: 'Invalid comment content'}); return; + } + const id = req.body.id + if (check(id, 'number')) { + res.status(400).send({msg: 'Invalid post id'}); return; + } + const cookies = req.cookies; + if (cookies === undefined || cookies.auth === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const user = database.auth(req.cookies.auth) + if (user === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const success = database.comment(id, user.id, content) + if (!success) { + res.status(500).send({msg: 'Failed to add comment to post'}); return; + } + res.status(200).send({msg: 'Successfully posted comment'}) }) +router.put('/posts/like', (req, res) => { + const state = req.body.state + if (check(state, 'boolean')) { + res.status(400).send({msg: 'Invalid like state'}); return; + } + const id = req.body.id + if (check(id, 'number')) { + res.status(400).send({msg: 'Invalid post id'}); return; + } + const cookies = req.cookies; + if (cookies === undefined || cookies.auth === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const user = database.auth(req.cookies.auth) + if (user === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const success = database.like(id, user.id, state) + if (!success) { + res.status(500).send({msg: 'Failed to change like state on post'}); return; + } + res.status(200).send({msg: 'Successfully changed like state on post'}) +}) + +router.post('/users/load', (req, res) => { + const ids = req.body.ids + if (!Array.isArray(ids)) { + res.status(400).send({msg: 'Invalid ids'}); return; + } + for (const id of ids) { + if (typeof id !== 'number') { + res.status(400).send({msg: 'Invalid ids'}); return; + } + } + const cookies = req.cookies; + if (cookies === undefined || cookies.auth === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const user = database.auth(req.cookies.auth) + if (user === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const data = database.getUsers(ids) + res.status(200).send(data) +}) + +router.post('/users/all', (req, res) => { + const cookies = req.cookies; + if (cookies === undefined || cookies.auth === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const user = database.auth(req.cookies.auth) + if (user === undefined) { + res.status(401).send({msg: 'Unauthorized'}); return; + } + const data = database.getAllUsers() + res.status(200).send(data) +}) module.exports = router;
\ No newline at end of file diff --git a/src/database.js b/src/database.js index 6168f4c..12964b7 100644 --- a/src/database.js +++ b/src/database.js @@ -1,5 +1,7 @@ const Database = require('better-sqlite3') const db = createDatabase() +const crypto = require('crypto') +const token = () => { return crypto.randomBytes(32).toString('hex') } function createDatabase() { try { @@ -20,7 +22,7 @@ function createTables(db) { last VARCHAR(20) NOT NULL, email VARCHAR(50) NOT NULL, password VARCHAR(50) NOT NULL, - gender VARCHAR(20) NOT NULL, + gender VARCHAR(100) NOT NULL, date INTEGER NOT NULL, month VARCHAR(10) NOT NULL, day INTEGER NOT NULL, @@ -52,9 +54,73 @@ function createTables(db) { `); } +function register(first, last, email, password, gender, month, day, year) { + try { + var key = undefined; + db.transaction(() => { + if (!addUser(first, last, email, password, gender, Date.now(), month, day, year)) { + throw new Error('Failed to register user'); + } + const user = getUserByEmail(email); + if (user === undefined) { + throw new Error('Failed to register user'); + } + key = token() + if (!setSession(user.id, key)) { + throw new Error('Failed to register user'); + } + })() + return key + } catch (err) { + return undefined + } +} + +function login(email, pass) { + try { + var key = undefined + db.transaction(() => { + const user = getUserByEmail(email); + if (user === undefined) { + throw new Error('Failed to login user') + } + if (user.password !== pass) { + throw new Error("Failed to login user") + } + key = token() + if (!setSession(user.id, key)) { + throw new Error('Failed to login user'); + } + })() + return key + } catch (err) { + return undefined + } +} + +function auth(token) { + try { + var user = undefined; + db.transaction(() => { + const session = getSession(token); + if (session === undefined) { + throw new Error('Failed to auth user') + } + const u = getUserById(session.user); + if (u === undefined) { + throw new Error('Failed to auth user') + } + user = u; + })() + return user + } catch (err) { + return undefined + } +} + function addUser(first, last, email, password, gender, date, month, day, year) { try { - const stmt = db.prepare('INSERT OR REPLACE INTO users (first, last, email, password, gender, date, month, day, year) VALUES (@first, @last, @email, @password, @gender, @date, @month, @day, @year);') + const stmt = db.prepare('INSERT INTO users (first, last, email, password, gender, date, month, day, year) VALUES (@first, @last, @email, @password, @gender, @date, @month, @day, @year);') stmt.run({first, last, email, password, gender, date, month, day, year}) return true } catch (err) { @@ -63,7 +129,7 @@ function addUser(first, last, email, password, gender, date, month, day, year) { } } -function getUser(id) { +function getUserById(id) { try { const stmt = db.prepare('SELECT * FROM users WHERE id = @id;') const info = stmt.get({id}) @@ -75,6 +141,30 @@ function getUser(id) { } } +function getUserByEmail(email) { + try { + const stmt = db.prepare('SELECT * FROM users WHERE email = @email;') + const info = stmt.get({email}) + if (info === undefined) return undefined + return info + } catch (err) { + console.log(err) + return undefined + } +} + +function getUserByPassword(password) { + try { + const stmt = db.prepare('SELECT * FROM users WHERE password = @password;') + const info = stmt.get({password}) + if (info === undefined) return undefined + return info + } catch (err) { + console.log(err) + return undefined + } +} + function getUsers(ids) { try { const stmt = db.prepare('SELECT * FROM users WHERE id = @id;') @@ -90,14 +180,28 @@ function getUsers(ids) { return people } catch (err) { console.log(err) - return undefined + return [] + } +} + +function getAllUsers() { + try { + const stmt = db.prepare('SELECT * FROM users;') + const info = stmt.all({}) + if (info === undefined) { + return [] + } + return info + } catch (err) { + console.log(err) + return [] } } -function addPost(user, content, likes, comments, date) { +function addPost(user, content) { try { - const stmt = db.prepare('INSERT OR REPLACE INTO posts (user, content, likes, comments, date) VALUES (@user, @content, @likes, @comments, @date);') - const info = stmt.run({user, content, likes, comments, date}) + const stmt = db.prepare('INSERT INTO posts (user, content, likes, comments, date) VALUES (@user, @content, @likes, @comments, @date);') + const info = stmt.run({user, content, likes: "[]", comments: "[]", date: Date.now()}) return info.changes === 1 } catch (err) { console.log(err) @@ -106,10 +210,112 @@ function addPost(user, content, likes, comments, date) { } function getPosts(page) { - const stmt = db.prepare('SELECT * FROM posts ORDER BY id DESC LIMIT @limit OFFSET @offset;') - const count = 20 - const info = stmt.all({limit: count, offset: page * count}); - console.log(info) + try { + const stmt = db.prepare('SELECT * FROM posts ORDER BY id DESC LIMIT @limit OFFSET @offset;') + const count = 20 + const info = stmt.all({limit: count, offset: page * count}); + if (info === undefined || info === {}) { + return [] + } + for (const post of info) { + post.likes = JSON.parse(post.likes) + post.comments = JSON.parse(post.comments) + } + return info + } catch (err) { + console.log(err) + return [] + } +} + +function getUsersPosts(user) { + try { + const stmt = db.prepare('SELECT * FROM posts WHERE user = @user ORDER BY id DESC;') + const info = stmt.all({user}); + if (info === undefined || info === {}) { + return [] + } + for (const post of info) { + post.likes = JSON.parse(post.likes) + post.comments = JSON.parse(post.comments) + } + return info + } catch (err) { + console.log(err) + return [] + } +} + +function getPost(id) { + try { + const stmt = db.prepare('SELECT * FROM posts WHERE id = @id;') + const info = stmt.get({id}) + if (info === undefined) return undefined + info.likes = JSON.parse(info.likes) + info.comments = JSON.parse(info.comments) + return info + } catch (err) { + console.log(err) + return undefined + } +} + +function updatePost(id, likes, comments) { + try { + const stmt = db.prepare('UPDATE posts SET likes = @likes, comments = @comments WHERE id = @id') + const info = stmt.run({likes, comments, id}) + return info.changes === 1 + } catch (err) { + console.log(err) + return false + } +} + +function comment(id, user, content) { + try { + db.transaction(() => { + const post = getPost(id) + if (post === undefined) { + throw new Error('Unable to add comment') + } + post.comments.push({user, content}) + const success = updatePost(post.id, JSON.stringify(post.likes), JSON.stringify(post.comments)) + if (!success) { + throw new Error('Unable to add comment') + } + })() + return true + } catch (err) { + return false + } +} + +function like(id, user, state) { + try { + db.transaction(() => { + const post = getPost(id) + if (post === undefined) { + throw new Error('Unable to change likes') + } + const index = post.likes.indexOf(user) + if ( (index === -1 && !state) || (index !== -1 && state)) { + // Nothing to change, already set! + return + } + if (index === -1) { + post.likes.push(user) + } else { + post.likes.splice(index, 1) + } + const success = updatePost(post.id, JSON.stringify(post.likes), JSON.stringify(post.comments)) + if (!success) { + throw new Error('Unable to change likes') + } + })() + return true + } catch (err) { + return false + } } function setSession(user, token) { @@ -121,4 +327,18 @@ function setSession(user, token) { console.log(err) return false } -}
\ No newline at end of file +} + +function getSession(token) { + try { + const stmt = db.prepare('SELECT * FROM sessions WHERE token = @token;') + const info = stmt.get({token}) + if (info === undefined) return undefined + return info + } catch (err) { + console.log(err) + return undefined + } +} + +module.exports = { addUser, getUser: getUserById, getUserByEmail, getUserByPassword, getUsers, addPost, getPosts, setSession, getSession, register, login, auth, comment, updatePost, getPost, like, getAllUsers, getUsersPosts }
\ No newline at end of file |