diff --git a/APIDOCS.md b/APIDOCS.md index de1f615..a499cd9 100644 --- a/APIDOCS.md +++ b/APIDOCS.md @@ -13,6 +13,12 @@ You need this headers for send request to API: ``` But in front end, the API will works with session. +## Limits: +- 3 - 25 char for username, password and category name +- 256 char for user about and desp of category +- 5 - 128 char for thread titles. +- 5 - 1024 char for messages. + ## How to request? ### Request types: diff --git a/README.md b/README.md index d912f92..cddb120 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,6 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn - upload other photos, model for it - categories page is need a update. - preview for send messages in markdown format. -- Limits for thread title, message content, username, user about - desp => description ## Major Version History diff --git a/models/Message.js b/models/Message.js index 691bd77..2510d9a 100644 --- a/models/Message.js +++ b/models/Message.js @@ -5,7 +5,7 @@ const schema = new mongoose.Schema({ author: Object, threadID: String, authorID: String, - content: String, + content: { type: String, maxlength: 1024 }, time: { type: Date, default: Date.now }, deleted: { type: Boolean, default: false }, edited: { type: Boolean, default: false }, @@ -30,7 +30,7 @@ const model = mongoose.model('message', schema); model.get = async id => { const message = await model.findOne({ id }) - return await message.get_author(); + return await message.get_author(); }; module.exports = model; \ No newline at end of file diff --git a/models/Secret.js b/models/Secret.js index e8c71e0..63e6c6d 100644 --- a/models/Secret.js +++ b/models/Secret.js @@ -1,7 +1,7 @@ const mongoose = require("mongoose") const schema = new mongoose.Schema({ - username: { type: String, unique: true }, + username: { type: String, unique: true, maxlength: 25 }, password: String, id: { type: String, unique: true } }); diff --git a/models/Thread.js b/models/Thread.js index 7126c2c..7eb0261 100644 --- a/models/Thread.js +++ b/models/Thread.js @@ -8,7 +8,7 @@ const schema = new mongoose.Schema({ authorID: String, author: Object, - title: String, + title: { type: String, maxlength: 128 }, time: { type: Date, default: Date.now }, deleted: { type: Boolean, default: false }, edited: { type: Boolean, default: false }, @@ -21,10 +21,10 @@ const schema = new mongoose.Schema({ schema.methods.get_author = cache.getAuthor; schema.methods.get_category = () => async function () { - return await require("./Category").findOne({ id: this.categoryID }) || {id: this.categoryID, name: "Unknown"} ; + return await require("./Category").findOne({ id: this.categoryID }) || { id: this.categoryID, name: "Unknown" }; } schema.methods.messageCount = async function (admin = false) { - const query = { threadID: this.id }; + const query = { threadID: this.id }; if (!admin) query.deleted = false; return await MessageModel.count(query) || 0; }; @@ -47,7 +47,7 @@ const model = mongoose.model('thread', schema); model.get = async id => { const thread = await model.findOne({ id }) - return await thread.get_author(); + return await thread.get_author(); }; module.exports = model; \ No newline at end of file diff --git a/models/User.js b/models/User.js index 328892a..5373ae7 100644 --- a/models/User.js +++ b/models/User.js @@ -1,14 +1,13 @@ const mongoose = require("mongoose") const { def_theme } = require("../config.json"); const schema = new mongoose.Schema({ - id: { type: String }, - - name: String, + id: { type: String, unique: true }, + name: { type: String, maxlength: 25 }, avatar: { type: String, default: "/images/avatars/default.jpg" }, time: { type: Date, default: Date.now }, deleted: { type: Boolean, default: false }, edited: { type: Boolean, default: false }, - about: { type: String, default: "" }, + about: { type: String, default: "", maxlength: 256 }, admin: { type: Boolean, default: false }, theme: { type: String, default: def_theme }, lastSeen: { type: Date, default: Date.now, select: false }, diff --git a/routes/api/routes/messages.js b/routes/api/routes/messages.js index ac13ccc..345be88 100644 --- a/routes/api/routes/messages.js +++ b/routes/api/routes/messages.js @@ -27,6 +27,8 @@ 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."); + if (content.length < 5 || content.length > 1024) return res.error(400, "content must be between 5 - 1024 characters"); + message.content = content; message.edited = true; @@ -43,6 +45,7 @@ app.post("/", rateLimit({ const { threadID, content } = req.body; if (!content) return res.error(400, "Missing message content in request body."); + if (content.length < 5 || content.length > 1024) return res.error(400, "content must be between 5 - 1024 characters"); const thread = await ThreadModel.get(threadID); diff --git a/routes/api/routes/threads.js b/routes/api/routes/threads.js index 3f7527e..d0a5f1c 100644 --- a/routes/api/routes/threads.js +++ b/routes/api/routes/threads.js @@ -41,7 +41,8 @@ app.post("/", async (req, res) => { const { title, content, category } = req.body; if (!content || !title) return res.error(400, "Missing content/title in request body."); - + if (title.length < 5 || title.length > 128) return res.error(400, "title must be between 5 - 128 characters"); + if (content.length < 5 || content.length > 1024) return res.error(400, "content must be between 5 - 1024 characters"); const { user } = req; const thread = await new ThreadModel({ title, author: user }).takeId() if (category) @@ -60,6 +61,8 @@ app.patch("/:id/", async (req, res) => { if (user.id !== thread.authorID && !user.admin) return res.error(403, "You have not got permission for this."); const { title } = req.body; if (!title) return res.error(400, "Missing thread title in request body."); + if (title.length < 5 || title.length > 128) return res.error(400, "title must be between 5 - 128 characters"); + thread.title = title; await thread.save(); diff --git a/routes/api/routes/users.js b/routes/api/routes/users.js index 7094ab1..40bcf04 100644 --- a/routes/api/routes/users.js +++ b/routes/api/routes/users.js @@ -5,10 +5,10 @@ const multer = require("multer"); const app = Router(); app.param("id", async (req, res, next, id) => { - req.member = await UserModel.get(id, req.user.admin ? "+lastSeen": ""); + req.member = await UserModel.get(id, req.user.admin ? "+lastSeen" : ""); if (!req.member) return res.error(404, `We don't have any user with id ${id}.`); - + if (req.member.deleted && !req.user?.admin) return res.error(404, `You do not have permissions to view this user with id ${id}.`); @@ -58,12 +58,18 @@ app.patch("/:id/", async (req, res) => { if ((admin?.length || "deleted" in req.body) && !req.user.admin) return res.error(403, "You have not got permission for edit 'admin' and 'deleted' information, or bad request."); + if (name) { + + if (name.length < 3 || name.length > 25) return res.error(400, "Username must be between 3 - 25 characters"); await SecretModel.updateOne({ id: member.id }, { username: name }); member.name = name; } - if (about) member.about = about; + if (about) { + if (about.length > 256) return res.error(400, "About must be under 256 characters"); + member.about = about; + } if (theme || ["default", "black"].includes(theme)) member.theme = theme; if (typeof admin === "boolean" || ["false", "true"].includes(admin)) member.admin = admin; diff --git a/routes/register.js b/routes/register.js index c7f9591..effaccc 100644 --- a/routes/register.js +++ b/routes/register.js @@ -11,18 +11,24 @@ app.post("/", rateLimit({ handler: (_r, response, _n, options) => response.error(options.statusCode, "You are begin ratelimited") }), async (req, res) => { - req.session.userID=null; + req.session.userID = null; let { username = null, password: body_pass = null, about } = req.body; - if (!username || !body_pass) return res.error(res, 400, "You forgot entering some values"); + if (!username || !body_pass) return res.error(400, "You forgot entering some values"); + if (username.length < 3 || username.length > 25) return res.error(400, "Username must be between 3 - 25 characters"); + if (body_pass.length < 3 || body_pass.length > 25) return res.error(400, "Password must be between 3 - 25 characters"); + const user = await SecretModel.findOne({ username }); - if (user) return res.error(res, 400, `We have got an user named ${username}!`) + if (user) return res.error(400, `We have got an user named ${username}!`) - const user2 = new UserModel({ name: req.body.username }) + const user2 = new UserModel({ name: username }) - if (about) user2.about = about; + if (about) { + if (about.length > 256) return res.error(400, "about must be under 256 characters"); + user2.about = about; + } await user2.takeId() await user2.save(); diff --git a/views/create_category.ejs b/views/create_category.ejs index c9e6717..33dee2a 100644 --- a/views/create_category.ejs +++ b/views/create_category.ejs @@ -9,9 +9,9 @@

Name:

- +

Description:

- +
@@ -22,7 +22,7 @@ document.addEventListener("submit", async e => { e.preventDefault(); const data = new FormData(e.target); - + const response = await request("/api/categories/", "POST", { name: data.get("name"), desp: data.get("desp") diff --git a/views/create_thread.ejs b/views/create_thread.ejs index 6a01f12..15fdea0 100644 --- a/views/create_thread.ejs +++ b/views/create_thread.ejs @@ -10,10 +10,10 @@
-

Title:

- +

Title:

+

Content:

- +

Category:

- - - - + + +
diff --git a/views/thread.ejs b/views/thread.ejs index 5b4a2ce..2872860 100644 --- a/views/thread.ejs +++ b/views/thread.ejs @@ -109,11 +109,10 @@
- + -
diff --git a/views/user.ejs b/views/user.ejs index 1eca186..8b1a69b 100644 --- a/views/user.ejs +++ b/views/user.ejs @@ -28,9 +28,9 @@

Edit <%= member.name %>

- + - + <% if (user?.admin){ %> Is Admin? >