Last active
January 22, 2023 01:03
-
-
Save MrChickenRocket/d272579179adc94314f78c135580a700 to your computer and use it in GitHub Desktop.
Roblox proxy server for writing files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local module = {} | |
local HttpService = game:GetService("HttpService") | |
function to_base64(data) | |
local b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' | |
return ((data:gsub('.', function(x) | |
local r,b='',x:byte() | |
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end | |
return r; | |
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x) | |
if (#x < 6) then return '' end | |
local c=0 | |
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end | |
return b:sub(c+1,c+1) | |
end)..({ '', '==', '=' })[#data%3+1]) | |
end | |
function module:WriteFile(filePath, fileData) | |
local url = "http://localhost:3050/file" | |
local chunks = {} | |
local chunkSize = 512 * 1024 -- 512 KB | |
local chunksCount = math.ceil(#fileData / chunkSize) | |
for i = 1, chunksCount do | |
local start = (i - 1) * chunkSize + 1 | |
local finish = i * chunkSize | |
chunks[i] = fileData:sub(start, finish) | |
end | |
for i = 1, chunksCount do | |
local jsonData = HttpService:JSONEncode({path = filePath, data = to_base64(chunks[i]), index = i, total = chunksCount}) | |
local success, response = pcall(function() | |
return HttpService:PostAsync(url, jsonData) | |
end) | |
if not success then | |
warn("Failed to write file: " .. response) | |
return false | |
end | |
end | |
return true | |
end | |
return module |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const express = require('express'); | |
const fs = require('fs'); | |
const path = require("path"); | |
const bodyParser = require("body-parser"); | |
var base64 = require('base64-arraybuffer'); | |
const app = express(); | |
const { check, validationResult } = require('express-validator'); | |
const port = process.argv[2] || 3050; //Default port of 3050 | |
app.use(bodyParser.json({ limit: '50mb' })); | |
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true })); | |
function GetMostRecentRobloxFolder() | |
{ | |
const appData = process.env.appData; | |
let systemFolder = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/' : process.env.HOME + "/.local/") | |
const robloxFolder = path.join(systemFolder, "..", "Local", "Roblox", "Versions"); | |
try { | |
const files = fs.readdirSync(robloxFolder); | |
let mostRecent; | |
let mostRecentTime = 0; | |
files.forEach(file => { | |
const filePath = path.join(robloxFolder, file); | |
const fileStat = fs.statSync(filePath); | |
if (fileStat.isDirectory() && fileStat.ctimeMs > mostRecentTime) { | |
mostRecent = filePath; | |
mostRecentTime = fileStat.ctimeMs; | |
} | |
}); | |
return mostRecent; | |
} catch (err) { | |
throw err; | |
} | |
} | |
function GetContentFolder(robloxPath) | |
{ | |
const contentFolder = path.join(robloxPath, "content", "procmesh"); | |
try { | |
if (!fs.existsSync(contentFolder)) { | |
fs.mkdirSync(contentFolder); | |
console.log(`'${contentFolder}' folder created.`); | |
} else { | |
console.log(`'${contentFolder}' folder already exists.`); | |
} | |
} catch (err) { | |
console.error(err); | |
} | |
return contentFolder; | |
} | |
let robloxFolder = ''; | |
function Setup() | |
{ | |
console.log("Checking folders..."); | |
robloxFolder = GetContentFolder(GetMostRecentRobloxFolder()) | |
console.log(`Most recent roblox path is ${robloxFolder}`); | |
} | |
/* | |
app.post('/file', [ | |
check('path').not().isEmpty().withMessage('File path is required'), | |
check('path').isString().withMessage('File path must be a string'), | |
], (req, res) => { | |
const errors = validationResult(req); | |
if (!errors.isEmpty()) { | |
return res.status(400).json({ errors: errors.array() }); | |
} | |
// Handle file writing | |
const fileName = req.body.path; | |
console.log('writing ' + fileName); | |
let finalPath = path.join(robloxFolder, fileName); | |
const data = base64.decode(req.body.data); | |
const bufferData = Buffer.from(data); | |
fs.writeFile(finalPath, bufferData, err => { | |
if (err) { | |
res.status(500).json({ message: `Error writing file: ${err}` }); | |
} else { | |
res.status(200).json({ message: 'File written successfully' }); | |
} | |
}); | |
}); | |
*/ | |
let chunks = {} | |
app.post('/file', [ | |
check('path').not().isEmpty().withMessage('File path is required'), | |
check('path').isString().withMessage('File path must be a string'), | |
check('index').not().isEmpty().withMessage('Chunk index is required'), | |
check('total').not().isEmpty().withMessage('Total chunks count is required'), | |
], (req, res) => { | |
const errors = validationResult(req); | |
if (!errors.isEmpty()) { | |
return res.status(400).json({ errors: errors.array() }); | |
} | |
// Handle file writing | |
const fileName = req.body.path; | |
console.log('writing ' + fileName); | |
const index = req.body.index; | |
const total = req.body.total; | |
let finalPath = path.join(robloxFolder, fileName); | |
const data = base64.decode(req.body.data); | |
const bufferData = Buffer.from(data); | |
chunks[index] = bufferData; | |
if (Object.keys(chunks).length === total) { | |
let finalData = Buffer.concat(Object.values(chunks)); | |
fs.writeFile(finalPath, finalData, err => { | |
if (err) { | |
res.status(500).json({ message: `Error writing file: ${err}` }); | |
} else { | |
res.status(200).json({ message: 'File written successfully' }); | |
} | |
chunks = {} | |
}); | |
} else { | |
res.status(200).json({ message: 'Chunk received' }); | |
} | |
}); | |
Setup(); | |
app.listen(port, () => { | |
console.log(`Server listening on port ${port}`); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This writes to somewhere accessible to rbxasset://