Changed file structure to implement the frontend properly and created frontend template
This commit is contained in:
parent
feceab03b1
commit
32c0ffd715
41 changed files with 3784 additions and 0 deletions
27
backend/src/utils/appError.js
Normal file
27
backend/src/utils/appError.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
class AppError extends Error {
|
||||
constructor(statusCode, message, status = "", debugMsg = "") {
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
this.debugMsg = debugMsg;
|
||||
// Get status
|
||||
if (status === "") {
|
||||
if (statusCode.toString().startsWith("4")) {
|
||||
this.status = "Fail";
|
||||
} else {
|
||||
this.status = "Error";
|
||||
}
|
||||
} else {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.tryCatch = (controller) => async (req, res, next) => {
|
||||
try {
|
||||
await controller(req, res, next);
|
||||
} catch(err) {
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AppError;
|
||||
89
backend/src/utils/configManager.js
Normal file
89
backend/src/utils/configManager.js
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
// --- Define constants ---
|
||||
|
||||
// Imports
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { version } = require("../../package.json");
|
||||
|
||||
|
||||
// Var decalaration
|
||||
const config_folder = "config";
|
||||
const config_file_name = "config.json"
|
||||
|
||||
// Global variables
|
||||
let config = {};
|
||||
|
||||
// --- Default config ---
|
||||
|
||||
const default_config = {
|
||||
|
||||
"port": 8000,
|
||||
|
||||
"users": {
|
||||
"admin": {
|
||||
"username": "admin",
|
||||
"password": "admin"
|
||||
}
|
||||
},
|
||||
|
||||
"database": {
|
||||
"type": "sqlite"
|
||||
},
|
||||
|
||||
"auth" : {
|
||||
"JWT_secret": "HGF7654EGBNKJNBJH6754356788GJHGY",
|
||||
"tokenExpiry": "1h"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- Functions ---
|
||||
|
||||
function loadConfig() {
|
||||
|
||||
let user_config;
|
||||
|
||||
// Parse
|
||||
try {
|
||||
// Get user config
|
||||
user_config = JSON.parse(fs.readFileSync(path.resolve(path.join(config_folder, config_file_name))));
|
||||
|
||||
// Warns
|
||||
if (!user_config.auth || !user_config.auth.JWT_secret) {
|
||||
console.warn("WARNING: No JWT secret provided, using the default one. Please note that using the default secret is a major security risk.")
|
||||
}
|
||||
|
||||
// Merge default and user configs (default values)
|
||||
config = { ...default_config, ...user_config };
|
||||
}
|
||||
catch (err) {
|
||||
// Error messages
|
||||
console.debug("Error:", err)
|
||||
console.error("Error loading configuration, using the default settings");
|
||||
console.debug("Search path:", path.resolve("./"));
|
||||
console.debug("Config file:", path.resolve(path.join(config_folder, config_file_name)))
|
||||
|
||||
config = default_config;
|
||||
}
|
||||
|
||||
return config;
|
||||
|
||||
}
|
||||
|
||||
|
||||
async function getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
async function getJWTSecret() {
|
||||
return config.auth.JWT_secret || process.env.JWT_secret;
|
||||
}
|
||||
|
||||
async function getVersion() {
|
||||
// Could be done with process.env.npm_package_version
|
||||
// but may not work without without npm
|
||||
return version;
|
||||
}
|
||||
|
||||
// Exports
|
||||
module.exports = { loadConfig, getConfig, getVersion, getJWTSecret };
|
||||
11
backend/src/utils/convert.js
Normal file
11
backend/src/utils/convert.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
const marked = require("marked");
|
||||
|
||||
async function mdToHtml(md_content) {
|
||||
if (md_content) {
|
||||
return marked.parse(md_content);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { mdToHtml };
|
||||
61
backend/src/utils/crypto.js
Normal file
61
backend/src/utils/crypto.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// --- Imports ---
|
||||
const jwt = require("jsonwebtoken");
|
||||
const bcrypt = require("bcrypt");
|
||||
const { getConfig, getJWTSecret } = require("./configManager");
|
||||
|
||||
|
||||
// --- Config ---
|
||||
|
||||
// Declarations
|
||||
let JWT_Secret;
|
||||
let token_expiry;
|
||||
// Constant values
|
||||
const saltRounds = 12;
|
||||
// Load
|
||||
(async () => {
|
||||
const config = await getConfig();
|
||||
JWT_Secret = await getJWTSecret();
|
||||
token_expiry = config.auth.tokenExpiry;
|
||||
signature_algorithm = config.auth.signatureAlgorithm;
|
||||
})();
|
||||
|
||||
|
||||
// --- Functions ---
|
||||
|
||||
async function hashPassword(passwd) {
|
||||
const hash = bcrypt.hashSync(passwd, saltRounds);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
async function passwordsMatch(password, hashed_password) {
|
||||
return await bcrypt.compare(password, hashed_password);
|
||||
}
|
||||
|
||||
|
||||
async function signToken(payload, options = null) {
|
||||
if (options == null) {
|
||||
return jwt.sign(payload, JWT_Secret, { expiresIn: token_expiry, });
|
||||
}
|
||||
else {
|
||||
return jwt.sign(payload, JWT_Secret, options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function verifyToken(token) {
|
||||
return new Promise( async (resolve, reject) => {
|
||||
await jwt.verify( token, JWT_Secret, (err, user) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(user);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// --- Exports ---
|
||||
module.exports = { passwordsMatch, hashPassword, verifyToken, signToken };
|
||||
19
backend/src/utils/sanitize.js
Normal file
19
backend/src/utils/sanitize.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
const createDOMPurify = require("dompurify");
|
||||
const { JSDOM } = require("jsdom");
|
||||
|
||||
// Initialize
|
||||
const window = new JSDOM("").window;
|
||||
const DOMPurify = createDOMPurify(window);
|
||||
|
||||
async function sanitizeText(text) {
|
||||
return DOMPurify.sanitize(text);
|
||||
}
|
||||
|
||||
async function sanitizeModData(mod_data) {
|
||||
console.warn("Skipping sanitanization (not implemented)");
|
||||
// mod_data.displayName = await sanitizeText(mod_data.displayName);
|
||||
// mod_data.otherInfos.description = await sanitizeText(mod_data.otherInfos.description);
|
||||
// mod_data.otherInfos.changelogs = await sanitizeText(mod_data.otherInfos.changelogs);
|
||||
}
|
||||
|
||||
module.exports = { sanitizeText, sanitizeModData };
|
||||
51
backend/src/utils/validate.js
Normal file
51
backend/src/utils/validate.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// --- Imports ---
|
||||
const AppError = require("./appError");
|
||||
|
||||
|
||||
// --- Functions ---
|
||||
|
||||
async function validateNewModData(mod_data) {
|
||||
|
||||
throw new AppError(501, "Not implemented");
|
||||
//TODO
|
||||
// try {
|
||||
// node_schemas.validateNewModData(node_data);
|
||||
// } catch (err) {
|
||||
// throw new AppError(400, "Missing or invalid fields", "Bad request", err);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
async function validateNewUserData(user_data) {
|
||||
|
||||
throw new AppError(501, "Not implemented");
|
||||
//TODO
|
||||
// try {
|
||||
// node_schemas.validateNewUserData(node_data);
|
||||
// } catch (err) {
|
||||
// throw new AppError(400, "Missing or invalid fields", "Bad request", err);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
async function validateCretendials(identifier, password) {
|
||||
|
||||
throw new AppError(501, "Not implemented");
|
||||
}
|
||||
|
||||
|
||||
// --- Utils ---
|
||||
|
||||
async function isEmail(text) {
|
||||
const email_regex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
|
||||
return email_regex.test(text);
|
||||
}
|
||||
|
||||
async function isID(text) {
|
||||
const id_regex = /[a-zA-Z0-9_]+/;
|
||||
return id_regex.test(text);
|
||||
}
|
||||
|
||||
|
||||
module.exports = { validateNewModData, validateNewUserData, isEmail, isID };
|
||||
98
backend/src/utils/validate_legacy.js
Normal file
98
backend/src/utils/validate_legacy.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
const mod_model = require("../models/mod");
|
||||
const user_model = require("../models/user");
|
||||
const AppError = require("./appError");
|
||||
|
||||
async function validateModData(mod_data) {
|
||||
//TODO WIP
|
||||
// Check fields existence
|
||||
const not_null = mod_data &&
|
||||
Object.keys(mod_data).length == 5 &&
|
||||
mod_data.name &&
|
||||
mod_data.displayName &&
|
||||
mod_data.author &&
|
||||
mod_data.versions != null;
|
||||
|
||||
// mod_data.otherInfos != null &&
|
||||
// Object.keys(mod_data.otherInfos).length == 0 &&
|
||||
// mod_data.otherInfos.description != null &&
|
||||
// mod_data.otherInfos.links != null &&
|
||||
// mod_data.otherInfos.tags != null &&
|
||||
// mod_data.otherInfos.screenshots != null &&
|
||||
// mod_data.otherInfos.license != null &&
|
||||
// mod_data.otherInfos.changelogs != null;
|
||||
|
||||
if (!not_null) {
|
||||
console.debug("Item is missing expected fields:", mod_data);
|
||||
throw new AppError(400, "Bad request", "Missing expected fields");
|
||||
}
|
||||
|
||||
// Check fields format (check if sanitized)
|
||||
const is_valid_name = /^[a-zA-Z0-9_]+$/.test(mod_data.name);
|
||||
const is_valid_displayName = true;
|
||||
// const is_valid_displayName = /^[a-zA-Z0-9_]+$/.test(mod_data.name); // Temporary
|
||||
// const
|
||||
|
||||
const is_valid = is_valid_name && is_valid_displayName;
|
||||
if (!is_valid) {
|
||||
console.debug("Fields are not following the expected formats");
|
||||
throw new AppError(400, "Bad request", "The provided fields don't match the expected format");
|
||||
}
|
||||
|
||||
// Check if mod already exists
|
||||
const exists = await mod_model.exists(mod_data.name);
|
||||
if (exists) {
|
||||
console.debug("Error: Item already exists");
|
||||
throw new AppError(403, "Forbidden", "Content with this name already exists");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function validateUserData(user_data) {
|
||||
throw new AppError(501, "Not implemented");
|
||||
|
||||
//TODO
|
||||
|
||||
// Check fields existence
|
||||
// ...
|
||||
|
||||
if (!not_null) {
|
||||
console.debug("Missing expected fields:", mod_data);
|
||||
throw new AppError(400, "Bad request: Missing expected fields");
|
||||
}
|
||||
|
||||
// Check fields format (check if sanitized)
|
||||
const is_valid_username = /^[a-zA-Z0-9_]+$/.test(user_data.username);
|
||||
// const is_valid_email = ...
|
||||
// ...
|
||||
|
||||
const is_valid = is_valid_username && is_valid_email;
|
||||
if (!is_valid) {
|
||||
console.debug("Fields are not following the expected formats");
|
||||
throw new AppError(400, "Bad request: The provided fields don't match the expected format");
|
||||
}
|
||||
|
||||
// Check if user already exists
|
||||
const exists = await user_model.exists(user_data.username);
|
||||
if (exists) {
|
||||
console.debug("Error: User already exists");
|
||||
throw new AppError(403, "Forbidden: User with this name already exists");
|
||||
}
|
||||
}
|
||||
|
||||
async function validateCretendials(identifier, password) {
|
||||
|
||||
throw new AppError(501, "Not implemented");
|
||||
}
|
||||
|
||||
async function isEmail(text) {
|
||||
const email_regex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
|
||||
return email_regex.test(text);
|
||||
}
|
||||
|
||||
async function isID(text) {
|
||||
const id_regex = /[a-zA-Z0-9_]+/;
|
||||
return id_regex.test(text);
|
||||
}
|
||||
|
||||
|
||||
module.exports = { validateModData, validateUserData, isEmail, isID };
|
||||
Loading…
Add table
Add a link
Reference in a new issue