forked from kaverti/website
368 lines
18 KiB
JavaScript
368 lines
18 KiB
JavaScript
let bcrypt = require('bcryptjs')
|
|
let multer = require('multer')
|
|
let express = require('express')
|
|
let router = express.Router()
|
|
const auth = require('../lib/auth')
|
|
var Recaptcha = require('express-recaptcha').RecaptchaV3;
|
|
var recaptcha = new Recaptcha('6LdlbrwZAAAAAKvtcVQhVl_QaNOqmQ4PgyW3SKHy', '6LdlbrwZAAAAAMAWPVDrL8eNPxrws6AMDtLf1bgd');
|
|
var reCAPTCHASecret = "6LdlbrwZAAAAAKvtcVQhVl_QaNOqmQ4PgyW3SKHy";
|
|
const Errors = require('../lib/errors.js')
|
|
var format = require('date-format');
|
|
let {
|
|
User, AuditLog, Team, Item, Post, ProfilePicture, StaffApplications, AdminToken, PassKey, Thread, Category, Sequelize, Ip, Ban, sequelize
|
|
} = require('../models')
|
|
let pagination = require('../lib/pagination.js')
|
|
var fs = require("fs");
|
|
const rateLimit = require("express-rate-limit");
|
|
const cryptoRandomString = require("crypto-random-string")
|
|
const limiter = rateLimit({
|
|
windowMs: 60 * 1000,
|
|
max: 3,
|
|
message: "{\"errors\":[{\"name\":\"rateLimit\",\"message\":\"You may only make 3 requests to this endpoint per minute, if you performed an action such as avatar color changing, those changes were saved, however your avatar was not re-rendered, please re-render your avatar.\",\"status\":429}]}"
|
|
});
|
|
router.all('*', auth, async(req, res, next) => {
|
|
let user = await User.findOne({ where: {
|
|
username: req.userData.username
|
|
}})
|
|
if(!user) throw Errors.requestNotAuthorized
|
|
if(req.userData.admin && user.admin) {
|
|
next()
|
|
} else {
|
|
res.status(401)
|
|
res.json({
|
|
errors: [Errors.sessionAdminProtection]
|
|
})
|
|
}
|
|
})
|
|
|
|
router.put('/user/scrub', auth, async(req, res, next) => {
|
|
try {
|
|
if(!req.userData.admin) {
|
|
throw Errors.requestNotAuthorized
|
|
}
|
|
await Ban.ReadOnlyMode(req.userData.UserId)
|
|
|
|
if(req.autosan.body.description === "descscram") {
|
|
let user = await User.findOne({ where: {
|
|
username: req.autosan.body.user
|
|
}})
|
|
if(user.admin) {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' attempted to modify ' + req.autosan.body.user + ' but an error was thrown (Is admin, scrub description).'})
|
|
throw Errors.modifyAdminUser
|
|
}
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' modified user ' + req.autosan.body.user + ' and succeeded (scrub description).'})
|
|
let userUpdate = await User.update({ description: "Description was removed by an administrator"}, { where: {
|
|
username: req.autosan.body.user
|
|
}})
|
|
res.status(200)
|
|
res.json({success: "true"})
|
|
|
|
} else if(req.body.username === "usernamescram") {
|
|
let user = await User.findOne({ where: {
|
|
username: req.autosan.body.user
|
|
}})
|
|
if(user.admin) {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' attempted to modify ' + req.autosan.body.user + ' but an error was thrown (Is admin, scrub username).'})
|
|
throw Errors.modifyAdminUser
|
|
}
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' modified user ' + req.autosan.body.user + ' and succeeded (scrub username).'})
|
|
let userUpdate = await User.update({username: Math.random().toString(36).substring(2)}, {
|
|
where: {
|
|
username: req.autosan.body.user
|
|
}
|
|
})
|
|
res.json({success: true})
|
|
} else {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' attempted to modify ' + req.autosan.body.user + ' but an error was thrown (unknown, scrub username).'})
|
|
res.json({ success: false })
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.put('/user/modify', auth, async(req, res, next) => {
|
|
try {
|
|
if(!req.userData.admin) {
|
|
throw Errors.requestNotAuthorized
|
|
}
|
|
|
|
await Ban.ReadOnlyMode(req.userData.UserId)
|
|
|
|
if(req.body.username) {
|
|
let user = await User.findOne({ where: {
|
|
username: req.body.username
|
|
}})
|
|
let user1 = await User.findOne({ where: {
|
|
username: req.userData.username
|
|
}})
|
|
if(!user) throw Errors.accountDoesNotExist
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' modified ' + req.body.username + ' and succeeded (changed roles).'})
|
|
if(user.admin && !user1.executive) {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' attempted to modify ' + req.body.username + ' but an error was thrown (Is admin, changed roles).'})
|
|
throw Errors.modifyAdminUser
|
|
}
|
|
if(user.executive) {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' attempted to modify ' + req.body.username + ' but an error was thrown (Is executive, changed roles).'})
|
|
throw Errors.modifyAdminUser
|
|
}
|
|
if(user1.executive) {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' modified ' + req.body.username + ' and succeeded (changed roles, executive action).'})
|
|
let userUpdate = await User.update({
|
|
booster: req.body.booster,
|
|
bot: req.body.bot,
|
|
system: req.body.system,
|
|
admin: req.body.admin,
|
|
hidden: req.body.hidden
|
|
}, {
|
|
where: {
|
|
username: req.body.username
|
|
}
|
|
})
|
|
res.status(200)
|
|
res.json({success: true})
|
|
} else {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' modified ' + req.body.username + ' and succeeded (changed roles, admin action).'})
|
|
let userUpdate = await User.update({
|
|
booster: req.body.booster,
|
|
bot: req.body.bot,
|
|
system: req.body.system,
|
|
hidden: req.body.hidden
|
|
}, {
|
|
where: {
|
|
username: req.body.username
|
|
}
|
|
})
|
|
res.status(200)
|
|
res.json({success: true})
|
|
}
|
|
} else {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' attempted to modify ' + req.body.username + ' but an error was thrown (account does not exist).'})
|
|
res.status(400)
|
|
throw Errors.accountDoesNotExist
|
|
}
|
|
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/privileges', auth, async(req, res, next) => {
|
|
try {
|
|
let queryObj = {
|
|
attributes: {include: ['username', 'admin', 'executive'], exclude: ['hash', 'email', 'emailVerified', 'koins', 'currency2', 'emailToken', 'passwordResetExpiry', 'passwordResetToken', 'experimentMode', 'developerMode', 'cookieOptOut', 'deleteCode', 'jwtOffset', 'description', 'theme', 'contributor', 'passwordResetOptOut', 'picture', 'createdAt', 'updatedAt', 'id']},
|
|
where: {username: req.userData.username},
|
|
}
|
|
let user = await User.findOne(queryObj)
|
|
res.json(user)
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/teams/pending', auth, async(req, res, next) => {
|
|
try {
|
|
await Ban.isIpBanned(req.ip)
|
|
|
|
let team = await Team.findAll({where: {approved: false, banned: false}})
|
|
if(!team) {
|
|
res.status(200)
|
|
res.json({success: false})
|
|
}
|
|
res.json(team)
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.put('/teams/approve', auth, async(req, res, next) => {
|
|
try {
|
|
await Ban.isIpBanned(req.ip)
|
|
|
|
let team = await Team.findOne({where: {username: req.body.username}})
|
|
if(!team) {
|
|
throw Errors.accountDoesNotExist
|
|
}
|
|
if(req.body.approve) {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' approved the ' + req.body.username + ' team and succeeded (approved team).'})
|
|
await team.update({approved: true});
|
|
res.status(200)
|
|
res.json({success: true})
|
|
} else if(!req.body.approve && req.body.reason) {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' banned the ' + req.body.username + ' team and succeeded (banned team).'})
|
|
await team.update({banned: true, banReason: req.body.reason})
|
|
res.status(200)
|
|
res.json({success: true})
|
|
} else {
|
|
throw Errors.requestNotAuthorized
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/marketplace/pending', auth, async(req, res, next) => {
|
|
try {
|
|
await Ban.isIpBanned(req.ip)
|
|
|
|
let item = await Item.findAll({where: {approved: false, deleted: false}, include: { model: User, attributes: ['username', 'createdAt', 'id', 'color', 'picture', 'locked', 'admin', 'booster', 'executive', 'bot'] }})
|
|
if(!item) {
|
|
res.status(200)
|
|
res.json({success: false})
|
|
}
|
|
res.json(item)
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.put('/marketplace/approve', auth, async(req, res, next) => {
|
|
try {
|
|
await Ban.isIpBanned(req.ip)
|
|
|
|
let item = await Item.findOne({where: {id: req.body.id}})
|
|
if(!item) {
|
|
throw Errors.accountDoesNotExist
|
|
}
|
|
if(req.body.approve && !req.body.delete) {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' approved the Marketplace Item MID: ' + req.body.id + ' and succeeded (approved marketplace item).'})
|
|
await item.update({approved: true});
|
|
res.status(200)
|
|
res.json({success: true})
|
|
} else if(req.body.delete && !req.body.approve) {
|
|
AuditLog.create({UserId: req.userData.UserId, action: req.userData.username + ' removed the Marketplace Item MID: ' + req.body.id + ' and succeeded (removed marketplace item).'})
|
|
await item.update({deleted: true, approved: false});
|
|
res.status(200)
|
|
res.json({success: true})
|
|
} else {
|
|
throw Errors.requestNotAuthorized
|
|
}
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.get('/logs', auth, async(req, res, next) => {
|
|
try {
|
|
await Ban.isIpBanned(req.ip)
|
|
|
|
let logs = await AuditLog.findAll()
|
|
if(!logs) {
|
|
res.status(200)
|
|
res.json({success: false})
|
|
}
|
|
res.json(logs)
|
|
} catch (e) { next(e) }
|
|
})
|
|
|
|
router.put("/user/avatar", limiter, auth, async(req, res, next) => {
|
|
let userCheck = await User.findOne({ where: {
|
|
username: req.userData.username
|
|
}
|
|
})
|
|
if(!userCheck.admin) {
|
|
throw Errors.requestNotAuthorized
|
|
}
|
|
if(!req.userData.admin) {
|
|
throw Errors.requestNotAuthorized
|
|
}
|
|
let user = await User.findOne({ where: {
|
|
username: req.body.user
|
|
}
|
|
})
|
|
if(!user) {
|
|
throw Errors.unknown
|
|
}
|
|
const { exec } = require('child_process');
|
|
if(user.pantsId) {
|
|
var pantsModel = await Item.findOne({
|
|
where: {
|
|
id: user.pantsId
|
|
}
|
|
})
|
|
}
|
|
if(user.hatId) {
|
|
var hatModel = await Item.findOne({
|
|
where: {
|
|
id: user.hatId
|
|
}
|
|
})
|
|
}
|
|
if(user.faceId) {
|
|
var faceModel = await Item.findOne({
|
|
where: {
|
|
id: user.faceId
|
|
}
|
|
})
|
|
}
|
|
if(user.shirtId) {
|
|
var shirtModel = await Item.findOne({
|
|
where: {
|
|
id: user.shirtId
|
|
}
|
|
})
|
|
}
|
|
let rootPathRender = "C:/Users/matth/Documents/GitHub/website/";
|
|
let img2 = cryptoRandomString({length: 32})
|
|
let img = img2
|
|
var blendFilePath = rootPathRender + "rendering/avatar.blend";
|
|
var blendFilePathHs = rootPathRender + "rendering/avatarhs.blend";
|
|
var imageSavePath = "C:/xampp21/htdocs/user/avatars/full/" + img + ".png";
|
|
var imageSavePathHS = "C:/xampp21/htdocs/user/avatars/headshot/" + img + ".png";
|
|
var pythonFilePath = "rendering/usercontent/"+req.userData.UserId+".py";
|
|
if(user.faceId) {
|
|
var faceFilePath = rootPathRender + "rendering/global/" + faceModel.sourceFile + ".png";
|
|
} else {
|
|
var faceFilePath = rootPathRender + "rendering/global/defaultFace.png";
|
|
}
|
|
if(user.shirtId) {
|
|
var shirtFilePath = rootPathRender + "rendering/global/" + shirtModel.sourceFile + ".png"; // should be set to 0 by default, 0.png will just be a transparent image
|
|
} else {
|
|
var shirtFilePath = rootPathRender + "rendering/global/0.png"; // should be set to 0 by default, 0.png will just be a transparent image
|
|
}
|
|
if(user.pantsId) {
|
|
var pantsFilePath = rootPathRender + "rendering/global/" + pantsModel.sourceFile + ".png"; // should be set to 0 by default, 0.png will just be a transparent image
|
|
} else {
|
|
var pantsFilePath = rootPathRender + "rendering/global/0.png"; // should be set to 0 by default, 0.png will just be a transparent image
|
|
}
|
|
if(user.hatId) {
|
|
var hatFilePath = rootPathRender + "rendering/global/" + hatModel.sourceFile + ".obj"
|
|
var hat = "hat_import = bpy.ops.import_scene.obj(filepath='"+hatFilePath+"')\nhat = bpy.context.selected_objects[0]\nbpy.context.selected_objects[0].data.name = 'hat'\nbpy.context.selected_objects[0].name = 'hat'\nhat_material = bpy.data.materials.new('hat')\nhat_material.diffuse_shader = 'LAMBERT'\nhat.active_material = hat_material\nhat_image = bpy.data.images.load(filepath = '" + rootPathRender + "rendering/global/"+hatModel.sourceFile+".png')\nhat_texture = bpy.data.textures.new('ColorTex', type = 'IMAGE')\nhat_texture.image = hat_image\nhat_add = bpy.data.objects['hat'].active_material.texture_slots.add()\nhat_add.texture = hat_texture";
|
|
} else {
|
|
var hat = ''
|
|
}
|
|
|
|
var imports = "import bpy";
|
|
var functions = "def hex_to_rgb(value):\n gamma = 2.05\n value = value.lstrip('#')\n lv = len(value)\n fin = list(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))\n r = pow(fin[0] / 255, gamma)\n g = pow(fin[1] / 255, gamma)\n b = pow(fin[2] / 255, gamma)\n fin.clear()\n fin.append(r)\n fin.append(g)\n fin.append(b)\n return tuple(fin)";
|
|
var blenderImport = "bpy.ops.wm.open_mainfile(filepath='"+blendFilePath+"')";
|
|
var blenderImportHs = "bpy.ops.wm.open_mainfile(filepath='"+blendFilePathHs+"')";
|
|
var headColor = "bpy.data.objects['Head'].select = True\nbpy.data.materials['Head'].diffuse_color = hex_to_rgb('"+user.headColor+"')\nbpy.data.materials['Face'].diffuse_color = hex_to_rgb('"+user.headColor+"')";
|
|
var leftArmColor = "bpy.data.objects['Left Arm'].select = True\nbpy.data.objects['Left Arm'].active_material.diffuse_color = hex_to_rgb('"+user.leftArmColor+"')";
|
|
var rightArmColor = "bpy.data.objects['Right Arm'].select = True\nbpy.data.objects['Right Arm'].active_material.diffuse_color = hex_to_rgb('"+user.rightArmColor+"')";
|
|
var bodyColor = "bpy.data.objects['Torso'].select = True\nbpy.data.objects['Torso'].active_material.diffuse_color = hex_to_rgb('"+user.color+"')";
|
|
var leftLegColor = "bpy.data.objects['Left Leg'].select = True\nbpy.data.objects['Left Leg'].active_material.diffuse_color = hex_to_rgb('"+user.leftLegColor+"')";
|
|
var rightLegColor = "bpy.data.objects['Right Leg'].select = True\nbpy.data.objects['Right Leg'].active_material.diffuse_color = hex_to_rgb('"+user.rightLegColor+"')";
|
|
var colors = headColor+"\n"+leftArmColor+"\n"+bodyColor+"\n"+rightArmColor+"\n"+leftLegColor+"\n"+rightLegColor;
|
|
|
|
if(user.hatId) {
|
|
var hat = "hat_import = bpy.ops.import_scene.obj(filepath='"+hatFilePath+"')\nhat = bpy.context.selected_objects[0]\nbpy.context.selected_objects[0].data.name = 'hat'\nbpy.context.selected_objects[0].name = 'hat'\nhat_material = bpy.data.materials.new('hat')\nhat_material.diffuse_shader = 'LAMBERT'\nhat.active_material = hat_material\nhat_image = bpy.data.images.load(filepath = '" + rootPathRender + "rendering/global/"+hatModel.sourceFile+".png')\nhat_texture = bpy.data.textures.new('ColorTex', type = 'IMAGE')\nhat_texture.image = hat_image\nhat_add = bpy.data.objects['hat'].active_material.texture_slots.add()\nhat_add.texture = hat_texture";
|
|
} else {
|
|
var hat = ''
|
|
}
|
|
var face = "face_Image = bpy.data.images.load(filepath = '"+faceFilePath+"')\nbpy.data.textures['Face'].image = face_Image";
|
|
var shirt = "shirt_Image = bpy.data.images.load(filepath = '"+shirtFilePath+"')\nbpy.data.textures['Shirt'].image = shirt_Image\nbpy.data.textures['ShirtR'].image = shirt_Image\nbpy.data.textures['ShirtL'].image = shirt_Image";
|
|
var pants = "pants_Image = bpy.data.images.load(filepath = '"+pantsFilePath+"')\nbpy.data.textures['PantsR'].image = pants_Image\nbpy.data.textures['PantsL'].image = pants_Image";
|
|
var render = "for obj in bpy.data.objects:\n obj.select = False\n bpy.ops.object.select_all(action='SELECT')\nbpy.ops.view3d.camera_to_view_selected()\nscene = bpy.context.scene\nscene.render.image_settings.file_format = 'PNG'\nscene.render.filepath = '"+imageSavePath+"'\nbpy.ops.render.render(write_still = 1)";
|
|
var renderHS = "scene = bpy.context.scene\nscene.render.image_settings.file_format = 'PNG'\nscene.render.filepath = '"+imageSavePathHS+"'\nbpy.ops.render.render(write_still = 1)";
|
|
var python = imports+"\n"+functions+"\n"+blenderImport+"\n"+colors+"\n"+hat+"\n"+face+"\n"+shirt+"\n"+pants+"\n"+render;
|
|
var pythonHS = imports+"\n"+functions+"\n"+blenderImportHs+"\n"+colors+"\n"+hat+"\n"+face+"\n"+shirt+"\n"+pants+"\n"+renderHS;
|
|
fs.writeFile("rendering/usercontent/"+req.userData.UserId+".py", python, function(err,data){
|
|
if(err) { console.log(err) }
|
|
})
|
|
fs.writeFile("rendering/usercontent/hs/"+req.userData.UserId+".py", pythonHS, function(err,data){
|
|
if(err) { console.log(err) }
|
|
})
|
|
|
|
exec("blender -b -P rendering/usercontent/"+req.userData.UserId+".py", (err, stdout, stderr) => {
|
|
if(err) { console.log(err) }
|
|
console.log("stdout: " + stdout);
|
|
console.log("stderr: " + stderr);
|
|
});
|
|
exec("blender -b -P rendering/usercontent/hs/"+req.userData.UserId+".py", (err, stdout, stderr) => {
|
|
if(err) { console.log(err) }
|
|
console.log("stdout: " + stdout);
|
|
console.log("stderr: " + stderr);
|
|
res.status(200)
|
|
res.json({success: true})
|
|
});
|
|
user.update({picture: img})
|
|
});
|
|
|
|
module.exports = router;
|