A LOT of fixes
This commit is contained in:
parent
ca080b3e59
commit
106646f306
|
@ -12,5 +12,8 @@
|
||||||
"type": "sqlite"
|
"type": "sqlite"
|
||||||
},
|
},
|
||||||
|
|
||||||
"JWT_secret": "HGF7654EGBNKJNBJH6754356788GJHGY"
|
"auth": {
|
||||||
|
"JWT_secret": "HGF7654EGBNKJNBJH6754356788GJHGY",
|
||||||
|
"tokenExpiry": "1h"
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,10 +3,15 @@ const authService = require("../services/authService");
|
||||||
|
|
||||||
async function login(req, res) {
|
async function login(req, res) {
|
||||||
try {
|
try {
|
||||||
const token = await authService.login(req.body.username, req.body.password);
|
const username = req.body.username;
|
||||||
|
const email = req.body.email;
|
||||||
|
const password = req.body.password
|
||||||
|
const token = await authService.login(username, email, password);
|
||||||
res.json({ token });
|
res.json({ token });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
handleError(err, res);
|
handleError(err, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = { login };
|
|
@ -66,7 +66,7 @@ async function initDatabase() {
|
||||||
creation_date TINYTEXT NOT NULL,
|
creation_date TINYTEXT NOT NULL,
|
||||||
downloads_count INT NOT NULL,
|
downloads_count INT NOT NULL,
|
||||||
|
|
||||||
FOREIGN KEY (mod) REFERENCES Users(username)
|
FOREIGN KEY (mod) REFERENCES Mods(name)
|
||||||
);`);
|
);`);
|
||||||
|
|
||||||
// Mods tags
|
// Mods tags
|
||||||
|
|
|
@ -29,11 +29,11 @@ async function authorizeModModification(req) {
|
||||||
// Auth token
|
// Auth token
|
||||||
await authenticateToken(req);
|
await authenticateToken(req);
|
||||||
// Get mod infos
|
// Get mod infos
|
||||||
if (!req.params || req.params.id) {
|
if (!req.params || !req.params.name) {
|
||||||
throw new AppError(400, "No mod name was scpecified", "Bad request");
|
throw new AppError(400, "No mod name was scpecified", "Bad request");
|
||||||
}
|
}
|
||||||
const mod_name = req.params.id;
|
const mod_name = req.params.name;
|
||||||
const mod = getModByName(mod_name);
|
const mod = await getModByName(mod_name);
|
||||||
if (!mod) {
|
if (!mod) {
|
||||||
throw new AppError(404, "No mod was found with this name", "Not found");
|
throw new AppError(404, "No mod was found with this name", "Not found");
|
||||||
}
|
}
|
||||||
|
@ -48,11 +48,11 @@ async function authorizeModpackModification(req) {
|
||||||
// Auth token
|
// Auth token
|
||||||
await authenticateToken(req);
|
await authenticateToken(req);
|
||||||
// Get mod infos
|
// Get mod infos
|
||||||
if (!req.params || req.params.id) {
|
if (!req.params || !req.params.name) {
|
||||||
throw new AppError(400, "No mod name was scpecified", "Bad request");
|
throw new AppError(400, "No mod name was scpecified", "Bad request");
|
||||||
}
|
}
|
||||||
const modpack_name = req.params.id;
|
const modpack_name = req.params.name;
|
||||||
const modpack = getModpackByName(modpack_name);
|
const modpack = await getModpackByName(modpack_name);
|
||||||
if (!modpack) {
|
if (!modpack) {
|
||||||
throw new AppError(404, "No mod was found with this name", "Not found");
|
throw new AppError(404, "No mod was found with this name", "Not found");
|
||||||
}
|
}
|
||||||
|
@ -67,17 +67,17 @@ async function authorizeUserModification(req) {
|
||||||
// Auth token
|
// Auth token
|
||||||
await authenticateToken(req);
|
await authenticateToken(req);
|
||||||
// Get mod infos
|
// Get mod infos
|
||||||
if (!req.params || req.params.id) {
|
if (!req.params || !req.params.name) {
|
||||||
throw new AppError(400, "No mod name was scpecified", "Bad request");
|
throw new AppError(400, "No mod name was scpecified", "Bad request");
|
||||||
}
|
}
|
||||||
const user_name = req.params.id;
|
const user_name = req.params.name;
|
||||||
const user = getUserByName(user_name);
|
const user = await getUserByName(user_name);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new AppError(404, "No mod was found with this name", "Not found");
|
throw new AppError(404, "No user was found with this name", "Not found");
|
||||||
}
|
}
|
||||||
// Authorize
|
// Authorize
|
||||||
if ( user.username != req.token_infos.username) {
|
if ( user.username != req.token_infos.username) {
|
||||||
throw new AppError(401, "Mod author differs from current user", "Unauthorized");
|
throw new AppError(401, "User to modify differs from current user", "Unauthorized");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,16 @@ const handleError = (err, res) => {
|
||||||
|
|
||||||
// Send error infos
|
// Send error infos
|
||||||
if (err instanceof AppError) {
|
if (err instanceof AppError) {
|
||||||
|
|
||||||
|
// Log
|
||||||
|
if (err.statusCode == 500) {
|
||||||
|
console.error("Error:", err.message);
|
||||||
|
if (err.debugMsg) {
|
||||||
|
console.debug(" >", err.debugMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response
|
||||||
return res.status(err.statusCode).json({
|
return res.status(err.statusCode).json({
|
||||||
status: err.status,
|
status: err.status,
|
||||||
message: err.message
|
message: err.message
|
||||||
|
@ -11,6 +21,7 @@ const handleError = (err, res) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default error
|
// Default error
|
||||||
|
console.error("Error:", err.message);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
message: 'Internal server error',
|
message: 'Internal server error',
|
||||||
status: 500
|
status: 500
|
||||||
|
|
|
@ -62,22 +62,27 @@ async function createMod(name, display_name, author, description, mod_infos) {
|
||||||
[name, display_name, author, description]);
|
[name, display_name, author, description]);
|
||||||
|
|
||||||
// ModInfos table
|
// ModInfos table
|
||||||
await db.prepare(`INSERT INTO ModInfos (mod, full_description, license, links, creation_date)
|
await db.prepare(`INSERT INTO ModInfos (mod, full_description, license, links, creation_date, downloads_count)
|
||||||
VALUES (?, ?, ?, ?, ?)`,
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
||||||
[name, full_description, license.type, links.toString(), creation_date]);
|
[name, full_description, license.type, links.toString(), creation_date, 0]);
|
||||||
|
|
||||||
// Tags
|
// Tags
|
||||||
const tags_proc = addTags(name, tags, []);
|
if (tags) {
|
||||||
|
const tags_proc = addTags(name, tags, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// License
|
// License
|
||||||
if (license_type == "custom") {
|
if (license.type == "custom") {
|
||||||
await db.prepare(`UPDATE ModInfos SET custom_license = ?
|
await db.prepare(`UPDATE ModInfos SET custom_license = ?
|
||||||
WHERE mod = ?`,
|
WHERE mod = ?`,
|
||||||
[license.content, name]);
|
[license.content, name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Await
|
// Await
|
||||||
await tags_proc;
|
if (tags) {
|
||||||
|
await tags_proc;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ const db = getDatabase();
|
||||||
|
|
||||||
// --- Get ---
|
// --- Get ---
|
||||||
|
|
||||||
async function getAllUsers(name) {
|
async function getAllUsers() {
|
||||||
return db.query("SELECT username, display_name, email, profile_picture FROM Users WHERE username = ?", [name]);
|
return db.query("SELECT username, display_name, email, profile_picture FROM Users");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUserByName(name) {
|
async function getUserByName(name) {
|
||||||
|
@ -35,8 +35,9 @@ async function exists(name) {
|
||||||
async function createUser( username, email, password, displayName, profilePicture, settings ) {
|
async function createUser( username, email, password, displayName, profilePicture, settings ) {
|
||||||
|
|
||||||
// Create user
|
// Create user
|
||||||
await db.prepare("INSERT INTO Users (username, email, password, display_name, role) \
|
await db.prepare(`INSERT INTO Users (username, email, password, display_name, role )
|
||||||
VALUES (?, ?, ?, ?, ?)", [username, email, password, displayName, "user"]);
|
VALUES (?, ?, ?, ?, ? )`,
|
||||||
|
[username, email, password, displayName, "user"]);
|
||||||
|
|
||||||
// Handle nullable fields
|
// Handle nullable fields
|
||||||
if (profilePicture) {
|
if (profilePicture) {
|
||||||
|
|
|
@ -5,27 +5,21 @@ const router = express.Router();
|
||||||
|
|
||||||
// List users
|
// List users
|
||||||
router.get("/", async (req,res) => {
|
router.get("/", async (req,res) => {
|
||||||
console.debug("Accessing users list");
|
|
||||||
controller.listUsers(req,res);
|
controller.listUsers(req,res);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a user
|
// Create a user
|
||||||
router.post("/", async (req, res) => {
|
router.post("/", async (req, res) => {
|
||||||
console.debug("Creating user ", req.body.name);
|
|
||||||
controller.createUser(req, res);
|
controller.createUser(req, res);
|
||||||
})
|
})
|
||||||
|
|
||||||
// Get user infos
|
// Get user infos
|
||||||
router.get("/:name", async (req,res) => {
|
router.get("/:name", async (req,res) => {
|
||||||
const name = req.params.name;
|
|
||||||
console.debug("Accessing user " + name)
|
|
||||||
controller.getUserByName(req, res);
|
controller.getUserByName(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Delete user
|
// Delete user
|
||||||
router.delete("/:name", async (req,res) => {
|
router.delete("/:name", async (req,res) => {
|
||||||
const name = req.params.name;
|
|
||||||
console.debug("Deleting user " + name)
|
|
||||||
controller.deleteUser(req, res);
|
controller.deleteUser(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,48 +1,79 @@
|
||||||
const bcrypt = require("bcrypt");
|
|
||||||
const jwt = require("jsonwebtoken");
|
|
||||||
const userModel = require("../models/user");
|
const userModel = require("../models/user");
|
||||||
const AppError = require("../utils/appError");
|
const AppError = require("../utils/appError");
|
||||||
|
const cryptoUtils = require("../utils/crypto");
|
||||||
const configManager = require("../utils/configManager");
|
const configManager = require("../utils/configManager");
|
||||||
const validate = require("../utils/validate_legacy");
|
const validate = require("../utils/validate_legacy");
|
||||||
|
|
||||||
const JWT_Secret = configManager.getJWTSecret();
|
const JWT_Secret = configManager.getJWTSecret();
|
||||||
|
|
||||||
async function login(identifier, password) {
|
async function login(username, email, password) {
|
||||||
|
|
||||||
// Check for null
|
// Check for null
|
||||||
if (!username || !password) {
|
if (!(username || email) || !password) {
|
||||||
throw new AppError(400, "Bad request", "missing credentials");
|
throw new AppError(400, "Bad request", "missing credentials");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get user data
|
// Get user data
|
||||||
let user;
|
let user_get;
|
||||||
if (validate.isEmail(identifier)) { // If matches email
|
if (email) { // If matches email
|
||||||
user = await userModel.getUserByEmail(username);
|
user_get = await userModel.getUserByEmail(email);
|
||||||
} else
|
} else
|
||||||
if (validate.isID(identifier)) { // if matches username
|
if (username) { // if matches username
|
||||||
user = await userModel.getUserByName(username);
|
user_get = await userModel.getUserByName(username);
|
||||||
} else {
|
} else {
|
||||||
|
console.debug("Failed finding user, weird...")
|
||||||
throw new AppError(401, "Unauthorized", "Invalid credentials");
|
throw new AppError(401, "Unauthorized", "Invalid credentials");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user exists
|
// Check if user exists
|
||||||
if (!user || user.length == 0) {
|
if (!user_get || user_get.length == 0) {
|
||||||
// throw new AppError(401, "Unauthorized: No user with this name");
|
// throw new AppError(401, "Unauthorized: No user with this name");
|
||||||
throw new AppError(401, "Unauthorized", "Invalid credentials");
|
throw new AppError(401, "Unauthorized", "Invalid credentials");
|
||||||
}
|
}
|
||||||
// Just in case
|
// Just in case
|
||||||
if (user.length > 1) {
|
if (user_get.length > 1) {
|
||||||
throw new AppError(500, "Internal server error", "Found multiple users with this name or email, please contact administration");
|
throw new AppError(500, "Internal server error", "Found multiple users with this name or email, please contact administration");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const user = user_get[0];
|
||||||
|
|
||||||
|
// Get user password
|
||||||
|
const saved_password_get = await userModel.getUserPassword(user.username);
|
||||||
|
// Check if retrieved password sucessfully
|
||||||
|
if (!saved_password_get || saved_password_get.length == 0) {
|
||||||
|
throw new AppError(500, "Unable to retrieve user password");
|
||||||
|
}
|
||||||
|
saved_password = saved_password_get[0].password;
|
||||||
|
// Check if retrieved password sucessfully again
|
||||||
|
if (!saved_password) {
|
||||||
|
throw new AppError(500, "Unable to retrieve user password");
|
||||||
|
}
|
||||||
|
|
||||||
// Check if passwords match
|
// Check if passwords match
|
||||||
const passwords_match = await bcrypt.compare(password, user[0].password);
|
const passwords_match = await cryptoUtils.passwordsMatch(password, saved_password)
|
||||||
if (!passwords_match) {
|
if (!passwords_match) {
|
||||||
// throw new AppError(401, "Unauthorized: Invalid password");
|
// throw new AppError(401, "Unauthorized: Invalid password");
|
||||||
|
console.debug(password, "differs from", saved_password);
|
||||||
throw new AppError(401, "Unauthorized", "Invalid credentials");
|
throw new AppError(401, "Unauthorized", "Invalid credentials");
|
||||||
}
|
}
|
||||||
|
|
||||||
return jwt.sign({ username: user[0].username, role: user[0].role }, await JWT_Secret);
|
const payload = { type: "user",
|
||||||
|
username: user.username,
|
||||||
|
email: user.email,
|
||||||
|
role: user.role };
|
||||||
|
|
||||||
|
const token = await cryptoUtils.signToken(payload);
|
||||||
|
return token;
|
||||||
|
|
||||||
|
// // Check if passwords match
|
||||||
|
// const passwords_match = await bcrypt.compare(password, user[0].password);
|
||||||
|
// if (!passwords_match) {
|
||||||
|
// // throw new AppError(401, "Unauthorized: Invalid password");
|
||||||
|
// console.debug("Password doesn't match")
|
||||||
|
// throw new AppError(401, "Unauthorized", "Invalid credentials");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return jwt.sign({ username: user[0].username, role: user[0].role }, await JWT_Secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// function authorizeRole(user, roles) {
|
// function authorizeRole(user, roles) {
|
||||||
|
|
|
@ -51,10 +51,10 @@ async function createMod(mod_data, author) {
|
||||||
mod_infos.full_description = await mdToHtml(mod_infos.full_description); // Convert
|
mod_infos.full_description = await mdToHtml(mod_infos.full_description); // Convert
|
||||||
await sanitizeModData(mod_data); // Sanitize
|
await sanitizeModData(mod_data); // Sanitize
|
||||||
//TODO
|
//TODO
|
||||||
// mod_infos.creation_date = ...
|
mod_infos.creation_date = 0
|
||||||
|
|
||||||
// Write changes to database
|
// Write changes to database
|
||||||
model.createMod(name, display_name, author, description, mod_data);
|
await model.createMod(name, display_name, author, description, mod_infos);
|
||||||
|
|
||||||
// Return
|
// Return
|
||||||
return getModByName(name);
|
return getModByName(name);
|
||||||
|
|
|
@ -1,30 +1,32 @@
|
||||||
const model = require("../models/user");
|
const model = require("../models/user");
|
||||||
const AppError = require("../utils/appError");
|
const AppError = require("../utils/appError");
|
||||||
|
const cryptoUtils = require("../utils/crypto");
|
||||||
const { validateUserData } = require("../utils/validate_legacy");
|
const { validateUserData } = require("../utils/validate_legacy");
|
||||||
const { sanitizeUserData } = require("../utils/sanitize");
|
const { sanitizeUserData } = require("../utils/sanitize");
|
||||||
|
|
||||||
async function getAllUsers() {
|
async function getAllUsers() {
|
||||||
return model.getAllUsers();
|
return await model.getAllUsers();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUserByName(name) {
|
async function getUserByName(name) {
|
||||||
return model.getUserByName(name);
|
const res = await model.getUserByName(name);
|
||||||
|
return res[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createUser(user_data) {
|
async function createUser(user_data) {
|
||||||
|
|
||||||
// Check body validity
|
// Check body validity
|
||||||
await validateUserData(user_data);
|
// TODO
|
||||||
|
|
||||||
// Check authenticity
|
|
||||||
//TODO no auth provider
|
|
||||||
|
|
||||||
// Sanitize
|
// Sanitize
|
||||||
await sanitizeUserData(user_data);
|
// TODO
|
||||||
|
|
||||||
console.debug("Passed validity checks");
|
// Gather data
|
||||||
model.createUser(user_data);
|
const { username, email, password, display_name, profile_picture, settings } = user_data
|
||||||
return;
|
const password_hash = await cryptoUtils.hashPassword(password);
|
||||||
|
|
||||||
|
await model.createUser(username, email, password_hash, display_name, null, null);
|
||||||
|
return model.getUserByName(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteUser(name, token_user) {
|
async function deleteUser(name, token_user) {
|
||||||
|
@ -35,13 +37,10 @@ async function deleteUser(name, token_user) {
|
||||||
throw new AppError(404, "Cannot find user with this name", "Not found");
|
throw new AppError(404, "Cannot find user with this name", "Not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check authenticity
|
const res = await model.getUserByName(name);
|
||||||
if (name != token_user) {
|
await model.deleteUser(name);
|
||||||
throw new AppError(401, "", "Unauthorized");
|
|
||||||
}
|
|
||||||
|
|
||||||
model.deleteUser(name);
|
return res;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { getAllUsers, getUserByName, createUser, deleteUser };
|
module.exports = { getAllUsers, getUserByName, createUser, deleteUser };
|
|
@ -31,7 +31,8 @@ const default_config = {
|
||||||
},
|
},
|
||||||
|
|
||||||
"auth" : {
|
"auth" : {
|
||||||
"JWT_secret": "HGF7654EGBNKJNBJH6754356788GJHGY"
|
"JWT_secret": "HGF7654EGBNKJNBJH6754356788GJHGY",
|
||||||
|
"tokenExpiry": "1h"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ function loadConfig() {
|
||||||
user_config = JSON.parse(fs.readFileSync(path.resolve(path.join(config_folder, config_file_name))));
|
user_config = JSON.parse(fs.readFileSync(path.resolve(path.join(config_folder, config_file_name))));
|
||||||
|
|
||||||
// Warns
|
// Warns
|
||||||
if (!user_config.auth || !user_config.auth.jwtSecret) {
|
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.")
|
console.warn("WARNING: No JWT secret provided, using the default one. Please note that using the default secret is a major security risk.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +76,7 @@ async function getConfig() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getJWTSecret() {
|
async function getJWTSecret() {
|
||||||
return config.auth.JWT_Secret || process.env.JWT_Secret;
|
return config.auth.JWT_secret || process.env.JWT_secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getVersion() {
|
async function getVersion() {
|
||||||
|
|
|
@ -10,9 +10,10 @@ async function sanitizeText(text) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sanitizeModData(mod_data) {
|
async function sanitizeModData(mod_data) {
|
||||||
mod_data.displayName = await sanitizeText(mod_data.displayName);
|
console.warn("Skipping sanitanization (not implemented)");
|
||||||
mod_data.otherInfos.description = await sanitizeText(mod_data.otherInfos.description);
|
// mod_data.displayName = await sanitizeText(mod_data.displayName);
|
||||||
mod_data.otherInfos.changelogs = await sanitizeText(mod_data.otherInfos.changelogs);
|
// mod_data.otherInfos.description = await sanitizeText(mod_data.otherInfos.description);
|
||||||
|
// mod_data.otherInfos.changelogs = await sanitizeText(mod_data.otherInfos.changelogs);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { sanitizeText, sanitizeModData };
|
module.exports = { sanitizeText, sanitizeModData };
|
Loading…
Reference in a new issue