ratelimit & crypto & .ejs fix

added ratelimit to post threads and messages.
Added encryption to passwords.
Thread.ejs is fixed
This commit is contained in:
Akif9748 2022-08-10 00:22:12 +03:00
parent 086f2b5713
commit 11965e8de9
9 changed files with 44 additions and 12 deletions

View file

@ -6,9 +6,10 @@ A forum software written in Node.js.
## Installation ## Installation
- Clone or download this repo. - Clone or download this repo.
- Run `npm i` to install **dependencies**. - Run `npm i` to install **dependencies**.
- Run `node util/reset` to **reset the database**, and `npm start` for run it. - Run `npm start` for run it.
**Note:** Reseting the database is important! ### Extra
Run `node util/reset` to **reset the database**, and run `node util/admin` for give admin perms for first member.
## API ## API
Akf-forum has got an API for other clients etc. You can test api with run apitest.py. Akf-forum has got an API for other clients etc. You can test api with run apitest.py.
@ -21,7 +22,6 @@ And, you can learn about API in `util/APIDOCS.md`.
## To do (Backend, bug fixes) ## To do (Backend, bug fixes)
- `/errors/error` will change, better error page. - `/errors/error` will change, better error page.
- Redirect query. - Redirect query.
- middleware for timeouts
- Will fix API - Will fix API
## Roadmap ## Roadmap
@ -42,7 +42,7 @@ And, you can learn about API in `util/APIDOCS.md`.
### Messages ### Messages
| To do | Is done? | Priority | | To do | Is done? | Priority |
| ----- | -------- | -------- | | ----- | -------- | -------- |
| Ratelimit | 🔴 | HIGH | | Ratelimit | 🟢 | HIGH |
| Send | 🟢 | HIGH | | Send | 🟢 | HIGH |
| Delete | 🟢 | HIGH | | Delete | 🟢 | HIGH |
| Edit | 🔴 | HIGH | | Edit | 🔴 | HIGH |

View file

@ -1,7 +1,7 @@
const mongoose = require("mongoose") const mongoose = require("mongoose")
const schema = new mongoose.Schema({ const schema = new mongoose.Schema({
id: { type: String, unique: true }, id: { type: String },
name: String, name: String,
avatar: { type: String, default: "/images/guest.png" }, avatar: { type: String, default: "/images/guest.png" },

18
package-lock.json generated
View file

@ -14,6 +14,7 @@
"dotenv": "^16.0.1", "dotenv": "^16.0.1",
"ejs": "^3.1.6", "ejs": "^3.1.6",
"express": "^4.17.3", "express": "^4.17.3",
"express-rate-limit": "^6.5.1",
"express-session": "^1.17.2", "express-session": "^1.17.2",
"mongoose": "^6.5.1" "mongoose": "^6.5.1"
} }
@ -486,6 +487,17 @@
"node": ">= 0.10.0" "node": ">= 0.10.0"
} }
}, },
"node_modules/express-rate-limit": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.5.1.tgz",
"integrity": "sha512-pxO6ioBLd3i8IHL+RmJtL4noYzte5fugoMdaDabtU4hcg53+x0QkTwfPtM7vWD0YUaXQgNj9NRdzmps+CHEHlA==",
"engines": {
"node": ">= 12.9.0"
},
"peerDependencies": {
"express": "^4 || ^5"
}
},
"node_modules/express-session": { "node_modules/express-session": {
"version": "1.17.2", "version": "1.17.2",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz",
@ -1904,6 +1916,12 @@
"vary": "~1.1.2" "vary": "~1.1.2"
} }
}, },
"express-rate-limit": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.5.1.tgz",
"integrity": "sha512-pxO6ioBLd3i8IHL+RmJtL4noYzte5fugoMdaDabtU4hcg53+x0QkTwfPtM7vWD0YUaXQgNj9NRdzmps+CHEHlA==",
"requires": {}
},
"express-session": { "express-session": {
"version": "1.17.2", "version": "1.17.2",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz",

View file

@ -26,6 +26,7 @@
"dotenv": "^16.0.1", "dotenv": "^16.0.1",
"ejs": "^3.1.6", "ejs": "^3.1.6",
"express": "^4.17.3", "express": "^4.17.3",
"express-rate-limit": "^6.5.1",
"express-session": "^1.17.2", "express-session": "^1.17.2",
"mongoose": "^6.5.1" "mongoose": "^6.5.1"
} }

View file

