organized files better

This commit is contained in:
scoliono 2020-09-03 12:41:46 -07:00
parent ccdd7ad589
commit 74f3706852
6 changed files with 209 additions and 168 deletions

96
package-lock.json generated
View File

@ -1974,31 +1974,12 @@
"dev": true
},
"bcrypt": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-4.0.1.tgz",
"integrity": "sha512-hSIZHkUxIDS5zA2o00Kf2O5RfVbQ888n54xQoF/eIaquU4uaLxK8vhhBdktd0B3n2MjkcAWzv4mnhogykBKOUQ==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.0.tgz",
"integrity": "sha512-jB0yCBl4W/kVHM2whjfyqnxTmOHkCX4kHEa5nYKSoGeYe8YrjTYTc87/6bwt1g8cmV0QrbhKriETg9jWtcREhg==",
"requires": {
"node-addon-api": "^2.0.0",
"node-pre-gyp": "0.14.0"
},
"dependencies": {
"node-pre-gyp": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz",
"integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==",
"requires": {
"detect-libc": "^1.0.2",
"mkdirp": "^0.5.1",
"needle": "^2.2.1",
"nopt": "^4.0.1",
"npm-packlist": "^1.1.6",
"npmlog": "^4.0.2",
"rc": "^1.2.7",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4.4.2"
}
}
"node-addon-api": "^3.0.0",
"node-pre-gyp": "0.15.0"
}
},
"big.js": {
@ -4767,9 +4748,9 @@
}
},
"needle": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.5.0.tgz",
"integrity": "sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==",
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.5.2.tgz",
"integrity": "sha512-LbRIwS9BfkPvNwNHlsA41Q29kL2L/6VaOJ0qisM5lLWsTV3nP15abO5ITL6L81zqFhzjRKDAYjpcBcwM0AVvLQ==",
"requires": {
"debug": "^3.2.6",
"iconv-lite": "^0.4.4",
@ -4823,9 +4804,9 @@
"integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q=="
},
"node-addon-api": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.1.tgz",
"integrity": "sha512-2WVfwRfIr1AVn3dRq4yRc2Hn35ND+mPJH6inC6bjpYCZVrpXPB4j3T6i//OGVfqVsR1t/X/axRulDsheq4F0LQ=="
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz",
"integrity": "sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg=="
},
"node-libs-browser": {
"version": "2.2.1",
@ -4866,6 +4847,23 @@
}
}
},
"node-pre-gyp": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz",
"integrity": "sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==",
"requires": {
"detect-libc": "^1.0.2",
"mkdirp": "^0.5.3",
"needle": "^2.5.0",
"nopt": "^4.0.1",
"npm-packlist": "^1.1.6",
"npmlog": "^4.0.2",
"rc": "^1.2.7",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4.4.2"
}
},
"node-releases": {
"version": "1.1.60",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz",
@ -5385,6 +5383,11 @@
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
"dev": true
},
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
},
"public-encrypt": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
@ -6522,6 +6525,14 @@
"setimmediate": "^1.0.4"
}
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"requires": {
"os-tmpdir": "~1.0.2"
}
},
"to-arraybuffer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
@ -6787,6 +6798,31 @@
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
"dev": true
},
"useragent": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz",
"integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==",
"requires": {
"lru-cache": "4.1.x",
"tmp": "0.0.x"
},
"dependencies": {
"lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
}
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
}
}
},
"util": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",

View File

@ -12,7 +12,7 @@
"test": "run-p --race dev cy:run"
},
"dependencies": {
"bcrypt": "^4.0.1",
"bcrypt": "^5.0.0",
"body-parser": "^1.19.0",
"cl-editor": "^2.1.0",
"compression": "^1.7.1",
@ -28,7 +28,8 @@
"passport": "^0.4.1",
"passport-local": "^1.0.0",
"rate-limiter-flexible": "^2.1.10",
"session-file-store": "^1.4.0"
"session-file-store": "^1.4.0",
"useragent": "^2.3.0"
},
"devDependencies": {
"@babel/core": "^7.11.4",

View File

@ -0,0 +1,93 @@
import User from '../../models/user.js';
export async function post(req, res)
{
if (req.user) {
res.writeHead(401, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `You are already logged in`
}));
return false;
}
let { username, password, password_confirm, realname } = req.body;
if (!username || !password || !password_confirm || !realname) {
res.writeHead(422, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `You need to supply a username, real name, password, and password confirmation.`
}));
return false;
}
if (password.length < 8) {
res.writeHead(422, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `The password must be at least 8 characters long.`
}));
return false;
}
if (password !== password_confirm) {
res.writeHead(422, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `The password does not match the confirmation.`
}));
return false;
}
if (!/^[a-z0-9.]+$/i.test(username)) {
res.writeHead(422, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `The username can only contain letters, numbers, and periods.`
}));
return false;
}
/*
try {
await registerRateLimiter.consume();
} catch (err) {
res.writeHead(429, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `Too Many Requests`
}));
return false;
}
*/
try {
const user = await User.findOne({ username: req.body.username });
if (user) {
res.writeHead(401, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `This username is taken.`
}));
return false;
}
// password gets automatically hashed
const newUser = await new User({ username, realname, password });
await newUser.save();
req.login(newUser, err => {
if (err) throw err;
return res.redirect('/cms');
});
} catch (err) {
console.error(err);
res.writeHead(500, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `Internal server error`
}));
return false;
}
}

