Compare commits
No commits in common. "0aa9e663ff416d286eef2bb2ab7da7985be1add3" and "988667bde88493605c177560f92222633fcfcd04" have entirely different histories.
0aa9e663ff
...
988667bde8
|
@ -13,7 +13,6 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"packageManager": "pnpm@10.5.2",
|
"packageManager": "pnpm@10.5.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^8.17.1",
|
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"better-sqlite3": "^11.9.1",
|
"better-sqlite3": "^11.9.1",
|
||||||
"dompurify": "^3.2.4",
|
"dompurify": "^3.2.4",
|
||||||
|
|
|
@ -8,9 +8,6 @@ importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv:
|
|
||||||
specifier: ^8.17.1
|
|
||||||
version: 8.17.1
|
|
||||||
bcrypt:
|
bcrypt:
|
||||||
specifier: ^5.1.1
|
specifier: ^5.1.1
|
||||||
version: 5.1.1
|
version: 5.1.1
|
||||||
|
@ -95,9 +92,6 @@ packages:
|
||||||
resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
|
resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
ajv@8.17.1:
|
|
||||||
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
|
|
||||||
|
|
||||||
ansi-regex@5.0.1:
|
ansi-regex@5.0.1:
|
||||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -302,12 +296,6 @@ packages:
|
||||||
resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==}
|
resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==}
|
||||||
engines: {node: '>= 18'}
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
fast-deep-equal@3.1.3:
|
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
|
||||||
|
|
||||||
fast-uri@3.0.6:
|
|
||||||
resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==}
|
|
||||||
|
|
||||||
file-uri-to-path@1.0.0:
|
file-uri-to-path@1.0.0:
|
||||||
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
|
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
|
||||||
|
|
||||||
|
@ -470,9 +458,6 @@ packages:
|
||||||
canvas:
|
canvas:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
json-schema-traverse@1.0.0:
|
|
||||||
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
|
|
||||||
|
|
||||||
jsonwebtoken@9.0.2:
|
jsonwebtoken@9.0.2:
|
||||||
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
|
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
|
||||||
engines: {node: '>=12', npm: '>=6'}
|
engines: {node: '>=12', npm: '>=6'}
|
||||||
|
@ -700,10 +685,6 @@ packages:
|
||||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||||
engines: {node: '>=8.10.0'}
|
engines: {node: '>=8.10.0'}
|
||||||
|
|
||||||
require-from-string@2.0.2:
|
|
||||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
|
|
||||||
rimraf@3.0.2:
|
rimraf@3.0.2:
|
||||||
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
|
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
|
||||||
deprecated: Rimraf versions prior to v4 are no longer supported
|
deprecated: Rimraf versions prior to v4 are no longer supported
|
||||||
|
@ -993,13 +974,6 @@ snapshots:
|
||||||
|
|
||||||
agent-base@7.1.3: {}
|
agent-base@7.1.3: {}
|
||||||
|
|
||||||
ajv@8.17.1:
|
|
||||||
dependencies:
|
|
||||||
fast-deep-equal: 3.1.3
|
|
||||||
fast-uri: 3.0.6
|
|
||||||
json-schema-traverse: 1.0.0
|
|
||||||
require-from-string: 2.0.2
|
|
||||||
|
|
||||||
ansi-regex@5.0.1: {}
|
ansi-regex@5.0.1: {}
|
||||||
|
|
||||||
anymatch@3.1.3:
|
anymatch@3.1.3:
|
||||||
|
@ -1223,10 +1197,6 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
|
||||||
|
|
||||||
fast-uri@3.0.6: {}
|
|
||||||
|
|
||||||
file-uri-to-path@1.0.0: {}
|
file-uri-to-path@1.0.0: {}
|
||||||
|
|
||||||
fill-range@7.1.1:
|
fill-range@7.1.1:
|
||||||
|
@ -1417,8 +1387,6 @@ snapshots:
|
||||||
- supports-color
|
- supports-color
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
json-schema-traverse@1.0.0: {}
|
|
||||||
|
|
||||||
jsonwebtoken@9.0.2:
|
jsonwebtoken@9.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
jws: 3.2.2
|
jws: 3.2.2
|
||||||
|
@ -1646,8 +1614,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
require-from-string@2.0.2: {}
|
|
||||||
|
|
||||||
rimraf@3.0.2:
|
rimraf@3.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
glob: 7.2.3
|
glob: 7.2.3
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
const index_service = require("../services/indexService");
|
|
||||||
const handleError = require("../middleware/errors");
|
const handleError = require("../middleware/errors");
|
||||||
|
|
||||||
|
async function helloWorld(req, res) {
|
||||||
async function getVersion(req, res) {
|
|
||||||
try {
|
try {
|
||||||
const query_result = await index_service.getVersion();
|
const query_result = "Unknown development version";
|
||||||
res.json(query_result);
|
res.send(query_result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, res);
|
handleError(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { getVersion };
|
module.exports = { helloWorld };
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
const { getConfig } = require("../utils/configManager");
|
||||||
const MySQLDatabase = require("./mysql");
|
const MySQLDatabase = require("./mysql");
|
||||||
const SQLiteDatabase = require("./sqlite");
|
const SQLiteDatabase = require("./sqlite");
|
||||||
const { getConfig } = require("../utils/configManager");
|
|
||||||
|
|
||||||
let db;
|
let db;
|
||||||
|
|
||||||
|
@ -11,11 +11,11 @@ async function connectDatabase() {
|
||||||
|
|
||||||
// Choose database type
|
// Choose database type
|
||||||
if (config.type === "mysql") {
|
if (config.type === "mysql") {
|
||||||
db = new MySQLDatabase(config);
|
db = new MySQLDatabase(config);
|
||||||
} else if (config.type === "sqlite") {
|
} else if (config.type === "sqlite") {
|
||||||
db = new SQLiteDatabase(config);
|
db = new SQLiteDatabase(config);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Invalid database type: ", config.type);
|
throw new Error("Invalid database type: ", config.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect
|
// Connect
|
||||||
|
@ -31,80 +31,45 @@ async function initDatabase() {
|
||||||
throw new Error("Database is not connected");
|
throw new Error("Database is not connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Users ---
|
// Create mods table
|
||||||
|
db.exec("CREATE TABLE IF NOT EXISTS mods ( \
|
||||||
|
Username tinytext PRIMARY KEY, \
|
||||||
|
DisplayName tinytext, \
|
||||||
|
Author tinytext,\
|
||||||
|
Versions longtext,\
|
||||||
|
OtherInfos longtext \
|
||||||
|
);");
|
||||||
|
|
||||||
|
// Insert example mod
|
||||||
|
// if (!(await db.exists("mods", "Name", "example"))) {
|
||||||
|
// console.debug("Creating default mod");
|
||||||
|
// db.exec(`INSERT INTO mods (Name, DisplayName, Author, Versions, OtherInfos) \
|
||||||
|
// VALUES ('example', 'Example mod', '${config.users.admin.username}', '', '');`);
|
||||||
|
// }
|
||||||
|
|
||||||
// Uers table
|
db.exec("DROP TABLE users");
|
||||||
db.exec("CREATE TABLE IF NOT EXISTS Users ( \
|
// Create users table
|
||||||
username TINYTEXT PRIMARY KEY, \
|
db.exec("CREATE TABLE IF NOT EXISTS users ( \
|
||||||
display_name TINYTEXT, \
|
Username tinytext PRIMARY KEY, \
|
||||||
email TINYTEXT,\
|
DisplayName tinytext, \
|
||||||
password TINYTEXT,\
|
Email tinytext,\
|
||||||
profile_picture LONGTEXT,\
|
Password tinytext,\
|
||||||
settings LONGTEXT, \
|
ProfilePicture longtext,\
|
||||||
);");
|
Preferences longtext, \
|
||||||
|
Favorites longtext \
|
||||||
// --- Mods ---
|
);");
|
||||||
|
|
||||||
// Mods table
|
|
||||||
db.exec(`CREATE TABLE IF NOT EXISTS Mods (
|
|
||||||
name TINYTEXT PRIMARY KEY,
|
|
||||||
display_name TINYTEXT NOT NULL,
|
|
||||||
author TINYTEXT NOT NULL,
|
|
||||||
description TINYTEXT NOT NULL,
|
|
||||||
|
|
||||||
FOREIGN KEY author REFERENCES Users(username)
|
|
||||||
);`);
|
|
||||||
|
|
||||||
// Mods complementary infos
|
|
||||||
db.exec(`CREATE TABLE IF NOT EXISTS ModInfos (
|
|
||||||
mod TINYTEXT PRIMARY KEY,
|
|
||||||
full_description TEXT NOT NULL,
|
|
||||||
license TINYTEXT,
|
|
||||||
custom_license TEXT,
|
|
||||||
links TEXT,
|
|
||||||
creation_date TINYTEXT NOT NULL,
|
|
||||||
downloads_count INT NOT NULL,
|
|
||||||
|
|
||||||
FOREIGN KEY mod REFERENCES Users(username)
|
|
||||||
);`);
|
|
||||||
|
|
||||||
// Mods tags
|
|
||||||
db.exec(`CREATE TABLE IF NOT EXISTS ModTags (
|
|
||||||
mod TINYTEXT NOT NULL,
|
|
||||||
tag TINYTEXT NOT NULL,
|
|
||||||
|
|
||||||
FOREIGN KEY mod REFERENCES Mods(name)
|
|
||||||
);`);
|
|
||||||
|
|
||||||
// Mods versions
|
|
||||||
db.exec(`CREATE TABLE IF NOT EXISTS ModVersions (
|
|
||||||
mod TINYTEXT NOT NULL,
|
|
||||||
version_number TINYTEXT NOT NULL,
|
|
||||||
channel TINYTEXT NOT NULL,
|
|
||||||
changelog TEXT NOT NULL,
|
|
||||||
release_date TINYTEXT NOT NULL,
|
|
||||||
game_version TINYTEXT NOT NULL,
|
|
||||||
platform TINYTEXT NOT NULL,
|
|
||||||
environment TINYTEXT NOT NULL,
|
|
||||||
url TINYTEXT NOT NULL,
|
|
||||||
|
|
||||||
FOREGIN KEY mod REFERENCES Mods(name)
|
|
||||||
);`);
|
|
||||||
|
|
||||||
// User favorites (mods)
|
|
||||||
db.exec(`CREATE TABLE IF NOT EXISTS UserFavoriteMods (
|
|
||||||
username TINYTEXT NOT NULL,
|
|
||||||
mod TINYTEXT NOT NULL,
|
|
||||||
|
|
||||||
FOREIGN KEY username REFERENCES Users(username),
|
|
||||||
FOREGIN KEY mod REFERENCES Mods(name)
|
|
||||||
);`);
|
|
||||||
|
|
||||||
|
// Insert default admin account
|
||||||
|
// if (!(await db.exists("users", "Username", config.users.admin.username))) {
|
||||||
|
// console.debug("Creating default admin user");
|
||||||
|
// db.exec(`INSERT INTO users (Username, DisplayName, Email, Password, ProfilePicture, Preferences, Favorites) \
|
||||||
|
// VALUES ('${config.users.admin.username}', 'Admin', '', '${config.users.admin.password}', '', '', '' );`);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getDatabase() {
|
function getDatabase() {
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,83 +1,23 @@
|
||||||
const { getModByName } = require("../services/modService");
|
const authService = require("../services/authService");
|
||||||
const { getModpackByName } = require("../services/modpackService");
|
|
||||||
const { getUserByName } = require("../services/userService");
|
|
||||||
const { verifyToken } = require("../utils/crypto");
|
|
||||||
const AppError = require("../utils/appError");
|
const AppError = require("../utils/appError");
|
||||||
|
|
||||||
|
|
||||||
async function authenticateToken(req) {
|
function authenticateToken(req, res, next) {
|
||||||
|
|
||||||
const token = req.header("Authorization");
|
const auth_header = req.headers["authorization"];
|
||||||
|
const token = auth_header && auth_header.split(' ')[1];
|
||||||
|
|
||||||
if (!token) {
|
if (token == null) {
|
||||||
throw new AppError(401, "Missing authorization header", "Unauthorized");
|
throw new AppError(401, "Unauthorized: missing or bad authorization header");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
req.token_infos = await verifyToken(token);
|
req.user = authService.verifyToken(token);
|
||||||
console.debug("Authorizing token from", req.token_infos);
|
next();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new AppError(403, "Forbidden: Error verifying the authorization token");
|
throw new AppError(403, "Forbidden: Error verifying the authorization token");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function authorizeModModification(req) {
|
module.exports = { authenticateToken }
|
||||||
|
|
||||||
// Auth token
|
|
||||||
await authenticateToken(req);
|
|
||||||
// Get mod infos
|
|
||||||
if (!req.params || req.params.id) {
|
|
||||||
throw new AppError(400, "No mod name was scpecified", "Bad request");
|
|
||||||
}
|
|
||||||
const mod_name = req.params.id;
|
|
||||||
const mod = getModByName(mod_name);
|
|
||||||
if (!mod) {
|
|
||||||
throw new AppError(404, "No mod was found with this name", "Not found");
|
|
||||||
}
|
|
||||||
// Authorize
|
|
||||||
if ( mod.author != req.token_infos.username) {
|
|
||||||
throw new AppError(401, "Mod author differs from current user", "Unauthorized");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function authorizeModpackModification(req) {
|
|
||||||
|
|
||||||
// Auth token
|
|
||||||
await authenticateToken(req);
|
|
||||||
// Get mod infos
|
|
||||||
if (!req.params || req.params.id) {
|
|
||||||
throw new AppError(400, "No mod name was scpecified", "Bad request");
|
|
||||||
}
|
|
||||||
const modpack_name = req.params.id;
|
|
||||||
const modpack = getModpackByName(modpack_name);
|
|
||||||
if (!modpack) {
|
|
||||||
throw new AppError(404, "No mod was found with this name", "Not found");
|
|
||||||
}
|
|
||||||
// Authorize
|
|
||||||
if ( modpack.author != req.token_infos.username) {
|
|
||||||
throw new AppError(401, "Mod author differs from current user", "Unauthorized");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function authorizeUserModification(req) {
|
|
||||||
|
|
||||||
// Auth token
|
|
||||||
await authenticateToken(req);
|
|
||||||
// Get mod infos
|
|
||||||
if (!req.params || req.params.id) {
|
|
||||||
throw new AppError(400, "No mod name was scpecified", "Bad request");
|
|
||||||
}
|
|
||||||
const user_name = req.params.id;
|
|
||||||
const user = getUserByName(user_name);
|
|
||||||
if (!user) {
|
|
||||||
throw new AppError(404, "No mod was found with this name", "Not found");
|
|
||||||
}
|
|
||||||
// Authorize
|
|
||||||
if ( user.username != req.token_infos.username) {
|
|
||||||
throw new AppError(401, "Mod author differs from current user", "Unauthorized");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = { authenticateToken, authorizeModModification, authorizeModpackModification, authorizeUserModification };
|
|
|
@ -1,12 +0,0 @@
|
||||||
const { getVersion } = require("../utils/configManager");
|
|
||||||
|
|
||||||
async function getVersion() {
|
|
||||||
|
|
||||||
const version = await getVersion();
|
|
||||||
const res = {
|
|
||||||
version: version
|
|
||||||
};
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { getVersion }
|
|
|
@ -3,16 +3,27 @@ const AppError = require('../utils/appError');
|
||||||
const db = getDatabase();
|
const db = getDatabase();
|
||||||
|
|
||||||
async function getAllMods() {
|
async function getAllMods() {
|
||||||
return db.query("SELECT name FROM Mods");
|
return db.query("SELECT * FROM mods");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getModByName(name) {
|
async function getModByName(name) {
|
||||||
return await db.query("SELECT name, display_name, author FROM Mods WHERE name = ?;", [name]);
|
try {
|
||||||
|
console.debug("Searching for", name);
|
||||||
|
const res = await db.query("SELECT * FROM mods WHERE Name = ?;", [name]);
|
||||||
|
if (res && res.length > 0) {
|
||||||
|
return res[0];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error in getModByName:", err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function exists(name) {
|
async function exists(name) {
|
||||||
return db.exists("Mods", "name", name);
|
return db.exists("mods", "Name", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createMod(mod_data) {
|
async function createMod(mod_data) {
|
||||||
|
@ -20,8 +31,8 @@ async function createMod(mod_data) {
|
||||||
const { name, displayName, author, versions, otherInfos } = mod_data;
|
const { name, displayName, author, versions, otherInfos } = mod_data;
|
||||||
const { description, links, tags, screenshots, license, changelogs, counts } = otherInfos;
|
const { description, links, tags, screenshots, license, changelogs, counts } = otherInfos;
|
||||||
|
|
||||||
await db.prepare("INSERT INTO mods (name, display_name, author) \
|
await db.prepare("INSERT INTO mods (Name, DisplayName, Author, Versions) \
|
||||||
VALUES (?, ?, ?, ?)", [name, displayName, author]);
|
VALUES (?, ?, ?, ?)", [name, displayName, author, versions]);
|
||||||
// db.prepare("INSERT INTO modsDescription (Name, Description, Links, Tags, Screenshots, License, Changelogs, Counts) \
|
// db.prepare("INSERT INTO modsDescription (Name, Description, Links, Tags, Screenshots, License, Changelogs, Counts) \
|
||||||
// VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [name, description, links, tags, screenshots, license, changelogs, counts]);
|
// VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [name, description, links, tags, screenshots, license, changelogs, counts]);
|
||||||
return;
|
return;
|
||||||
|
@ -29,7 +40,7 @@ async function createMod(mod_data) {
|
||||||
|
|
||||||
async function deleteMod(name) {
|
async function deleteMod(name) {
|
||||||
console.log("WARNING: using a WIP function : deleteMod (models/mods.js)");
|
console.log("WARNING: using a WIP function : deleteMod (models/mods.js)");
|
||||||
db.prepare("DELETE FROM Mods WHERE name = ?", [name]);
|
db.prepare("DELETE FROM mods WHERE Name = ?", [name]);
|
||||||
// db.prepare("DELETE FROM modsDescription WHERE Name = ?", [name]);
|
// db.prepare("DELETE FROM modsDescription WHERE Name = ?", [name]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,29 +7,52 @@ async function getAllUsers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUserByName(name) {
|
async function getUserByName(name) {
|
||||||
return await db.query("SELECT * FROM Users WHERE username = ?;", [name]);
|
try {
|
||||||
|
console.debug("Searching for", name);
|
||||||
|
const res = await db.query("SELECT * FROM users WHERE Username = ?;", [name]);
|
||||||
|
if (res && res.length > 0) {
|
||||||
|
return res[0];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error in getUserByName:", err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUserByEmail(email) {
|
async function getUserByEmail(email) {
|
||||||
return await db.query("SELECT * FROM Users WHERE email = ?;", [email]);
|
try {
|
||||||
|
console.debug("Searching for", email);
|
||||||
|
const res = await db.query("SELECT * FROM users WHERE Email = ?;", [email]);
|
||||||
|
if (res && res.length > 0) {
|
||||||
|
return res[0];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error in getUserByName:", err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function exists(name) {
|
async function exists(name) {
|
||||||
return db.exists("Users", "username", name);
|
return db.exists("users", "Username", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createUser(user_data) {
|
async function createUser(user_data) {
|
||||||
|
|
||||||
const { name, email, password, displayName, profilePicture, favorites, preferences } = user_data;
|
const { name, email, password, displayName, profilePicture, favorites, preferences } = user_data;
|
||||||
|
|
||||||
//TODO breakdown to handle partial updates
|
await db.prepare("INSERT INTO users (Username, Email, Password, DisplayName, ProfilePicture, Favorites, Preferences) \
|
||||||
await db.prepare("INSERT INTO Users (username, email, password, display_name, profile_picture, favorites, preferences) \
|
|
||||||
VALUES (?, ?, ?, ?)", [name, email, password, displayName, profilePicture, favorites, preferences]);
|
VALUES (?, ?, ?, ?)", [name, email, password, displayName, profilePicture, favorites, preferences]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteUser(name) {
|
async function deleteUser(name) {
|
||||||
await db.prepare("DELETE FROM Users WHERE username = ?", [name]);
|
db.prepare("DELETE FROM users WHERE Username = ?", [name]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,4 +68,4 @@ async function updateUser(user_data) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = { getAllUsers, getUserByName, getUserByEmail, createUser, deleteUser, exists }
|
module.exports = { getAllUsers, getUserByName, createUser, deleteUser, exists }
|
|
@ -3,8 +3,12 @@ const controller = require("../controllers/index");
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.get('/', (res, req) => {
|
||||||
|
console.debug("Triggered hello world");
|
||||||
|
controller.helloWorld(res, req);
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/version', async (res, req) => {
|
router.get('/version', (res, req) => {
|
||||||
controller.getVersion(res, req);
|
controller.getVersion(res, req);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
const Ajv = require("ajv");
|
|
||||||
const ajv = new Ajv();
|
|
||||||
|
|
||||||
// --- Schemas ---
|
|
||||||
|
|
||||||
const AuthUserSchema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
email: { type: 'string', format: 'email' },
|
|
||||||
password: { type: 'string', minLength: 3, maxLength: 30 },
|
|
||||||
},
|
|
||||||
required: ['email', 'password'],
|
|
||||||
additionalProperties: false
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateAuthUserData = ajv.compile(AuthUserSchema);
|
|
||||||
|
|
||||||
|
|
||||||
// --- Exports ---
|
|
||||||
|
|
||||||
module.exports = { validateAuthUserData, validateAuthNodeData };
|
|
|
@ -1,21 +0,0 @@
|
||||||
const Ajv = require("ajv");
|
|
||||||
const ajv = new Ajv();
|
|
||||||
|
|
||||||
// --- Schemas ---
|
|
||||||
//TODO
|
|
||||||
|
|
||||||
const newModSchema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
name: { type: 'string'},
|
|
||||||
},
|
|
||||||
required: ['name'],
|
|
||||||
additionalProperties: false
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateNewModData = ajv.compile(newModSchema);
|
|
||||||
|
|
||||||
|
|
||||||
// --- Exports ---
|
|
||||||
|
|
||||||
module.exports = { validateNewModData };
|
|
|
@ -1,21 +0,0 @@
|
||||||
const Ajv = require("ajv");
|
|
||||||
const ajv = new Ajv();
|
|
||||||
|
|
||||||
// --- Schemas ---
|
|
||||||
//TODO
|
|
||||||
|
|
||||||
const newModpackSchema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
name: { type: 'string'},
|
|
||||||
},
|
|
||||||
required: ['name'],
|
|
||||||
additionalProperties: false
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateNewModpackData = ajv.compile(newModpackSchema);
|
|
||||||
|
|
||||||
|
|
||||||
// --- Exports ---
|
|
||||||
|
|
||||||
module.exports = { validateNewModpackData };
|
|
|
@ -1,23 +0,0 @@
|
||||||
const Ajv = require("ajv");
|
|
||||||
const ajv = new Ajv();
|
|
||||||
|
|
||||||
// --- Schemas ---
|
|
||||||
//TODO
|
|
||||||
|
|
||||||
const newUserSchema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
email: { type: 'string', format: 'email' },
|
|
||||||
name: { type: 'string' },
|
|
||||||
password: { type: 'string', minLength: 3, maxLength: 30 },
|
|
||||||
},
|
|
||||||
required: ['name', 'email', 'password'],
|
|
||||||
additionalProperties: false
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateNewUserData = ajv.compile(newUserSchema);
|
|
||||||
|
|
||||||
|
|
||||||
// --- Exports ---
|
|
||||||
|
|
||||||
module.exports = { validateNewUserData };
|
|
|
@ -3,7 +3,7 @@ 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 configManager = require("../utils/configManager");
|
const configManager = require("../utils/configManager");
|
||||||
const validate = require("../utils/validate_legacy");
|
const validate = require("../utils/validate");
|
||||||
|
|
||||||
const JWT_Secret = configManager.getJWTSecret();
|
const JWT_Secret = configManager.getJWTSecret();
|
||||||
|
|
||||||
|
@ -45,10 +45,22 @@ async function login(identifier, password) {
|
||||||
return jwt.sign({ username: user[0].username, role: user[0].role }, await JWT_Secret);
|
return jwt.sign({ username: user[0].username, role: user[0].role }, await JWT_Secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function verifyToken(token) {
|
||||||
|
return new Promise( (resolve, reject) => {
|
||||||
|
jwt.verify( token, JWT_Secret, (err, user) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err);
|
||||||
|
} else {
|
||||||
|
resolve(user);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// function authorizeRole(user, roles) {
|
// function authorizeRole(user, roles) {
|
||||||
// if (!user || !roles.includes(user.role)) {
|
// if (!user || !roles.includes(user.role)) {
|
||||||
// throw new AppError(401, "Unauthorized: You don't have the necessary permissions to access this resource");
|
// throw new AppError(401, "Unauthorized: You don't have the necessary permissions to access this resource");
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
module.exports = { login };
|
module.exports = { login, verifyToken };
|
|
@ -1,7 +0,0 @@
|
||||||
const model = require("../models/index");
|
|
||||||
|
|
||||||
async function getVersion() {
|
|
||||||
return model.getVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { getVersion }
|
|
|
@ -1,6 +1,6 @@
|
||||||
const model = require("../models/mod");
|
const model = require("../models/mod");
|
||||||
const AppError = require("../utils/appError");
|
const AppError = require("../utils/appError");
|
||||||
const { validateModData } = require("../utils/validate_legacy");
|
const { validateModData } = require("../utils/validate");
|
||||||
const { mdToHtml } = require("../utils/convert");
|
const { mdToHtml } = require("../utils/convert");
|
||||||
const { sanitizeModData } = require("../utils/sanitize");
|
const { sanitizeModData } = require("../utils/sanitize");
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const model = require("../models/user");
|
const model = require("../models/user");
|
||||||
const AppError = require("../utils/appError");
|
const AppError = require("../utils/appError");
|
||||||
const { validateUserData } = require("../utils/validate_legacy");
|
const { validateUserData } = require("../utils/validate");
|
||||||
const { sanitizeUserData } = require("../utils/sanitize");
|
const { sanitizeUserData } = require("../utils/sanitize");
|
||||||
|
|
||||||
async function getAllUsers() {
|
async function getAllUsers() {
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
// --- 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 };
|
|
|
@ -1,32 +1,82 @@
|
||||||
// --- Imports ---
|
const mod_model = require("../models/mod");
|
||||||
|
const user_model = require("../models/user");
|
||||||
const AppError = require("./appError");
|
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;
|
||||||
|
|
||||||
// --- Functions ---
|
if (!not_null) {
|
||||||
|
console.debug("Item is missing expected fields:", mod_data);
|
||||||
|
throw new AppError(400, "Bad request", "Missing expected fields");
|
||||||
|
}
|
||||||
|
|
||||||
async function validateNewModData(mod_data) {
|
// Check fields format (check if sanitized)
|
||||||
|
const is_valid_name = /^[a-zA-Z0-9_]+$/.test(mod_data.name);
|
||||||
throw new AppError(501, "Not implemented");
|
const is_valid_displayName = true;
|
||||||
//TODO
|
// const is_valid_displayName = /^[a-zA-Z0-9_]+$/.test(mod_data.name); // Temporary
|
||||||
// try {
|
// const
|
||||||
// node_schemas.validateNewModData(node_data);
|
|
||||||
// } catch (err) {
|
const is_valid = is_valid_name && is_valid_displayName;
|
||||||
// throw new AppError(400, "Missing or invalid fields", "Bad request", err);
|
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 validateNewUserData(user_data) {
|
async function validateUserData(user_data) {
|
||||||
|
|
||||||
throw new AppError(501, "Not implemented");
|
throw new AppError(501, "Not implemented");
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
// try {
|
|
||||||
// node_schemas.validateNewUserData(node_data);
|
|
||||||
// } catch (err) {
|
|
||||||
// throw new AppError(400, "Missing or invalid fields", "Bad request", err);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
// 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) {
|
async function validateCretendials(identifier, password) {
|
||||||
|
@ -34,9 +84,6 @@ async function validateCretendials(identifier, password) {
|
||||||
throw new AppError(501, "Not implemented");
|
throw new AppError(501, "Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- Utils ---
|
|
||||||
|
|
||||||
async function isEmail(text) {
|
async function isEmail(text) {
|
||||||
const email_regex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
|
const email_regex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
|
||||||
return email_regex.test(text);
|
return email_regex.test(text);
|
||||||
|
@ -48,4 +95,4 @@ async function isID(text) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = { validateNewModData, validateNewUserData, isEmail, isID };
|
module.exports = { validateModData, validateUserData, isEmail, isID };
|
|
@ -1,98 +0,0 @@
|
||||||
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…
Reference in a new issue