const { response } = require("express") const express = require("express") const router = express.Router() const fs = require("fs") var path = require("path") const crypto = require("crypto") require("dotenv").config() const RCC_HOST = process.env.RCC_HOST const ACCESS_KEY = process.env.ACCESS_KEY const User = require("../model/user.js") const catalog = require("../model/item") const games = require("./../model/games.js") const fetch = (...args) => import("node-fetch").then(({ default: fetch }) => fetch(...args)) //redirect hmmmm var rgx = /^[0-9]*\.?[0-9]*$/ router.get("/", async (req, res) => { if (req.query.name) { const user = await User.findOne({ userid: req.query.name }).lean() if (!user) { return res.json({ status: "error", error: "User not found!" }) } if (req.query.rcc) { var empty = [] for (var key of user.colors) { empty.push(key.value) } return res.json(empty) } res.type("application/xml") var colorsxml = ` null nil ` + user.colors.find(x => x.name === "Head").value + ` ` + user.colors.find(x => x.name === "Left Arm").value + ` ` + user.colors.find(x => x.name === "Left Leg").value + ` Body Colors ` + user.colors.find(x => x.name === "Right Arm").value + ` ` + user.colors.find(x => x.name === "Right Leg").value + ` ` + user.colors.find(x => x.name === "Torso").value + ` true ` return res.send(colorsxml) } if ( req.query.method || /*req.headers?.["requester"] === "Server" &&*/ req.headers?.[ "assettype" ] === "Place" ) { var ip = req.headers["cf-connecting-ip"] || req.socket.remoteAddress console.log(ip) var sanitizedid = req.query.id.match(rgx) if (ip === RCC_HOST || ip === "::ffff:" + RCC_HOST) { console.log(req.headers["accesskey"]) if (req.headers?.["accesskey"] === ACCESS_KEY) { fs.access( "./assets/ugc/gamefile-" + sanitizedid + ".rbxl", fs.F_OK, err => { if (err) { res.status(404).send("not found") return } //file exists res.sendFile( path.resolve( "./assets/ugc/gamefile-" + sanitizedid + ".rbxl", ), ) return }, ) } } return res.status(401).end() } else { if (!req.query.id) { req.query.id = req.query.assetversionid } if (isNaN(parseFloat(req.query.id)) === true) { res.writeHead(302, { Location: "https://assetdelivery.roblox.com/v1/asset?id=" + req.query.id, }) return res.end() } var sanitizedid = parseFloat(req.query.id) const response = await catalog.findOne({ ItemId: sanitizedid }).lean() var ip = req.headers["cf-connecting-ip"] || req.socket.remoteAddress if ( response?.approved === false && (ip != RCC_HOST || ip === "::ffff:" + RCC_HOST) && !req.query.nonapproved ) { return res.status(401).end() } //this will only allow numbers in our system so that we don't allow nodejs to expose our whole server filesystem fs.access( "./assets/ugc/itemfile-" + sanitizedid + ".rbxm", fs.F_OK, async err => { //console.log("./assets/ugc/itemfile-"+sanitizedid+".rbxm") if (err) { if ( req.headers?.["user-agent"]?.includes("Android") === true || req.headers?.["user-agent"]?.includes("iPhone") === true ) { const response = await fetch( "https://assetdelivery.roblox.com/v1/assetId/" + req.query.id, { headers: { "User-Agent": "Roblox/WinInet" } }, ) const data = await response.json() if (data) { if (data.location) { res.writeHead(302, { Location: data.location }) res.end() return } } } if (req.query.id === "507766666") { // 2018 r15 animation use legacy res.writeHead(302, { Location: "https://assetdelivery.roblox.com/v1/asset?id=" + req.query.id + "&version=3", }) return res.end() } if (req.query.id === "507766388") { res.writeHead(302, { Location: "https://assetdelivery.roblox.com/v1/asset?id=" + req.query.id + "&version=2", }) return res.end() } if (req.query.id === "62633901") { return res.sendFile( path.resolve( "./assets/ugc/common/itemfile-" + sanitizedid + ".rbxm", ), ) } res.writeHead(302, { Location: "https://assetdelivery.roblox.com/v1/asset?id=" + req.query.id, }) res.end() return } res.sendFile( path.resolve( "./assets/ugc/itemfile-" + sanitizedid + ".rbxm", ), ) return }, ) } }) module.exports = router