@ -2,6 +2,7 @@ const { UserModel, SecretModel } = require("../models");
const { Router } = require("express"); const { Router } = require("express");
const error = require("../errors/error"); const error = require("../errors/error");
const app = Router(); const app = Router();
const bcrypt = require("bcrypt");
app.get("/", (req, res) => res.render("login")); app.get("/", (req, res) => res.render("login"));
@ -13,7 +14,10 @@ app.post("/", async (req, res) => {
if (username && password) { if (username && password) {
const user = await SecretModel.findOne({ username }); const user = await SecretModel.findOne({ username });
if (user) { if (user) {
if (user.password !== password) return error(res, 403, 'Incorrect Password!')
const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) return error(res, 403, 'Incorrect Password!')
const member = await UserModel.findOne({ name: username }); const member = await UserModel.findOne({ name: username });
if (!member || member.deleted) return error(res, 403, 'Incorrect Username and/or Password!') if (!member || member.deleted) return error(res, 403, 'Incorrect Username and/or Password!')

View file

@ -1,5 +1,6 @@
const { ThreadModel, MessageModel } = require("../models"); const { ThreadModel, MessageModel } = require("../models");
const error = require("../errors/error") const error = require("../errors/error")
const rateLimit = require('express-rate-limit')
const { Router } = require("express"); const { Router } = require("express");
@ -15,8 +16,9 @@ app.get("/:id", async (req, res) => {
app.use(require("../middlewares/login")); app.use(require("../middlewares/login"));
app.post("/", rateLimit({
app.post("/", async (req, res) => { windowMs: 60_000, max: 1, standardHeaders: true, legacyHeaders: false
}), async (req, res) => {
const thread = await ThreadModel.get(req.body.threadID); const thread = await ThreadModel.get(req.body.threadID);
if (thread) { if (thread) {

View file

@ -1,6 +1,7 @@
const { UserModel, SecretModel } = require("../models"); const { UserModel, SecretModel } = require("../models");
const { Router } = require("express") const { Router } = require("express")
const error = require("../errors/error") const error = require("../errors/error")
const bcrypt = require("bcrypt");
const app = Router(); const app = Router();
@ -24,6 +25,9 @@ app.post("/", async (req, res) => {
const user2 = new UserModel({ name: req.body.username, avatar }) const user2 = new UserModel({ name: req.body.username, avatar })
await user2.takeId() await user2.takeId()
await user2.save(); await user2.save();
const salt = await bcrypt.genSalt(10);
password = await bcrypt.hash(password, salt);
await SecretModel.create({ username, password, id: user2.id }) await SecretModel.create({ username, password, id: user2.id })
req.session.userid = user2.id; req.session.userid = user2.id;

View file

@ -1,5 +1,6 @@
const { Router } = require("express"); const { Router } = require("express");
const app = Router(); const app = Router();
const rateLimit = require('express-rate-limit')
const error = require("../errors/error") const error = require("../errors/error")
const { ThreadModel, MessageModel } = require("../models") const { ThreadModel, MessageModel } = require("../models")
@ -47,7 +48,9 @@ app.get("/:id", async (req, res) => {
app.use(require("../middlewares/login")); app.use(require("../middlewares/login"));
app.post("/", async (req, res) => { app.post("/", rateLimit({
windowMs: 10*60_000, max: 1, standardHeaders: true, legacyHeaders: false
}), async (req, res) => {
const { title = null, content = null } = req.body; const { title = null, content = null } = req.body;

View file

@ -12,7 +12,7 @@
<%= thread.title %> <%= thread.title %>
</h1> </h1>
<h2>By <a style="color: #bcbcbc;" href=<%="/users/" + thread.author.id %>> <%= thread.author.name %></a> <h2>By <a href=<%="/users/" + thread.author.id %>> <%= thread.author.name %></a>
<img class="yuvarlak" src=<%= thread.author.avatar %> alt=<%= thread.author.name %>> <img class="yuvarlak" src=<%= thread.author.avatar %> alt=<%= thread.author.name %>>
</h2> </h2>
<hr> <hr>
@ -27,7 +27,7 @@
<h2> <h2>
<img class="yuvarlak" src=<%=message.author.avatar %> alt=<%= message.author.name %>> <img class="yuvarlak" src=<%=message.author.avatar %> alt=<%= message.author.name %>>
<a style="color: #bcbcbc;" href=<%="/users/" + message.author.id %>> <%= message.author.name %></a>: <a href=<%="/users/" + message.author.id %>> <%= message.author.name %></a>:
</h2> </h2>
<h2> <h2>