diff --git a/backend/core/core.js b/backend/core/core.js index 0ac804e..fe39f0c 100644 --- a/backend/core/core.js +++ b/backend/core/core.js @@ -5,6 +5,7 @@ const { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, ListO const { getSignedUrl } = require("@aws-sdk/s3-request-presigner"); let s3; const crypto = require("crypto"); +const validate = require("../form_validation"); const md = require("markdown-it")() .use(require("markdown-it-underline")) .use(require("markdown-it-footnote")) @@ -59,22 +60,23 @@ function _initS3Storage() { // Users async function newUser({ username, password, role } = {}) { - if (!username) return _r(false, "Username not specified"); - if (!password) return _r(false, "Password not specified"); + // Sanity check on user registration. + const valid = validate.newUser({ username: username, password: password }); + if (!valid.success) return _r(false, valid.message); // Create the account try { user_database_entry = await prisma.user.create({ data: { username: username, password: password, role: role } }); } catch (e) { let message = "Unknown error"; - return { success: false, message: message }; + return _r(false, message); } // Create the profile page and link try { user_profile_database_entry = await prisma.profilePage.create({ data: { owner: { connect: { id: user_database_entry.id } } } }); } catch (e) { - return { success: false, message: `Error creating profile page for user ${username}` }; + return _r(false, `Error creating profile page for user ${username}`); } // Master user was created; server initialized diff --git a/backend/core/internal_api.js b/backend/core/internal_api.js index 8bc5354..91ecfd3 100644 --- a/backend/core/internal_api.js +++ b/backend/core/internal_api.js @@ -62,7 +62,7 @@ async function patchBlog(req, res) { // User is admin, or user is author // Validate blog info - let valid = await validate.postBlog(req.body); + let valid = await validate.patchPost(req.body); if (!valid.success) return { success: false, message: valid.message || "Post failed validation" }; valid = valid.data; diff --git a/backend/form_validation.js b/backend/form_validation.js index de46b88..1d2f771 100644 --- a/backend/form_validation.js +++ b/backend/form_validation.js @@ -1,33 +1,36 @@ +// +// Form validation +// +// Preform sanity checks on content +// Format given data in an accessible way +// + const core = require("./core/core"); -async function registerUser(username, password) { - if (!username) return { success: false, message: "No username provided" }; - if (!password) return { success: false, message: "No password provided" }; - if (password.length < core.settings["USER_MINIMUM_PASSWORD_LENGTH"]) return { success: false, message: "Password not long enough" }; +// Make sure the user registration data is safe and valid. +function newUser({ username, password } = {}) { + if (!username) return _r(false, "No username provided"); + if (!password) return _r(false, "No password provided"); + if (password.length < core.settings["USER_MINIMUM_PASSWORD_LENGTH"]) return _r(false, `Password is not long enough. Minimum length is ${core.settings["USER_MINIMUM_PASSWORD_LENGTH"]}`); - // Check if username only uses URL safe characters - if (!_isUrlSafe(username)) return { success: false, message: "Username is not URL safe" }; + // TODO: Method to block special characters + if (!_isUrlSafe(username)) return _r(false, "Invalid Username. Please only use a-z A-Z 0-9"); - // All good! Validation complete - return { success: true }; + return _r(true); } -async function postBlog(blog_object) { - // TODO: Validate blog posts before upload - // Check title length - // Check description length - // Check content length - // Check valid date - // Return formatted object +function patchPost(post_content) { + let post_formatted = {}; // The formatted post content object that will be returned upon success + let publish_date; // Time and date the post should be made public + let tags = []; // An array of tags for the post // Get the publish date in a standard format - const [year, month, day] = blog_object.date.split("-"); - const [hour, minute] = blog_object.time.split(":"); - let publish_date = new Date(year, month - 1, day, hour, minute); + const [year, month, day] = post_content.date.split("-"); + const [hour, minute] = post_content.time.split(":"); + publish_date = new Date(year, month - 1, day, hour, minute); - // Go though our tags and ensure they are: - let valid_tag_array = []; - blog_object.tags.forEach((tag) => { + // Go though tags list, and turn into a pretty array + post_content.tags.forEach((tag) => { // Trimmed tag = tag.trim(); @@ -35,27 +38,31 @@ async function postBlog(blog_object) { tag = tag.toLowerCase(); // Non-empty - if (tag.length !== 0) valid_tag_array.push(tag); + if (tag.length !== 0) tags.push(tag); }); - // Format our data to save - let blog_post_formatted = { - title: blog_object.title, - description: blog_object.description, - content: blog_object.content, - visibility: blog_object.visibility, + // Format the post content + post_formatted = { + // Autofill the given data + ...post_content, + + // Update tags to our pretty array + tags: tags, + + // Update date publish_date: publish_date, - tags: valid_tag_array, - media: blog_object.media, - thumbnail: blog_object.thumbnail, }; - return { success: true, data: blog_post_formatted }; + return _r(true, null, post_formatted); } +// Helper functions -------------------- function _isUrlSafe(str) { const pattern = /^[A-Za-z0-9\-_.~]+$/; return pattern.test(str); } +function _r(s, m, d) { + return { success: s, m: m ? m || "Unknown error" : undefined, data: d }; +} -module.exports = { registerUser, postBlog }; +module.exports = { newUser, patchPost };