i changed a lot of shit
This commit is contained in:
parent
4b0a9dd484
commit
15f2b32511
17 changed files with 1068 additions and 563 deletions
195
index.js
195
index.js
|
@ -1,96 +1,135 @@
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
const cookie = require('cookie-parser')
|
|
||||||
const app = express()
|
const app = express()
|
||||||
const port = 8080
|
const cache = require('./src/cache')
|
||||||
|
const con = require('./src/console')
|
||||||
|
|
||||||
|
|
||||||
|
const auth = require('./src/api/auth')
|
||||||
|
const pages = require('./src/api/pages')
|
||||||
|
const posts = require('./src/api/posts')
|
||||||
|
const users = require('./src/api/users')
|
||||||
|
|
||||||
|
|
||||||
app.set('trust proxy', true)
|
app.set('trust proxy', true)
|
||||||
app.use(cookie())
|
|
||||||
app.use(express.json());
|
|
||||||
app.use(express.static('public'))
|
app.use(express.static('public'))
|
||||||
|
app.use(require('cookie-parser')())
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
const database = require('./src/database.js')
|
|
||||||
const con = require('./src/console.js')
|
|
||||||
const api = require('./src/api.js')
|
|
||||||
|
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
var ip = req.headers['x-real-ip'] || req.connection.remoteAddress;
|
|
||||||
if (req.path !== '/console') {
|
var ip = req.headers['x-real-ip'] || req.socket.remoteAddress;
|
||||||
const public = { ... req.body }
|
|
||||||
if (public.password !== undefined) {
|
if (req.path !== '/console') {
|
||||||
public.password = '********'
|
|
||||||
|
let body = { ...req.body }
|
||||||
|
|
||||||
|
if (body.password !== undefined) {
|
||||||
|
body.password = '********'
|
||||||
|
}
|
||||||
|
|
||||||
|
con.log(
|
||||||
|
ip,
|
||||||
|
req.method,
|
||||||
|
req.path,
|
||||||
|
body
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
console.log(ip, req.method, req.path, public)
|
|
||||||
con.requests.push({ip: ip, method: req.method, path: req.path, body: public})
|
next()
|
||||||
}
|
|
||||||
next()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/', (req, res) => {
|
|
||||||
const cookies = req.cookies;
|
|
||||||
if (cookies === undefined || cookies.auth === undefined) {
|
|
||||||
res.redirect('/login')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const user = database.auth(req.cookies.auth)
|
|
||||||
if (user === undefined) {
|
|
||||||
res.redirect('/login')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res.redirect('/home')
|
|
||||||
})
|
|
||||||
|
|
||||||
app.get('/login', (req, res) => {
|
|
||||||
const cookies = req.cookies;
|
|
||||||
if (cookies === undefined || cookies.auth === undefined) {
|
|
||||||
res.sendFile('login.html', { root: './public' })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const user = database.auth(req.cookies.auth)
|
|
||||||
if (user === undefined) {
|
|
||||||
res.sendFile('login.html', { root: './public' })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res.redirect('/home')
|
|
||||||
})
|
|
||||||
|
|
||||||
app.get('/home', (req, res) => {
|
|
||||||
const cookies = req.cookies;
|
|
||||||
if (cookies === undefined || cookies.auth === undefined) {
|
|
||||||
res.redirect('/login')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const user = database.auth(req.cookies.auth)
|
|
||||||
if (user === undefined) {
|
|
||||||
res.redirect('/login')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res.sendFile('home.html', { root: './public' })
|
|
||||||
})
|
|
||||||
|
|
||||||
app.get('/people', (req, res) => {
|
|
||||||
res.sendFile('people.html', { root: './public' })
|
|
||||||
})
|
|
||||||
|
|
||||||
app.get('/profile', (req, res) => {
|
|
||||||
res.sendFile('profile.html', { root: './public' })
|
|
||||||
})
|
|
||||||
|
|
||||||
app.use('/api', api);
|
|
||||||
app.use('/console', con.router);
|
|
||||||
|
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
res.status(404).sendFile('404.html', { root: './public' })
|
|
||||||
|
if (req.path.startsWith('/api/auth')) {
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const cookies = req.cookies
|
||||||
|
|
||||||
|
if (cookies === undefined || cookies.auth === undefined) {
|
||||||
|
|
||||||
|
if (req.method !== 'GET' && req.path.startsWith('/api')) {
|
||||||
|
res.status(401).send({msg: 'Unauthorized'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = cache.auth(req.cookies.auth)
|
||||||
|
|
||||||
|
if (user !== undefined) {
|
||||||
|
|
||||||
|
res.locals.user = user
|
||||||
|
|
||||||
|
} else if (req.method !== 'GET' && req.path.startsWith('/api')) {
|
||||||
|
|
||||||
|
res.status(401).send({msg: 'Unauthorized'})
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
app.use('/api/auth', auth)
|
||||||
|
app.use('/api/posts', posts)
|
||||||
|
app.use('/api/users', users)
|
||||||
|
app.use('/', pages)
|
||||||
|
|
||||||
|
|
||||||
|
app.get('/console', (req, res) => {
|
||||||
|
res.send(con.render())
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
res.status(404).sendFile('404.html', { root: './public' })
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
app.use((err, req, res, next) => {
|
app.use((err, req, res, next) => {
|
||||||
if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
|
|
||||||
res.status(400).send({msg: 'Invalid json body'})
|
if (err instanceof SyntaxError && err.status === 400 && 'body' in err) {
|
||||||
return
|
res.status(400).send({ msg: 'Invalid json body' })
|
||||||
}
|
return
|
||||||
console.error(err)
|
}
|
||||||
res.status(500).send({msg: 'Internal server error'})
|
|
||||||
|
console.error(err)
|
||||||
|
res.status(500).send({ msg: 'Internal server error' })
|
||||||
})
|
})
|
||||||
|
|
||||||
app.listen(port, () => {
|
|
||||||
console.log(`App listening on port http://127.0.0.1:${port}`)
|
const cron = require('node-cron').schedule('*/5 * * * *', () => {
|
||||||
})
|
con.msg('Writing cache to database')
|
||||||
|
cache.dump()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const port = 8080
|
||||||
|
const server = app.listen(port, () => {
|
||||||
|
console.log(`App listening on port http://127.0.0.1:${port}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
console.log('Writing cache to database')
|
||||||
|
cache.dump()
|
||||||
|
console.log('Stopping cron jobs')
|
||||||
|
cron.stop()
|
||||||
|
server.close(() => {
|
||||||
|
console.log('HTTP server closed')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
process.on('SIGINT', close)
|
||||||
|
process.on('SIGTERM', close)
|
||||||
|
process.on('SIGQUIT', close)
|
61
package-lock.json
generated
61
package-lock.json
generated
|
@ -12,10 +12,9 @@
|
||||||
"better-sqlite3": "^8.0.1",
|
"better-sqlite3": "^8.0.1",
|
||||||
"cheerio": "^1.0.0-rc.12",
|
"cheerio": "^1.0.0-rc.12",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
"crypto": "^1.0.1",
|
|
||||||
"dotenv": "^16.0.3",
|
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"express-rate-limit": "^6.7.0"
|
"express-rate-limit": "^6.7.0",
|
||||||
|
"node-cron": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
|
@ -238,12 +237,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||||
},
|
},
|
||||||
"node_modules/crypto": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
|
|
||||||
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in."
|
|
||||||
},
|
|
||||||
"node_modules/css-select": {
|
"node_modules/css-select": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
|
||||||
|
@ -376,14 +369,6 @@
|
||||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dotenv": {
|
|
||||||
"version": "16.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
|
||||||
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ee-first": {
|
"node_modules/ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
@ -781,6 +766,17 @@
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/node-cron": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": "8.3.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/nth-check": {
|
"node_modules/nth-check": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||||
|
@ -1207,6 +1203,14 @@
|
||||||
"node": ">= 0.4.0"
|
"node": ">= 0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uuid": {
|
||||||
|
"version": "8.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vary": {
|
"node_modules/vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
|
@ -1384,11 +1388,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||||
},
|
},
|
||||||
"crypto": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig=="
|
|
||||||
},
|
|
||||||
"css-select": {
|
"css-select": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
|
||||||
|
@ -1475,11 +1474,6 @@
|
||||||
"domhandler": "^5.0.1"
|
"domhandler": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dotenv": {
|
|
||||||
"version": "16.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
|
||||||
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ=="
|
|
||||||
},
|
|
||||||
"ee-first": {
|
"ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
@ -1766,6 +1760,14 @@
|
||||||
"semver": "^7.3.5"
|
"semver": "^7.3.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node-cron": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-iP8l0yGlNpE0e6q1o185yOApANRe47UPbLf4YxfbiNHt/RU5eBcGB/e0oudruheSf+LQeDMezqC5BVAb5wwRcQ==",
|
||||||
|
"requires": {
|
||||||
|
"uuid": "8.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nth-check": {
|
"nth-check": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||||
|
@ -2068,6 +2070,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
|
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
|
||||||
},
|
},
|
||||||
|
"uuid": {
|
||||||
|
"version": "8.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||||
|
},
|
||||||
"vary": {
|
"vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
|
|
|
@ -12,9 +12,8 @@
|
||||||
"better-sqlite3": "^8.0.1",
|
"better-sqlite3": "^8.0.1",
|
||||||
"cheerio": "^1.0.0-rc.12",
|
"cheerio": "^1.0.0-rc.12",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
"crypto": "^1.0.1",
|
|
||||||
"dotenv": "^16.0.3",
|
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"express-rate-limit": "^6.7.0"
|
"express-rate-limit": "^6.7.0",
|
||||||
|
"node-cron": "^3.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,15 +179,4 @@ body {
|
||||||
width: calc(100% - 20px);
|
width: calc(100% - 20px);
|
||||||
background-color: #f0f2f5;
|
background-color: #f0f2f5;
|
||||||
font-family: sfpro;
|
font-family: sfpro;
|
||||||
}
|
|
||||||
|
|
||||||
#load {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#load a:hover {
|
|
||||||
border-bottom: #606770 1px solid;
|
|
||||||
}
|
}
|
|
@ -293,4 +293,15 @@ form {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#load {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#load a:hover {
|
||||||
|
border-bottom: #606770 1px solid;
|
||||||
}
|
}
|
|
@ -20,8 +20,8 @@ const login = async (email, password) => {
|
||||||
return await request('/auth/login', {email, password})
|
return await request('/auth/login', {email, password})
|
||||||
}
|
}
|
||||||
|
|
||||||
const register = async (first, last, email, password, gender, month, day, year) => {
|
const register = async (firstname, lastname, email, password, gender, month, day, year) => {
|
||||||
return await request('/auth/register', {first, last, email, password, gender, month, day, year})
|
return await request('/auth/register', {firstname, lastname, email, password, gender, month, day, year})
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadposts = async (page) => {
|
const loadposts = async (page) => {
|
||||||
|
@ -36,12 +36,12 @@ const loadusers = async (ids) => {
|
||||||
return await request('/users/load', {ids})
|
return await request('/users/load', {ids})
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadallusers = async () => {
|
const loaduserspage = async (page) => {
|
||||||
return await request('/users/all', {})
|
return await request('/users/page', {page})
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadself = async () => {
|
const loadself = async () => {
|
||||||
return await request("/auth/self", {})
|
return await request("/users/self", {})
|
||||||
}
|
}
|
||||||
|
|
||||||
const postcomment = async (id, content) => {
|
const postcomment = async (id, content) => {
|
||||||
|
|
|
@ -44,13 +44,13 @@ function parsePost(post) {
|
||||||
${post.content.replace(/\n/g,'<br>')}
|
${post.content.replace(/\n/g,'<br>')}
|
||||||
</p>
|
</p>
|
||||||
<span class="gtext mtext">
|
<span class="gtext mtext">
|
||||||
${post.likes.length} Likes
|
${Object.keys(post.likes).length} Likes
|
||||||
</span>
|
</span>
|
||||||
<div class="fullline nb"></div>
|
<div class="fullline nb"></div>
|
||||||
<div class="postbuttons">
|
<div class="postbuttons">
|
||||||
<span onclick="like(this)">
|
<span onclick="like(this)">
|
||||||
<i class="icons like ${post.likes.includes(data.user.id) ? 'blue' : ''}"></i>
|
<i class="icons like ${post.likes[data.user.id] ? 'blue' : ''}"></i>
|
||||||
<span class="bold ${post.likes.includes(data.user.id) ? 'blue' : ''}">Like</span>
|
<span class="bold ${post.likes[data.user.id] ? 'blue' : ''}">Like</span>
|
||||||
</span>
|
</span>
|
||||||
<span onclick="this.parentElement.parentElement.getElementsByClassName('newcomment')[0].focus()">
|
<span onclick="this.parentElement.parentElement.getElementsByClassName('newcomment')[0].focus()">
|
||||||
<i class="icons comm"></i>
|
<i class="icons comm"></i>
|
||||||
|
@ -87,15 +87,10 @@ function getPost(id) {
|
||||||
async function like(span) {
|
async function like(span) {
|
||||||
const id = parseInt(span.parentElement.parentElement.getAttribute('postid'))
|
const id = parseInt(span.parentElement.parentElement.getAttribute('postid'))
|
||||||
const post = data.posts[getPost(id)]
|
const post = data.posts[getPost(id)]
|
||||||
const index = post.likes.indexOf(data.user.id)
|
const current = post.likes[data.user.id]
|
||||||
const state = index === -1;
|
const response = await postlike(id, !current)
|
||||||
const response = await postlike(id, state)
|
|
||||||
if (response.status != 200) return;
|
if (response.status != 200) return;
|
||||||
if (index == -1) {
|
post.likes[data.user.id] = !current
|
||||||
post.likes.push(data.user.id)
|
|
||||||
} else {
|
|
||||||
post.likes.splice(index, 1)
|
|
||||||
}
|
|
||||||
render()
|
render()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +122,7 @@ async function post() {
|
||||||
}
|
}
|
||||||
error.innerHTML = '';
|
error.innerHTML = '';
|
||||||
data.posts.unshift({
|
data.posts.unshift({
|
||||||
id: data.posts[0].id + 1,
|
id: response.msg,
|
||||||
user: data.user.id,
|
user: data.user.id,
|
||||||
date: Date.now(),
|
date: Date.now(),
|
||||||
content: text,
|
content: text,
|
||||||
|
@ -182,7 +177,7 @@ function render() {
|
||||||
|
|
||||||
const load = `
|
const load = `
|
||||||
<div id="load">
|
<div id="load">
|
||||||
<a class="bold gtext" onclick="load()">Load More posts</a>
|
<a class="bold gtext" onclick="load()">Load more posts</a>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -203,9 +198,9 @@ const data = {
|
||||||
async function load() {
|
async function load() {
|
||||||
const posts = (await loadposts(page)).json
|
const posts = (await loadposts(page)).json
|
||||||
if (posts.length === 0) {
|
if (posts.length === 0) {
|
||||||
page = -1;
|
page = -1
|
||||||
} else {
|
} else {
|
||||||
page++;
|
page++
|
||||||
}
|
}
|
||||||
data.posts.push(... posts)
|
data.posts.push(... posts)
|
||||||
const batch = []
|
const batch = []
|
||||||
|
|
|
@ -16,6 +16,7 @@ function parseUser(user) {
|
||||||
<span class="gtext">Joined ${parseDate(new Date(user.date))}</span>
|
<span class="gtext">Joined ${parseDate(new Date(user.date))}</span>
|
||||||
<span class="gtext">Gender: ${user.gender}</span>
|
<span class="gtext">Gender: ${user.gender}</span>
|
||||||
<span class="gtext">Birthday: ${user.month + ' ' + user.day + ', ' + user.year}</span>
|
<span class="gtext">Birthday: ${user.month + ' ' + user.day + ', ' + user.year}</span>
|
||||||
|
<span class="gtext" style="margin-bottom: -100px;">User ID: ${user.id}</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
`
|
`
|
||||||
|
@ -29,17 +30,34 @@ function render() {
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
|
||||||
add(html, 'usres')
|
add(html, 'users')
|
||||||
|
|
||||||
|
const load = `
|
||||||
|
<div id="load">
|
||||||
|
<a class="bold gtext" onclick="load()">Load more users</a>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
if (page !== -1) {
|
||||||
|
add(load, 'load')
|
||||||
|
} else {
|
||||||
|
remove('load')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var page = 0
|
||||||
var data = {
|
var data = {
|
||||||
users: []
|
users: []
|
||||||
}
|
}
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
const users = (await loadallusers()).json
|
const users = (await loaduserspage(page)).json
|
||||||
console.log(users)
|
if (users.length === 0) {
|
||||||
data.users = users
|
page = -1
|
||||||
|
} else {
|
||||||
|
page++
|
||||||
|
}
|
||||||
|
data.users.push(... users)
|
||||||
render()
|
render()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
238
src/api.js
238
src/api.js
|
@ -1,238 +0,0 @@
|
||||||
const express = require('express')
|
|
||||||
const router = express.Router()
|
|
||||||
const database = require('./database.js')
|
|
||||||
const cheerio = require('cheerio');
|
|
||||||
|
|
||||||
const check = (test, type) => {
|
|
||||||
return text === undefined || text === null || typeof test !== type
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseText = (test) => {
|
|
||||||
if (typeof test !== 'string') return undefined;
|
|
||||||
const $ = cheerio.load(test)
|
|
||||||
return $("body").html()
|
|
||||||
}
|
|
||||||
|
|
||||||
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('/auth/register', (req, res) => {
|
|
||||||
const first = parseText(req.body.first);
|
|
||||||
if (text(first, 1, 20)) {
|
|
||||||
res.status(400).send( {msg: 'Invalid first name'} ); return;
|
|
||||||
}
|
|
||||||
const last = parseText(req.body.last);
|
|
||||||
if (text(last, 1, 20)) {
|
|
||||||
res.status(400).send( {msg: 'Invalid last name'} ); return;
|
|
||||||
}
|
|
||||||
const email = parseText(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 = parseText(req.body.gender);
|
|
||||||
if (text(gender, 1, 100)) {
|
|
||||||
res.status(400).send( {msg: 'Invalid gender'} ); return;
|
|
||||||
}
|
|
||||||
const month = parseText(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, { maxAge: 365 * 24 * 60 * 60 * 1000, sameSite: 'strict' }).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, { maxAge: 365 * 24 * 60 * 60 * 1000, sameSite: 'strict' }).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 = parseText(req.body.content)
|
|
||||||
if (text(content, 1, 1000)) {
|
|
||||||
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 = parseText(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;
|
|
72
src/api/auth.js
Normal file
72
src/api/auth.js
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
const express = require('express')
|
||||||
|
const router = express.Router()
|
||||||
|
const cache = require('../cache')
|
||||||
|
const check = require('../check')
|
||||||
|
|
||||||
|
|
||||||
|
router.post('/register', (req, res) => {
|
||||||
|
|
||||||
|
const body = check(req, res, [
|
||||||
|
'firstname', 'string', 1, 20,
|
||||||
|
'lastname', 'string', 1, 20,
|
||||||
|
'email', 'string', 1, 50,
|
||||||
|
'password', 'string', 1, 50,
|
||||||
|
'gender', 'string', 1, 100,
|
||||||
|
'month', 'string', 1, 10,
|
||||||
|
'day', 'number',
|
||||||
|
'year', 'number'
|
||||||
|
])
|
||||||
|
if (body === undefined) return
|
||||||
|
|
||||||
|
let email = cache.getUserByEmail(body.email);
|
||||||
|
if (email !== undefined) {
|
||||||
|
res.status(400).send({ msg: 'Email is already in use' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let password = cache.getUserByPassword(req.body.password);
|
||||||
|
if (password !== undefined) {
|
||||||
|
res.status(400).send({ msg: `Password is already in use by ${password.email}` })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = cache.register(body.firstname, body.lastname, body.email, req.body.password, body.gender, body.month, body.day, body.year)
|
||||||
|
if (key === undefined) {
|
||||||
|
res.status(500).send({ msg: 'Failed to register user' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
.status(200)
|
||||||
|
.cookie('auth', key, {
|
||||||
|
maxAge: 365 * 24 * 60 * 60 * 1000,
|
||||||
|
sameSite: 'strict'
|
||||||
|
})
|
||||||
|
.send({ msg: 'Successfully registered new user' })
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.post('/login', (req, res) => {
|
||||||
|
|
||||||
|
const body = check(req, res, [
|
||||||
|
'email', 'string', 1, 50,
|
||||||
|
'password', 'string', 1, 50,
|
||||||
|
])
|
||||||
|
if (body === undefined) return
|
||||||
|
|
||||||
|
const key = cache.login(body.email, body.password)
|
||||||
|
if (key === undefined) {
|
||||||
|
res.status(400).send( {msg: 'Invalid login combination'} )
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
.status(200)
|
||||||
|
.cookie('auth', key, {
|
||||||
|
maxAge: 365 * 24 * 60 * 60 * 1000,
|
||||||
|
sameSite: 'strict'
|
||||||
|
})
|
||||||
|
.send({msg: 'Successfully logged in'})
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router;
|
77
src/api/pages.js
Normal file
77
src/api/pages.js
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
const express = require('express')
|
||||||
|
const router = express.Router()
|
||||||
|
const cache = require('../cache')
|
||||||
|
|
||||||
|
|
||||||
|
router.get('/', (req, res) => {
|
||||||
|
|
||||||
|
if (res.locals.user === undefined) {
|
||||||
|
res.redirect('/login')
|
||||||
|
} else {
|
||||||
|
res.redirect('/home')
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.get('/login', (req, res) => {
|
||||||
|
|
||||||
|
if (res.locals.user !== undefined) {
|
||||||
|
res.redirect('/home')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.sendFile('login.html', { root: './public' })
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.get('/logout', (req, res) => {
|
||||||
|
|
||||||
|
if (res.locals.user === undefined) {
|
||||||
|
res.redirect('/login')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cache.logout(req.cookies.auth)) {
|
||||||
|
res.status(500).send({msg: 'Failed to logout'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.clearCookie('auth').redirect('/login')
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.get('/home', (req, res) => {
|
||||||
|
|
||||||
|
if (res.locals.user === undefined) {
|
||||||
|
res.redirect('/login')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.sendFile('home.html', { root: './public' })
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.get('/people', (req, res) => {
|
||||||
|
|
||||||
|
if (res.locals.user === undefined) {
|
||||||
|
res.redirect('/login')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.sendFile('people.html', { root: './public' })
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.get('/profile', (req, res) => {
|
||||||
|
|
||||||
|
if (res.locals.user === undefined) {
|
||||||
|
res.redirect('/login')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.sendFile('profile.html', { root: './public' })
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = router
|
81
src/api/posts.js
Normal file
81
src/api/posts.js
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
const express = require('express')
|
||||||
|
const router = express.Router()
|
||||||
|
const cache = require('../cache')
|
||||||
|
const check = require('../check')
|
||||||
|
|
||||||
|
|
||||||
|
router.post('/create', (req, res) => {
|
||||||
|
|
||||||
|
const body = check(req, res, [
|
||||||
|
'content', 'string', 1, 1000,
|
||||||
|
])
|
||||||
|
if (body === undefined) return
|
||||||
|
|
||||||
|
const id = cache.addPost(res.locals.user.id, content)
|
||||||
|
if (id === -1) {
|
||||||
|
res.status(500).send({msg: 'Failed to create post'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).send({msg: id})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.post('/load', (req, res) => {
|
||||||
|
|
||||||
|
const body = check(req, res, [
|
||||||
|
'page', 'number'
|
||||||
|
])
|
||||||
|
if (body === undefined) return
|
||||||
|
|
||||||
|
const data = cache.getPostsPage(body.page)
|
||||||
|
res.status(200).send(data)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.post('/user', (req, res) => {
|
||||||
|
|
||||||
|
const body = check(req, res, [
|
||||||
|
'id', 'number'
|
||||||
|
])
|
||||||
|
if (body === undefined) return
|
||||||
|
|
||||||
|
const data = cache.getUsersPosts(body.id)
|
||||||
|
res.status(200).send(data)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.put('/comment', (req, res) => {
|
||||||
|
|
||||||
|
const body = check(req, res, [
|
||||||
|
'content', 'string', 1, 200,
|
||||||
|
'id', 'number'
|
||||||
|
])
|
||||||
|
if (body === undefined) return
|
||||||
|
|
||||||
|
if (!cache.comment(body.id, res.locals.user.id, body.content)) {
|
||||||
|
res.status(500).send({msg: 'Failed to add comment to post'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).send({msg: 'Successfully posted comment'})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.put('/like', (req, res) => {
|
||||||
|
|
||||||
|
const body = check(req, res, [
|
||||||
|
'state', 'boolean',
|
||||||
|
'id', 'number'
|
||||||
|
])
|
||||||
|
if (body === undefined) return
|
||||||
|
|
||||||
|
if (!cache.like(body.id, res.locals.user.id, body.state)) {
|
||||||
|
res.status(500).send({msg: 'Failed to change like state on post'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).send({msg: 'Successfully changed like state on post'})
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router;
|
35
src/api/users.js
Normal file
35
src/api/users.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
const express = require('express')
|
||||||
|
const router = express.Router()
|
||||||
|
const cache = require('../cache')
|
||||||
|
const check = require('../check')
|
||||||
|
|
||||||
|
|
||||||
|
router.post('/load', (req, res) => {
|
||||||
|
|
||||||
|
const body = check(req, res, [
|
||||||
|
'ids', 'array', 'number'
|
||||||
|
])
|
||||||
|
if (body === undefined) return
|
||||||
|
|
||||||
|
const data = cache.getUsers(body.ids)
|
||||||
|
res.status(200).send(data)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.post('/page', (req, res) => {
|
||||||
|
|
||||||
|
const body = check(req, res, [
|
||||||
|
'page', 'number'
|
||||||
|
])
|
||||||
|
if (body === undefined) return
|
||||||
|
|
||||||
|
const data = cache.getUsersPage(body.page)
|
||||||
|
res.status(200).send(data)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
router.post('/self', (req, res) => {
|
||||||
|
res.status(200).send(res.locals.user)
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router;
|
277
src/cache.js
Normal file
277
src/cache.js
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
const e = require('express')
|
||||||
|
const database = require('./database.js')
|
||||||
|
const con = require('./console')
|
||||||
|
|
||||||
|
const NO_VALUE = null
|
||||||
|
const NO_CACHE = undefined
|
||||||
|
|
||||||
|
const users = {}
|
||||||
|
const email_links = {}
|
||||||
|
const password_links = {}
|
||||||
|
const session_links = {}
|
||||||
|
var newest_user = database.getNewestUserId();
|
||||||
|
|
||||||
|
const getUserByEmail = (email) => {
|
||||||
|
const fast = email_links[email]
|
||||||
|
if (fast === NO_VALUE) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if (fast === NO_CACHE) {
|
||||||
|
const slow = database.getUserByEmail(email)
|
||||||
|
if (slow === undefined) {
|
||||||
|
email_links[email] = NO_VALUE
|
||||||
|
} else {
|
||||||
|
email_links[email] = slow.id
|
||||||
|
if (users[slow.id] === NO_CACHE) {
|
||||||
|
users[slow.id] = slow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slow
|
||||||
|
}
|
||||||
|
return users[fast]
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUserByPassword = (password) => {
|
||||||
|
const fast = password_links[password]
|
||||||
|
if (fast === NO_VALUE) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if (fast === NO_CACHE) {
|
||||||
|
const slow = database.getUserByPassword(password)
|
||||||
|
if (slow === undefined) {
|
||||||
|
password_links[password] = NO_VALUE
|
||||||
|
} else {
|
||||||
|
password_links[password] = slow.id
|
||||||
|
if (users[slow.id] === NO_CACHE) {
|
||||||
|
users[slow.id] = slow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slow
|
||||||
|
}
|
||||||
|
return users[fast]
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUsers = (ids) => {
|
||||||
|
const fast = {}
|
||||||
|
const batch = []
|
||||||
|
for (const id of ids) {
|
||||||
|
if (users[id] === NO_CACHE) {
|
||||||
|
batch.push(id)
|
||||||
|
} else {
|
||||||
|
fast[id] = users[id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (batch.length > 0) {
|
||||||
|
const slow = database.getUsers(batch)
|
||||||
|
for(const [id, user] of Object.entries(slow)) {
|
||||||
|
fast[id] = user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fast
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUsersPage = (page) => {
|
||||||
|
const COUNT = 10
|
||||||
|
const INDEX = newest_user - page * COUNT
|
||||||
|
const batch = []
|
||||||
|
for (let i = INDEX; i > INDEX - COUNT && i >= 0; i--) {
|
||||||
|
batch.push(i)
|
||||||
|
}
|
||||||
|
const users = getUsers(batch)
|
||||||
|
return batch.map(i => users[i]).filter(u => u !== undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
const register = (first, last, email, password, gender, month, day, year) => {
|
||||||
|
const data = database.register(first, last, email, password, gender, month, day, year)
|
||||||
|
if (data === undefined) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
newest_user = data.user.id
|
||||||
|
session_links[data.key] = data.user.id
|
||||||
|
users[data.user.id] = data.user
|
||||||
|
return data.key
|
||||||
|
}
|
||||||
|
|
||||||
|
const login = (email, pass) => {
|
||||||
|
const data = database.login(email, pass)
|
||||||
|
if (data === undefined) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
session_links[data.key] = data.user.id
|
||||||
|
users[data.user.id] = data.user
|
||||||
|
return data.key
|
||||||
|
}
|
||||||
|
|
||||||
|
const logout = (token) => {
|
||||||
|
|
||||||
|
if (session_links[token] === NO_VALUE) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database.deleteSession(token)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
delete session_links[token]
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const auth = (token) => {
|
||||||
|
const fast = session_links[token]
|
||||||
|
if (fast === NO_VALUE) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if (fast === NO_CACHE) {
|
||||||
|
const slow = database.auth(token)
|
||||||
|
if (slow === undefined) {
|
||||||
|
session_links[token] = NO_VALUE
|
||||||
|
} else {
|
||||||
|
session_links[token] = slow.id
|
||||||
|
if (users[slow.id] === NO_CACHE) {
|
||||||
|
users[slow.id] = slow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slow
|
||||||
|
}
|
||||||
|
return users[fast]
|
||||||
|
}
|
||||||
|
|
||||||
|
const posts = {}
|
||||||
|
const users_posts = {}
|
||||||
|
const updated_posts = {}
|
||||||
|
var newest_post = database.getNewestPostId();
|
||||||
|
|
||||||
|
const addPost = (user, content) => {
|
||||||
|
const id = database.addPost(user, content)
|
||||||
|
if (id === undefined) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
newest_post = id
|
||||||
|
if (users_posts[user] === NO_VALUE) {
|
||||||
|
users[posts] = [id]
|
||||||
|
} else if (users_posts[user] === NO_CACHE) {
|
||||||
|
getUsersPosts(user)
|
||||||
|
} else {
|
||||||
|
users_posts[user].unshift(id)
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPosts = (ids) => {
|
||||||
|
const fast = {}
|
||||||
|
const batch = []
|
||||||
|
for (const id of ids) {
|
||||||
|
if (posts[id] === NO_CACHE) {
|
||||||
|
batch.push(id)
|
||||||
|
} else {
|
||||||
|
fast[id] = posts[id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (batch.length > 0) {
|
||||||
|
const slow = database.getPosts(batch)
|
||||||
|
for(const [id, post] of Object.entries(slow)) {
|
||||||
|
fast[id] = post
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fast
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUsersPosts = (user) => {
|
||||||
|
const fast = users_posts[user]
|
||||||
|
if (fast === NO_CACHE) {
|
||||||
|
const posts = database.getUsersPosts(user)
|
||||||
|
if (posts === undefined) {
|
||||||
|
users_posts[user] = NO_VALUE
|
||||||
|
} else {
|
||||||
|
const slow = []
|
||||||
|
for (const post in posts) {
|
||||||
|
slow.push[post.id]
|
||||||
|
if (posts[post.id] === NO_CACHE) {
|
||||||
|
posts[post.id] = post
|
||||||
|
}
|
||||||
|
}
|
||||||
|
users_posts[user] = slow
|
||||||
|
}
|
||||||
|
return posts
|
||||||
|
} else {
|
||||||
|
return getPosts(fast)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPostsPage = (page) => {
|
||||||
|
const COUNT = 10
|
||||||
|
const INDEX = newest_post - page * COUNT
|
||||||
|
const batch = []
|
||||||
|
for (let i = INDEX; i > INDEX - COUNT && i >= 0; i--) {
|
||||||
|
batch.push(i)
|
||||||
|
}
|
||||||
|
const posts = getPosts(batch)
|
||||||
|
return batch.map(i => posts[i]).filter(p => p !== undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
const comment = (id, user, content) => {
|
||||||
|
var fast = posts[id]
|
||||||
|
if (fast === NO_VALUE) {
|
||||||
|
return false
|
||||||
|
} else if (fast === NO_CACHE) {
|
||||||
|
const slow = getPosts([id])
|
||||||
|
if (slow[id] === undefined) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
fast = slow[id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fast.comments.push({user, content})
|
||||||
|
posts[id] = fast
|
||||||
|
updated_posts[id] = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const like = (id, user, state) => {
|
||||||
|
var fast = posts[id]
|
||||||
|
if (fast === NO_VALUE) {
|
||||||
|
return false
|
||||||
|
} else if (fast === NO_CACHE) {
|
||||||
|
const slow = getPosts([id])
|
||||||
|
if (slow[id] === undefined) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
fast = slow[id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fast.likes[user] = state
|
||||||
|
posts[id] = fast
|
||||||
|
updated_posts[id] = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const dump = () => {
|
||||||
|
for (id in updated_posts) {
|
||||||
|
const post = posts[id]
|
||||||
|
if (post === NO_CACHE || post === NO_VALUE) continue;
|
||||||
|
if (!database.updatePost(post.id, JSON.stringify(post.likes), JSON.stringify(post.comments))) {
|
||||||
|
con.error(`Failed to saved cached post id ${id}`)
|
||||||
|
} else {
|
||||||
|
delete updated_posts.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
con.msg('Saved cache successfully')
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getUserByEmail,
|
||||||
|
getUserByPassword,
|
||||||
|
getUsers,
|
||||||
|
getUsersPage,
|
||||||
|
register,
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
auth,
|
||||||
|
addPost,
|
||||||
|
getPosts,
|
||||||
|
getUsersPosts,
|
||||||
|
getPostsPage,
|
||||||
|
comment,
|
||||||
|
like,
|
||||||
|
dump
|
||||||
|
}
|
84
src/check.js
Normal file
84
src/check.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
const cheerio = require('cheerio');
|
||||||
|
const e = require('express');
|
||||||
|
|
||||||
|
const parseText = (text) => {
|
||||||
|
|
||||||
|
if (typeof text !== 'string') {
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const $ = cheerio.load(text)
|
||||||
|
|
||||||
|
return $('body').html()
|
||||||
|
}
|
||||||
|
|
||||||
|
const check = (req, res, params) => {
|
||||||
|
|
||||||
|
const result = {}
|
||||||
|
|
||||||
|
for(let i = 0; i < params.length;) {
|
||||||
|
|
||||||
|
const key = params[i]
|
||||||
|
const value = req.body[key]
|
||||||
|
const type = params[i+1]
|
||||||
|
|
||||||
|
if (type === 'array') {
|
||||||
|
|
||||||
|
if (!Array.isArray(value)) {
|
||||||
|
|
||||||
|
res.status(400).send({msg: 'Invalid ' + key})
|
||||||
|
return undefined
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const arr_type = params[i+2];
|
||||||
|
|
||||||
|
for (const v of value) {
|
||||||
|
|
||||||
|
if (typeof v !== arr_type) {
|
||||||
|
|
||||||
|
res.status(400).send({msg: 'Invalid ' + key})
|
||||||
|
return undefined
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
} else if (value === undefined || value === null || typeof value !== type) {
|
||||||
|
|
||||||
|
res.status(400).send({msg: 'Invalid ' + key})
|
||||||
|
return undefined
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'string') {
|
||||||
|
|
||||||
|
const min = params[i+2]
|
||||||
|
const max = params[i+3]
|
||||||
|
|
||||||
|
if (value.length < min || value.length > max) {
|
||||||
|
|
||||||
|
res.status(400).send({msg: 'Invalid ' + key})
|
||||||
|
return undefined
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
result[key] = parseText(value)
|
||||||
|
i += 4
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
result[key] = value;
|
||||||
|
i += 2
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = check
|
200
src/console.js
200
src/console.js
|
@ -1,84 +1,144 @@
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
|
|
||||||
|
const msg = (msg) => {
|
||||||
|
requests.push({msg})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const error = (error) => {
|
||||||
|
requests.push({error})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const log = (ip, method, path, body) => {
|
||||||
|
console.log(ip, method, path, body)
|
||||||
|
requests.push({ip, method, path, body})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var requests = []
|
var requests = []
|
||||||
|
|
||||||
router.get('/', async (req, res) => {
|
|
||||||
res.send(render())
|
const method = (method) => {
|
||||||
if(requests.length > 200) {
|
|
||||||
requests.splice(0, 50)
|
switch(method) {
|
||||||
|
case 'GET':
|
||||||
|
return '4ae04a'
|
||||||
|
case 'POST':
|
||||||
|
return 'b946db'
|
||||||
|
case 'PUT':
|
||||||
|
return 'ff9705'
|
||||||
|
case 'PATCH':
|
||||||
|
return `42caff`
|
||||||
|
case 'DELETE':
|
||||||
|
return `ff4a4a`
|
||||||
|
case 'HEAD':
|
||||||
|
return '424cff'
|
||||||
|
case 'OPTIONS':
|
||||||
|
return 'ff9757'
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
function parseMethod(method) {
|
|
||||||
switch(method) {
|
|
||||||
case 'GET':
|
|
||||||
return '4ae04a'
|
|
||||||
case 'POST':
|
|
||||||
return 'b946db'
|
|
||||||
case 'PUT':
|
|
||||||
return 'ff9705'
|
|
||||||
case 'PATCH':
|
|
||||||
return `42caff`
|
|
||||||
case 'DELETE':
|
|
||||||
return `ff4a4a`
|
|
||||||
case 'HEAD':
|
|
||||||
return '424cff'
|
|
||||||
case 'OPTIONS':
|
|
||||||
return 'ff9757'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseJson(json) {
|
|
||||||
if (typeof json != 'string') {
|
const json = (json) => {
|
||||||
json = JSON.stringify(json, undefined, 2);
|
|
||||||
}
|
if (typeof json != 'string') {
|
||||||
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
json = JSON.stringify(json, undefined, 2);
|
||||||
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
|
}
|
||||||
var cls = 'number';
|
|
||||||
if (/^"/.test(match)) {
|
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||||
if (/:$/.test(match)) {
|
|
||||||
cls = 'key';
|
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
|
||||||
} else {
|
|
||||||
cls = 'string';
|
var cls = 'number';
|
||||||
}
|
|
||||||
} else if (/true|false/.test(match)) {
|
if (/^"/.test(match)) {
|
||||||
cls = 'boolean';
|
|
||||||
} else if (/null/.test(match)) {
|
if (/:$/.test(match)) {
|
||||||
cls = 'null';
|
|
||||||
}
|
cls = 'key';
|
||||||
return '<span class="' + cls + '">' + match + '</span>';
|
|
||||||
});
|
} else {
|
||||||
|
|
||||||
|
cls = 'string';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (/true|false/.test(match)) {
|
||||||
|
|
||||||
|
cls = 'boolean';
|
||||||
|
|
||||||
|
} else if (/null/.test(match)) {
|
||||||
|
|
||||||
|
cls = 'null';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<span class="' + cls + '">' + match + '</span>';
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseRequest(req) {
|
|
||||||
const html = `
|
const parse = (req) => {
|
||||||
<div>
|
|
||||||
<span class="ip">${req.ip}</span>
|
var html;
|
||||||
<span class="method" style="color: #${parseMethod(req.method)}">${req.method}</span>
|
|
||||||
<span class="path">${req.path}</span>
|
if (req.msg !== undefined) {
|
||||||
<span class="json">${parseJson(req.body)}</span>
|
|
||||||
</div>
|
html = `
|
||||||
`
|
<div>
|
||||||
return html
|
<span style="color: #00aaff">SERVER MESSAGE: ${req.msg}</span>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
} else if (req.error !== undefined) {
|
||||||
|
|
||||||
|
html = `
|
||||||
|
<div>
|
||||||
|
<span style="color: #ff4050">SERVER ERROR: ${req.error}</span>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
html = `
|
||||||
|
<div>
|
||||||
|
<span class="ip">${req.ip}</span>
|
||||||
|
<span class="method" style="color: #${method(req.method)}">${req.method}</span>
|
||||||
|
<span class="path">${req.path}</span>
|
||||||
|
<span class="json">${json(req.body)}</span>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return html
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
|
||||||
const html = `
|
const render = () => {
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
const html = `
|
||||||
<head>
|
<!DOCTYPE html>
|
||||||
<meta charset="UTF-8">
|
<html lang="en">
|
||||||
<meta http-equiv="refresh" content="5">
|
<head>
|
||||||
<link rel="stylesheet" href="css/console.css">
|
<meta charset="UTF-8">
|
||||||
<title>XSSBook - Console</title>
|
<meta http-equiv="refresh" content="5">
|
||||||
</head>
|
<link rel="stylesheet" href="css/console.css">
|
||||||
<body>
|
<title>XSSBook - Console</title>
|
||||||
${requests.map(r => parseRequest(r)).join('')}
|
</head>
|
||||||
</body>
|
<body>
|
||||||
</html>
|
${requests.map(r => parse(r)).join('')}
|
||||||
`
|
</body>
|
||||||
return html
|
</html>
|
||||||
|
`
|
||||||
|
|
||||||
|
return html
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { router, requests };
|
module.exports = { render, log, msg, error }
|
223
src/database.js
223
src/database.js
|
@ -1,9 +1,7 @@
|
||||||
const Database = require('better-sqlite3')
|
const Database = require('better-sqlite3')
|
||||||
const db = createDatabase()
|
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const token = () => { return crypto.randomBytes(32).toString('hex') }
|
|
||||||
|
|
||||||
function createDatabase() {
|
const createDatabase = () => {
|
||||||
try {
|
try {
|
||||||
var db = new Database('xssbook.db', { fileMustExist: true });
|
var db = new Database('xssbook.db', { fileMustExist: true });
|
||||||
return db
|
return db
|
||||||
|
@ -14,7 +12,7 @@ function createDatabase() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTables(db) {
|
const createTables = (db) => {
|
||||||
db.exec(`
|
db.exec(`
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
@ -54,9 +52,14 @@ function createTables(db) {
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function register(first, last, email, password, gender, month, day, year) {
|
const db = createDatabase()
|
||||||
|
|
||||||
|
const token = () => { return crypto.randomBytes(32).toString('hex') }
|
||||||
|
|
||||||
|
const register = (first, last, email, password, gender, month, day, year) => {
|
||||||
try {
|
try {
|
||||||
var key = undefined;
|
var key = undefined;
|
||||||
|
var u = undefined
|
||||||
db.transaction(() => {
|
db.transaction(() => {
|
||||||
if (!addUser(first, last, email, password, gender, Date.now(), month, day, year)) {
|
if (!addUser(first, last, email, password, gender, Date.now(), month, day, year)) {
|
||||||
throw new Error('Failed to register user');
|
throw new Error('Failed to register user');
|
||||||
|
@ -65,20 +68,22 @@ function register(first, last, email, password, gender, month, day, year) {
|
||||||
if (user === undefined) {
|
if (user === undefined) {
|
||||||
throw new Error('Failed to register user');
|
throw new Error('Failed to register user');
|
||||||
}
|
}
|
||||||
|
u = user
|
||||||
key = token()
|
key = token()
|
||||||
if (!setSession(user.id, key)) {
|
if (!setSession(user.id, key)) {
|
||||||
throw new Error('Failed to register user');
|
throw new Error('Failed to register user');
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
return key
|
return {key, user: u}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function login(email, pass) {
|
const login = (email, pass) => {
|
||||||
try {
|
try {
|
||||||
var key = undefined
|
var key = undefined
|
||||||
|
var u = undefined
|
||||||
db.transaction(() => {
|
db.transaction(() => {
|
||||||
const user = getUserByEmail(email);
|
const user = getUserByEmail(email);
|
||||||
if (user === undefined) {
|
if (user === undefined) {
|
||||||
|
@ -87,22 +92,23 @@ function login(email, pass) {
|
||||||
if (user.password !== pass) {
|
if (user.password !== pass) {
|
||||||
throw new Error("Failed to login user")
|
throw new Error("Failed to login user")
|
||||||
}
|
}
|
||||||
|
u = user
|
||||||
key = token()
|
key = token()
|
||||||
if (!setSession(user.id, key)) {
|
if (!setSession(user.id, key)) {
|
||||||
throw new Error('Failed to login user');
|
throw new Error('Failed to login user');
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
return key
|
return {key, user: u}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function auth(token) {
|
const auth = (token) => {
|
||||||
try {
|
try {
|
||||||
var user = undefined;
|
var user = undefined;
|
||||||
db.transaction(() => {
|
db.transaction(() => {
|
||||||
const session = getSession(token);
|
const session = getSession(token)
|
||||||
if (session === undefined) {
|
if (session === undefined) {
|
||||||
throw new Error('Failed to auth user')
|
throw new Error('Failed to auth user')
|
||||||
}
|
}
|
||||||
|
@ -118,18 +124,7 @@ function auth(token) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addUser(first, last, email, password, gender, date, month, day, year) {
|
const getUserById = (id) => {
|
||||||
try {
|
|
||||||
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) {
|
|
||||||
console.log(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUserById(id) {
|
|
||||||
try {
|
try {
|
||||||
const stmt = db.prepare('SELECT * FROM users WHERE id = @id;')
|
const stmt = db.prepare('SELECT * FROM users WHERE id = @id;')
|
||||||
const info = stmt.get({id})
|
const info = stmt.get({id})
|
||||||
|
@ -141,7 +136,7 @@ function getUserById(id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserByEmail(email) {
|
const getUserByEmail = (email) => {
|
||||||
try {
|
try {
|
||||||
const stmt = db.prepare('SELECT * FROM users WHERE email = @email;')
|
const stmt = db.prepare('SELECT * FROM users WHERE email = @email;')
|
||||||
const info = stmt.get({email})
|
const info = stmt.get({email})
|
||||||
|
@ -153,7 +148,7 @@ function getUserByEmail(email) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserByPassword(password) {
|
const getUserByPassword = (password) => {
|
||||||
try {
|
try {
|
||||||
const stmt = db.prepare('SELECT * FROM users WHERE password = @password;')
|
const stmt = db.prepare('SELECT * FROM users WHERE password = @password;')
|
||||||
const info = stmt.get({password})
|
const info = stmt.get({password})
|
||||||
|
@ -165,7 +160,18 @@ function getUserByPassword(password) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUsers(ids) {
|
const addUser = (first, last, email, password, gender, date, month, day, year) => {
|
||||||
|
try {
|
||||||
|
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) {
|
||||||
|
console.log(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUsers = (ids) => {
|
||||||
try {
|
try {
|
||||||
const stmt = db.prepare('SELECT * FROM users WHERE id = @id;')
|
const stmt = db.prepare('SELECT * FROM users WHERE id = @id;')
|
||||||
const people = {}
|
const people = {}
|
||||||
|
@ -180,55 +186,67 @@ function getUsers(ids) {
|
||||||
return people
|
return people
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
return []
|
return {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAllUsers() {
|
const getNewestUserId = () => {
|
||||||
try {
|
try {
|
||||||
const stmt = db.prepare('SELECT * FROM users;')
|
const stmt = db.prepare('SELECT MAX(id) FROM users')
|
||||||
const info = stmt.all({})
|
const info = stmt.get({})
|
||||||
if (info === undefined) {
|
if (info === undefined || info['MAX(id)'] === undefined) {
|
||||||
return []
|
return 0
|
||||||
}
|
}
|
||||||
return info
|
return info['MAX(id)']
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
return []
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPost(user, content) {
|
const addPost = (user, content) => {
|
||||||
try {
|
try {
|
||||||
const stmt = db.prepare('INSERT INTO posts (user, content, likes, comments, date) VALUES (@user, @content, @likes, @comments, @date);')
|
var id = undefined
|
||||||
const info = stmt.run({user, content, likes: "[]", comments: "[]", date: Date.now()})
|
db.transaction(() => {
|
||||||
return info.changes === 1
|
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()})
|
||||||
|
if (info.changes !== 1) {
|
||||||
|
throw new Error('Failed to create post')
|
||||||
|
}
|
||||||
|
const last = db.prepare('SELECT last_insert_rowid();').get({})
|
||||||
|
if (last === undefined || last['last_insert_rowid()'] === undefined) {
|
||||||
|
throw new Error('Failed to get new post')
|
||||||
|
}
|
||||||
|
id = last['last_insert_rowid()']
|
||||||
|
})()
|
||||||
|
return id
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
return false
|
return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPosts(page) {
|
const getPosts = (ids) => {
|
||||||
try {
|
try {
|
||||||
const stmt = db.prepare('SELECT * FROM posts ORDER BY id DESC LIMIT @limit OFFSET @offset;')
|
const stmt = db.prepare('SELECT * FROM posts WHERE id = @id;')
|
||||||
const count = 10
|
const posts = {}
|
||||||
const info = stmt.all({limit: count, offset: page * count});
|
db.transaction((ids) => {
|
||||||
if (info === undefined || info === {}) {
|
for (const id of ids) {
|
||||||
return []
|
const info = stmt.get({id})
|
||||||
}
|
if (info === undefined) continue;
|
||||||
for (const post of info) {
|
info.comments = JSON.parse(info.comments)
|
||||||
post.likes = JSON.parse(post.likes)
|
info.likes = JSON.parse(info.likes)
|
||||||
post.comments = JSON.parse(post.comments)
|
posts[id] = info
|
||||||
}
|
}
|
||||||
return info
|
})(ids)
|
||||||
|
return posts
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
return []
|
return {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUsersPosts(user) {
|
const getUsersPosts = (user) => {
|
||||||
try {
|
try {
|
||||||
const stmt = db.prepare('SELECT * FROM posts WHERE user = @user ORDER BY id DESC;')
|
const stmt = db.prepare('SELECT * FROM posts WHERE user = @user ORDER BY id DESC;')
|
||||||
const info = stmt.all({user});
|
const info = stmt.all({user});
|
||||||
|
@ -246,21 +264,7 @@ function getUsersPosts(user) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPost(id) {
|
const updatePost = (id, likes, comments) => {
|
||||||
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 {
|
try {
|
||||||
const stmt = db.prepare('UPDATE posts SET likes = @likes, comments = @comments WHERE id = @id')
|
const stmt = db.prepare('UPDATE posts SET likes = @likes, comments = @comments WHERE id = @id')
|
||||||
const info = stmt.run({likes, comments, id})
|
const info = stmt.run({likes, comments, id})
|
||||||
|
@ -271,54 +275,21 @@ function updatePost(id, likes, comments) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function comment(id, user, content) {
|
const getNewestPostId = () => {
|
||||||
try {
|
try {
|
||||||
db.transaction(() => {
|
const stmt = db.prepare('SELECT MAX(id) FROM posts')
|
||||||
const post = getPost(id)
|
const info = stmt.get({})
|
||||||
if (post === undefined) {
|
if (info === undefined || info['MAX(id)'] === undefined) {
|
||||||
throw new Error('Unable to add comment')
|
return 0
|
||||||
}
|
}
|
||||||
post.comments.push({user, content})
|
return info['MAX(id)']
|
||||||
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) {
|
} catch (err) {
|
||||||
return false
|
console.log(err)
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function like(id, user, state) {
|
const setSession = (user, token) => {
|
||||||
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) {
|
|
||||||
try {
|
try {
|
||||||
const stmt = db.prepare('INSERT OR REPLACE INTO sessions (user, token) VALUES (@user, @token);')
|
const stmt = db.prepare('INSERT OR REPLACE INTO sessions (user, token) VALUES (@user, @token);')
|
||||||
stmt.run({user, token})
|
stmt.run({user, token})
|
||||||
|
@ -329,7 +300,7 @@ function setSession(user, token) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSession(token) {
|
const getSession = (token) => {
|
||||||
try {
|
try {
|
||||||
const stmt = db.prepare('SELECT * FROM sessions WHERE token = @token;')
|
const stmt = db.prepare('SELECT * FROM sessions WHERE token = @token;')
|
||||||
const info = stmt.get({token})
|
const info = stmt.get({token})
|
||||||
|
@ -341,4 +312,32 @@ function getSession(token) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { addUser, getUser: getUserById, getUserByEmail, getUserByPassword, getUsers, addPost, getPosts, setSession, getSession, register, login, auth, comment, updatePost, getPost, like, getAllUsers, getUsersPosts }
|
const deleteSession = (token) => {
|
||||||
|
try {
|
||||||
|
const stmt = db.prepare('DELETE FROM sessions WHERE token = @token;')
|
||||||
|
const info = stmt.run({token})
|
||||||
|
return info.changes === 1
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getUserById,
|
||||||
|
getUserByEmail,
|
||||||
|
getUserByPassword,
|
||||||
|
getUsers,
|
||||||
|
getNewestUserId,
|
||||||
|
register,
|
||||||
|
login,
|
||||||
|
auth,
|
||||||
|
addPost,
|
||||||
|
getPosts,
|
||||||
|
getUsersPosts,
|
||||||
|
getNewestPostId,
|
||||||
|
updatePost,
|
||||||
|
getSession,
|
||||||
|
setSession,
|
||||||
|
deleteSession
|
||||||
|
}
|
Loading…
Reference in a new issue