mirror of
https://github.com/Zandercraft/TechnicFlux.git
synced 2026-10-28 04:29:20 +00:00
Move different schemas and their related functions into their own modules.
This commit is contained in:
20
.env.example
20
.env.example
@@ -11,17 +11,17 @@
|
||||
# See https://www.mongodb.com/docs/manual/reference/connection-string/
|
||||
MONGODB_CONN_STRING="mongodb://localhost:27017/technicflux"
|
||||
|
||||
# (REQUIRED) Admin Username and Password
|
||||
# The username and password for the administrator account. CHANGE THIS!
|
||||
ADMIN_USER="flux"
|
||||
ADMIN_PASS="flux"
|
||||
|
||||
# (REQUIRED) The name of your TechnicFlux instance.
|
||||
NAME="A TechnicFlux Instance"
|
||||
|
||||
# (REQUIRED) The public hostname of the website (i.e. the full domain name without any path, http://, or https://)
|
||||
HOST="example.com"
|
||||
|
||||
# (REQUIRED) Admin Username and Password
|
||||
# The username and password for the administrator account. CHANGE THIS!
|
||||
ADMIN_USER="flux"
|
||||
ADMIN_PASS="flux"
|
||||
|
||||
# (REQUIRED) Solder API Key
|
||||
# 1. Go to https://www.technicpack.net/
|
||||
# 2. Sign into your account and navigate to Edit My Profile
|
||||
@@ -34,12 +34,18 @@ API_KEY=""
|
||||
# Unset behaviour: You will need to specify the author every time.
|
||||
AUTHOR_NAME="John Doe"
|
||||
|
||||
# --- Rate Limiting ---
|
||||
# With the default values, it would take approximately an average of 3.9462372476248917e+28 minutes*
|
||||
# to brute-force a single API key. If you want to increase the limit for other reasons (performance, etc.)
|
||||
# or are encountering issues and need to increase it, feel free to do so.
|
||||
# * This value may not be accurate. As per our license, I place no warranty or guaruntee on it.
|
||||
|
||||
# (Optional) API Rate-limit Requests
|
||||
# The number of requests that can be made to the API by one IP address within the set window before it will block them.
|
||||
# Default: 1000
|
||||
# Unset behaviour: Defaults to 1000
|
||||
API_RATE_REQUESTS=1000
|
||||
|
||||
# (Optional) API Rate-limit Window
|
||||
# The amount of time (in milliseconds) that the request limit is applied to.
|
||||
# Default: 60000
|
||||
# Unset behaviour: Defaults to 60000
|
||||
API_RATE_WINDOW=60000
|
||||
|
||||
2
bin/www
2
bin/www
@@ -34,7 +34,7 @@ for (let variable of required_variables) {
|
||||
const app = require('../app').app;
|
||||
const debug = require('debug')('technicflux:server');
|
||||
const http = require('http');
|
||||
const database = require('../database')
|
||||
const database = require('../database/database')
|
||||
|
||||
/**
|
||||
* Get port from environment and store in Express.
|
||||
|
||||
523
database.js
523
database.js
@@ -1,523 +0,0 @@
|
||||
const debug = require('debug')('technicflux:server')
|
||||
const mongoose = require('mongoose')
|
||||
const { SchemaTypes } = require('mongoose')
|
||||
const bcrypt = require('bcryptjs')
|
||||
const Schema = mongoose.Schema
|
||||
|
||||
// --- Schemas ---
|
||||
const userSchema = new Schema({
|
||||
username: {
|
||||
type: String,
|
||||
unique: true
|
||||
},
|
||||
display_name: String,
|
||||
password: String,
|
||||
created_on: Date,
|
||||
login_history: [{ timestamp: Date, userAgent: String }]
|
||||
})
|
||||
|
||||
const apiKeySchema = new Schema({
|
||||
owner: { type: SchemaTypes.ObjectId, ref: 'technicflux_users' },
|
||||
key: String,
|
||||
name: String,
|
||||
created_at: Date
|
||||
})
|
||||
|
||||
const modpackSchema = new Schema({
|
||||
name: String,
|
||||
display_name: String,
|
||||
url: String,
|
||||
recommended: String,
|
||||
latest: String,
|
||||
builds: [{ type: SchemaTypes.ObjectId, ref: 'technicflux_builds' }],
|
||||
owners: [{ type: SchemaTypes.ObjectId, ref: 'technicflux_users' }],
|
||||
contributors: [{ type: SchemaTypes.ObjectId, ref: 'technicflux_users' }]
|
||||
})
|
||||
|
||||
const modSchema = new Schema({
|
||||
mod_id: Number,
|
||||
name: String,
|
||||
pretty_name: String,
|
||||
version: String,
|
||||
mc_version: String,
|
||||
type: String, // Can be forgemod, neoforgemod, fabricmod, quiltmod, <modloadernamemod>, or modloader(handled separately)
|
||||
md5: String,
|
||||
author: String,
|
||||
description: String,
|
||||
link: String,
|
||||
donate: String,
|
||||
url: String,
|
||||
filesize: Number
|
||||
})
|
||||
|
||||
const buildSchema = new Schema({
|
||||
modpack: { type: SchemaTypes.ObjectId, ref: 'technicflux_modpacks' },
|
||||
version: String,
|
||||
minecraft: String,
|
||||
java: String,
|
||||
memory: Number,
|
||||
forge: String,
|
||||
mods: [{ type: SchemaTypes.ObjectId, ref: 'technicflux_mods' }]
|
||||
})
|
||||
|
||||
// --- Models ---
|
||||
const User = mongoose.model('technicflux_users', userSchema)
|
||||
const APIKey = mongoose.model('technicflux_keys', apiKeySchema)
|
||||
const Modpack = mongoose.model('technicflux_modpacks', modpackSchema)
|
||||
const Mod = mongoose.model('technicflux_mods', modSchema)
|
||||
const Build = mongoose.model('technicflux_builds', buildSchema)
|
||||
|
||||
// --- Functions ---
|
||||
|
||||
exports.connectToDB = (connectionString) => {
|
||||
debug('Connecting to MongoDB database...')
|
||||
mongoose.connect(connectionString)
|
||||
debug('Connected to database.')
|
||||
}
|
||||
|
||||
// --- User-Related Functions ---
|
||||
|
||||
/*
|
||||
* Creates a new user with the given information.
|
||||
*/
|
||||
exports.createUser = (uUsername, uDisplayName, uPassword) => {
|
||||
// Encrypt the password using bcrypt and save user
|
||||
return bcrypt.genSalt(10).then((Salt) => {
|
||||
return bcrypt.hash(uPassword, Salt).then((hash) => {
|
||||
// Create a user object
|
||||
const newUser = new User({
|
||||
username: uUsername,
|
||||
display_name: uDisplayName,
|
||||
password: hash
|
||||
})
|
||||
|
||||
// Commit it to the database
|
||||
return newUser.save().then((user) => {
|
||||
process.stdout.write(`Successfully added new user ${user.username}\n`)
|
||||
return user
|
||||
}).catch((reason) => {
|
||||
process.stdout.write(`ERROR (when saving new user): ${reason}\n`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed password
|
||||
process.stdout.write(`ERROR (while hashing password): ${err}`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed object salt
|
||||
process.stdout.write(`ERROR (while generating password salt): ${err}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the user with the provided id.
|
||||
*/
|
||||
exports.getUserById = (uId) => {
|
||||
// Fetch information about the user with the given id
|
||||
return User.findOne({ _id: uId }).exec().then((user) => {
|
||||
// User found.
|
||||
return user
|
||||
}).catch((reason) => {
|
||||
// No user found with this id.
|
||||
console.log(reason)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the user with the provided username.
|
||||
*/
|
||||
exports.getUserByUsername = (uUsername) => {
|
||||
// Fetch information about the user with the given username
|
||||
return User.findOne({ username: uUsername }).exec().then((user) => {
|
||||
// User found.
|
||||
return user
|
||||
}).catch((reason) => {
|
||||
// No user found with this username.
|
||||
console.log(reason)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets an array of all existing users.
|
||||
*/
|
||||
exports.getAllUsers = () => {
|
||||
// Fetch an array of all users
|
||||
return User.find({ }).exec().then((users) => {
|
||||
// Users found.
|
||||
return users
|
||||
}).catch((reason) => {
|
||||
console.log(reason)
|
||||
// Error retrieving users.
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the corresponding password matches that of the provided username.
|
||||
*/
|
||||
exports.authUser = (uUsername, uPassword, logHistory = false, uAgent = 'Unknown') => {
|
||||
// Fetch information about the user with the given username
|
||||
return User.findOne({ username: uUsername }).exec().then((user) => {
|
||||
// User found. Check password.
|
||||
return bcrypt.compare(uPassword, user.password).then(async (isMatch) => {
|
||||
// Check if it is a match
|
||||
if (isMatch) {
|
||||
// Update the user's login history.
|
||||
if (logHistory) {
|
||||
const newLogin = { timestamp: new Date(), userAgent: String(uAgent) }
|
||||
|
||||
// Add the new login to the user's login history
|
||||
return await User.updateOne(
|
||||
{ username: uUsername },
|
||||
{ $push: { login_history: newLogin } }
|
||||
).exec().then(() => {
|
||||
// Auth was successful and login history updated.
|
||||
user.login_history.push(newLogin)
|
||||
return [true, user]
|
||||
}).catch((reason) => {
|
||||
user.login_history.push(newLogin)
|
||||
// Auth was successful, but failed to update the user's login history.
|
||||
process.stdout.write(`ERROR (while updating user's login history): ${reason}\n`)
|
||||
return [true, user]
|
||||
})
|
||||
} else {
|
||||
// Auth was successful. Return user without logging to user's history.
|
||||
return [true, user]
|
||||
}
|
||||
} else {
|
||||
// User's authentication was invalid.
|
||||
return [false, undefined]
|
||||
}
|
||||
})
|
||||
}).catch((reason) => {
|
||||
console.log(reason)
|
||||
// No user found with this username.
|
||||
return [false]
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the user with the given username.
|
||||
*/
|
||||
exports.updateUser = (uUsername, object) => {
|
||||
return bcrypt.genSalt(10).then((Salt) => {
|
||||
return bcrypt.hash(object.password, Salt).then((hash) => {
|
||||
if (object.password.length > 0) {
|
||||
object.password = hash
|
||||
} else {
|
||||
object.password = object.old_password
|
||||
}
|
||||
delete object.old_password
|
||||
|
||||
// Update User
|
||||
return User.updateOne(
|
||||
{ username: uUsername },
|
||||
{ $set: object }
|
||||
).exec().then(() => {
|
||||
// Updated user successfully
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to update the user
|
||||
process.stdout.write(`ERROR (while updating user): ${reason}\n`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed password
|
||||
process.stdout.write(`ERROR (while hashing password): ${err}`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed object salt
|
||||
process.stdout.write(`ERROR (while generating password salt): ${err}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
// --- API-Key-Related Functions
|
||||
|
||||
/*
|
||||
* Creates a new api key with the given information.
|
||||
*/
|
||||
exports.createAPIKey = (kOwner, kKey, kName) => {
|
||||
// Encrypt the password using bcrypt and save user
|
||||
return bcrypt.genSalt(10).then((Salt) => {
|
||||
return bcrypt.hash(kKey, Salt).then((hash) => {
|
||||
// Create an APIKey object
|
||||
const newKey = new APIKey({
|
||||
owner: kOwner,
|
||||
key: hash,
|
||||
name: kName,
|
||||
created_at: new Date()
|
||||
})
|
||||
|
||||
// Commit it to the database
|
||||
return newKey.save().then((key) => {
|
||||
process.stdout.write(`Successfully added new API key '${kName}' for ${kOwner}\n`)
|
||||
return key
|
||||
}).catch((reason) => {
|
||||
process.stdout.write(`ERROR (when saving new API key): ${reason}\n`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed api key
|
||||
process.stdout.write(`ERROR (while hashing key): ${err}`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed object salt
|
||||
process.stdout.write(`ERROR (while generating api key salt): ${err}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the corresponding password matches that of the provided username.
|
||||
*/
|
||||
exports.authAPIKey = (uKey) => {
|
||||
// Fetch information about the user with the given username
|
||||
return APIKey.find({ }).exec().then(async (keys) => {
|
||||
// Check if any of the keys match.
|
||||
let valid = [false, undefined]
|
||||
for (const key of keys) {
|
||||
await bcrypt.compare(uKey, key.key).then((isMatch) => {
|
||||
// Check if it is a match
|
||||
if (isMatch) {
|
||||
// The key matched.
|
||||
valid = [true, key]
|
||||
}
|
||||
})
|
||||
}
|
||||
return valid
|
||||
}).catch((reason) => {
|
||||
console.log(reason)
|
||||
// DB error
|
||||
debug('ERROR (DB): Could not fetch API keys.')
|
||||
return [false, undefined]
|
||||
})
|
||||
}
|
||||
|
||||
exports.getAPIKeysByOwner = (mOwner) => {
|
||||
return APIKey.find({ owner: mOwner }).populate('owner').exec().then((keys) => {
|
||||
// API Keys found.
|
||||
return keys
|
||||
}).catch((reason) => {
|
||||
// No API keys found for this owner.
|
||||
debug(`ERROR (DB): Failed to find any API keys with this owner because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.deleteAPIKey = (kId) => {
|
||||
return APIKey.deleteOne({ _id: kId }).exec().then(() => {
|
||||
// Successfully deleted this api key
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to delete the api key
|
||||
debug(`ERROR (DB): Failed to delete API Key '${kId}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
// --- Modpack-Related Functions ---
|
||||
exports.createModpack = (mSlug, mDisplayName, mOwner) => {
|
||||
// Create a modpack object
|
||||
const newModpack = new Modpack({
|
||||
name: mSlug,
|
||||
display_name: mDisplayName,
|
||||
owners: [mOwner]
|
||||
})
|
||||
|
||||
// Commit it to the database
|
||||
return newModpack.save().then((modpack) => {
|
||||
// Modpack successfully created
|
||||
debug(`Successfully added new project ${modpack.display_name}: ${modpack.name}\n`)
|
||||
return modpack
|
||||
}).catch((reason) => {
|
||||
// Modpack failed to create
|
||||
debug(`ERROR (DB: when saving new modpack): ${reason}\n`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModpackBySlug = (mSlug) => {
|
||||
return Modpack.findOne({ name: mSlug }).populate('owners').populate('contributors').populate('builds').exec().then((modpack) => {
|
||||
// Modpack found
|
||||
return modpack
|
||||
}).catch((reason) => {
|
||||
// No modpack found with this slug
|
||||
debug(`ERROR (DB): Failed to find a modpack with this slug because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModpacksByOwner = (mOwner) => {
|
||||
return Modpack.find({ owners: mOwner }).populate('owners').populate('contributors').populate('builds').exec().then((modpacks) => {
|
||||
// Modpacks found.
|
||||
return modpacks
|
||||
}).catch((reason) => {
|
||||
// No modpacks found for this owner.
|
||||
debug(`ERROR (DB): Failed to find any modpacks with this owner because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModpacksByContributor = (mContributor) => {
|
||||
return Modpack.find({ contributors: mContributor }).populate('owners').populate('contributors').populate('builds').exec().then((modpacks) => {
|
||||
// Modpacks found.
|
||||
return modpacks
|
||||
}).catch((reason) => {
|
||||
// No modpacks found for this collaborator.
|
||||
debug(`ERROR (DB): Failed to find any modpacks with this contributor because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getAllModpacks = () => {
|
||||
// Fetch an array of all modpacks
|
||||
return Modpack.find({}).populate('owners').populate('contributors').populate('builds').exec().then((modpacks) => {
|
||||
// Modpacks found
|
||||
return modpacks
|
||||
}).catch((reason) => {
|
||||
// Failed to get any modpacks.
|
||||
debug(`ERROR (DB): Failed to fetch any modpacks because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.updateModpack = (mSlug, mObject) => {
|
||||
return Modpack.updateOne(
|
||||
{ name: mSlug },
|
||||
{ $set: mObject }
|
||||
).exec().then(() => {
|
||||
// Successfully updated the modpack
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to update the modpack
|
||||
debug(`ERROR (DB): Failed to update modpack '${mSlug}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.deleteModpack = (mSlug) => {
|
||||
return Modpack.deleteOne({ name: mSlug }).exec().then(() => {
|
||||
// Successfully deleted this modpack
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to delete the modpack
|
||||
debug(`ERROR (DB): Failed to delete modpack '${mSlug}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
// --- Mod-Related Functions ---
|
||||
exports.getModBySlug = (mSlug) => {
|
||||
return Mod.find({ name: mSlug }).exec().then((mods) => {
|
||||
if (mods === null || mods.length === 0) {
|
||||
// Mod not found
|
||||
return null
|
||||
} else {
|
||||
// Mod found
|
||||
return {
|
||||
id: mods[0].mod_id,
|
||||
name: mods[0].name,
|
||||
pretty_name: mods[0].pretty_name,
|
||||
author: mods[0].author,
|
||||
description: mods[0].description,
|
||||
link: mods[0].link,
|
||||
versions: mods.map((modVersion) => modVersion.version)
|
||||
}
|
||||
}
|
||||
}).catch((reason) => {
|
||||
// No mod found with this slug
|
||||
debug(`ERROR (DB): Failed to find a mod with slug '${mSlug}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModVersion = (mSlug, mVersion) => {
|
||||
return Mod.findOne({ name: mSlug, version: mVersion }).exec().then((mod) => {
|
||||
// Mod found
|
||||
return mod
|
||||
}).catch((reason) => {
|
||||
// No mod found with this slug and version
|
||||
debug(`ERROR (DB): Failed to find a mod '${mSlug}:${mVersion}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModsByType = (mType) => {
|
||||
return Mod.find({ type: mType }).exec().then((mods) => {
|
||||
// Mods found
|
||||
return mods
|
||||
}).catch((reason) => {
|
||||
// No mods found with this modloader
|
||||
debug(`ERROR (DB): Failed to find a mod with modloader '${mType}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModsByMinecraftVersion = (mVersion) => {
|
||||
return Mod.find({ mc_version: mVersion }).exec().then((mods) => {
|
||||
// Mods found
|
||||
return mods
|
||||
}).catch((reason) => {
|
||||
// No mods found with this Minecraft version.
|
||||
debug(`ERROR (DB): Failed to find a mod with Minecraft version '${mVersion}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModsByMinecraftAndLoaderVersion = (mVersion, mType) => {
|
||||
return Mod.find({ mc_version: mVersion, type: mType }).exec().then((mods) => {
|
||||
// Mods found
|
||||
return mods
|
||||
}).catch((reason) => {
|
||||
// No mods found with this Minecraft and modloader version.
|
||||
debug(`ERROR (DB): Failed to find a mod with Minecraft version '${mVersion}' and modloader version '${mType}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getAllMods = () => {
|
||||
return Mod.find({}).exec().then((mods) => {
|
||||
// Mods found
|
||||
return mods
|
||||
}).catch((reason) => {
|
||||
// No mods found
|
||||
debug(`ERROR (DB): Failed to find any mods because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.updateMod = (mSlug, mObject) => {
|
||||
return Mod.updateOne(
|
||||
{ name: mSlug },
|
||||
{ $set: mObject }
|
||||
).exec().then(() => {
|
||||
// Successfully updated the modpack
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to update the modpack
|
||||
debug(`ERROR (DB): Failed to update modpack '${mSlug}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.deleteModpack = (mSlug) => {
|
||||
return Modpack.deleteOne({ name: mSlug }).exec().then(() => {
|
||||
// Successfully deleted this modpack
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to delete the modpack
|
||||
debug(`ERROR (DB): Failed to delete modpack '${mSlug}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
// --- Modloader-Related Functions ---
|
||||
|
||||
// --- Build-Related Functions ---
|
||||
101
database/api_key.js
Normal file
101
database/api_key.js
Normal file
@@ -0,0 +1,101 @@
|
||||
const debug = require('debug')('technicflux:server')
|
||||
const mongoose = require('mongoose')
|
||||
const bcrypt = require('bcryptjs')
|
||||
const { SchemaTypes } = require('mongoose')
|
||||
const Schema = mongoose.Schema
|
||||
|
||||
// --- Schema ---
|
||||
const apiKeySchema = new Schema({
|
||||
owner: { type: SchemaTypes.ObjectId, ref: 'technicflux_users' },
|
||||
key: String,
|
||||
name: String,
|
||||
created_at: Date
|
||||
})
|
||||
|
||||
// --- Model ---
|
||||
exports.APIKey = mongoose.model('technicflux_keys', apiKeySchema)
|
||||
|
||||
// --- Related Functions ---
|
||||
|
||||
/*
|
||||
* Creates a new api key with the given information.
|
||||
*/
|
||||
exports.createAPIKey = (kOwner, kKey, kName) => {
|
||||
// Encrypt the password using bcrypt and save user
|
||||
return bcrypt.genSalt(10).then((Salt) => {
|
||||
return bcrypt.hash(kKey, Salt).then((hash) => {
|
||||
// Create an APIKey object
|
||||
const newKey = new exports.APIKey({
|
||||
owner: kOwner,
|
||||
key: hash,
|
||||
name: kName,
|
||||
created_at: new Date()
|
||||
})
|
||||
|
||||
// Commit it to the database
|
||||
return newKey.save().then((key) => {
|
||||
process.stdout.write(`Successfully added new API key '${kName}' for ${kOwner}\n`)
|
||||
return key
|
||||
}).catch((reason) => {
|
||||
process.stdout.write(`ERROR (when saving new API key): ${reason}\n`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed api key
|
||||
process.stdout.write(`ERROR (while hashing key): ${err}`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed object salt
|
||||
process.stdout.write(`ERROR (while generating api key salt): ${err}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the corresponding password matches that of the provided username.
|
||||
*/
|
||||
exports.authAPIKey = (uKey) => {
|
||||
// Fetch information about the user with the given username
|
||||
return exports.APIKey.find({ }).exec().then(async (keys) => {
|
||||
// Check if any of the keys match.
|
||||
let valid = [false, undefined]
|
||||
for (const key of keys) {
|
||||
await bcrypt.compare(uKey, key.key).then((isMatch) => {
|
||||
// Check if it is a match
|
||||
if (isMatch) {
|
||||
// The key matched.
|
||||
valid = [true, key]
|
||||
}
|
||||
})
|
||||
}
|
||||
return valid
|
||||
}).catch((reason) => {
|
||||
console.log(reason)
|
||||
// DB error
|
||||
debug('ERROR (DB): Could not fetch API keys.')
|
||||
return [false, undefined]
|
||||
})
|
||||
}
|
||||
|
||||
exports.getAPIKeysByOwner = (mOwner) => {
|
||||
return exports.APIKey.find({ owner: mOwner }).populate('owner').exec().then((keys) => {
|
||||
// API Keys found.
|
||||
return keys
|
||||
}).catch((reason) => {
|
||||
// No API keys found for this owner.
|
||||
debug(`ERROR (DB): Failed to find any API keys with this owner because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.deleteAPIKey = (kId) => {
|
||||
return exports.APIKey.deleteOne({ _id: kId }).exec().then(() => {
|
||||
// Successfully deleted this api key
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to delete the api key
|
||||
debug(`ERROR (DB): Failed to delete API Key '${kId}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
20
database/build.js
Normal file
20
database/build.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const debug = require('debug')('technicflux:server')
|
||||
const mongoose = require('mongoose')
|
||||
const { SchemaTypes } = require('mongoose')
|
||||
const Schema = mongoose.Schema
|
||||
|
||||
// --- Schema ---
|
||||
const buildSchema = new Schema({
|
||||
modpack: { type: SchemaTypes.ObjectId, ref: 'technicflux_modpacks' },
|
||||
version: String,
|
||||
minecraft: String,
|
||||
java: String,
|
||||
memory: Number,
|
||||
forge: String,
|
||||
mods: [{ type: SchemaTypes.ObjectId, ref: 'technicflux_mods' }]
|
||||
})
|
||||
|
||||
// --- Model ---
|
||||
exports.Build = mongoose.model('technicflux_builds', buildSchema)
|
||||
|
||||
// --- Related Functions ---
|
||||
11
database/counter.js
Normal file
11
database/counter.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const mongoose = require('mongoose')
|
||||
const Schema = mongoose.Schema
|
||||
|
||||
// --- Incremental Counter ---
|
||||
// Used for tracking the value of fields
|
||||
const CounterSchema = Schema({
|
||||
_id: {type: String, required: true},
|
||||
seq: { type: Number, default: 0 }
|
||||
});
|
||||
|
||||
exports.Counter = mongoose.model('technicflux_modcounter', CounterSchema);
|
||||
18
database/database.js
Normal file
18
database/database.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const debug = require('debug')('technicflux:server')
|
||||
const mongoose = require('mongoose')
|
||||
|
||||
// --- Functions ---
|
||||
|
||||
exports.connectToDB = (connectionString) => {
|
||||
debug('Connecting to MongoDB database...')
|
||||
mongoose.connect(connectionString)
|
||||
debug('Connected to database.')
|
||||
}
|
||||
|
||||
// Schema Modules
|
||||
exports.counter = require('./counter')
|
||||
exports.user = require('./user')
|
||||
exports.apiKey = require('./api_key')
|
||||
exports.modpack = require('./modpack')
|
||||
exports.mod = require('./mod')
|
||||
exports.build = require('./build')
|
||||
145
database/mod.js
Normal file
145
database/mod.js
Normal file
@@ -0,0 +1,145 @@
|
||||
const debug = require('debug')('technicflux:server')
|
||||
const mongoose = require('mongoose')
|
||||
const database = require('./database')
|
||||
const Schema = mongoose.Schema
|
||||
|
||||
// --- Schema ---
|
||||
const modSchema = new Schema({
|
||||
mod_id: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
name: String,
|
||||
pretty_name: String,
|
||||
version: String,
|
||||
mc_version: String,
|
||||
type: String, // Can be forgemod, neoforgemod, fabricmod, quiltmod, <modloadernamemod>, or modloader(handled separately)
|
||||
md5: String,
|
||||
author: String,
|
||||
description: String,
|
||||
link: String,
|
||||
donate: String,
|
||||
url: String,
|
||||
filesize: Number
|
||||
})
|
||||
|
||||
// Handle incremental updates of the mod_id
|
||||
modSchema.pre('save', (next) => {
|
||||
let doc = this;
|
||||
database.counter.Counter.findByIdAndUpdate({_id: 'modId'}, {$inc: { seq: 1 }}, (error, counter) => {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
doc.mod_id = counter.seq
|
||||
next()
|
||||
})
|
||||
})
|
||||
|
||||
// --- Model ---
|
||||
exports.Mod = mongoose.model('technicflux_mods', modSchema)
|
||||
|
||||
// --- Related Functions ---
|
||||
|
||||
exports.getModBySlug = (mSlug) => {
|
||||
return exports.Mod.find({ name: mSlug }).exec().then((mods) => {
|
||||
if (mods === null || mods.length === 0) {
|
||||
// Mod not found
|
||||
return null
|
||||
} else {
|
||||
// Mod found
|
||||
return {
|
||||
id: mods[0].mod_id,
|
||||
name: mods[0].name,
|
||||
pretty_name: mods[0].pretty_name,
|
||||
author: mods[0].author,
|
||||
description: mods[0].description,
|
||||
link: mods[0].link,
|
||||
versions: mods.map((modVersion) => modVersion.version)
|
||||
}
|
||||
}
|
||||
}).catch((reason) => {
|
||||
// No mod found with this slug
|
||||
debug(`ERROR (DB): Failed to find a mod with slug '${mSlug}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModVersion = (mSlug, mVersion) => {
|
||||
return exports.Mod.findOne({ name: mSlug, version: mVersion }).exec().then((mod) => {
|
||||
// Mod found
|
||||
return mod
|
||||
}).catch((reason) => {
|
||||
// No mod found with this slug and version
|
||||
debug(`ERROR (DB): Failed to find a mod '${mSlug}:${mVersion}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModsByType = (mType) => {
|
||||
return exports.Mod.find({ type: mType }).exec().then((mods) => {
|
||||
// Mods found
|
||||
return mods
|
||||
}).catch((reason) => {
|
||||
// No mods found with this modloader
|
||||
debug(`ERROR (DB): Failed to find a mod with modloader '${mType}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModsByMinecraftVersion = (mVersion) => {
|
||||
return exports.Mod.find({ mc_version: mVersion }).exec().then((mods) => {
|
||||
// Mods found
|
||||
return mods
|
||||
}).catch((reason) => {
|
||||
// No mods found with this Minecraft version.
|
||||
debug(`ERROR (DB): Failed to find a mod with Minecraft version '${mVersion}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModsByMinecraftAndLoaderVersion = (mVersion, mType) => {
|
||||
return exports.Mod.find({ mc_version: mVersion, type: mType }).exec().then((mods) => {
|
||||
// Mods found
|
||||
return mods
|
||||
}).catch((reason) => {
|
||||
// No mods found with this Minecraft and modloader version.
|
||||
debug(`ERROR (DB): Failed to find a mod with Minecraft version '${mVersion}' and modloader version '${mType}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getAllMods = () => {
|
||||
return exports.Mod.find({}).exec().then((mods) => {
|
||||
// Mods found
|
||||
return mods
|
||||
}).catch((reason) => {
|
||||
// No mods found
|
||||
debug(`ERROR (DB): Failed to find any mods because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.updateMod = (mSlug, mObject) => {
|
||||
return exports.Mod.updateOne(
|
||||
{ name: mSlug },
|
||||
{ $set: mObject }
|
||||
).exec().then(() => {
|
||||
// Successfully updated the modpack
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to update the modpack
|
||||
debug(`ERROR (DB): Failed to update modpack '${mSlug}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.deleteMod = (mSlug) => {
|
||||
return exports.Mod.deleteOne({ name: mSlug }).exec().then(() => {
|
||||
// Successfully deleted this mod
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to delete the mod
|
||||
debug(`ERROR (DB): Failed to delete mod '${mSlug}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
113
database/modpack.js
Normal file
113
database/modpack.js
Normal file
@@ -0,0 +1,113 @@
|
||||
const debug = require('debug')('technicflux:server')
|
||||
const mongoose = require('mongoose')
|
||||
const { SchemaTypes } = require('mongoose')
|
||||
const Schema = mongoose.Schema
|
||||
|
||||
// --- Schema ---
|
||||
const modpackSchema = new Schema({
|
||||
name: String,
|
||||
display_name: String,
|
||||
url: String,
|
||||
recommended: String,
|
||||
latest: String,
|
||||
builds: [{ type: SchemaTypes.ObjectId, ref: 'technicflux_builds' }],
|
||||
owners: [{ type: SchemaTypes.ObjectId, ref: 'technicflux_users' }],
|
||||
contributors: [{ type: SchemaTypes.ObjectId, ref: 'technicflux_users' }],
|
||||
admin: Boolean // whether the pack is owned by the admin user.
|
||||
})
|
||||
|
||||
// --- Model ---
|
||||
exports.Modpack = mongoose.model('technicflux_modpacks', modpackSchema)
|
||||
|
||||
// --- Related Functions ---
|
||||
|
||||
exports.createModpack = (mSlug, mDisplayName, mOwner, mAdmin) => {
|
||||
// Create a modpack object
|
||||
const newModpack = new exports.Modpack({
|
||||
name: mSlug,
|
||||
display_name: mDisplayName,
|
||||
owners: [mOwner],
|
||||
admin: mAdmin
|
||||
})
|
||||
|
||||
// Commit it to the database
|
||||
return newModpack.save().then((modpack) => {
|
||||
// Modpack successfully created
|
||||
debug(`Successfully added new project ${modpack.display_name}: ${modpack.name}\n`)
|
||||
return modpack
|
||||
}).catch((reason) => {
|
||||
// Modpack failed to create
|
||||
debug(`ERROR (DB: when saving new modpack): ${reason}\n`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModpackBySlug = (mSlug) => {
|
||||
return exports.Modpack.findOne({ name: mSlug }).populate('owners').populate('contributors').populate('builds').exec().then((modpack) => {
|
||||
// Modpack found
|
||||
return modpack
|
||||
}).catch((reason) => {
|
||||
// No modpack found with this slug
|
||||
debug(`ERROR (DB): Failed to find a modpack with this slug because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModpacksByOwner = (mOwner) => {
|
||||
return exports.Modpack.find({ owners: mOwner }).populate('owners').populate('contributors').populate('builds').exec().then((modpacks) => {
|
||||
// Modpacks found.
|
||||
return modpacks
|
||||
}).catch((reason) => {
|
||||
// No modpacks found for this owner.
|
||||
debug(`ERROR (DB): Failed to find any modpacks with this owner because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getModpacksByContributor = (mContributor) => {
|
||||
return exports.Modpack.find({ contributors: mContributor }).populate('owners').populate('contributors').populate('builds').exec().then((modpacks) => {
|
||||
// Modpacks found.
|
||||
return modpacks
|
||||
}).catch((reason) => {
|
||||
// No modpacks found for this collaborator.
|
||||
debug(`ERROR (DB): Failed to find any modpacks with this contributor because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.getAllModpacks = () => {
|
||||
// Fetch an array of all modpacks
|
||||
return exports.Modpack.find({}).populate('owners').populate('contributors').populate('builds').exec().then((modpacks) => {
|
||||
// Modpacks found
|
||||
return modpacks
|
||||
}).catch((reason) => {
|
||||
// Failed to get any modpacks.
|
||||
debug(`ERROR (DB): Failed to fetch any modpacks because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.updateModpack = (mSlug, mObject) => {
|
||||
return exports.Modpack.updateOne(
|
||||
{ name: mSlug },
|
||||
{ $set: mObject }
|
||||
).exec().then(() => {
|
||||
// Successfully updated the modpack
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to update the modpack
|
||||
debug(`ERROR (DB): Failed to update modpack '${mSlug}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.deleteModpack = (mSlug) => {
|
||||
return exports.Modpack.deleteOne({ name: mSlug }).exec().then(() => {
|
||||
// Successfully deleted this modpack
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to delete the modpack
|
||||
debug(`ERROR (DB): Failed to delete modpack '${mSlug}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
192
database/user.js
Normal file
192
database/user.js
Normal file
@@ -0,0 +1,192 @@
|
||||
const debug = require('debug')('technicflux:server')
|
||||
const mongoose = require('mongoose')
|
||||
const bcrypt = require('bcryptjs')
|
||||
const Schema = mongoose.Schema
|
||||
|
||||
// --- Schema ---
|
||||
const userSchema = new Schema({
|
||||
username: {
|
||||
type: String,
|
||||
unique: true
|
||||
},
|
||||
display_name: String,
|
||||
password: String,
|
||||
created_on: Date,
|
||||
login_history: [{ timestamp: Date, userAgent: String }]
|
||||
})
|
||||
|
||||
// --- Model ---
|
||||
exports.User = mongoose.model('technicflux_users', userSchema)
|
||||
|
||||
// --- Related Functions ---
|
||||
|
||||
/*
|
||||
* Creates a new user with the given information.
|
||||
*/
|
||||
exports.createUser = (uUsername, uDisplayName, uPassword) => {
|
||||
// Encrypt the password using bcrypt and save user
|
||||
return bcrypt.genSalt(10).then((Salt) => {
|
||||
return bcrypt.hash(uPassword, Salt).then((hash) => {
|
||||
// Create a user object
|
||||
const newUser = new exports.User({
|
||||
username: uUsername,
|
||||
display_name: uDisplayName,
|
||||
password: hash
|
||||
})
|
||||
|
||||
// Commit it to the database
|
||||
return newUser.save().then((user) => {
|
||||
process.stdout.write(`Successfully added new user ${user.username}\n`)
|
||||
return user
|
||||
}).catch((reason) => {
|
||||
process.stdout.write(`ERROR (when saving new user): ${reason}\n`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed password
|
||||
process.stdout.write(`ERROR (while hashing password): ${err}`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed object salt
|
||||
process.stdout.write(`ERROR (while generating password salt): ${err}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the user with the provided id.
|
||||
*/
|
||||
exports.getUserById = (uId) => {
|
||||
// Fetch information about the user with the given id
|
||||
return exports.User.findOne({ _id: uId }).exec().then((user) => {
|
||||
// User found.
|
||||
return user
|
||||
}).catch((reason) => {
|
||||
// No user found with this id.
|
||||
console.log(reason)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the user with the provided username.
|
||||
*/
|
||||
exports.getUserByUsername = (uUsername) => {
|
||||
// Fetch information about the user with the given username
|
||||
return exports.User.findOne({ username: uUsername }).exec().then((user) => {
|
||||
// User found.
|
||||
return user
|
||||
}).catch((reason) => {
|
||||
// No user found with this username.
|
||||
console.log(reason)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets an array of all existing users.
|
||||
*/
|
||||
exports.getAllUsers = () => {
|
||||
// Fetch an array of all users
|
||||
return exports.User.find({ }).exec().then((users) => {
|
||||
// Users found.
|
||||
return users
|
||||
}).catch((reason) => {
|
||||
console.log(reason)
|
||||
// Error retrieving users.
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the corresponding password matches that of the provided username.
|
||||
*/
|
||||
exports.authUser = (uUsername, uPassword, logHistory = false, uAgent = 'Unknown') => {
|
||||
// Fetch information about the user with the given username
|
||||
return exports.User.findOne({ username: uUsername }).exec().then((user) => {
|
||||
// User found. Check password.
|
||||
return bcrypt.compare(uPassword, user.password).then(async (isMatch) => {
|
||||
// Check if it is a match
|
||||
if (isMatch) {
|
||||
// Update the user's login history.
|
||||
if (logHistory) {
|
||||
const newLogin = { timestamp: new Date(), userAgent: String(uAgent) }
|
||||
|
||||
// Add the new login to the user's login history
|
||||
return await exports.User.updateOne(
|
||||
{ username: uUsername },
|
||||
{ $push: { login_history: newLogin } }
|
||||
).exec().then(() => {
|
||||
// Auth was successful and login history updated.
|
||||
user.login_history.push(newLogin)
|
||||
return [true, user]
|
||||
}).catch((reason) => {
|
||||
user.login_history.push(newLogin)
|
||||
// Auth was successful, but failed to update the user's login history.
|
||||
process.stdout.write(`ERROR (while updating user's login history): ${reason}\n`)
|
||||
return [true, user]
|
||||
})
|
||||
} else {
|
||||
// Auth was successful. Return user without logging to user's history.
|
||||
return [true, user]
|
||||
}
|
||||
} else {
|
||||
// User's authentication was invalid.
|
||||
return [false, undefined]
|
||||
}
|
||||
})
|
||||
}).catch((reason) => {
|
||||
console.log(reason)
|
||||
// No user found with this username.
|
||||
return [false]
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the user with the given username.
|
||||
*/
|
||||
exports.updateUser = (uUsername, object) => {
|
||||
return bcrypt.genSalt(10).then((Salt) => {
|
||||
return bcrypt.hash(object.password, Salt).then((hash) => {
|
||||
if (object.password.length > 0) {
|
||||
object.password = hash
|
||||
} else {
|
||||
object.password = object.old_password
|
||||
}
|
||||
delete object.old_password
|
||||
|
||||
// Update User
|
||||
return exports.User.updateOne(
|
||||
{ username: uUsername },
|
||||
{ $set: object }
|
||||
).exec().then(() => {
|
||||
// Updated user successfully
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to update the user
|
||||
process.stdout.write(`ERROR (while updating user): ${reason}\n`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed password
|
||||
process.stdout.write(`ERROR (while hashing password): ${err}`)
|
||||
return false
|
||||
})
|
||||
}).catch((err) => {
|
||||
// Issue creating hashed object salt
|
||||
process.stdout.write(`ERROR (while generating password salt): ${err}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
exports.deleteUser = (uId) => {
|
||||
return exports.User.deleteOne({ _id: uId }).exec().then(() => {
|
||||
// Successfully deleted this user.
|
||||
return true
|
||||
}).catch((reason) => {
|
||||
// Failed to delete the user
|
||||
debug(`ERROR (DB): Failed to delete user '${uId}' because of: ${reason}`)
|
||||
return false
|
||||
})
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
const express = require('express')
|
||||
const rateLimit = require('express-rate-limit')
|
||||
const MongoStore = require('rate-limit-mongo')
|
||||
const database = require('../database')
|
||||
const database = require('../database/database')
|
||||
const branchName = require('current-git-branch')() || 'release'
|
||||
const pckg = require('../package.json')
|
||||
const router = express.Router()
|
||||
@@ -67,7 +67,7 @@ router.get('/mod/:modname/:modversion?', (req, res) => {
|
||||
const modName = req.params.modname
|
||||
const modVersion = req.params?.modversion
|
||||
|
||||
return database.getModBySlug(`${modName}`).then((mod) => {
|
||||
return database.mod.getModBySlug(`${modName}`).then((mod) => {
|
||||
// Check if a mod was found
|
||||
if (mod === null) {
|
||||
// Mod Not Found
|
||||
@@ -79,7 +79,7 @@ router.get('/mod/:modname/:modversion?', (req, res) => {
|
||||
return res.json(mod)
|
||||
} else {
|
||||
// Request is for a particular version.
|
||||
return database.getModVersion(modName, modVersion).then((version) => {
|
||||
return database.mod.getModVersion(modName, modVersion).then((version) => {
|
||||
if (version === null) {
|
||||
// Version Not Found
|
||||
return res.status(404).json({
|
||||
@@ -111,7 +111,7 @@ router.get('/mod/:modname/:modversion?', (req, res) => {
|
||||
* Purpose: Displays a list of all modpacks that are on this TechnicFlux instance.
|
||||
*/
|
||||
router.get('/modpack', (req, res) => {
|
||||
return database.getAllModpacks().then((modpacks) => {
|
||||
return database.modpack.getAllModpacks().then((modpacks) => {
|
||||
// Modpack Index
|
||||
return res.json({
|
||||
modpacks: (modpacks === null)
|
||||
@@ -137,7 +137,7 @@ router.get('/modpack/:slug/:build?', (req, res) => {
|
||||
const slug = req.params.slug
|
||||
const build = req.params?.build
|
||||
|
||||
return database.getModpackBySlug(`${slug}`).then((modpack) => {
|
||||
return database.modpack.getModpackBySlug(`${slug}`).then((modpack) => {
|
||||
if (modpack === null) {
|
||||
// Modpack Not Found
|
||||
return res.status(404).json({
|
||||
@@ -192,7 +192,7 @@ router.get('/verify/:key?', (req, res) => {
|
||||
const apiKey = req.params?.key
|
||||
|
||||
if (apiKey !== undefined) {
|
||||
database.authAPIKey(apiKey).then((key) => {
|
||||
database.apiKey.authAPIKey(apiKey).then((key) => {
|
||||
if (apiKey === process.env?.API_KEY) {
|
||||
// Key validated
|
||||
return res.json({
|
||||
|
||||
Reference in New Issue
Block a user