diff --git a/README.md b/README.md index 3b8a10f..a46ab04 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn ## TO-DO list | To do | Is done? | | ----- | -------- | -| Profile Message | ⚪ | +| Profile Message or DM | ⚪ | | Better Auth for API way | 🟢 | | mod role, permissions | ⚪ | | upload other photos, model for it | ⚪ | @@ -50,7 +50,10 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn | DC auth will store code for taking tokens, and create secret model setting | ⚪ | - IF a person liked a message, view. - Disable last seen button. - +- email auth. +- thread.state =="approval" for threads. +- old contents / titles add to forum interface + ## Major Version History - V4: Caching - V3: New Theme diff --git a/index.js b/index.js index 392fa05..b725f61 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,7 @@ const app = express(), { urlencoded: BP } = require('body-parser'), { mw: IP } = require('request-ip'), - RL = require('express-rate-limit'), + { RL } = require('./lib'), SES = require('express-session'), MS = require("connect-mongo"), DB = mongoose.connect(process.env.MONGO_DB_URL) @@ -47,8 +47,7 @@ app.use(express.static("public"), express.json(), IP(), BP({ extended: true }), if (discord_auth) app.set("discord_auth", `https://discord.com/api/oauth2/authorize?client_id=${process.env.DISCORD_CLIENT}&redirect_uri=${host}%2Fdiscord_auth%2Fhash&response_type=token&scope=identify`); -if (RLS.enabled) - app.use(RL({ ...RLS, handler: (req, res, next, opts) => !req.user?.admin ? res.error(opts.statusCode, "You are begin ratelimited") : next() })); +if (RLS.enabled) app.use(RL(RSL.windowMs, RLS.max)); for (const file of fs.readdirSync("./routes")) app.use("/" + file.replace(".js", ""), require(`./routes/${file}`)); diff --git a/lib.js b/lib.js new file mode 100644 index 0000000..1e567ba --- /dev/null +++ b/lib.js @@ -0,0 +1,7 @@ +const RL = require('express-rate-limit'); + +module.exports.RL = (windowMs = 60_000, max = 1) => + RL({ + windowMs, max, standardHeaders: true, legacyHeaders: false, + handler: (req, res, next, opts) => !req.user?.admin ? res.error(opts.statusCode, "You are begin ratelimited") : next() + }) diff --git a/models/Message.js b/models/Message.js index 9e05201..796aad9 100644 --- a/models/Message.js +++ b/models/Message.js @@ -8,7 +8,7 @@ const schema = new mongoose.Schema({ threadID: String, authorID: String, content: { type: String, maxlength: limits.message }, - oldContents: [{ type: String, maxlength: limits.message }], + oldContents: [String], time: { type: Date, default: Date.now }, deleted: { type: Boolean, default: false }, edited: { type: Boolean, default: false }, diff --git a/models/Thread.js b/models/Thread.js index 3319c0f..2d19d74 100644 --- a/models/Thread.js +++ b/models/Thread.js @@ -11,6 +11,8 @@ const schema = new mongoose.Schema({ author: Object, title: { type: String, maxlength: limits.title }, + oldTitles: [String], + time: { type: Date, default: Date.now }, deleted: { type: Boolean, default: false }, edited: { type: Boolean, default: false }, diff --git a/routes/api/routes/messages.js b/routes/api/routes/messages.js index b119dfc..ef984bf 100644 --- a/routes/api/routes/messages.js +++ b/routes/api/routes/messages.js @@ -1,6 +1,5 @@ const { MessageModel, ThreadModel } = require("../../../models"); -const rateLimit = require('express-rate-limit') - +const { RL } = require('../../../lib'); const { Router } = require("express") const app = Router(); @@ -27,11 +26,15 @@ app.patch("/:id/", async (req, res) => { if (user.id !== message.authorID && !user.admin) return res.error(403, "You have not got permission for this."); const { content = null } = req.body; if (!content) return res.error(400, "Missing message content in request body."); - + const limits = req.app.get("limits"); if (content.length < 5 || content.length > limits.message) return res.error(400, "content must be between 5 - 1024 characters"); message.content = content; + + if (!message.oldContents.includes(content)) + message.oldContents.push(content); + message.edited = true; await message.save(); @@ -39,11 +42,7 @@ app.patch("/:id/", async (req, res) => { }) -app.post("/", rateLimit({ - windowMs: 60_000, max: 1, standardHeaders: true, legacyHeaders: false, - handler: (request, response, next, options) => - !request.user.admin ? response.error(options.statusCode, "You are begin ratelimited") : next() -}), async (req, res) => { +app.post("/", RL(), async (req, res) => { const { threadID, content } = req.body; if (!content) return res.error(400, "Missing message content in request body."); diff --git a/routes/api/routes/threads.js b/routes/api/routes/threads.js index c668c24..b6659b4 100644 --- a/routes/api/routes/threads.js +++ b/routes/api/routes/threads.js @@ -1,5 +1,6 @@ const { MessageModel, ThreadModel } = require("../../../models"); const { Router } = require("express") +const { RL } = require('../../../lib'); const app = Router(); app.param("id", async (req, res, next, id) => { @@ -36,7 +37,7 @@ app.get("/:id/messages/", async (req, res) => { }) -app.post("/", async (req, res) => { +app.post("/", RL(5 * 60_000, 1), async (req, res) => { const { title, content, category } = req.body; @@ -68,6 +69,10 @@ app.patch("/:id/", async (req, res) => { if (title.length < 5 || title.length > limits.title) return res.error(400, "title must be between 5 - 128 characters"); thread.title = title; + + if (!thread.oldTitles.includes(title)) + thread.oldTitles.push(title); + await thread.save(); res.complate(thread); diff --git a/routes/register.js b/routes/register.js index 2824094..38c5af9 100644 --- a/routes/register.js +++ b/routes/register.js @@ -1,22 +1,19 @@ const { UserModel, SecretModel } = require("../models"); const { Router } = require("express") const bcrypt = require("bcrypt"); -const rateLimit = require('express-rate-limit'); +const { RL } = require('../lib'); const app = Router(); app.get("/", (req, res) => res.reply("register", { user: null, discord: req.app.get("discord_auth") })); -app.post("/", rateLimit({ - windowMs: 24 * 60 * 60_000, max: 5, standardHeaders: true, legacyHeaders: false, - handler: (_r, response, _n, options) => response.error(options.statusCode, "You are begin ratelimited") -}), async (req, res) => { +app.post("/", RL(24 * 60 * 60_000, 5), async (req, res) => { req.session.userID = null; let { username, password: body_pass, about } = req.body; if (!username || !body_pass) return res.error(400, "You forgot entering some values"); - const {names} = req.app.get("limits"); + const { names } = req.app.get("limits"); if (username.length < 3 || names > 25) return res.error(400, "Username must be between 3 - 25 characters"); if (body_pass.length < 3 || names > 25) return res.error(400, "Password must be between 3 - 25 characters");