azures04 1fe46a03fd Add skin upload and texture management endpoints
Introduces endpoints and logic for uploading Minecraft skins via file or URL, storing textures, and managing player skins. Adds new repository and service methods for texture registration and retrieval, updates authorization handling, and uses process.cwd() for data paths. Also includes static serving of textures and rate limiting for skin uploads.
2025-12-28 07:49:31 +01:00

71 lines
2.3 KiB
JavaScript

const express = require("express")
const router = express.Router()
const multer = require("multer")
const rateLimit = require("express-rate-limit")
const userService = require("../../../../../services/userService")
const authService = require("../../../../../services/authService")
const { DefaultError } = require("../../../../../errors/errors")
const TEMP_DIR = path.join(process.cwd(), "data", "temp")
if (!fs.existsSync(TEMP_DIR)) {
fs.mkdirSync(TEMP_DIR, { recursive: true })
}
const upload = multer({
dest: TEMP_DIR,
limits: { fileSize: 2 * 1024 * 1024 }
})
const uploadLimiter = rateLimit({
windowMs: 60 * 1000,
max: 20,
standardHeaders: true,
legacyHeaders: false,
keyGenerator: (req) => {
return req.headers.authorization || req.ip
},
handler: (req, res, next, options) => {
throw new DefaultError(429, "Too many requests. Please try again later.")
}
})
router.post("/", uploadLimiter, async (req, res, next) => {
if (req.is('application/json')) {
try {
const token = req.headers.authorization.replace("Bearer ", "").trim()
const player = await authService.verifyAccessToken({ accessToken: token })
await userService.uploadSkinFromUrl(player.user.uuid, req.body.url, req.body.variant)
return res.status(200).send()
} catch (err) {
return next(err)
}
}
else {
upload.single("file")(req, res, async (err) => {
if (err) return next(err)
try {
if (!req.headers.authorization) {
if (req.file) await fs.promises.unlink(req.file.path).catch(() => {})
throw new DefaultError(401, "Missing Authorization Header")
}
const token = req.headers.authorization.replace("Bearer ", "").trim()
const player = await authService.verifyAccessToken({ accessToken: token })
await userService.uploadSkin(player.user.uuid, req.file, req.body.variant)
return res.status(200).send()
} catch (error) {
if (req.file) await fs.promises.unlink(req.file.path).catch(() => {})
return next(error)
}
})
}
})
module.exports = router