26
src/routes/me/avatar.js Normal file
View File

@ -0,0 +1,26 @@
import fs from 'fs';
import User from '../../models/user.js';
export async function del(req, res)
{
if (!req.user) {
res.writeHead(401, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `You must be logged in to set an avatar.`
}));
return false;
}
const user = await User.findById(req.user._id);
const filename = 'default.jpg';
if (user.avatar !== filename) {
fs.unlinkSync(`./static/u/${user.avatar}`);
}
req.user.avatar = user.avatar = filename;
await user.save();
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({ filename }));
}

16
src/routes/me/index.js Normal file
View File

@ -0,0 +1,16 @@
export function get(req, res, next)
{
if (req.user) {
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify(req.user));
} else {
res.writeHead(401, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `You are not logged in`
}));
}
}

View File

@ -12,6 +12,7 @@ import fileUpload from 'express-fileupload';
import fs from 'fs';
import cors from 'cors';
import helmet from 'helmet';
import useragent from 'useragent';
import crypto from 'crypto';
import Article from './models/article.js';
import Category from './models/category.js';
@ -130,101 +131,6 @@ express()
.use(passport.initialize())
.use(passport.session())
.post('/cms/register',
function(req, res, next) {
if (!req.user) {
next();
} else {
res.writeHead(401, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `You are already logged in`
}));
}
}, async (req, res) => {
let { username, password, password_confirm, realname } = req.body;
if (!username || !password || !password_confirm || !realname) {
res.writeHead(422, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `You need to supply a username, real name, password, and password confirmation.`
}));
return false;
}
if (password.length < 8) {
res.writeHead(422, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `The password must be at least 8 characters long.`
}));
return false;
}
if (password !== password_confirm) {
res.writeHead(422, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `The password does not match the confirmation.`
}));
return false;
}
if (!/^[a-z0-9.]+$/i.test(username)) {
res.writeHead(422, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `The username can only contain letters, numbers, and periods.`
}));
return false;
}
/*
try {
await registerRateLimiter.consume();
} catch (err) {
res.writeHead(429, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `Too Many Requests`
}));
return false;
}
*/
try {
const user = await User.findOne({ username: req.body.username });
if (user) {
res.writeHead(401, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `This username is taken.`
}));
return false;
}
// password gets automatically hashed
const newUser = await new User({ username, realname, password });
await newUser.save();
req.login(newUser, err => {
if (err) throw err;
return res.redirect('/cms');
});
} catch (err) {
console.error(err);
res.writeHead(500, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `Internal server error`
}));
return false;
}
}
)
.post('/cms/login',
// rateLimiterMiddleware(loginAttemptRateLimiter),
passport.authenticate('local', { failWithError: true }),
@ -433,22 +339,6 @@ express()
}
)
.get('/me', function(req, res, next) {
if (req.user) {
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify(req.user));
} else {
res.writeHead(401, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `You are not logged in`
}));
}
})
.post('/me/avatar',
async function(req, res, next) {
if (!req.user) {
@ -511,33 +401,12 @@ express()
}
)
.delete('/me/avatar',
async function(req, res, next) {
if (!req.user) {
res.writeHead(401, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `You must be logged in to set an avatar.`
}));
return false;
}
const user = await User.findById(req.user._id);
const filename = 'default.jpg';
if (user.avatar !== filename) {
fs.unlinkSync(`./static/u/${user.avatar}`);
}
req.user.avatar = user.avatar = filename;
await user.save();
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({ filename }));
}
)
.use(compression({ threshold: 0 }))
.use(express.static('./static'))
.use(async function (req, res, next) {
if (req.useragent.browser) {
}
})
.use(sapper.middleware({
session: req => ({
user: req.session.passport ? req.session.passport.user : null