Initialise repository with SushiDesigner/Meteor-Front and SushiDesigner/Meteor-back

This commit is contained in:
Lewin Kelly 2023-09-10 01:51:41 +01:00
commit 24e44a3b50
No known key found for this signature in database
GPG Key ID: C103AD9C84014FD7
226 changed files with 30030 additions and 0 deletions

7
Back/.env.example Normal file
View File

@ -0,0 +1,7 @@
JWT_SECRET=
RCC_HOST=
logshook=
PROD=true
LOCALCERTIFICATEPATH=
LOCALREDISCONNECTION=
DB_PASSWORD=

3
Back/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules/
assets/release.zip
assets/hash.txt

View File

@ -0,0 +1,3 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQC04Nimx5hGYvQ54rZPWJ9qvvoPSsBXt3PREKhramu1gXpv+W4Mh/vdzlTsNqmedZ2gaX0rd9smy3Kp2lgxKsuyX1gc918k9L/PUzKvnfxy93RDwXdo6qJze+mdQlkDi9U5W4MAzcx6ann3YTHyiKHfs9DqF+kBJQiloPgcnk3HPQIDAQABAoGBAJsAR4h8aGiA6esk9bf/KPWP3Lf4BeXlRrF0xe7uzohHAYYtSHoimdqUsz+NBEPPZJmPbH0wg7O2Cne1rXfMxaqPoZAl/N5kN0uFFY6U7FS+rssF0/OXZPuehmBkOscVGGNM6glAzOfW2/3rZcm8Z3XhdhTQIzZq2D1rjhKU3YT9AkEA08e3BTsV3iqjf8kJhwdt7EGX9/QutNaUSkAoW1d/pRdjZbbfcFwLri2WcTA2taoIa892hSTz/qaHYWMfu3oy/wJBANqlVeqRxFX8YJ0yFZfblx/QEkA5ospJI5pd3J6kSqK9A3NqBCbFPxH6NO8rXBSHk8cE2vNVc0K7qSCzn6sqEcMCQCCHIlNJWfh/sBEmfbIhr/6DrKXG+Y2JD8m/xPMSo2ZmCzxKNFN7r8eW9O55q02HyjdU7C1TGa7ZQR3yLaOMB10CQAY3Iv0bDbDADuMJFHIPrPkbihlHSihj8d4mguoDk5eStfFm9x0/CC7zpOOToPd4byv+KFc4e6FPAlzKnmRYOs8CQQCDMYYdcIw5e5nf20yLUhwzJL4q8ZyR7OGXkjz6ACxoxQSncr/adjecz21ngdx3nq13RdpppWNuZ/2exvS3ObTG
-----END RSA PRIVATE KEY-----

27
Back/PrivateKey2020.txt Normal file
View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEApH8yULE5/DRBnSTqcOM3PplW2UGD4povfR8zCBNP1n69uKoG
mcJm4AiPAR18TpLXPNAyp8UwlrQc4+GCqU/ktipFp//W6r90BWyiY69flfTGU8Zs
Bcy2DNjQipilSaJoOjxUbT++D7qrQSCiMh6fzUfEcUyk2kx4ICErQ2/HqHOxHbLi
+R7L/bIU9pZYWB6aU0WM7ATuzDYFVETUSlXpMAVKeusEqae8lEfV5TqZxb3eIUPU
P1iz7eqd7jQH6UygOnjFksSYxOInbr4KK2rQYDt6507ohO/+AzhlH+FPM3/ziqN6
LObRkLF4u4HCUaKZqPQTREIz8zYdNXuY43YeEQIDAQABAoIBABdUjv9Q04eIpdGy
3albIIe5Wc8AcsMd2SRm22cGzij+2supGbyPDOYzcIzY8Lt4KhzO7pBK8GQ/cWWE
o3J+CVMo1a5JI+MxejQWv0ViJy1uhP52wvVjnmJeEd3GXpL9/MhdrB++jadPc2CO
T1LKcyG7Two+s5beh58O9ULgRLIIU0m6n+svCIDHY0VlxuAh/i5axqk/aaCzvtAh
DeFNS6vrBRMhAY8Tzlhlm/SXEiIubHjrO+CYhLLe0hh0AmaLQNQ0JLFW/eJwMWxw
qEoT+tL1cMYZCudjfmffILXLxYWfd5HqOWz/ghFiSayAdKJZr1gcA3ZAQQVS5qUW
6VDRvF0CgYEA+LBOBLMWyG57PZAI2n85h4PDZKgn6hzJMVlXGelMiRhI/mNcCL/M
Ay006mZ22QyR0Fm59OTHeWxyz8AtCSrSn6rLi4fiLYlh3xxTN1O8Q4Rf7HqNgvTf
rgpjGJ8fIHTvzqQesclKN+MXhsaw3NpS/MyzGEc7ORTTtzqwRDHYKWcCgYEAqVU+
C087RxG8v2ruNeIf+fxnDkrpeHeklfWzCVTNo18FnQhvmFkW0SpfjwhAhjfEEOHZ
VfsDp/kmXZTynkce1DTfWv8iAac990bgBVx6/rC4VoAYQ18jg72FcICGYX4rv9bo
gHi87rPJ1qsVVW2poJyYWr5ZpxIqNtQcQ8NaOccCgYBcS/q4rcrf2nks0P8oMJ2m
WNW0zt/5eHOHODQmbrq0CupUV4X5zU0nRKjl8d9cENkxLYvhguMxgnld92H/jAAd
uCLRBz5/TgSf7IBKAW7W1BNRze4lU0KM8lfy9GN2BVBXLfwiWaWM9mBt6eIMJY81
ObeiZBVryvoEf+iZdrJWMwKBgQCAPkDJC+6W+oX6ap+SS3lwOIpMNsvvIp2RvQ0l
CgbbrgFwVo090msHapIIn3VOsTlal9Gj3oF8W6OEyGOfH7nneUuXfRZiLikt941+
QfYcofZZ/JVjoNAi3AwNkikz+PxlQ/u+ILLmDV/Vpqh3lKAdNbvlLbh0Ybt63tWx
NGhGzQKBgC2gnP65oBbORgdCkMvrs+fbBX5LdCTrBUkxX4yVMr/25GS1oqX6LiGK
Oxjs326pGGns91cMEUbxSFQwaWPCcTWhEbK/epdlY3NkFQ4WPDPkEmhhp49ebMA7
BYWSO7nSEMv4S6rRnVxts9lCihNclblbg3erXx77PRKnLtVbE+KG
-----END RSA PRIVATE KEY-----

24
Back/README.md Normal file
View File

@ -0,0 +1,24 @@
# SushiBlox-Website
Website for sushiblox I guess.
~~Private for now might open source.~~
The setup is ~~easy install required node modules and setup a nginx reverse proxy on port 9000.~~
Uses MongoDB for datastorage. Redis for special things
# Advice
~~This uses hardcoded domain names in the code~~ and relies on cloudflare headers for IP configs. so yeahhhhhhhhhhhhhhhhhhhhhhhhhh
# Redis
idk set it up nerd
# setup
easy enough
# Example
```
PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host pm2 start server.mjs
```

235
Back/actualgameserver.lua Normal file
View File

@ -0,0 +1,235 @@
local url = "http://mete0r.xyz" -- have to set to https for production
------------------- UTILITY FUNCTIONS --------------------------
function waitForChild(parent, childName)
while true do
local child = parent:findFirstChild(childName)
if child then
return child
end
parent.ChildAdded:wait()
end
end
-----------------------------------END UTILITY FUNCTIONS -------------------------
-----------------------------------"CUSTOM" SHARED CODE----------------------------------
--print(port)
pcall(function() settings().Network.UseInstancePacketCache = true end)
pcall(function() settings().Network.UsePhysicsPacketCache = true end)
--pcall(function() settings()["Task Scheduler"].PriorityMethod = Enum.PriorityMethod.FIFO end)
pcall(function() settings()["Task Scheduler"].PriorityMethod = Enum.PriorityMethod.AccumulatedError end)
--settings().Network.PhysicsSend = 1 -- 1==RoundRobin
--settings().Network.PhysicsSend = Enum.PhysicsSendMethod.ErrorComputation2
settings().Network.PhysicsSend = Enum.PhysicsSendMethod.TopNErrors
settings().Network.ExperimentalPhysicsEnabled = true
settings().Network.WaitingForCharacterLogRate = 100
pcall(function() settings().Diagnostics:LegacyScriptMode() end)
-----------------------------------START GAME SHARED SCRIPT------------------------------
local assetId = placeId -- might be able to remove this now
local scriptContext = game:GetService('ScriptContext')
pcall(function() scriptContext:AddStarterScript(37801172) end)
scriptContext.ScriptsDisabled = true
game:SetPlaceID(assetId, false)
game:GetService("ChangeHistoryService"):SetEnabled(false)
-- establish this peer as the Server
local ns = game:GetService("NetworkServer")
if url~=nil then
pcall(function() game:GetService("Players"):SetAbuseReportUrl(url .. "/AbuseReport/InGameChatHandler.ashx") end)
---@diagnostic disable-next-line: invalid-class-name
pcall(function() game:GetService("ScriptInformationProvider"):SetAssetUrl(url .. "/Asset/") end)
pcall(function() game:GetService("ContentProvider"):SetBaseUrl(url .. "/") end)
--pcall(function() game:GetService("Players"):SetChatFilterUrl(url .. "/Game/ChatFilter.ashx") end)
game:GetService("BadgeService"):SetPlaceId(placeId)
game:GetService("BadgeService"):SetIsBadgeLegalUrl("")
game:GetService("InsertService"):SetBaseSetsUrl(url .. "/Game/Tools/InsertAsset.ashx?nsets=10&type=base")
game:GetService("InsertService"):SetUserSetsUrl(url .. "/Game/Tools/InsertAsset.ashx?nsets=20&type=user&userid=%d")
game:GetService("InsertService"):SetCollectionUrl(url .. "/Game/Tools/InsertAsset.ashx?sid=%d")
game:GetService("InsertService"):SetAssetUrl(url .. "/Asset/?id=%d")
game:GetService("InsertService"):SetAssetVersionUrl(url .. "/Asset/?assetversionid=%d")
pcall(function() loadfile(url .. "/Game/LoadPlaceInfo.ashx?PlaceId=" .. placeId)() end)
-- pcall(function()
-- if access then
-- loadfile(url .. "/Game/PlaceSpecificScript.ashx?PlaceId=" .. placeId .. "&" .. access)()
-- end
-- end)
end
pcall(function() game:GetService("NetworkServer"):SetIsPlayerAuthenticationRequired(true) end)
settings().Diagnostics.LuaRamLimit = 0
--settings().Network:SetThroughputSensitivity(0.08, 0.01)
--settings().Network.SendRate = 35
--settings().Network.PhysicsSend = 0 -- 1==RoundRobin
if placeId~=nil and url~=nil then
-- yield so that file load happens in the heartbeat thread
wait()
-- load the game
game:Load(url .. "/asset?id=" .. placeId .. "&method=rcc")
end
-- Now start the connection
local success, message = pcall(function() ns:Start(port) end)
if not success then
local HttpService = game:GetService("HttpService")
game:GetService("HttpService").HttpEnabled = true
-- failed job close it
local arguments = {
["game"] = placeId
}
HttpService:PostAsync(
url .. "/api/updategameinfo/closejob",
HttpService:JSONEncode(arguments)
)
else
local HttpService = game:GetService("HttpService")
local arguments = {
["game"] = placeId
}
game:HttpPostAsync(url .. "/api/updategameinfo/gameloaded",HttpService:JSONEncode(arguments),"application/json")
end
scriptContext:SetTimeout(10)
scriptContext.ScriptsDisabled = false
------------------------------END START GAME SHARED SCRIPT--------------------------
-- StartGame --
game:GetService("RunService"):Run()
local HttpService = game:GetService("HttpService")
game:GetService("HttpService").HttpEnabled = true
spawn(function()
-- if a player doesn't join in 60 seconds because of failed job or they didn't join close the job
wait(60)
if #game:GetService("Players"):GetPlayers() < 1 then
print("Shutdown time")
-- less than one player is in the game so lets shut down
local arguments = {
["game"] = placeId
}
HttpService:PostAsync(
url .. "/api/updategameinfo/closejob",
HttpService:JSONEncode(arguments)
)
end
end)
local function addAttachment(part, name, position, orientation)
local attachment = Instance.new("Attachment")
attachment.Name = name
attachment.Parent = part
if position then
attachment.Position = position
end
if orientation then
attachment.Orientation = orientation
end
return attachment
end
game:GetService("Players").PlayerAdded:connect(function(player)
print("Player " .. player.userId .. " joining")
player.CharacterAdded:connect(function(Character)
addAttachment(Character.HumanoidRootPart, "RootRigAttachment")
addAttachment(Character.Head, "FaceCenterAttachment")
addAttachment(Character.Head, "FaceFrontAttachment", Vector3.new(0, 0, -0.6))
addAttachment(Character.Head, "HairAttachment", Vector3.new(0, 0.6, 0))
addAttachment(Character.Head, "HatAttachment", Vector3.new(0, 0.6, 0))
addAttachment(Character.Head, "NeckRigAttachment", Vector3.new(0, -0.5, 0))
end)
local presenceargs = {
["game"] = placeId,
["player"] = player.userId,
["name"] = player.Name,
["action"] = "joining"
}
HttpService:PostAsync(
url .. "/api/updategameinfo/updatepresence",
HttpService:JSONEncode(presenceargs)
)
wait(2)
local arguments = {
["game"] = placeId,
["players"] = #game:GetService("Players"):GetPlayers()
}
HttpService:PostAsync(
url .. "/api/updategameinfo",
HttpService:JSONEncode(arguments)
)
local visitarguments = {
["game"] = placeId
}
HttpService:PostAsync(
url .. "/api/updategameinfo/updatevisits",
HttpService:JSONEncode(visitarguments)
)
end)
game:GetService("Players").PlayerRemoving:connect(function(player)
print("Player " .. player.userId .. " leaving")
local presenceargs = {
["game"] = placeId,
["player"] = player.userId,
["name"] = player.Name,
["action"] = "leaving"
}
HttpService:PostAsync(
url .. "/api/updategameinfo/updatepresence",
HttpService:JSONEncode(presenceargs)
)
wait(2)
local arguments = {
["game"] = placeId,
["players"] = #game:GetService("Players"):GetPlayers()
}
HttpService:PostAsync(
url .. "/api/updategameinfo",
HttpService:JSONEncode(arguments)
)
if #game:GetService("Players"):GetPlayers() < 1 then
print("Shutdown time")
-- less than one player is in the game so lets shut down
local arguments = {
["game"] = placeId
}
HttpService:PostAsync(
url .. "/api/updategameinfo/closejob",
HttpService:JSONEncode(arguments)
)
end
end)
local StringToDetect = ";ec";
game:GetService("Players").PlayerAdded:connect(function(Player)
Player.Chatted:connect(function(Message)
if string.find(string.lower(Message), string.lower(StringToDetect)) then
if Player.Character then
Player.Character.Humanoid.Health = 0;
end;
end;
end);
end);

BIN
Back/assets/approval.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

BIN
Back/assets/audio/wof.mp3 Normal file

Binary file not shown.

BIN
Back/assets/default.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
Back/assets/defaultold.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

1
Back/assets/hash2014.txt Normal file
View File

@ -0,0 +1 @@
3b5f1470aa859d3782f72ba07c72ed7d7bc2e461f5f85bb9fd007bf66349d5ee

1
Back/assets/hash2018.txt Normal file
View File

@ -0,0 +1 @@
4cd4d51885b3127d72cf4bbc3e889ec4afa5c4bd725dfba4beab239c2d51b7c5

1
Back/assets/hash2020.txt Normal file
View File

@ -0,0 +1 @@
ecfbc1e4cadd0167cddf1c9920adadf7183f690d7101c1b84d51616a35fada55

View File

@ -0,0 +1 @@
d650fafa3e969e786d874def30f32208dc1ebe57d051fc719fe8a0e75af339eb

View File

@ -0,0 +1 @@
f13b90a25b1d1d3ff7dfc0628d6fe554cb3b4eb809fe7289632e41670effb197

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 24.08"><defs><style>.cls-1{fill:#00a2ff;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="BC"><g id="BC-2" data-name="BC"><path class="cls-1" d="M30,8.58h2.1c1.3,0,2.3.39,2.3,1.6a1.37,1.37,0,0,1-1.1,1.4h0c.9.19,1.5.69,1.5,1.5,0,1.29-1.1,1.89-2.5,1.89H30Zm2,2.69c.9,0,1.3-.3,1.3-1s-.4-.8-1.3-.8h-.8v1.8Zm.1,2.91c1,0,1.5-.4,1.5-1.1s-.5-1-1.5-1h-1v2.1Z"/><path class="cls-1" d="M38.6,8.38a3,3,0,0,1,1.9.8l-.6.7a1.66,1.66,0,0,0-1.2-.5c-1.1,0-1.8.89-1.8,2.4s.7,2.4,1.8,2.4a1.82,1.82,0,0,0,1.4-.6l.6.7a2.52,2.52,0,0,1-2,.9c-1.7,0-3-1.2-3-3.4S36.9,8.38,38.6,8.38Z"/><path class="cls-1" d="M47,20.08H25a1,1,0,0,1,0-2H46v-12H25a1,1,0,0,1-1-1,.94.94,0,0,1,1-1H47a.94.94,0,0,1,1,1v14A.94.94,0,0,1,47,20.08Z"/><path class="cls-1" d="M17,4.08a.76.76,0,0,1-.4-.1L12,2.17,7.4,4a1,1,0,0,1-1.3-.6.93.93,0,0,1,.6-1.3l5-2a.78.78,0,0,1,.7,0l5,2a1,1,0,0,1-.4,2Z"/><path class="cls-1" d="M23.4,12.18,22,11.47V5.08a.89.89,0,0,0-.3-.7l-1-1a1,1,0,0,0-1.4,1.4l.7.7v6.6a1,1,0,0,0,.6.89l1.4.7v.41H2v-.4L3.4,13a1,1,0,0,0,.6-.9V5.48l.7-.7a1,1,0,0,0-1.4-1.4l-1,1a.89.89,0,0,0-.3.7v6.39l-1.4.7a1,1,0,0,0-.6.91v2a.94.94,0,0,0,1,1H2.1c.5,4.7,4.5,8,9.9,8s9.4-3.3,9.9-8H23a.94.94,0,0,0,1-1v-2A1,1,0,0,0,23.4,12.18ZM12,22.08c-4.3,0-7.4-2.4-7.9-6H19.9C19.4,19.68,16.3,22.08,12,22.08Z"/></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 23.97"><defs><style>.cls-1{fill:#f68802;}.cls-2{fill:#191919;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="BC"><g id="OBC"><path class="cls-1" d="M26.3,11.67c0-2.1,1.2-3.4,2.9-3.4s2.9,1.2,2.9,3.4-1.2,3.4-2.9,3.4S26.3,13.77,26.3,11.67Zm4.6,0c0-1.5-.7-2.3-1.7-2.3s-1.7.9-1.7,2.3.7,2.4,1.7,2.4S30.9,13.17,30.9,11.67Z"/><path class="cls-1" d="M33.3,8.47h2.1c1.3,0,2.3.4,2.3,1.6a1.37,1.37,0,0,1-1.1,1.4h0c.9.2,1.5.7,1.5,1.5,0,1.3-1.1,1.9-2.5,1.9H33.3Zm2,2.7c.9,0,1.3-.3,1.3-1s-.4-.8-1.3-.8h-.8v1.8Zm.2,2.9c1,0,1.5-.4,1.5-1.1s-.5-1-1.5-1h-1v2.1Z"/><path class="cls-1" d="M41.9,8.27a3,3,0,0,1,1.9.81l-.6.69a1.66,1.66,0,0,0-1.2-.5c-1.1,0-1.8.91-1.8,2.41s.7,2.4,1.8,2.4a1.82,1.82,0,0,0,1.4-.6l.6.7a2.55,2.55,0,0,1-2,.9c-1.7,0-3-1.2-3-3.4A3,3,0,0,1,41.9,8.27Z"/><path class="cls-2" d="M47,20H25a1,1,0,0,1,0-2H46V6H25a.94.94,0,0,1-1-1,.94.94,0,0,1,1-1H47a.94.94,0,0,1,1,1V19A.94.94,0,0,1,47,20Z"/><path class="cls-1" d="M17,4a.76.76,0,0,1-.4-.1L12,2.07,7.4,4a1,1,0,0,1-1.3-.6.93.93,0,0,1,.6-1.3l5-2a.94.94,0,0,1,.7,0l5,2a1,1,0,0,1,.6,1.3A1.1,1.1,0,0,1,17,4Z"/><path class="cls-1" d="M17,8a.76.76,0,0,1-.4-.1L12,6.07,7.4,8a1,1,0,0,1-1.3-.6.93.93,0,0,1,.6-1.3l5-2a.85.85,0,0,1,.7,0l5,2a1,1,0,0,1,.6,1.3A1.1,1.1,0,0,1,17,8Z"/><path class="cls-1" d="M17,12a.76.76,0,0,1-.4-.1L12,10.07,7.4,12a1,1,0,0,1-1.3-.6.93.93,0,0,1,.6-1.3l5-2a.85.85,0,0,1,.7,0l5,2a1,1,0,0,1,.6,1.3A1.1,1.1,0,0,1,17,12Z"/><path class="cls-2" d="M23.4,12.07l-1.4-.7V5a.91.91,0,0,0-.3-.7l-1-1a1,1,0,1,0-1.4,1.4l.7.7V12a1,1,0,0,0,.6.9l1.4.7V14H2v-.4l1.4-.7A1,1,0,0,0,4,12V5.37l.7-.7a1,1,0,1,0-1.4-1.4l-1,1A.91.91,0,0,0,2,5v6.4l-1.4.7A1,1,0,0,0,0,13v2a.94.94,0,0,0,1,1H2.1c.5,4.7,4.5,8,9.9,8s9.4-3.3,9.9-8H23a.94.94,0,0,0,1-1V13A1,1,0,0,0,23.4,12.07ZM12,22c-4.3,0-7.4-2.4-7.9-6H19.9C19.4,19.57,16.3,22,12,22Z"/></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
Back/assets/images/bar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
Back/assets/images/gt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
Back/assets/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
Back/assets/images/lol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
Back/assets/images/oops.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 MiB

BIN
Back/assets/moderated.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
Back/assets/release2018.zip Normal file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,10 @@
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
<External>null</External>
<External>nil</External>
<Item class="StringValue" referent="RBX0">
<Properties>
<string name="Name">ScriptHashWhitelist</string>
<string name="Value">b3f0342949bc9635e34e278c04d6fd90;1cb5c76965c37c216582cee7e1433262;4c6721f4bea2341a4d4a684c7f966d90;8e56422fe1414961d2edff32f944bf92;786406a29a6e8490cb266c06201aa92e;b3ac4e73d3733a57dea03d692aa26e34;a53eba1de89dbfdb80b3254ee388531d;d15e92a3f0fc1e66cf41a5d73cebb840;f1dfdef5f37e69ddd3fd6333f26e88c8;433d57e8472a8a870e274598229a93d4;f5221aae14307e3bcb1a5d154c5ef2f5;5e18b9ddf23c4f03c0fd00ee9f74a6e8;e84848af1e7a5ef61fccd70017a1499c;ee2fda1680f29d1e15e9d70f9d061df3;a30f58b57cb09ac1655cde37c750b02b;8ee09525290e5fd8b1d7d90ff4e08772;;d39de7b8e14666fafed115fcac1bd42a;f9a3b2366970250006eb5871718d1386;d46bd2f63d3743df0d65fba0026b1b3e;79edcc2cec0a91fd1ba03de301277bf9;cae4b54d5a33a04fcc08b71a4910aa98;3a6bbcd590fb50a1ab2c96d4c5381354;047683e14c39fb0726d37978027e7e41;60fcf891d61f15810f7fc1fbc306085a;85da2a691ca195ba0c8b727be3708854;ab1d7c5bd750ad0445c5468199ba01c7;111a198bfda686f90c974c4bd51b0bbb;6b0f7786df852254ad76584baf51f8a7;aa5868b23b2df1bd213fc34f55daf17b;50fcb8a21a10b8125d4573eaf71318ad;c0a7d6ca6e952ec6ebcc37002cb8b290;9b726d1c7771bc42aa03175c6c8a43d0;9b726d1c7771bc42aa03175c6c8a43d0;f10d555101c69e7bc5445b363865835e;4a143d0239140a90a111a3f316ee3349;f52510d8205181ca455a559ec153be7acaa15d93952e7366992e31df5af18441;3fa1b59b140c7babcb10b61b186020ad;1ab108f066289efd10a903744e2d3fe1;fabd28d867d693e3e465703956169f81;22dbbfb129b56c2f44ed52daa5ae1739;eeaadc007ef349e545ea6cd8295ad541;7bb0d01aea154912c3200cf964766fd4;84bf56ebe05f1f5c78a7a9c4cad52f74;bf3cda0e4a61be31f3e628d60d409a84;3987ae32127e39d9a7703b024f931bcf;9a53dc1d8a18035c7500513833761fa9;66c6d6dcf60ba2cceb8a9e613587ca6b;dbae0bffeb10d9f2152d87d94db62496;89254cffbaa0282d6e5971c2a8c09e55;46cbe9b2a510f6257a7eac135aad5651;8b56bcdc48551aff9edeabae48d5141c;ff58e3a4e3f0e514ad0b6258432f4fcd;89254cffbaa0282d6e5971c2a8c09e55;0321b9659210929462de367df55322bb;1b011d0e9868c56338b00fc891895fc1;6c52a6ca7f539564dc7c0a4eb3969eeb;2c7a8324161637f30405729b19885573;92b59508c397fcb6086f287ebd1ea3cd;90846a9269ae1b0bada8b205d156cfc0;2f5206f708e95f55bbb1ea712267445b;0276a5c631983f84e676a6162dad4a11;b5c2f8dea2ab79fafa1139aa22e70588;193dcfdb1e760c52c4573873a441deab;0276a5c631983f84e676a6162dad4a11;</string>
</Properties>
</Item>
</roblox>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
Back/assets/video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

BIN
Back/assets/videos/test.mp4 Normal file

Binary file not shown.

View File

@ -0,0 +1,66 @@
-- This is the thumbnail script for R6 avatars. Straight up and down, with the right arm out if they have a gear.
local asset = 0
local baseurl = "http://mete0r.xyz" -- have to set to https for production
local HttpService = game:GetService("HttpService")
HttpService.HttpEnabled = true
---@diagnostic disable-next-line: invalid-class-name
local ThumbnailGenerator = game:GetService("ThumbnailGenerator")
pcall(function() game:GetService("ContentProvider"):SetBaseUrl(baseurl) end)
game:GetService("InsertService"):SetBaseSetsUrl(baseurl .. "/Game/Tools/InsertAsset.ashx?nsets=10&type=base")
game:GetService("InsertService"):SetUserSetsUrl(baseurl .. "/Game/Tools/InsertAsset.ashx?nsets=20&type=user&userid=%d")
game:GetService("InsertService"):SetCollectionUrl(baseurl .. "/Game/Tools/InsertAsset.ashx?sid=%d")
game:GetService("InsertService"):SetAssetUrl(baseurl .. "/Asset/?id=%d")
game:GetService("InsertService"):SetAssetVersionUrl(baseurl .. "/Asset/?assetversionid=%d")
---@diagnostic disable-next-line: invalid-class-name
pcall(function() game:GetService("ScriptInformationProvider"):SetAssetUrl(url .. "/Asset/") end)
game:GetService("ScriptContext").ScriptsDisabled = true
thing = game:GetService("InsertService"):LoadAsset(asset)
if thing:GetChildren()[1]:IsA("Shirt") or thing:GetChildren()[1]:IsA("Pants") then
local player = game:GetService("Players"):CreateLocalPlayer(0)
player:LoadCharacter()
thing:GetChildren()[1].Parent = player.Character
bcolor = Instance.new("BodyColors", player.Character)
bcolor.HeadColor = BrickColor.new(1001)
bcolor.TorsoColor = BrickColor.new(1001)
bcolor.LeftArmColor = BrickColor.new(1001)
bcolor.RightArmColor = BrickColor.new(1001)
bcolor.LeftLegColor = BrickColor.new(1001)
bcolor.RightLegColor = BrickColor.new(1001)
elseif thing:GetChildren()[1]:IsA("Decal") then
local player = game:GetService("Players"):CreateLocalPlayer(0)
player:LoadCharacter()
player.Character.Head.face:Destroy()
thing:GetChildren()[1].Parent = player.Character.Head
bcolor = Instance.new("BodyColors", player.Character)
bcolor.HeadColor = BrickColor.new(1001)
bcolor.TorsoColor = BrickColor.new(1001)
bcolor.LeftArmColor = BrickColor.new(1001)
bcolor.RightArmColor = BrickColor.new(1001)
bcolor.LeftLegColor = BrickColor.new(1001)
bcolor.RightLegColor = BrickColor.new(1001)
for _, child in pairs(player.Character:GetChildren()) do
if child.Name ~= "Head" and child:IsA("BasePart") then
child:Destroy()
end
end
else
thing.Parent = game.workspace
end
local arguments = {
["thumbnail"] = ThumbnailGenerator:Click("PNG", 400, 400, --[[hideSky = ]] true),
["asset"] = asset
}
HttpService:PostAsync(
baseurl .. "/api/thumbnailrender/rccasset",
HttpService:JSONEncode(arguments)
)

1
Back/clientid.txt Normal file
View File

@ -0,0 +1 @@
7c9f615b-8535-4e9c-96d0-dff4cecabdd1

View File

@ -0,0 +1,89 @@
const jwt = require('jsonwebtoken')
require('dotenv').config()
const JWT_SECRET = process.env.JWT_SECRET
const atob = require("atob");
const model = require("./../model/user.js")
const requireAuth = (req,res,next) => {
if (!req.cookies && req.headers['authorization']) {
return res.json({status: "error", error: "Unauthorized"})
}
let token = req.cookies.jwt??req.cookies['.ROBLOSECURITY']??req.headers['authorization']??req.headers['roblox-session-id']
if (!token) {
return res.status(401).json({status: "error", error: "Unauthorized"})
}
jwt.verify(token,JWT_SECRET, (err,decodedtoken) => {
if (err){
res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
return res.status(401).json({status: "error", error: "Unauthorized"})
}else{
var tokendata = decodedtoken
var name = tokendata.userid
try {
model.findOne({userid: name},async function(err, doc) {
req.numberofcoins = doc.coins
req.tokenData = tokendata
req.userdocument = doc
moderationstatus = JSON.parse(doc.moderation)
const actualTimeMilliseconds = new Date().getTime()
if (actualTimeMilliseconds - doc.timesincelastrequest >= 60000 * 1 || !doc.timesincelastrequest /*2 minutes make sure to update*/){
doc.timesincelastrequest = actualTimeMilliseconds
doc.markModified('timesincelastrequest')
await doc.save()
}
// check if they are eligble for daily login reward
if (actualTimeMilliseconds - req.userdocument.lastclaimofcurrency > 86400000){ // 24 hours
req.userdocument.lastclaimofcurrency = actualTimeMilliseconds
if (req.userdocument.membership === "TurboBuildersClub"){
req.userdocument.coins += 90
}else if (req.userdocument.membership === "BuildersClub"){
req.userdocument.coins += 60
}else if (req.userdocument.membership === "OutrageousBuildersClub"){
req.userdocument.coins += 150
}
else{
req.userdocument.coins += 35
}
req.userdocument.markModified('coins')
req.userdocument.markModified('lastclaimofcurrency')
await req.userdocument.save()
}
if (moderationstatus.status !== "ok") {
// if they are moderated then we invalidate the cookie and proceed
//res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
//return res.send("You have been moderated for "+moderationstatus.Reason+" expires at"+moderationstatus.ExpiresIn+" Moderated by "+moderationstatus.BannedBy )
var date = Date.parse(moderationstatus.ExpiresIn)
var datetime = new Date();
var datetime2 = Date.parse(datetime)
/*if (date <= datetime2){
// they have served there time
model.updateOne({userid: doc.userid}, {
$set: {
moderation: JSON.stringify({"status":"ok","Reason":"none","ExpiresIn":"none", "BannedBy": "none"})
}
},
function(err, doc) {
//console.log(err)
})
return next()
}*/
return res.json({status: "error", error:"Moderated", moderationstatus})
}
next()
})/*.lean() rip*/}
catch (error) {
console.error(error);
}
}
})
}
module.exports = {requireAuth}

View File

@ -0,0 +1,79 @@
const jwt = require('jsonwebtoken')
require('dotenv').config()
const JWT_SECRET = process.env.JWT_SECRET
const atob = require("atob");
const model = require("./../model/user.js")
// exactly the same as normal authimddleware but uses req.query instead of cookies for our client
const requireAuth = (req,res,next) => {
let token = req.query.auth
if (req.cookies && req.headers?.['user-agent'] != "Roblox/WinInet") { // Mobile
if (req.cookies.jwt) {
token = req.cookies.jwt
}
}
if (req.headers['roblox-session-id']) { // TeleportService
token = req.headers['roblox-session-id']
}
if (req.headers?.['user-agent']?.includes("Android") === true || req.headers?.['user-agent']?.includes("iPhone") === true){
console.log(token)
console.log(req.headers)
}
//console.log(req.headers)
if (!token) {
return res.status(405).end()
}
jwt.verify(token,JWT_SECRET, (err,decodedtoken) => {
if (err){
res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
return res.status(405)
}else{
var tokendata = decodedtoken
var name = tokendata.userid
try {
model.findOne({userid: name}, function(err, doc) {
req.numberofcoins = doc.coins
req.tokenData = tokendata
req.userdocument = doc
moderationstatus = JSON.parse(doc.moderation)
if (moderationstatus.status !== "ok") {
// if they are moderated then we invalidate the cookie and proceed
//res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
//return res.send("You have been moderated for "+moderationstatus.Reason+" expires at"+moderationstatus.ExpiresIn+" Moderated by "+moderationstatus.BannedBy )
var date = Date.parse(moderationstatus.ExpiresIn)
var datetime = new Date();
var datetime2 = Date.parse(datetime)
/*if (date <= datetime2){
// they have served there time
model.updateOne({userid: doc.userid}, {
$set: {
moderation: JSON.stringify({"status":"ok","Reason":"none","ExpiresIn":"none", "BannedBy": "none"})
}
},
function(err, doc) {
//console.log(err)
})
}*/
return res.json({status: "error", error:"Moderated", moderationstatus})
}
next()
})/*.lean() rip*/}
catch (error) {
console.error(error);
}
}
})
}
module.exports = {requireAuth}

View File

@ -0,0 +1,64 @@
const jwt = require('jsonwebtoken')
require('dotenv').config()
const JWT_SECRET = process.env.JWT_SECRET
const atob = require("atob");
const model = require("./../model/user.js")
const grabAuth = (req,res,next) => {
if (!req.cookies && req.headers['authorization']) {
return next()
}
const token = req.cookies.jwt??req.cookies['.ROBLOSECURITY']??req.headers['authorization']
if (!token) {
return next()
}
jwt.verify(token,JWT_SECRET, (err,decodedtoken) => {
if (err){
next()
}else{
var tokendata = decodedtoken
var name = tokendata.username
try {
model.findOne({username: new RegExp('^'+name+'$', "i")}, function(err, doc) {
req.numberofcoins = doc.coins
req.admin = doc.admin
req.tokenData = tokendata
req.userdocument = doc
moderationstatus = JSON.parse(doc.moderation)
if (moderationstatus.status !== "ok") {
// if they are moderated then we invalidate the cookie and proceed
//res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
//return res.send("You have been moderated for "+moderationstatus.Reason+" expires at"+moderationstatus.ExpiresIn+" Moderated by "+moderationstatus.BannedBy )
var date = Date.parse(moderationstatus.ExpiresIn)
var datetime = new Date();
var datetime2 = Date.parse(datetime)
if (date <= datetime2){
// they have served there time
model.updateOne({userid: doc.userid}, {
$set: {
moderation: JSON.stringify({"status":"ok","Reason":"none","ExpiresIn":"none", "BannedBy": "none"})
}
},
function(err, doc) {
//console.log(err)
})
}
return res.json({status: "error", error:"Moderated", moderationstatus})
}
next()
})/*.lean() rip*/}
catch (error) {
console.error(error);
}
}
})
}
module.exports = {grabAuth}

View File

@ -0,0 +1,11 @@
const requirediscord = (req,res,next) => {
const discordid = req.userdocument.discordid
if (!discordid) {
return res.json({status: "error", error: "Discord link required for develop. Link your discord in the settings panel."})
}else{
next();
}
};
module.exports = {requirediscord}

9
Back/model/bank.js Normal file
View File

@ -0,0 +1,9 @@
const mongoose = require('mongoose')
const bankSchema = new mongoose.Schema({
balance: {type: Number, required: true},
},
{collection: 'bank'}
)
const model = mongoose.model('bank', bankSchema)
module.exports = model

22
Back/model/comment.js Normal file
View File

@ -0,0 +1,22 @@
const mongoose = require('mongoose')
const CommentSchema = new mongoose.Schema({
associatedassetid: {type: Number, required: true, index: true},
associatedassettype: {type: String, required: true, index: true},
posterid: {type: Number, required: true},
content: {type: String, required: true},
date: {type: Number, required: true},
moderated: {type: Boolean, required: true}
},
{collection: 'comments'}
)
CommentSchema.virtual('poster', {
ref: 'UserSchema',
localField: 'posterid',
foreignField: 'userid',
justOne: true
})
const model = mongoose.model('CommentSchema', CommentSchema)
module.exports = model

13
Back/model/config.js Normal file
View File

@ -0,0 +1,13 @@
const mongoose = require('mongoose')
const ConfigSchema = new mongoose.Schema({
RegistrationEnabled: {type: Boolean, required: true},
MaintenanceEnabled: {type: Boolean, required: true},
KeysEnabled: {type: Boolean, required: true},
GamesEnabled: {type: Boolean, required: true}
},
{collection: 'config'}
)
const model = mongoose.model('ConfigSchema', ConfigSchema)
module.exports = model

29
Back/model/games.js Normal file
View File

@ -0,0 +1,29 @@
const mongoose = require('mongoose')
const GamesSchema = new mongoose.Schema({
useridofowner: {type: Number, required: true},
idofgame: {type: Number, required: true, index: true},
nameofgame: {type: String, required: true},
numberofplayers: {type: String, required: true},
descrption: {type: String, required: true},
datastore: {type: String, required: false},
visits: {type: Number, required: false},
version: {type: String, required: true},
featured: {type: Boolean, required: false},
players: {type: Object, required: false},
avatartype: {type: Object, required: false},
gearallowed: {type: Boolean, required: false},
comments: {type: Object, required: false}
},
{collection: 'games'}
)
GamesSchema.virtual('owner', {
ref: 'UserSchema',
localField: 'useridofowner',
foreignField: 'userid',
justOne: true
})
const model = mongoose.model('GamesSchema', GamesSchema)
module.exports = model

33
Back/model/groups.js Normal file
View File

@ -0,0 +1,33 @@
const mongoose = require('mongoose')
const GroupSchema = new mongoose.Schema({
Name: {type: String, required: true},
Description: {type: String, required: true},
Public: {type: Boolean, required: true},
IconApproved: {type: Boolean, required: true},
denied: {type: Boolean, required: false},
Hidden: {type: Boolean, required: false},
groupid: {type: Number, required: true},
ownerid : {type: Number, required: true},
memberscount: {type: Number, required: true},
members: {type: [{userId: Number, rank: Number}], required: true},
currentshout: {type: {content: String, shouter: Number}, required: false},
Roles: {type: [{RoleName: String, Permissions: {Shout: Boolean, Kick: Boolean, ChangeRoles: Boolean, ModerateWall: Boolean, ManageAllies: Boolean, All: Boolean}, Rank: Number}], required: true}, // default {}
},
{collection: 'groups'}
)
const model = mongoose.model('GroupSchema', GroupSchema)
GroupSchema.virtual('owner', {
ref: 'UserSchema',
localField: 'ownerid',
foreignField: 'userid',
justOne: true
})
GroupSchema.virtual('memberspoly', {
ref: 'UserSchema',
localField: 'members.userId',
foreignField: 'userid'
})
module.exports = model

View File

@ -0,0 +1,7 @@
import { Schema } from 'redis-om'
const ipWhiteListSchema = new Schema('ipWhiteListSchema', {
ip: { type: 'string' },
})
export default ipWhiteListSchema

23
Back/model/item.js Normal file
View File

@ -0,0 +1,23 @@
const mongoose = require('mongoose')
const CatalogSchema = new mongoose.Schema({
Name: {type: String, required: true},
Description: {type: String, required: false},
Price: {type: String, required: true},
Type: {type: String, required: true},
Creator: {type: Number, required: false},
Hidden: {type: Boolean, required: false},
ItemId: {type: String, required: true},
Sales: {type: Number, required: false},
ActiveAd: {type: Boolean, required: false}, // these 4 are for user generated ads
adtype: {type: String, required: false},
adredirectid: {type: String, required: false},
adstartedtime: {type: Number, required: false},
approved: {type: Boolean, required: true},
denied: {type: Boolean, required: false},
associatedgameid: {type: Number, required: false},
},
{collection: 'catalog'}
)
const model = mongoose.model('CatalogSchema', CatalogSchema)
module.exports = model

13
Back/model/keys.js Normal file
View File

@ -0,0 +1,13 @@
const mongoose = require('mongoose')
const KeysSchema = new mongoose.Schema({
Creator: {type: String, required: true},
Key: {type: String, required: true},
Used: {type: Boolean, required: true},
UsedBy: {type: String, required: false}
},
{collection: 'keys'}
)
const model = mongoose.model('KeysSchema', KeysSchema)
module.exports = model

11
Back/model/rcc.js Normal file
View File

@ -0,0 +1,11 @@
const mongoose = require('mongoose')
const RccSchema = new mongoose.Schema({
PlaceId: {type: Number, required: true},
Port: {type: Number, required: true},
Status: {type: Number, required: true},
},
{collection: 'RCC'}
)
const model = mongoose.model('RccSchema', RccSchema)
module.exports = model

10
Back/model/rcc2014.js Normal file
View File

@ -0,0 +1,10 @@
const mongoose = require('mongoose')
const Rcc2014Schema = new mongoose.Schema({
PlaceId: {type: Number, required: true},
Port: {type: Number, required: true}
},
{collection: 'RCC2014'}
)
const model = mongoose.model('Rcc2014Schema', Rcc2014Schema)
module.exports = model

11
Back/model/rcc2018.js Normal file
View File

@ -0,0 +1,11 @@
const mongoose = require('mongoose')
const Rcc2018Schema = new mongoose.Schema({
PlaceId: {type: Number, required: true},
Port: {type: Number, required: true},
Status: {type: Number, required: true},
},
{collection: 'RCC2018'}
)
const model = mongoose.model('Rcc2018Schema', Rcc2018Schema)
module.exports = model

11
Back/model/rcc2020.js Normal file
View File

@ -0,0 +1,11 @@
const mongoose = require('mongoose')
const Rcc2020Schema = new mongoose.Schema({
PlaceId: {type: Number, required: true},
Port: {type: Number, required: true},
Status: {type: Number, required: true},
},
{collection: 'RCC2020'}
)
const model = mongoose.model('Rcc2020Schema', Rcc2020Schema)
module.exports = model

62
Back/model/user.js Normal file
View File

@ -0,0 +1,62 @@
const mongoose = require('mongoose')
var uniqueValidator = require('mongoose-unique-validator');
const UserSchema = new mongoose.Schema({
username: {type: String, required: true, unique: true,uniqueCaseInsensitive: true},
password: {type: String, required: true},
coins: {type: Number, required: true},
admin: {type: Boolean, required: true},
ugcpermission: {type: Boolean, required: false},
userid: {type: Number, required: true, index: true},
moderation: {type: String, required: true},
moderationhistory: {type: Object, required: false},
inventory: {type: Object, required: false},
colors: {type: Object, required: false},
joindate: {type: String, required: true},
lastclaimofcurrency: {type: Number, required: true},
discordid: {type: String, required: false},
gamejoin: {type: String, required: false},
gamejoin2018: {type: String, required: false},
gamejoin2020: {type: String, required: false},
twofasecrets: {type: String, required: false},
followers: {type: Object, required: false},
friends: {type: Object, required: false},
friendrequests: {type: Object, required: false},
membership: {type: String, required: true},
badges: {type: Object, required: false},
status: {type: String, required: false},
timesincelastrequest: {type: Number, required: true},
avatartype: {type: String, required: false},
bio: {type: String, required: false},
recentlyplayed: {type: [{id: Number}], required: false},
css: {type: String, required: false},
aboutme: {type: String, required: false},
lastfeedsharetime: {type: Number, required: false},
feed: [{posterid: Number, content: String, date: Number, moderated: Boolean}], required: false},
{collection: 'users'}
)
UserSchema.plugin(uniqueValidator)
UserSchema.virtual('recentlyplayedgames', {
ref: 'GamesSchema',
localField: 'recentlyplayed.id',
foreignField: 'idofgame'
})
UserSchema.virtual('friendsdata', {
ref: 'UserSchema',
localField: 'friends.userid',
foreignField: 'userid'
})
UserSchema.virtual('feed.userdata', {
ref: 'UserSchema',
localField: 'feed.posterid',
foreignField: 'userid',
justOne: true
})
const model = mongoose.model('UserSchema', UserSchema)
module.exports = model

8812
Back/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

56
Back/package.json Normal file
View File

@ -0,0 +1,56 @@
{
"name": "datastoreservice",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"devStart": "cross-env PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host nodemon server.mjs",
"prod": "PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host pm2 start server.mjs",
"prodreload": "PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host pm2 reload server.mjs"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@mfd/rbxdatastoreservice": "^2.3.10",
"@yaireo/relative-time": "^1.0.3",
"atob": "^2.1.2",
"bcrypt": "^5.0.1",
"body-parser": "^1.20.0",
"connect-flash": "^0.1.1",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"daisyui": "^2.24.2",
"dotenv": "^16.0.1",
"easy-soap-request": "^4.8.0",
"esbuild": "0.17.4",
"express": "^4.18.1",
"express-flash-message": "^2.1.0",
"express-prom-bundle": "^6.5.0",
"express-rate-limit": "^6.7.0",
"express-session": "^1.17.3",
"file-type-checker": "^1.0.4",
"get-port": "^6.1.2",
"get-port-please": "^2.6.1",
"helmet": "^5.1.1",
"jsonwebtoken": "^9.0.0",
"mongo-sanitize": "^1.1.0",
"mongoose": "^6.5.2",
"mongoose-unique-validator": "^3.1.0",
"multer": "^1.4.5-lts.1",
"node-fetch": "^3.2.10",
"png-validator": "^1.1.0",
"prom-client": "^14.1.0",
"qrcode": "^1.5.1",
"redis": "^4.6.5",
"redis-om": "^0.4.0-beta.3",
"req-flash": "^0.0.3",
"speakeasy": "^2.0.0",
"xml-js": "^1.6.11",
"xss": "^1.0.13"
},
"devDependencies": {
"cross-env": "^7.0.3",
"nodemon": "^2.0.19"
}
}

320
Back/rcctalk.js Normal file
View File

@ -0,0 +1,320 @@
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
let controller = new AbortController();
require('dotenv').config()
const RCC_HOST = process.env.RCC_HOST
const url = 'http://'+RCC_HOST+':64989'; // change this to rcc soap
var convert = require('xml-js');
const sampleHeaders = {
'Content-Type': 'text/xml;charset=UTF-8',
};
async function OpenJob(jobid,script,expiration){
return new Promise(async (resolve, reject) => {
// this is all boilerplate because soap sucks
var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
'SOAP-ENV:Envelope': {
_attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:ns1': 'http://roblox.com/'
},
'SOAP-ENV:Body': {
'ns1:OpenJobEx': {
'ns1:job': {
'ns1:id': { _text: 'StringTest11' },
'ns1:expirationInSeconds': { _text: '10' },
'ns1:category': { _text: '0' },
'ns1:cores': { _text: '1' }
},
'ns1:script': {
'ns1:name': { _text: 'StringTest11-Script' },
'ns1:script': {
_text: 'print("Recieved job with ID " .. game.JobId)\r\n'
},
'ns1:arguments': {}
}
}
}
}
}
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobEx']['ns1:job']['ns1:id']._text = jobid
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobEx']['ns1:job']['ns1:expirationInSeconds']._text = expiration
if (!expiration) {
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobEx']['ns1:job']['ns1:expirationInSeconds']._text = "60"
}
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobEx']['ns1:script']['ns1:script']._text = script
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try {
const result = await fetch(url, { method: 'POST', body })
const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
return resolve(
convertedData
)
} catch (error) {
return reject(error)
}
})
}
async function GetAllJobs() {
return new Promise(async (resolve, reject) => {
const xmlData = (xml = {
_declaration: {
_attributes: { version: '1.0', encoding: 'UTF - 8' },
},
'SOAP-ENV:Envelope': {
_attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/',
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap',
'xmlns:ns1': 'http://roblox.com/',
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12',
},
'SOAP-ENV:Body': { 'ns1:GetAllJobsEx': {} },
},
})
const body = convert.js2xml(xmlData, { compact: true, spaces: 4 })
try {
const result = await fetch(url, { method: 'POST', body })
const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
return resolve(
convertedData['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:GetAllJobsExResponse']['ns1:GetAllJobsExResult']
)
} catch (error) {
return reject(error)
}
})
}
async function Execute(jobid,script) {
return new Promise(async (resolve, reject) => {
var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF - 8' } },
'SOAP-ENV:Envelope': {
_attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/',
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap',
'xmlns:ns1': 'http://roblox.com/',
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12'
},
'SOAP-ENV:Body': {
'ns1:ExecuteEx': {
'ns1:jobID': { _text: 'Test' },
'ns1:script': {
'ns1:name': { _text: 'Script' },
'ns1:script': { _text: 'print("no")' },
'ns1:arguments': { _text: '' }
}
}
}
}
}
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:ExecuteEx']['ns1:jobID']._text = jobid
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:ExecuteEx']['ns1:script']['ns1:script']._text = script
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try {
const result = await fetch(url, { method: 'POST', body })
const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
return resolve(
convertedData
)
} catch (error) {
return reject(error)
}
})
}
async function CloseJob(jobid) {
return new Promise(async (resolve, reject) => {
var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF - 8' } },
'SOAP-ENV:Envelope': {
_attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/',
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap',
'xmlns:ns1': 'http://roblox.com/',
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12'
},
'SOAP-ENV:Body': {
'ns1:CloseJob': {
'ns1:jobID': { _text: 'Test' }
}
}
}
}
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:CloseJob']['ns1:jobID']._text = jobid
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try {
const result = await fetch(url, { method: 'POST', body })
const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
return resolve(
convertedData
)
} catch (error) {
return reject(error)
}
})
}
async function RenewLease(jobid,expiration) {
return new Promise(async (resolve, reject) => {
var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
'SOAP-ENV:Envelope': {
_attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:ns1': 'http://roblox.com/',
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance'
},
'SOAP-ENV:Body': {
'ns1:RenewLease': {
'ns1:jobID': {
_attributes: { 'xsi:type': 'ns1:Job' },
'ns1:id': { _text: 'StringTest11' },
'ns1:expirationInSeconds': { _text: '10' },
'ns1:category': { _text: '0' },
'ns1:cores': { _text: '1' }
},
'ns1:expirationInSeconds': { _text: '100' }
}
}
}
}
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:RenewLease']['ns1:jobID']['ns1:id']._text = jobid
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:RenewLease']['ns1:expirationInSeconds']._text = expiration
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try {
const result = await fetch(url, { method: 'POST', body })
const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
return resolve(
convertedData
)
} catch (error) {
return reject(error)
}
})
}
async function GetExpiration(jobid){
return new Promise(async (resolve, reject) => {
var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
'SOAP-ENV:Envelope': {
_attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:ns1': 'http://roblox.com/'
},
'SOAP-ENV:Body': { 'ns1:GetExpiration': { 'ns1:jobID': { _text: 'Test' } } }
}
}
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:GetExpiration']['ns1:jobID']._text = jobid
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try {
const result = await fetch(url, { method: 'POST', body })
const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
return resolve(
convertedData
)
} catch (error) {
return reject(error)
}
})
}
//var gameservertxt = fs.readFileSync('actualgameserver.txt','utf-8')
//gameservertxt = gameservertxt.replace('function start(placeId, port, url)','function start(1111, port)')
async function CloseExpiredJobs(){
return new Promise(async (resolve, reject) => {
var xml = xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
'SOAP-ENV:Envelope': {
_attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:ns1': 'http://roblox.com/'
},
'SOAP-ENV:Body': { 'ns1:CloseExpiredJobs': {} }
}
}
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try {
const result = await fetch(url, { method: 'POST', body })
const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
return resolve(
convertedData
)
} catch (error) {
return reject(error)
}
})
}
async function CloseAllJobs(){
return new Promise(async (resolve, reject) => {
var xml = xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
'SOAP-ENV:Envelope': {
_attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:ns1': 'http://roblox.com/'
},
'SOAP-ENV:Body': { 'ns1:CloseAllJobs': {} }
}
}
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try {
const result = await fetch(url, { method: 'POST', body })
const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
return resolve(
convertedData
)
} catch (error) {
return reject(error)
}
})
}
module.exports = {OpenJob, GetAllJobs,Execute,CloseJob,RenewLease,GetExpiration,CloseExpiredJobs,CloseAllJobs}

300
Back/rcctalk2018.js Normal file
View File

@ -0,0 +1,300 @@
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
let controller = new AbortController();
require('dotenv').config()
const RCC_HOST = process.env.RCC_HOST
var convert = require('xml-js');
let url = 'http://'+RCC_HOST+':8000'; // change this to rcc soap
async function OpenGame(jobid,port,ip,placeid,creatorid){
return new Promise(async (resolve, reject) => {
let json = {"Mode":"GameServer","GameId":"game1","Settings":{"IsRobloxPlace":false,"PlaceId":1,"CreatorId":1,"GameId":"00000000-0000-0000-0000-000000000132","GsmInterval":50,"MaxPlayers":100,"MaxGameInstances":52,"ApiKey":"egg","GameCode":"AAAAAAAAAAAAAA-a","PreferredPlayerCapacity":10,"DatacenterId":1,"PlaceVisitAccessKey":"rbx_evt_ftp","UniverseId":13058,"PlaceFetchUrl":"https://mete0r.xyz/asset?id=11","MatchmakingContextId":1,"CreatorType":"User","PlaceVersion":123,"BaseUrl":"mete0r.xyz","MachineAddress":"localhost","JobId":"game1","PreferredPort":53640}}
json.GameId = jobid
json.Settings.PreferredPort = port
json.Settings.MachineAddress = ip
json.Settings.JobId = jobid
json.Settings.PlaceId = parseFloat(placeid)
json.Settings.UniverseId = json.Settings.PlaceId
json.Settings.CreatorId = creatorid
json.Settings.GameId = jobid
let xml = `<?xml version = "1.0" encoding = "UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://roblox.com/RCCServiceSoap" xmlns:ns1="http://roblox.com/" xmlns:ns3="http://roblox.com/RCCServiceSoap12">
<SOAP-ENV:Body>
<ns1:OpenJob>
<ns1:job>
<ns1:id>${jobid}</ns1:id>
<ns1:expirationInSeconds>60</ns1:expirationInSeconds>
<ns1:category>2</ns1:category>
<ns1:cores>1</ns1:cores>
</ns1:job>
<ns1:script>
<ns1:name>game1</ns1:name>
<ns1:script>${JSON.stringify(json)}</ns1:script>
</ns1:script>
</ns1:OpenJob>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>`
//console.log(encodeURIComponent(JSON.stringify(json)))
try {
const result = await fetch(url+"/opengame/"+jobid+"/"+encodeURIComponent(JSON.stringify(json)))
const data = await result.text()
return resolve(
data
)
} catch (error) {
return reject(error)
}
})
}
async function OpenGame2020(jobid,port,ip,placeid,creatorid){
return new Promise(async (resolve, reject) => {
let json = {"Mode":"GameServer","GameId":"game1","Settings":{"IsRobloxPlace":false,"PlaceId":1,"CreatorId":1,"GameId":"00000000-0000-0000-0000-000000000132","GsmInterval":50,"MaxPlayers":100,"MaxGameInstances":52,"ApiKey":"egg","GameCode":"AAAAAAAAAAAAAA-a","PreferredPlayerCapacity":10,"DatacenterId":1,"PlaceVisitAccessKey":"rbx_evt_ftp","UniverseId":13058,"PlaceFetchUrl":"https://mete0r.xyz/asset?id=11","MatchmakingContextId":1,"CreatorType":"User","PlaceVersion":123,"BaseUrl":"mete0r.xyz","MachineAddress":"localhost","JobId":"game1","PreferredPort":53640}}
json.GameId = jobid
json.Settings.PreferredPort = port
json.Settings.MachineAddress = ip
json.Settings.JobId = jobid
json.Settings.PlaceId = parseFloat(placeid)
json.Settings.UniverseId = json.Settings.PlaceId
json.Settings.CreatorId = creatorid
json.Settings.GameId = jobid
json.Settings.PlaceFetchUrl = "https://mete0r.xyz/asset?id="+parseFloat(placeid)
let xml = `<?xml version = "1.0" encoding = "UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://roblox.com/RCCServiceSoap" xmlns:ns1="http://roblox.com/" xmlns:ns3="http://roblox.com/RCCServiceSoap12">
<SOAP-ENV:Body>
<ns1:OpenJob>
<ns1:job>
<ns1:id>${jobid}</ns1:id>
<ns1:expirationInSeconds>60</ns1:expirationInSeconds>
<ns1:category>2</ns1:category>
<ns1:cores>1</ns1:cores>
</ns1:job>
<ns1:script>
<ns1:name>game1</ns1:name>
<ns1:script>${JSON.stringify(json)}</ns1:script>
</ns1:script>
</ns1:OpenJob>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>`
//console.log(encodeURIComponent(JSON.stringify(json)))
try {
const result = await fetch(url+"/opengame2020/"+jobid+"/"+encodeURIComponent(JSON.stringify(json)))
const data = await result.text()
return resolve(
data
)
} catch (error) {
return reject(error)
}
})
}
async function CloseJob(jobid) {
return new Promise(async (resolve, reject) => {
var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF - 8' } },
'SOAP-ENV:Envelope': {
_attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/',
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap',
'xmlns:ns1': 'http://roblox.com/',
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12'
},
'SOAP-ENV:Body': {
'ns1:CloseJob': {
'ns1:jobID': { _text: 'Test' }
}
}
}
}
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:CloseJob']['ns1:jobID']._text = jobid
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try {
const result = await fetch(url+"/closejob/"+jobid)
const data = await result.text()
return resolve(
data
)
} catch (error) {
return reject(error)
}
})
}
async function OpenRender(userid,closeup) {
return new Promise(async (resolve, reject) => {
try {
const result = await fetch(url+"/openrender/"+userid+"/"+closeup)
const data = await result.text()
//console.log(data)
if (data === '{"status": "error","error":"Already started"}'){
return resolve(
JSON.parse(data)
)
}
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
return resolve(
convertedData
)
} catch (error) {
return reject(error)
}
})
}
async function OpenRenderAsset(assetid,type) {
return new Promise(async (resolve, reject) => {
try {
const result = await fetch(url+"/openrenderasset/"+assetid+"/"+type)
const data = await result.text()
//console.log(data)
if (data === '{"status": "error","error":"Already started"}'){
return resolve(
JSON.parse(data)
)
}
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
return resolve(
convertedData
)
} catch (error) {
return reject(error)
}
})
}
async function lol2(){
const lol = await OpenRender(0)
console.log(lol['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobResponse']['ns1:OpenJobResult'][0]['ns1:value']._text)
}
async function RenewLease(jobid,expiration) {
return new Promise(async (resolve, reject) => {
var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
'SOAP-ENV:Envelope': {
_attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:ns1': 'http://roblox.com/',
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance'
},
'SOAP-ENV:Body': {
'ns1:RenewLease': {
'ns1:jobID': { _text: 'Test' },
'ns1:expirationInSeconds': { _text: '100' }
}
}
}
}
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:RenewLease']['ns1:jobID']._text = jobid
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:RenewLease']['ns1:expirationInSeconds']._text = expiration
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try {
const result = await fetch(url+"/renewlease/"+jobid+"/"+expiration)
const data = await result.text()
return resolve(
data
)
} catch (error) {
return reject(error)
}
})
}
async function Execute(jobid,json) {
return new Promise(async (resolve, reject) => {
try {
const result = await fetch(url+"/executejson/"+jobid+"/"+encodeURIComponent(JSON.stringify(json)))
const data = await result.text()
return resolve(
data
)
} catch (error) {
return reject(error)
}
})
}
async function GetAllJobs() {
return new Promise(async (resolve, reject) => {
const xmlData = (xml = {
_declaration: {
_attributes: { version: '1.0', encoding: 'UTF - 8' },
},
'SOAP-ENV:Envelope': {
_attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/',
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap',
'xmlns:ns1': 'http://roblox.com/',
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12',
},
'SOAP-ENV:Body': { 'ns1:GetAllJobsEx': {} },
},
})
const body = convert.js2xml(xmlData, { compact: true, spaces: 4 })
try {
const result = await fetch(url, { method: 'POST', body })
const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
return resolve(
convertedData['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:GetAllJobsExResponse']['ns1:GetAllJobsExResult']
)
} catch (error) {
return reject(error)
}
})
}
//RenewLease('game2',"69530318916789546987353800")
async function lol(){
let res = await GetAllJobs()
//console.dir(res,{ depth: null })
let exists = false
if (res != "{}"){
if (Array.isArray(res['ns1:Job']) === false){
console.log('asd')
//console.log(res['ns1:Job']['ns1:id']._text)
if (res['ns1:Job']['ns1:id']._text === 'game2'){
exists = true
}
}else{
res['ns1:Job'].forEach(element => {
if (element['ns1:id']?._text === 'game2'){
exists = true
}
})
}
}
console.log(exists)
}
//lol()
//GetAllJobs()
//OpenGame('game2','3333','127.0.0.1','2')
module.exports = {OpenGame,CloseJob,RenewLease,GetAllJobs,OpenRender,OpenRenderAsset,OpenGame2020,Execute}

110
Back/routes/2018/game.js Normal file
View File

@ -0,0 +1,110 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('../../middleware/authmiddlewaregame')
const crypto = require('crypto');
const fs = require('fs')
const key = fs.readFileSync('DefaultPrivateKey.pem')
const { getPort, checkPort, getRandomPort, waitForPort } = require('get-port-please')
const RCC_HOST = process.env.RCC_HOST
var sanitize = require('mongo-sanitize');
const games = require('./../../model/games.js')
const signatures = require("./../signatures.js")
const rcc = require('../../model/rcc2018.js')
const rcctalk = require('../../rcctalk2018')
const User = require('../../model/user.js')
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
const _2018placelauncher = async(req,res,next) => {
var enabled = req.config
if (enabled.GamesEnabled === false){
return res.json({status:"error",error:"Games are disabled bad boy"})
}
var joinJson = {"ClientPort":0,"MachineAddress":"localhost","ServerPort":25564,"PingUrl":"","PingInterval":120,"UserName":"default","SeleniumTestMode":false,"UserId":0,"SuperSafeChat":false,"CharacterAppearance":"http://shitncumblox.gq/game/charapp?name=default","ClientTicket":"","GameId":1,"PlaceId":1818,"MeasurementUrl":"","WaitingForCharacterGuid":"cad99b30-7983-434b-b24c-eac12595e5fd","BaseUrl":"http://www.mete0r.xyz/","ChatStyle":"ClassicAndBubble","VendorId":0,"ScreenShotInfo":"","VideoInfo":"<?xml version=\"1.0\"?><entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:media=\"http://search.yahoo.com/mrss/\" xmlns:yt=\"http://gdata.youtube.com/schemas/2007\"><media:group><media:title type=\"plain\"><![CDATA[ROBLOX Place]]></media:title><media:description type=\"plain\"><![CDATA[ For more games visit http://www.roblox.com]]></media:description><media:category scheme=\"http://gdata.youtube.com/schemas/2007/categories.cat\">Games</media:category><media:keywords>ROBLOX, video, free game, online virtual world</media:keywords></media:group></entry>","CreatorId":0,"CreatorTypeEnum":"User","MembershipType":"None","AccountAge":365,"CookieStoreFirstTimePlayKey":"rbx_evt_ftp","CookieStoreFiveMinutePlayKey":"rbx_evt_fmp","CookieStoreEnabled":true,"IsRobloxPlace":false,"GenerateTeleportJoin":false,"IsUnknownOrUnder13":false,"SessionId":"c25fd620-bbaa-4fb2-b022-3f053cdd1abd|00000000-0000-0000-0000-000000000000|0|204.236.226.210|8|2016-08-17T01:05:05.7115837Z|0|null|null|null|null","DataCenterId":0,"UniverseId":0,"BrowserTrackerId":0,"UsePortraitMode":false,"FollowUserId":0,"CharacterAppearanceId":1}
if (!req.query.name && !req.query.placeId && !req.query.placeid){
return res.json({status:"error",error:"no placeid bad"})
}
if (req.userdocument.gamejoin2018){
return res.json({"jobId":"Test","status":2,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2018&auth="+req.query.auth??req.cookies.jwt,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""})
}
var sanitizedplaceid = sanitize(req.query.name??req.query.placeId??req.query.placeid)
const game = await games.findOne({idofgame: sanitizedplaceid}).lean()
if (!game){
return res.json({status:"error",error:"that game doesn't exist!"})
}
if (game.version != "2018"){
return next()
}
let instance = await rcc.findOne({PlaceId: sanitizedplaceid}).lean()
if (instance && instance.Status === 2){
// if an rcc instance already exists we don't need to create a new one so we will just drag them into the existing game
joinJson.UserName = req.userdocument.username
joinJson.UserId = req.userdocument.userid
joinJson.CharacterAppearance = "http://mete0r.xyz/v1.1/avatar-fetch?userId" + req.userdocument.userid
joinJson.MachineAddress = RCC_HOST // need to put rcc host here lol
joinJson.ServerPort = instance.Port
joinJson.PlaceId = instance.PlaceId
joinJson.GameId = sanitizedplaceid
joinJson.CharacterAppearanceId = req.userdocument.userid
joinJson.MembershipType = req.userdocument.membership
joinJson.CreatorId = game.useridofowner
joinJson.SessionId = req.query.auth??req.cookies.jwt
const timestamp = Date.now()
joinJson.ClientTicket = timestamp+";" // timestamp
//create signature 1
const sign1 = crypto.createSign('SHA1');
sign1.update(`${req.userdocument.userid}\n`/*userid*/+`${req.userdocument.username}\n`/*username*/+`http://mete0r.xyz/v1.1/avatar-fetch?userId=${req.userdocument.userid}\n`/*charapp*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/)
var signature1 = sign1.sign(key, "base64")
joinJson.ClientTicket += signature1 + ";"
//create signature 2
const sign2 = crypto.createSign('SHA1');
sign2.update(`${req.userdocument.userid}\n`/*userid*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/)
var signature2 = sign2.sign(key, "base64")
joinJson.ClientTicket += signature2
req.userdocument.gamejoin2018 = JSON.stringify(joinJson)
req.userdocument.markModified('gamejoin2018')
await req.userdocument.save()
var joinScriptJson = {"jobId":"Test","status":2,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2018&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
return res.send(JSON.stringify(joinScriptJson))
}
if (instance && instance.Status === 1){
var joinScriptJson = {"jobId":"Test","status":1,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2018&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
return res.send(JSON.stringify(joinScriptJson))
}
var port = await getPort({random: true})
// launch job
rcctalk.OpenGame("game"+sanitizedplaceid,port,RCC_HOST,sanitizedplaceid,game.useridofowner)
//console.dir(response,{ depth: null })
//console.dir(response,{ depth: null })
await rcc.create({
PlaceId: sanitizedplaceid,
Port: port,
Status: 1 // 1 means loading
})
//console.log(newrenderscript)
var joinScriptJson = {"jobId":"Test","status":1,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2020&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
return res.send(JSON.stringify(joinScriptJson))
}
router.all("/2018/join",requireAuth,_2018placelauncher,async (req, res) => {
return res.json({status:"error",error:"Version different than client requested."})
})
//rcctalk.CloseJob('game2')
module.exports = {router: router, _2018placelauncher:_2018placelauncher}

207
Back/routes/2020/game.js Normal file
View File

@ -0,0 +1,207 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('../../middleware/authmiddlewaregame')
const crypto = require('crypto');
const fs = require('fs')
const key = fs.readFileSync('PrivateKey2020.txt')
const { getPort, checkPort, getRandomPort, waitForPort } = require('get-port-please')
const RCC_HOST = process.env.RCC_HOST
var sanitize = require('mongo-sanitize');
const games = require('./../../model/games.js')
const signatures = require("./../signatures.js")
const rcc = require('../../model/rcc2020.js')
const rcctalk = require('../../rcctalk2018')
const User = require('../../model/user.js')
const bodyParser = require('body-parser')
router.use(bodyParser.json())
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
const _2020placelauncher = async(req,res,next) => {
var enabled = req.config
if (enabled.GamesEnabled === false){
return res.json({status:"error",error:"Games are disabled bad boy"})
}
if (req.headers?.['user-agent']?.includes("Android") === true || req.headers?.['user-agent']?.includes("iPhone") === true){
console.log(req.headers)
console.log(req.userdocument.username)
}
if (req.method === "POST"){ // mobile join-game
req.query.name = req.body.placeId
}
var joinJson = {"ClientPort":0,"MachineAddress":"localhost","ServerPort":25564,"PingUrl":"","PingInterval":120,"UserName":"default","SeleniumTestMode":false,"UserId":0,"SuperSafeChat":false,"CharacterAppearance":"http://shitncumblox.gq/game/charapp?name=default","ClientTicket":"","GameId":1,"PlaceId":1818,"MeasurementUrl":"","WaitingForCharacterGuid":"cad99b30-7983-434b-b24c-eac12595e5fd","BaseUrl":"http://www.mete0r.xyz/","ChatStyle":"ClassicAndBubble","VendorId":0,"ScreenShotInfo":"","VideoInfo":"<?xml version=\"1.0\"?><entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:media=\"http://search.yahoo.com/mrss/\" xmlns:yt=\"http://gdata.youtube.com/schemas/2007\"><media:group><media:title type=\"plain\"><![CDATA[ROBLOX Place]]></media:title><media:description type=\"plain\"><![CDATA[ For more games visit http://www.roblox.com]]></media:description><media:category scheme=\"http://gdata.youtube.com/schemas/2007/categories.cat\">Games</media:category><media:keywords>ROBLOX, video, free game, online virtual world</media:keywords></media:group></entry>","CreatorId":0,"CreatorTypeEnum":"User","MembershipType":"None","AccountAge":365,"CookieStoreFirstTimePlayKey":"rbx_evt_ftp","CookieStoreFiveMinutePlayKey":"rbx_evt_fmp","CookieStoreEnabled":true,"IsRobloxPlace":false,"GenerateTeleportJoin":false,"IsUnknownOrUnder13":false,"SessionId":"c25fd620-bbaa-4fb2-b022-3f053cdd1abd|00000000-0000-0000-0000-000000000000|0|204.236.226.210|8|2016-08-17T01:05:05.7115837Z|0|null|null|null|null","DataCenterId":0,"UniverseId":0,"BrowserTrackerId":0,"UsePortraitMode":false,"FollowUserId":0,"CharacterAppearanceId":1}
if (!req.query.name && !req.query.placeId && !req.query.placeid){
return res.json({status:"error",error:"no placeid bad"})
}
if (req.userdocument.gamejoin2020){
return res.json({"jobId":"Test","status":2,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2020&auth="+req.query.auth??req.cookies.jwt,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""})
}
var sanitizedplaceid = sanitize(req.query.name??req.query.placeId??req.query.placeid)
const game = await games.findOne({idofgame: sanitizedplaceid}).lean()
if (!game){
return res.json({status:"error",error:"that game doesn't exist!"})
}
if (game.version != "2020"){
return next()
}
let instance = await rcc.findOne({PlaceId: sanitizedplaceid}).lean()
if (instance && instance.Status === 2){
// if an rcc instance already exists we don't need to create a new one so we will just drag them into the existing game
joinJson.UserName = req.userdocument.username
joinJson.UserId = req.userdocument.userid
joinJson.CharacterAppearance = "http://mete0r.xyz/v1.1/avatar-fetch?userId=" + req.userdocument.userid
joinJson.MachineAddress = RCC_HOST // need to put rcc host here lol
joinJson.ServerPort = instance.Port
joinJson.PlaceId = instance.PlaceId
joinJson.GameId = sanitizedplaceid
joinJson.CharacterAppearanceId = req.userdocument.userid
joinJson.MembershipType = req.userdocument.membership
joinJson.CreatorId = game.useridofowner
joinJson.SessionId = req.query.auth??req.cookies.jwt
const timestamp = Date.now()
joinJson.ClientTicket = timestamp+";" // timestamp
//create signature 1
const sign1 = crypto.createSign('SHA1');
sign1.update(`${req.userdocument.userid}\n`/*userid*/+`${req.userdocument.username}\n`/*username*/+`${"0"}\n`/*userid 2 that 0k wants for some reason what a retard*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/)
var signature1 = sign1.sign(key, "base64")
joinJson.ClientTicket += signature1 + ";"
//create signature 2
const sign2 = crypto.createSign('SHA1');
sign2.update(`${req.userdocument.userid}\n`/*userid*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/)
var signature2 = sign2.sign(key, "base64")
joinJson.ClientTicket += signature2 + ";4"
if (req.method === "POST" && req.body.isTeleport){ // mobile join-game
const mobileJoin =
{
"ClientPort": 0,
"MachineAddress": RCC_HOST,
"ServerPort": instance.Port,
"ServerConnections": [
{
"Address": RCC_HOST,
"Port": instance.Port
}
],
"DirectServerReturn": true,
"TokenGenAlgorithm": 0,
"PepperId": 0,
"TokenValue": "vg",
"PingUrl": "",
"PingInterval": 0,
"UserName": req.userdocument.username,
"SeleniumTestMode": false,
"UserId": req.userdocument.userid,
"RobloxLocale": "",
"GameLocale": "",
"SuperSafeChat": false,
"CharacterAppearance": "http://mete0r.xyz/v1.1/avatar-fetch?userId=" + req.userdocument.userid,
"ClientTicket": joinJson.ClientTicket,
"GameId": ""+sanitizedplaceid,
"PlaceId": sanitizedplaceid,
"BaseUrl": "http://www.mete0r.xyz/",
"ChatStyle": "ClassicAndBubble",
"CreatorId": game.useridofowner,
"CreatorTypeEnum": "User",
"MembershipType": req.userdocument.membership,
"AccountAge": 365,
"CookieStoreFirstTimePlayKey": "rbx_evt_ftp",
"CookieStoreFiveMinutePlayKey": "rbx_evt_fmp",
"CookieStoreEnabled": false,
"IsUnknownOrUnder13": false,
"GameChatType": "AllUsers",
"SessionId": req.query.auth??req.cookies.jwt,
"AnalyticsSessionId": "",
"DataCenterId": 0,
"UniverseId": sanitizedplaceid,
"FollowUserId": 0,
"characterAppearanceId": req.userdocument.userid,
"CountryCode": "US",
"AlternateName": "",
"RandomSeed1": "57575745353",
"ClientPublicKeyData": ""
}
console.log(mobileJoin)
return res.json({
"jobId": "Test",
"status": 2,
"joinScriptUrl": `http://mete0r.xyz/game/join.ashx?ver=2020&auth=${req.query.auth??req.cookies.jwt}`,
"authenticationUrl": "http://mete0r.xyz/Login/Negotiate.ashx",
"authenticationTicket": "SomeTicketThatDosentCrash",
"message": "",
"joinScript": mobileJoin
})
}
req.userdocument.gamejoin2020 = JSON.stringify(joinJson)
req.userdocument.markModified('gamejoin2020')
await req.userdocument.save()
var joinScriptJson = {"jobId":"Test","status":2,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2020&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
return res.send(JSON.stringify(joinScriptJson))
}
if (instance && instance.Status === 1){
var joinScriptJson = {"jobId":"Test","status":1,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2020&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
if (req.method === "POST" && req.body.isTeleport){ // mobile join-game
return res.json({
"jobId": "Test",
"status": 0,
"joinScriptUrl": "http://mete0r.xyz/game/join.ashx?ver=2020&auth="+req.query.auth??req.cookies.jwt,
"authenticationUrl": "http://mete0r.xyz/Login/Negotiate.ashx",
"authenticationTicket": "SomeTicketThatDosentCrash",
"message": ""
})
}
return res.send(JSON.stringify(joinScriptJson))
}
var port = 53640 + Math.floor(Math.random() * 100)
// launch job
rcctalk.OpenGame2020("game"+sanitizedplaceid,port,RCC_HOST,sanitizedplaceid,game.useridofowner)
//console.dir(response,{ depth: null })
await rcc.create({
PlaceId: sanitizedplaceid,
Port: port,
Status: 1 // 1 means loading
})
//console.log(newrenderscript)
var joinScriptJson = {"jobId":"Test","status":1,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2020&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
if (req.method === "POST" && req.body.isTeleport){ // mobile join-game
return res.json({
"jobId": "Test",
"status": 0,
"joinScriptUrl": "http://mete0r.xyz/game/join.ashx?ver=2020&auth="+req.query.auth??req.cookies.jwt,
"authenticationUrl": "http://mete0r.xyz/Login/Negotiate.ashx",
"authenticationTicket": "SomeTicketThatDosentCrash",
"message": ""
})
}
return res.send(JSON.stringify(joinScriptJson))
}
router.all(["/MTwentyTwenty.ashx","/2020/join","/join-game"],requireAuth,_2020placelauncher,async (req, res) => {
return res.json({status:"error",error:"Version different than client requested."})
})
//rcctalk.CloseJob('game2')
module.exports = {router: router, _2020placelauncher:_2020placelauncher}

188
Back/routes/admin.js Normal file
View File

@ -0,0 +1,188 @@
const express = require("express")
const router = express.Router()
var path = require('path')
const { requireAuth } = require('./../middleware/authmiddleware')
var multer = require('multer');
const bodyParser = require('body-parser')
router.use(bodyParser.json())
const User = require('./../model/games.js')
const ActualUser = require('./../model/user.js')
const catalog = require('./../model/item.js')
const games = require('./../model/games.js')
const rcc = require('./../model/rcc.js')
var numbtest = /^\d+\.?\d*$/;
const rcctalk = require('./../rcctalk')
require('dotenv').config()
const RCCDIR = process.env.RCC_Content
var thisistheplaceid = "1"
var storage = multer.diskStorage({
destination: function (req, file, cb) {
// Uploads is the Upload_folder_name
if (file.mimetype == "image/png"){
cb(null, "./assets/gameassets")
}else{
cb(null, "./assets/ugc")
}
},
filename: async function (req, file, cb) {
if (path.extname(file.originalname) === ".rbxl"){
const placeid = await User.countDocuments();
cb(null, file.fieldname + "-" + placeid +path.extname(file.originalname))
}else if (file.mimetype == "image/png"){
const placeid = await User.countDocuments();
cb(null, file.fieldname + "-" + placeid +path.extname(file.originalname))
}else if (file.mimetype == "application/octet-stream"){
const itemid = await catalog.countDocuments();
cb(null, file.fieldname + "-" + itemid +path.extname(file.originalname))
}
}
})
const upload = multer({storage: storage,
fileFilter: function (req, file, callback) {
var ext = path.extname(file.originalname);
if(ext !== '.png' && ext !== '.png' && ext !== '.rbxl') {
return callback('Only pngs and rbxl are allowed')
}
callback(null, true)
},
})
const itemupload = multer({storage: storage,
fileFilter: function (req, file, callback) {
var ext = path.extname(file.originalname);
if (req.userdocument.admin === "false"){
return callback('LEAVE')
}
if(ext !== '.png' && ext !== '.png' && ext !== '.rbxm') {
return callback('Only pngs and rbxm are allowed')
}
callback(null, true)
},
})
router.post("/uploaditem", requireAuth,itemupload.single("itemfile"),async (req, res) => {
if (req.userdocument.admin == false && req.userdocument?.ugcpermission == false) {
return res.redirect('/')
}
const xss = require('xss')
//console.log(req.body)
const {itemname, description, price,Type} = req.body
if (numbtest.test(price) == false){
return res.json({status: 'error', error: 'Price can only be a number!'})
}
try{
const itemid = await catalog.countDocuments();
const response = await catalog.create({
Name: xss(itemname),
Description: xss(description),
Price: price,
Type: Type,
Creator: req.userdocument.userid,
ItemId: itemid,
approved: true
})
}catch(error){
throw error
}
return res.json({status: "success", message: "Action completed."})
})
router.post("/moderateuser", requireAuth,async (req, res) => {
if (req.userdocument.admin == false) {
return res.redirect('/')
}
let {userid, reason, unbantime,Type} = req.body
if (numbtest.test(userid) == false){
return res.json({status: "error", error: "Userid can only be a number!"})
}
const lookupuser = await ActualUser.findOne({userid: userid}).lean()
if (!lookupuser) {
return res.json({status: "error", error: "User not found"})
}
if (Type === "Permanent Ban"){
unbantime = "2100-01-01"
}
if (Type === "Warning"){
unbantime = "2000-01-01"
}
//console.log(req.body)
//console.log(unbantime)
// if all above checks have passed lets set their moderation status and also log this entry for later lookup
var datetime = new Date();
ActualUser.updateOne({userid: userid}, {
$set: {
moderation: JSON.stringify({"status":Type,"Reason":reason,"ExpiresIn":unbantime, "BannedBy": req.userdocument.username})
},
$push: {
moderationhistory: {"status":Type,"Reason":reason, "BannedBy": req.userdocument.username, "Date": datetime.toISOString().slice(0,10)}
}
},
function(err, doc) {
//console.log(err)
})
return res.json({status: "success", message: "Action completed."})
})
router.post("/moderateuserlookup", requireAuth,async (req, res) => {
if (req.userdocument.admin == false) {
return res.redirect('/')
}
const {userid,username} = req.body
const whitelist = ["username","coins","userid","admin","moderation","colors","inventory","joindate","lastclaimofcurrency","membership","friendrequests","friends","badges","status","timesincelastrequest","avatartype","discordid","moderationhistory"]
if (numbtest.test(userid) == false && !username){
return res.json({status: "error", error: "Userid can only be a number!"})
}
let lookupuser
if (userid != ""){
lookupuser = await ActualUser.findOne({userid: userid}).lean().select(whitelist)
}else if (username){
lookupuser = await ActualUser.findOne({username: username}).lean().select(whitelist)
}
if (!lookupuser) {
return res.json({status: "error", error: "User not found reenter"})
}
return res.json({status: "success", data: lookupuser})
})
router.post("/queue", requireAuth,async (req, res) => {
if (req.userdocument.admin == false) {
return res.redirect('/')
}
const resultsPerPage = 30
let page = req.body.page ?? 0
if (page != 0){
page-=1
}
let {sort} = req.body
let response
let responsecount
if (sort != "All"){
response = await catalog.find({Type: sort, approved: false, Type: {$ne: "Image"}, denied: {$exists:false}}).limit(resultsPerPage).skip(0+parseFloat(page)*resultsPerPage).lean().select(['-_id'])
responsecount = await catalog.countDocuments({Type: sort, approved: false, Type: {$ne: "Image"}, denied: {$exists:false}})
}
if (sort === "All"){
response = await catalog.find({approved: false, Type: {$ne: "Image"}, denied: {$exists:false}}).limit(resultsPerPage).skip(0+parseFloat(page)*resultsPerPage).lean().select(['-_id'])
responsecount = await catalog.countDocuments({approved: false, Type: {$ne: "Image"}, denied: {$exists:false}})
}
return res.json({data: response, pages: Math.ceil(Math.max(responsecount/resultsPerPage, 1)), count: responsecount })
})
module.exports = router

View File

@ -0,0 +1,101 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const bodyParser = require('body-parser')
const User = require('./../../model/user.js')
const catalog = require('./../../model/item.js')
const games = require('./../../model/games.js')
router.use(bodyParser.json())
router.post("/",requireAuth,async (req, res) => {
let {itemid, AdId, type} = req.body
if (typeof itemid == "undefined"){
return res.json({status: "error", error: "ItemId not sent!"})
}
if (typeof AdId == "undefined"){
return res.json({status: "error", error: "Ad ID not sent!"})
}
if (typeof type == "undefined"){
return res.json({status: "error", error: "Type not sent!"})
}
if (type != "game" && type != "item"){
return res.json({status: "error", error: "Invalid Type!"})
}
if (req.userdocument.coins < 10){
return res.json({status: "error", error: "You don't have enough Rocks!"})
}
const Addoc = await catalog.findOne({ItemId: AdId})
if (!Addoc || Addoc?.Type != "User Ad"){
return res.json({status: "error", error: "Not found"})
}
if (Addoc.Creator != req.userdocument.userid){
return res.json({status: "error", error: "Not Authorized"}) // tried to use someone elses ad
}
if (Addoc.ActiveAd === true){ // ad is already running
return res.json({status: "error", error: "You are already running this ad!"})
}
if (Addoc.Hidden){
return res.json({status: "error", error: "Ad is moderated!"})
}
if (Addoc.approved === false){
return res.json({status: "error", error: "Ad is pending approval!"})
}
let itemdoc
if (type === "game"){
itemdoc = await games.findOne({idofgame: itemid}).lean()
}
if (!itemdoc){
return res.json({status: "error", error: "Not found"})
}
if (type === "game"){
if (itemdoc.useridofowner != req.userdocument.userid){ // make sure we only let game owners advertise there game
return res.json({status: "error", error: "Not Authorized"})
}
}
if (type === "item"){
if (itemdoc.Creator != req.userdocument.userid){ // make sure we only let item owners advertise there item
return res.json({status: "error", error: "Not Authorized"})
}
}
req.userdocument.coins -= 10
req.userdocument.markModified('coins')
await req.userdocument.save()
Addoc.adtype = type
Addoc.adredirectid = itemid
Addoc.ActiveAd = true
Addoc.adstartedtime = Date.now()
Addoc.markModified('adtype')
Addoc.markModified('adredirectid')
Addoc.markModified('ActiveAd')
Addoc.markModified('adstartedtime')
await Addoc.save()
return res.json({status: "success", message: "Done!"})
})
module.exports = router

80
Back/routes/api/auth.js Normal file
View File

@ -0,0 +1,80 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const bodyParser = require('body-parser')
const User = require('./../../model/user.js')
router.use(bodyParser.json())
function selectKeys(obj, keysArray) {
let result = {};
for (let i = 0; i < keysArray.length; i++) {
if (keysArray[i] in obj === true) {
result[keysArray[i]] = obj[keysArray[i]];
}
}
return result;
}
router.get("/",requireAuth,async (req, res) => {
const filtered = selectKeys(req.userdocument,["username","coins","userid","admin","ugcpermission","moderation","colors","inventory","joindate","lastclaimofcurrency","membership","friendrequests","friends","badges","status","timesincelastrequest","avatartype","discordid","bio","recentlyplayed","css"])
//console.log(filtered.recentlyplayedgames)
filtered._2faenabled = false
if (req.userdocument?.twofasecrets){
const json = JSON.parse(req.userdocument.twofasecrets)
if (json.verified === true){
filtered._2faenabled = true
}
}
return res.json(filtered)
})
router.post("/recentgames",requireAuth,async (req, res) => {
const response = await User.findOne({userid: req.userdocument.userid}).lean().populate({path: "recentlyplayedgames",select: ["useridofowner","nameofgame","numberofplayers","version","visits"] , populate: {path: "owner", select: ["username"]}}).select("recentlyplayed")
return res.json(response.recentlyplayedgames)
})
router.post("/requestfriends",requireAuth,async (req, res) => {
let response = await User.findOne({userid: req.userdocument.userid}).lean().populate({path: "friendsdata",select: ["username","status","timesincelastrequest"]}).select("friends")
let friendsdata = []
if (response.friendsdata){
response.friendsdata.forEach(function (item, index) {
let status = {status: "Offline"}
if (item.status){
status = JSON.parse(item.status)
}
const actualTimeMilliseconds = new Date().getTime()
if (item.timesincelastrequest && actualTimeMilliseconds - item.timesincelastrequest >= 60000 * 3 /*3 minutes*/ && status && status.status.includes("Playing") === false || item.timesincelastrequest && actualTimeMilliseconds - item.timesincelastrequest >= 60000 * 3 /*3 minutes*/ && !status){
// been 3 minutes since last request mark as offline make sure we don't mark them offline while they are playing a game
status.status = "Offline"
item.status = JSON.stringify(status)
status = JSON.parse(item.status)
}
if (item.timesincelastrequest && actualTimeMilliseconds - item.timesincelastrequest <= 60000 * 3 /*3 minutes*/ && status && status.status.includes("Playing") === false || item.timesincelastrequest && actualTimeMilliseconds - item.timesincelastrequest <= 60000 * 3 /*3 minutes*/ && !status){
status.status = "Online"
item.status = JSON.stringify(status)
status = JSON.parse(item.status)
}
item.status = status
friendsdata.push(item)
})
}
// playing is 1st online is second and offline is last :)
friendsdata.sort((a, b) => {
if (a.status.status.includes("Playing") === true && b.status.status !== 'Playing') {
return -1; // a should appear before b
} else if (a.status.status.includes("Playing") === false && b.status.status.includes("Playing") === true) {
return 1; // a should appear after b
} else if (a.status.status === 'Online' && b.status.status === 'Offline') {
return -1; // a should appear before b
} else if (a.status.status === 'Offline' && b.status.status === 'Online') {
return 1; // a should appear after b
} else {
return 0; // the order of a and b doesn't matter
}
})
return res.json(friendsdata)
})
module.exports = router

80
Back/routes/api/bank.js Normal file
View File

@ -0,0 +1,80 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const bodyParser = require('body-parser')
var numbtest = /^\d+\.?\d*$/;
const bank = require('./../../model/bank.js')
const User = require('./../../model/user.js')
router.use(bodyParser.json())
const speakeasy = require('speakeasy')
async function Fill(){
if (!await bank.findOne()) {
await bank.create({
balance: 5000
})
}
}
Fill()
router.get("/value",async (req, res) => {
const response = await bank.findOne()
return res.json({status: "success", balance: response.balance})
})
router.post("/transaction/:id",async (req, res) => {
const {apiKey, amount} = req.body
if (!apiKey || !amount){
return res.json({status: "error", error: "Missing parameters"})
}
if (apiKey !== "5#t#!aH52QAzY4@HF0C1k5quK&piuY9C"){
return res.json({status: "error", error: "Missing parameters"})
}
if (isNaN(amount) === true){
return res.json({status: "error", error: "Amount must be a number!"})
}
const response = await bank.findOne()
if (amount > response.balance){
return res.json({status: "error", error: "Not enough money"})
}
const user = await User.findOne({userid: req.params.id})
if (!user){
return res.json({status: "error", error: "User not found"})
}
if (amount < 0){ // negative
if (user.coins - Math.abs(amount) < 0){ // they will have negative coins
return res.json({status: "error", error: "User will have negative coins."})
}else{
user.coins += amount
user.markModified('coins')
await user.save()
}
}
if (amount > 0){
user.coins += amount
user.markModified('coins')
await user.save()
}
response.balance += amount * -1
response.markModified('balance')
await response.save()
return res.json({status: "success", balance: response.balance})
})
module.exports = router

View File

@ -0,0 +1,51 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const User = require('./../../model/user.js')
const bodyParser = require('body-parser')
const validTypes = [
'all',
'Head',
'Torso',
'Left Arm',
'Right Arm',
'Left Leg',
'Right Leg'
]
router.use(bodyParser.json())
router.post("/",requireAuth,async (req, res) => {
const {Type,color} = req.body
if (typeof Type == "undefined"){
return res.json("Send Type Please")
}
if (typeof color == "undefined"){
return res.json("Send Color Please")
}
if (!isNaN(color) === false){
return res.json("Color needs to be a number lol")
}
if (validTypes.includes(Type) === true){
try{
for (const obj of req.userdocument.colors) {
if (Type === "all"){
obj.value = color
req.userdocument.markModified('colors')
await req.userdocument.save()
}
if (obj.name === Type){
obj.value = color
req.userdocument.markModified('colors')
await req.userdocument.save()
}
}
}catch(err){
console.log(err)
}
return res.json({status: 'success', message: "Color change successful"})
}
// they tried to submit an invalid form
return res.json({status: "error", error: "Invalid Type"})
})
module.exports = router

View File

@ -0,0 +1,37 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const User = require('./../../model/user.js')
const bodyParser = require('body-parser')
const bcrypt = require('bcrypt')
router.use(bodyParser.json())
router.post("/",requireAuth,async (req, res) => {
const {oldpassword,newpassword} = req.body
if (!oldpassword || typeof oldpassword !== 'string') {
return res.json({status: 'error', error: 'Old password needs to be sent and it needs to be a string'})
}
if (!newpassword || typeof newpassword !== 'string') {
return res.json({status: 'error', error: 'New password needs to be sent and it needs to be a string'})
}
if(newpassword.length < 4) {
return res.json({status: 'error', error: 'Password needs to be at least 5 characters'})
}
if(await bcrypt.compare(oldpassword, req.userdocument.password)) {
// password matches
const newhashedpassword = (await bcrypt.hash(newpassword, 10))
try{
req.userdocument.password = newhashedpassword
req.userdocument.markModified('password')
await req.userdocument.save()
}catch{
}
return res.json({status: 'success', message: 'Changed Password!'})
}
res.json({status: 'error', error: 'Invalid old password'})
})
module.exports = router

103
Back/routes/api/comment.js Normal file
View File

@ -0,0 +1,103 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const games = require('./../../model/games.js')
const catalog = require('./../../model/item.js')
const comments = require('./../../model/comment.js')
const bodyParser = require('body-parser')
router.use(bodyParser.json())
const rateLimit = require('express-rate-limit')
const limiter = rateLimit({
windowMs: 10 * 1000, // 10 seconds
max: 1, // Limit each IP to 1 requests per `window`
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
handler: (request, response, next, options) =>{
return response.json({status: 'error', error: 'Too many requests try again later.'})
}
})
router.post("/post", requireAuth,limiter,async (req, res) => {
let {comment, AssociatedAssetType, AssociatedAssetId} = req.body
AssociatedAssetId = parseInt(AssociatedAssetId)
if (!comment || typeof AssociatedAssetType !== "string"){
return res.json("Send comment and associated asset id please")
}
if (comment.length > 200){
return res.json({status: 'error', error: "Comment too long!"})
}
if (AssociatedAssetType !== "game" && AssociatedAssetType !== "item"){
return res.json({status: 'error', error: "Invalid asset type!"})
}
if (AssociatedAssetType === "game"){
const game = await games.findOne({idofgame: AssociatedAssetId}).lean()
if (!game){
return res.json({status: 'error', error: "Game not found!"})
}
}
if (AssociatedAssetType === "item"){
const item = await catalog.findOne({ItemId: AssociatedAssetId}).lean()
if (!item){
return res.json({status: 'error', error: "Game not found!"})
}
}
await comments.create({
associatedassetid: AssociatedAssetId,
associatedassettype: AssociatedAssetType,
posterid: req.userdocument.userid,
content: comment,
date: new Date().getTime(),
moderated: false
})
return res.json({status: 'success', message: "Comment posted!"})
})
router.post("/get", requireAuth,async (req, res) => {
let {AssociatedAssetType, AssociatedAssetId} = req.body
AssociatedAssetId = parseInt(AssociatedAssetId)
const resultsPerPage = 20
let cursor = req.body.page >= 0 ? req.body.page : 0
if (cursor != 0){
cursor-=1
}
if (!AssociatedAssetType || typeof AssociatedAssetId === undefined){
return res.json({status: 'error', error: "Send comment and associated asset id please"})
}
if (AssociatedAssetType !== "game" && AssociatedAssetType !== "item"){
return res.json({status: 'error', error: "Invalid asset type!"})
}
let commentsarray
let commentscount
if (AssociatedAssetType === "game"){
const game = await games.findOne({idofgame: AssociatedAssetId}).lean()
if (!game){
return res.json({status: 'error', error: "Game not found!"})
}
}
if (AssociatedAssetType === "item"){
const item = await catalog.findOne({ItemId: AssociatedAssetId}).lean()
if (!item){
return res.json({status: 'error', error: "Game not found!"})
}
}
commentsarray = await comments.find({associatedassetid: AssociatedAssetId, associatedassettype: AssociatedAssetType}).lean().sort({date: 'descending'}).populate({path: "poster",select: ["username"]}).select(["posterid", "content", "date", "poster"]).skip(0+parseFloat(cursor)*resultsPerPage).limit(resultsPerPage)
commentscount = await comments.countDocuments({associatedassetid: AssociatedAssetId, associatedassettype: AssociatedAssetType})
return res.json({status: 'success', data: commentsarray, pages: Math.ceil(Math.max(commentscount/resultsPerPage, 1))})
})
module.exports = router

55
Back/routes/api/feed.js Normal file
View File

@ -0,0 +1,55 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const User = require('./../../model/user.js')
const bodyParser = require('body-parser')
router.use(bodyParser.json())
router.post("/share",requireAuth,async (req, res) => {
let { sharevalue } = req.body
if (!sharevalue || typeof sharevalue !== 'string'){
return res.json({status: "error", error: "Share value not sent!"})
}
if (sharevalue.length > 100){
return res.json({status: "error", error: "Share value too long!"})
}
const date = new Date().getTime()
if (date - req.userdocument?.lastfeedsharetime < 3600000){
return res.json({status: "error", error: "You can only share once an hour!"})
}
let posterid = req.userdocument.userid
User.updateOne({userid: req.userdocument.userid}, {
$push: {
feed: {posterid, content: sharevalue, date, moderated: false}
},
$set: {
lastfeedsharetime: date
}
},
function(err, doc) {
})
res.json({status: "success", message: "Done!"}) // the next operation could take some time and we wouldn't want the client to cancel during that!!
if (req.userdocument.friends){
//console.log(req.userdocument.friends)
for (let item of req.userdocument.friends) {
User.updateOne({userid: item.userid}, {
$push: {
feed: {posterid, content: sharevalue, date, moderated: false}
}
},
function(err, doc) {
})
}
}
})
router.post("/fetch",requireAuth,async (req, res) => {
let feed = await User.findOne({userid: req.userdocument.userid}).lean().populate({path: "feed.userdata",select: ["username"]}).select('feed')
return res.json({status: "success", data: feed.feed})
})
module.exports = router

188
Back/routes/api/friends.js Normal file
View File

@ -0,0 +1,188 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const games = require('./../../model/games.js')
const User = require('./../../model/user.js')
const bodyParser = require('body-parser')
router.use(bodyParser.json())
router.post("/request-friendship", requireAuth,async (req, res) => {
const tofriend = req.body.recipientUserId
if (!tofriend){
return res.json({status:"error",error:"Recipent not sent!"})
}
const usertofriend = await User.findOne({userid: tofriend}).lean()
if (!usertofriend){
return res.json({status:"error",error:"Can't find Recipent!"})
}
if (usertofriend.friends){
const friends = usertofriend.friends.some(word => word.userid == req.userdocument.userid)
if (friends === true){
return res.json({status:"error",error:"You are already friends!"})
}
// already friends
}
if (req.userdocument.friendrequests){
// check if the other user is already requesting to friend the player so then they both want to be firends so we can interperept this as an accept request
const bothwantobefriends = req.userdocument.friendrequests.some(word => word.userid == usertofriend.userid)
if (bothwantobefriends === true){
console.log(tofriend)
User.updateOne({userid: req.userdocument.userid}, {
$push: {
friends: {userid: usertofriend.userid, username: usertofriend.username}
},
$pull: {
friendrequests: {userid: usertofriend.userid, username: usertofriend.username}
}
},
function(err, doc) {
})
User.updateOne({userid: tofriend}, {
$push: {
friends: {userid: req.userdocument.userid, username: req.userdocument.username}
},
$pull: {
friendrequests: {userid: req.userdocument.userid, username: req.userdocument.username}
}
},
function(err, doc) {
})
return res.json({status:"success",message:"You are now friends :D"})
}
}
if (usertofriend.friendrequests){
const alreadyrequested = usertofriend.friendrequests.some(word => word.userid == req.userdocument.userid)
// already friend requested
if (alreadyrequested === true){
return res.json({status:"error",error:"You already sent this request!"})
}
}
User.updateOne({userid: usertofriend.userid}, {
$push: {
friendrequests: {userid: req.userdocument.userid, username: req.userdocument.username}
}
},
function(err, doc) {
})
return res.json({status:"success",message:"Friend request sent!"})
})
router.post("/decline-friend-request",requireAuth,async (req, res) => {
const tounfriend = req.body.recipientUserId
//console.log(tounfriend+" nerd")
if (!tounfriend){
return res.json({status:"error",error:"Recipent not sent!"})
}
const usertofriend = await User.findOne({userid: tounfriend}).lean()
if (!usertofriend){
return res.json({status:"error",error:"Can't find Recipent!"})
}
const alreadyfriends = req.userdocument?.friends?.some(word => word.userid == tounfriend )
if (alreadyfriends === true){
// already friends with the person so they want ro remove their friend
User.updateOne({userid: tounfriend}, {
$pull: {
friends: {userid: req.userdocument.userid, username: req.userdocument.username}
}
},
function(err, doc) {
//console.log(err)
})
User.updateOne({userid: req.userdocument.userid}, {
$pull: {
friends: {userid:usertofriend.userid, username: usertofriend.username}
}
},
function(err, doc) {
//console.log(err)
})
return res.json({status:"error",error:"Unfriended friend!"})
}
//otherwise the user isn't friends but still declines the friend request
User.updateOne({userid: tounfriend}, {
$pull: {
friendrequests: {userid: req.userdocument.userid, username: req.userdocument.username}
}
},
function(err, doc) {
//console.log(err)
})
User.updateOne({userid: req.userdocument.userid}, {
$pull: {
friendrequests: {userid: usertofriend.userid, username: usertofriend.username}
}
},
function(err, doc) {
//console.log(err)
})
return res.json({status:"success",message:"Declined friend request!"})
})
router.post("/has-sent-request",requireAuth,async (req, res) => {
const tofriend = req.body.recipientUserId
if (!tofriend){
return res.json({status:"error",error:"Recipent not sent!"})
}
const usertofriend = await User.findOne({userid: tofriend}).lean()
if (!usertofriend){
return res.json({status:"error",error:"Can't find Recipent!"})
}
const friends = usertofriend?.friends?.some(word => word.userid == req.userdocument.userid)
if (friends === true){
return res.json({status:"error",error:"You are already friends!"})
}
// already friends
const alreadyrequested = usertofriend?.friendrequests?.some(word => word.userid == req.userdocument.userid)
// already friend requested
if (alreadyrequested === true){
return res.json({status:"success",message:true})
}
const bothwantobefriends = req.userdocument?.friendrequests?.some(word => word.userid == usertofriend.userid)
if (bothwantobefriends === true){
return res.json({status:"success",message:"Other user wants to be friends."})
}
return res.json({status:"success",message:false})
})
router.post('/friend-requests',requireAuth, async (req, res) => {
res.json({data: req.userdocument?.friendrequests})
});
module.exports = router

View File

@ -0,0 +1,49 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const bodyParser = require('body-parser')
const keys = require('./../../model/keys.js')
router.use(bodyParser.json())
// hay this code hasn't been updated so it contains very old code because I haven't bothered to add key support since the last time they existed 2 months ago?
function stringGen(len) {
var text = "";
var charset = "abcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < len; i++)
text += charset.charAt(Math.floor(Math.random() * charset.length));
return text;
}
router.post("/",requireAuth,async (req, res) => {
if (req.userdocument.admin === true){
var key = stringGen(10)
const response = await keys.create({
Creator: req.userdocument.username,
Key: key,
Used: false
})
return res.redirect(req.get('referer'));
}
if (req.userdocument.coins >= 100){
// they have enough
req.userdocument.coins -= 100
req.userdocument.markModified('coins')
await req.userdocument.save()
var key = stringGen(10)
const response = await keys.create({
Creator: req.userdocument.username,
Key: key,
Used: false
})
return res.redirect(req.get('referer'));
}
return res.redirect(req.get('referer'));
})
module.exports = router

182
Back/routes/api/groups.js Normal file
View File

@ -0,0 +1,182 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const bodyParser = require('body-parser')
const groups = require('./../../model/groups.js')
var multer = require('multer');
const fs = require('fs');
const path = require('path')
router.use(bodyParser.json())
router.post("/", requireAuth,async (req, res) => {
let mygroups = await groups.find({"members.userId": req.userdocument.userid}).lean().select(["Name","Description","Public","groupid","ownerid","memberscount"])
return res.json(mygroups)
})
router.post("/:id", requireAuth,async (req, res) => {
const groupid = parseInt(req.params.id)
if (isNaN(groupid)){
return res.json({status: "error", error: "Not found"})
}
let groupresponse = await groups.findOne({groupid}).lean().select(["Name","Description","Public","groupid","ownerid","memberscount","currentshout"]).populate({path: "owner",select: ["username", "userid"]})
if (!groupresponse){
return res.json({status: "error", error: "Not found"})
}
return res.json({status: "success", data: groupresponse})
})
router.post("/:id/members", requireAuth,async (req, res) => {
const groupid = parseInt(req.params.id)
const {rank} = req.body
if (!rank){
return res.json({status: "error", error: "Rank not sent"})
}
const resultsPerPage = 5
let page = req.body.page ?? 0
if (page != 0){
page-=1
}
let skip = 0+parseFloat(page)*resultsPerPage
if (isNaN(groupid)){
return res.json({status: "error", error: "Not found"})
}
let groupresponse = await groups.findOne({groupid}).lean().select({"members": { "$slice" : [ skip, resultsPerPage ] }}).populate({path: "memberspoly",select: ["username", "userid"]})
if (!groupresponse){
return res.json({status: "error", error: "Not found"})
}
return res.json({status: "success", data: groupresponse.memberspoly})
})
async function validateImage(groupid,res){
return new Promise(async (resolve) => {
try {
const myArrayBuffer = await fs.promises.readFile(path.resolve(`assets/groupicons/icon-${groupid}.png`), null)
pngValidator(myArrayBuffer);
// success
} catch {
// file is invalid or corrupt
fs.unlink(path.resolve(`assets/groupicons/icon-${groupid}.png`), (err => {
if (err) console.log(err)
}));
return res.json({status: 'error', error: 'Image is invalid.'})
}
resolve()
})
}
var storage = multer.diskStorage({
destination: function (req, file, cb) {
// Uploads is the Upload_folder_name
cb(null, "./assets/groupicons")
},
filename: async function (req, file, cb) {
const groupid = await groups.countDocuments();
cb(null, "icon-" + groupid + ".png")
}
})
const uploadicon = multer({storage: storage,
fileFilter: function (req, file, callback) {
if(file.mimetype != 'image/png') {
return callback('Invalid file type')
}
callback(null, true)
},
limits: { fileSize: 1024 * 1024 } // 1mb
})
router.post("/create", requireAuth,async (req, res) => {
if (req.userdocument.coins < 100){
return res.json({status: "error", error: "You don't have enough Rocks!"})
}
uploadicon.single("groupicon")(req, res, async function (err) {
if (err) {
if (err?.message === "File too large"){
return res.status(400).send({status: 'error', error: "File too large! 1MB Limit"})
}
if (err === "Invalid file type"){
return res.status(400).send({status: 'error', error: "Invalid file type"})
}
return res.status(400).send({status: 'error', error: err.message})
}
var xss = require("xss")
const {groupname, description,publicgroup} = req.body
if (!groupname){
return res.json({status: 'error', error: 'Group name needs to be sent.'})
}
if (!description){
return res.json({status: 'error', error: 'Description needs to be sent.'})
}
if (!publicgroup){
return res.json({status: 'error', error: 'Public group needs to be sent.'})
}
if (publicgroup != "true" && type != "false"){
return res.json({status: 'error', error: 'Public group needs to be a true or false value.'})
}
const groupid = await groups.countDocuments();
// check if the file they just uploaded is valid
await validateImage(groupid,res)
let IconApproved = req.userdocument.admin === false ? false : true
await groups.create({
Name: xss(groupname),
Description: xss(description),
Public: publicgroup,
IconApproved,
groupid,
ownerid: req.userdocument.userid,
memberscount: 1,
members: [{userId: req.userdocument.userid, rank: 3}],
Roles: [{RoleName: "Members", Permissions: {Shout: false, Kick: false, ChangeRoles: false, ModerateWall: false, ManageAllies: false}, Rank: 1}, {RoleName: "Admin", Permissions: {Shout: true, Kick: true, ChangeRoles: true, ModerateWall: true, ManageAllies: false}, Rank: 2}, {RoleName: "Owner", Permissions: {All: true}, Rank: 3}]
})
return res.json({status: "success", message: "Group created!"})
})
})
router.post("/editgroup", requireAuth,async (req, res) => {
})
router.post("/postshout", requireAuth,async (req, res) => {
})
router.post("/joingroup", requireAuth,async (req, res) => {
})
router.post("/leavegroup", requireAuth,async (req, res) => {
})
router.post("/exile", requireAuth,async (req, res) => {
})
module.exports = router

View File

@ -0,0 +1,82 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const User = require('./../../model/user.js')
const bodyParser = require('body-parser')
router.use(bodyParser.json())
router.post("/", requireAuth,async (req, res) => {
const {action,itemid} = req.body
if (typeof action == "undefined"){
return res.json("Send Action Please")
}
if (typeof itemid == "undefined"){
return res.json("Send Itemid Please")
}
if (action === "wear"){
for (const obj of req.userdocument.inventory) {
if (parseInt(obj.ItemId) === itemid){
// they own it
// lets check if they already have it equipped
if (obj.Equipped === true){
return res.json({status: 'error', error: "You already have this Equipped!"})
}
// they own it and don't have it equipped already so lets add it
try{
obj.Equipped = true
req.userdocument.markModified('inventory')
await req.userdocument.save()
}catch(err){
console.log(err)
}
return res.json({status: 'ok', error: "Equipped!"})
}
}
// they don't own it
return res.json({status: 'error', error: "You don't own this!"})
}
if (action === "remove"){
for (const obj of req.userdocument.inventory) {
if (parseInt(obj.ItemId) === itemid){
// they own it
// lets check if they don't already don't it equipped
if (obj.Equipped === false){
return res.json({status: 'error', error: "You already don't this Equipped!"})
}
// they own it and don't have it not equipped already lets remove it
try{
obj.Equipped = false
req.userdocument.markModified('inventory')
await req.userdocument.save()
}catch(err){
console.log(err)
}
return res.json({status: 'ok', error: "Equipped!"})
}
}
// they don't own it
return res.json({status: 'error', error: "You don't own this!"})
}
})
module.exports = router

View File

@ -0,0 +1,91 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const items = require('./../../model/item.js')
const bodyParser = require('body-parser')
const fs = require('fs')
const path = require("path");
router.use(bodyParser.json())
router.post("/", requireAuth,async (req, res) => {
let {itemid} = req.body
if (typeof itemid == "undefined"){
return res.json({status: 'error', error: "itemid not sent!"})
}
itemid = parseInt(itemid)
if (req.userdocument.admin == false && req.userdocument?.ugcpermission == false) {
return res.redirect('/')
}
const item = await items.findOne({ItemId: itemid})
if (item.Creator != req.userdocument.userid && req.userdocument.admin === false){ // basically we want ugc uploaders to be able to delete there own items but not other peoples items
return res.json({status: 'error', error: "You don't own this item!"})
}
try{
items.updateOne({ItemId: itemid}, {
$set: {
Hidden: true
}
},
function(err, doc) {
//console.log(err)
})
// delete the item from our servers
fs.unlink(path.resolve(path.resolve(__dirname, "../../assets/ugc/itemfile-"+itemid+".rbxm")), (err => {
if (err) console.log(err)
}));
}catch(err){
console.log(err)
}
return res.json({status: 'success'})
})
router.post("/queue", requireAuth,async (req, res) => {
const {action,itemid} = req.body
if (typeof action == "undefined"){
return res.json("Send Action Please")
}
if (typeof itemid == "undefined"){
return res.json("Send Itemid Please")
}
if (req.userdocument.admin == false) {
return res.redirect('/')
}
const item = await items.findOne({ItemId: itemid})
if (!item){
return res.json({status: "error", error: "Send Itemid Please"})
}
console.log(action)
if (action === "deny"){
item.Hidden = true
item.denied = true
item.markModified("Hidden")
item.markModified("denied")
await item.save()
fs.unlink(path.resolve(path.resolve(__dirname, "../../assets/ugc/itemfile-"+itemid+".rbxm")), (err => {
if (err) console.log(err)
}));
}
if (action === "approve"){
item.approved = true
item.markModified("approved")
await item.save()
if (item.Type === "Shirts" || item.Type === "Pants"){
// we also have to approve the associated image
const image = await items.findOne({ItemId: parseInt(itemid)-1})
image.approved = true
image.markModified("approved")
await image.save()
}
}
// finish this LMAO pretty ez tho
return res.json({status: "success", message: "Done!"})
})
module.exports = router

View File

@ -0,0 +1,83 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const bodyParser = require('body-parser')
var numbtest = /^\d+\.?\d*$/;
const items = require('./../../model/item.js')
const User = require('./../../model/user.js')
router.use(bodyParser.json())
router.post("/", requireAuth,async (req, res) => {
if (!req.userdocument.discordid) {
return res.json({status: "error", error: "Discord link required for purchasing. Link your discord in the settings panel."})
}
const {itemid} = req.body
if (typeof itemid == "undefined"){
return res.json({status: "error", error: "You need sum itemids bozo"})
}
if (numbtest.test(itemid) == false){
return res.json({status: "error", error: "You need sum itemids bozo"})
}
const itemdoc = await items.findOne({ItemId: itemid})//.lean()
if (typeof req.userdocument.inventory !== "undefined"){
// check if user already owns item
for (var v of req.userdocument.inventory){
if (v.ItemId === itemdoc.ItemId){
// they already own it
return res.json({status: 'error', error: "You already own this!"})
}
}
}
if (itemdoc.Type === "Mesh" || itemdoc.Type === "Audio" || itemdoc.Type === "Mesh"){
return res.json({status: 'error', error: "You can't buy assets."})
}
if (itemdoc.Hidden){
return res.json({status: 'error', error: "You can't buy this."})
}
if (req.userdocument.coins >= itemdoc.Price){
// has enough money to purcahse item
try{
User.updateOne({userid: req.userdocument.userid}, {
$set: {
coins: req.userdocument.coins - itemdoc.Price
},
$push: {
inventory: {Type: itemdoc.Type,ItemId: itemdoc.ItemId, ItemName: itemdoc.Name, Equipped: false}
}
},
function(err, doc) {
//console.log(err)
})
// give owner cash
User.updateOne({userid: itemdoc.Creator}, {
$inc: {
coins: itemdoc.Price
}
},
function(err, doc) {
//console.log(err)
})
itemdoc.Sales += 1
if (!itemdoc.Sales){
itemdoc.Sales = 1
}
//console.log(itemdoc.Sales)
itemdoc.markModified('Sales')
await itemdoc.save()
}catch{
}
return res.json({status: 'success', message: 'Purchase successful'})
}
// too poor
return res.json({status: 'error', error: "You don't have enough rocks"})
})
module.exports = router

View File

@ -0,0 +1,249 @@
const express = require("express")
const router = express.Router()
const rcctalk = require('./../../thumbnailrcctalk')
const rcctalk2018 = require('./../../rcctalk2018')
const fs = require('fs')
const assetrenderscript = fs.readFileSync('assetthumbnailrenderer.lua','utf-8')
var path = require("path");
const User = require('./../../model/user.js')
const item = require('./../../model/item.js')
var rgx = /^[0-9]*\.?[0-9]*$/;
router.use(express.json({limit: '200mb'}));
const { requireAuth } = require('./../../middleware/authmiddleware.js')
const { grabAuth } = require('./../../middleware/grabauth.js')
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
require('dotenv').config()
const RCC_HOST = process.env.RCC_HOST
const rateLimit = require('express-rate-limit')
const limiter = rateLimit({
windowMs: 2 * 1000, // 5 seconds
max: 1, // Limit each IP to 1 requests per `window`
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
handler: (request, response, next, options) =>{
return response.sendFile(path.resolve("./assets/default.png"))
}
})
router.get("/",grabAuth,async (req, res) => {
if (!req.query.id && !req.query.userId) {
return res.status(400)
}
let headshot = false
if (req.query.type === "headshot"){
headshot = true
}
let id = req.query.id??req.query.userId
var sanitizedid = id.match(rgx)
const user = await User.findOne({userid: sanitizedid}).lean()
if (!user) {
return res.json({status: 'error', error: 'User does not exist'})
}
// lets get our file path with sanitized id
let path2=path.resolve(__dirname, "../../assets/userthumbnails/"+sanitizedid+".png")
if (headshot === true){
path2=path.resolve(__dirname, "../../assets/userthumbnailsheadshots/"+sanitizedid+".png")
}
fs.access(path2, fs.F_OK,async (err) => {
if (err) {
let newrender = await rcctalk2018.OpenRender(sanitizedid,headshot)
if (newrender.error){
return res.sendFile(path.resolve("./assets/default.png"))
}
newrender = newrender['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobResponse']['ns1:OpenJobResult'][0]['ns1:value']._text
res.writeHead(200, {'Content-Type': 'image/png'})
fs.writeFile(path2,newrender,'base64',function(err){
if (err) {
console.log("error")
}
})
return res.end(Buffer.from(newrender, 'base64'))
// if this timeouts and rcc doesn't return the image feor some reason then send the default fallback
//return res.sendFile(path.resolve("./assets/default.png"))
}
//file exists
if (req.query.method && req.userdocument && req.userdocument.userid == sanitizedid){ // don't allow unauthenticated users to regenerate avatars and don't allow authenticated users to regenerate other peoples avatars
if (req.query.method === "regenerate"){
fs.unlink(path2,async function (err) {
if (err){
console.log(err)
}
let newrender = await rcctalk2018.OpenRender(sanitizedid,headshot)
if (newrender.error){
return res.sendFile(path.resolve("./assets/default.png"))
}
newrender = newrender['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobResponse']['ns1:OpenJobResult'][0]['ns1:value']._text
res.writeHead(200, {'Content-Type': 'image/png'})
fs.writeFile(path2,newrender,'base64',function(err){
if (err) {
console.log("error")
}
})
return res.end(Buffer.from(newrender, 'base64'))
});
}
}else{
res.sendFile(path.resolve(path2))
return
}
})
})
router.post("/rcc", (req, res) => {
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress
if (ip == RCC_HOST || ip == "::ffff:"+RCC_HOST) {
const {player, thumbnail} = req.body
let path2=path.resolve(__dirname, "../../assets/userthumbnails/"+player+".png")
fs.writeFile(path2,thumbnail,'base64',function(err){
if (err) {
console.log("error")
// if writing fails we can still fallback
return res.sendFile(path.resolve("./../../assets/default.png"))
}
// if it succeeds then we can send the userthumbnail
// close the job after
rcctalk.CloseJob("Thumbnailfor"+player)
})
}
})
router.get(["/asset","/asset.ashx"],grabAuth,async (req, res) => {
if (!req.query.id && !req.query.assetid) {
return res.status(400)
}
let id = req.query.id??req.query.assetid
var sanitizedid = id.match(rgx)
const user = await item.findOne({ItemId: sanitizedid}).lean()
if (!user) {
return res.json({status: 'error', error: 'Item does not exist'})
}
if (user.Type === "Audio"){
return res.sendFile(path.resolve("./assets/images/audio.png"))
}
if (user.Hidden === true){
// if item isn't supposed to have a thumbnail
return res.sendFile(path.resolve("./assets/moderated.png"))
}
if (user.approved === false && !req.query.nonapproved){
return res.sendFile(path.resolve("./assets/approval.png"))
}
if (req.query.nonapproved && req?.userdocument?.admin === false){ // we only want admins to be able to see non approved assets anyways
return res.sendFile(path.resolve("./assets/approval.png"))
}
if (req.query.nonapproved && (user.Type === "Pants" || user.Type === "Shirts")){
sanitizedid -= 1
return res.sendFile(path.resolve(__dirname, "../../assets/ugc/itemfile-"+sanitizedid+".rbxm"))
}
if (req.query.nonapproved && user.Type === "Video"){
return res.sendFile(path.resolve(__dirname, "../../assets/ugc/itemfile-"+sanitizedid+".rbxm"))
}
if (user.Type === "Video"){
return res.sendFile(path.resolve("./assets/video.png"))
}
if (user.Type === "User Ad" || user.Type === "Gamepass"){
try{
await fs.promises.access(path.resolve(__dirname, "../../assets/ugc/itemfile-"+sanitizedid+".rbxm"), fs.constants.W_OK)
return res.sendFile(path.resolve(__dirname, "../../assets/ugc/itemfile-"+sanitizedid+".rbxm"))
}catch{
return res.sendFile(path.resolve("./assets/images/defaultadsky.png"))
}
}
// lets get our file path with sanitized id
let path2=path.resolve(__dirname, "../../assets/ugc/asset-"+sanitizedid+".png")
fs.access(path2, fs.F_OK,async (err) => {
if (err) {
// get our renderscript with the new character app
var newrenderscript = assetrenderscript.replace('local asset = 0','local asset = "'+sanitizedid+'"')
//open a new job for our thumbnail render request
var response = await rcctalk.OpenJob("Thumbnailfor"+sanitizedid,newrenderscript,"120")
if (response['SOAP-ENV:Envelope']['SOAP-ENV:Body']['SOAP-ENV:Fault']){
// if failed then print out error close job then send a fallback image
//console.dir(response,{ depth: null })
rcctalk.CloseJob("Thumbnailfor"+sanitizedid)
return res.sendFile(path.resolve("./assets/default.png"))
}else{
// send image to user
// wait for image to be uploaded by rcc
function check() {
setTimeout(() => {
fs.access(path2, fs.constants.F_OK, error => {
if (error) {
check()
} else {
return res.sendFile(path2)
}
});
},3000)
}
}
check()
// if this timeouts and rcc doesn't return the image feor some reason then send the default fallback
return res.sendFile(path.resolve("./assets/default.png"))
}
res.sendFile(path.resolve(path2))
return
})
})
router.post("/rccasset", (req, res) => {
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress
if (ip == RCC_HOST || ip == "::ffff:"+RCC_HOST) {
const {asset, thumbnail} = req.body
console.log(asset)
let path2=path.resolve(__dirname, "../../assets/ugc/asset-"+asset+".png")
fs.writeFile(path2,thumbnail,'base64',function(err){
if (err) {
console.log("error")
// if writing fails we can still fallback
return res.sendFile(path.resolve("./../../assets/default.png"))
}
// if it succeeds then we can send the userthumbnail
// close the job after
rcctalk.CloseJob("Thumbnailforasset"+asset)
})
}
})
module.exports = router

View File

@ -0,0 +1,40 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const bodyParser = require('body-parser')
const catalog = require('./../../model/item.js')
//const path = require('path');
router.use(bodyParser.json())
// only supports skyscraper ads for now
router.get("/",async (req, res) => {
const activeAdCount = await catalog.countDocuments({ActiveAd: true})
//console.log(activeAdCount)
let random = Math.floor(Math.random() * activeAdCount)
const Addoc = await catalog.findOne({ActiveAd: true}).skip(random)
if (!Addoc){
// no ads are running!
return res.json({imageUrl: "/assets/images/defaultadsky.png", redirectUrl: "#", AdID: 0})
}
if (Addoc.adstartedtime <= new Date(new Date().getTime() - (24 * 60 * 60 * 1000)).getTime() || Addoc.Hidden){
// more than 24 hours old invalidate ad OR ad was moderated
Addoc.ActiveAd = false
Addoc.markModified('ActiveAd')
await Addoc.save()
}
let redirectUrl
if (Addoc.adtype === "game"){
redirectUrl = "/games/"+Addoc.adredirectid
}
return res.json({imageUrl: "/api/thumbnailrender/asset?id="+Addoc.ItemId, redirectUrl, AdID: Addoc.ItemId})
})
module.exports = router

View File

@ -0,0 +1,270 @@
const express = require("express")
const router = express.Router()
const bodyParser = require('body-parser')
const rcc = require('./../../model/rcc.js')
const rcc2018 = require('./../../model/rcc2018.js')
const rcc2020 = require('./../../model/rcc2020.js')
const games = require('./../../model/games.js')
const rcctalk = require('./../../rcctalk')
const rcctalk2018 = require('./../../rcctalk2018')
const User = require('../../model/user.js')
router.use(bodyParser.json())
require('dotenv').config()
const RCC_HOST = process.env.RCC_HOST
router.post("/api/updategameinfo", async (req, res) => {
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress
if (ip == RCC_HOST || ip == "::ffff:"+RCC_HOST) {
const {game,players} = req.body
//const instance = await rcc.findOne({PlaceId: game}).lean()
games.updateOne({idofgame: game}, {
$set: {
numberofplayers: parseInt(players).toString()
}
},
function(err, doc) {
//console.log(err)
})
res.send("good")
}
})
router.all(["/api/updategameinfo/updatevisits","/game/placevisit.ashx"], async (req, res) => {
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress
if (ip == RCC_HOST || ip == "::ffff:"+RCC_HOST) {
let {game} = req.body
if (req.query.AssociatedPlaceID){
game = req.query.AssociatedPlaceID
}
//const instance = await rcc.findOne({PlaceId: game}).lean()
games.updateOne({idofgame: game}, {
$inc: {
visits: 1
}
},
function(err, doc) {
//console.log(err)
})
res.send("good")
}
})
router.all("/api/updategameinfo/gameloaded", async (req, res) => {
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress
if (ip == RCC_HOST || ip == "::ffff:"+RCC_HOST) {
let {game} = req.body
const gamedoc = await games.findOne({idofgame: game}).lean()
if (gamedoc.version === "2020"){
rcc2020.updateOne({PlaceId: game}, {
$set: {
Status: 2
}
},
function(err, doc) {
//console.log(err)
})
}
if (gamedoc.version === "2018"){
rcc2018.updateOne({PlaceId: game}, {
$set: {
Status: 2
}
},
function(err, doc) {
//console.log(err)
})
}
if (gamedoc.version === "2016"){
rcc.updateOne({PlaceId: game}, {
$set: {
Status: 2
}
},
function(err, doc) {
//console.log(err)
})
}
res.send("good")
}
})
router.post("/api/updategameinfo/closejob", async (req, res) => {
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress
if (ip == RCC_HOST || ip == "::ffff:"+RCC_HOST) {
console.log("closed")
let {game} = req.body
if(typeof game === 'string'){
game = game.replace('game','')
}
//const instance = await rcc.findOne({PlaceId: game}).lean()
games.updateOne({idofgame: game}, {
$set: {
numberofplayers: "0"
}
},
function(err, doc) {
//console.log(err)
})
games.updateOne({idofgame: game}, {
$set: {
players: []
}
},
function(err, doc) {
//console.log(err)
})
const gamedoc = await games.findOne({idofgame: game}).lean()
try{
if (gamedoc.version === "2018"){
await rcc2018.deleteOne({PlaceId: game})
rcctalk2018.CloseJob("game"+game)
}
}catch{}
try{
if (gamedoc.version === "2020"){
await rcc2020.deleteOne({PlaceId: game})
rcctalk2018.CloseJob("game"+game)
}
}catch{}
try{
if (gamedoc.version === "2016"){
await rcc.deleteOne({PlaceId: game})
rcctalk.CloseJob("game"+game)
}
}catch{}
res.send("good")
}
})
router.get("/api/updategameinfo/closealljobs", async (req, res) => {
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress
if (ip == RCC_HOST || ip == "::ffff:"+RCC_HOST) {
console.log("closed all")
//const instance = await rcc.findOne({PlaceId: game}).lean()
await rcc.deleteMany({})
games.updateMany({version: "2016"}, {
$set: {
numberofplayers: "0"
}
},
function(err, doc) {
//console.log(err)
})
games.updateMany({version: "2016"}, {
$set: {
players: []
}
},
function(err, doc) {
//console.log(err)
})
rcctalk.CloseAllJobs()
res.send("good")
}
})
router.all(["/api/updategameinfo/updatepresence"], async (req, res) => {
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress
if (ip == RCC_HOST || ip == "::ffff:"+RCC_HOST) {
let {game,player,name,action} = req.body
game = await games.findOne({idofgame: game})
if (action === "joining" || action === "connect"){
const updatedcount = parseFloat(game.numberofplayers)+1
games.updateOne({idofgame: game.idofgame}, {
$push: {
players: {userid: player, name: name}
},
$set: {
numberofplayers: updatedcount.toString()
}
},
function(err, doc) {
//console.log(err)
})
User.updateOne({userid: player}, {
$set: {
status: JSON.stringify({status: "Playing "+game.nameofgame,id: game.idofgame})
},
$addToSet: {
recentlyplayed: {id: game.idofgame}
},
},
function(err, doc) {
//console.log(err)
})
User.updateOne({userid: player}, {
$set: {
status: JSON.stringify({status: "Playing "+game.nameofgame,id: game.idofgame})
},
$push: {
recentlyplayed: {$each: [], $slice: -10}// limit for recently played is 10 so slice anything older than that
},
},
function(err, doc) {
//console.log(err)
})
if (game.version === "2018" || game.version === "2020"){
rcctalk2018.RenewLease("game"+game.idofgame,"69530318916789546987353800") // if someone joins we want to renew the lease so it doesn't expire
// mostly just for stopping people from spamming urls and keeping games loaded
}
if (game.version === "2020"){ // 2020 doesn't do visits for some reason
games.updateOne({idofgame: game.idofgame}, {
$inc: {
visits: 1
}
},
function(err, doc) {
//console.log(err)
})
}
}
if (action === "leaving"|| action === "disconnect"){
const updatedcount = parseFloat(game.numberofplayers)-1
games.updateOne({idofgame: game.idofgame}, {
$pull: {
players: {userid: player, name: name}
},
$set: {
numberofplayers: updatedcount.toString()
}
},
function(err, doc) {
//console.log(err)
})
User.updateOne({userid: player}, {
$set: {
status: JSON.stringify({status: "Offline"})
}
},
function(err, doc) {
//console.log(err)
})
}
res.send("good")
}
})
module.exports = router

View File

@ -0,0 +1,57 @@
const express = require("express")
const router = express.Router()
const user = require('./../..//model/user.js')
const { requireAuth } = require('./../../middleware/authmiddleware')
router.post("/buymembership",requireAuth,async (req, res) => {
if (req.userdocument?.membership != "None"){
return res.json({status:"error",error:"You already have membership!"})
}
if (req.userdocument.coins >= 200){
req.userdocument.coins -= 200
req.userdocument.membership = "BuildersClub"
req.userdocument.markModified('coins')
req.userdocument.markModified('membership')
await req.userdocument.save()
return res.json({status:"success",message:"You have builders club now!"})
}
return res.json({status: "error",error:"Not enough rocks!"})
})
router.post("/:id",async (req, res) => {
var id = req.params.id;
if (isNaN(parseFloat(id)) === true){
return res.json({error: true})
}
var key = req.query.key;
if (isNaN(parseFloat(key)) === true){
return res.json({error: true})
}
if (key !== "33808292371407362400921749206284699231416675010973"){
return res.json({error: true})
}
const response = await user.findOne({userid: id})
if (!response){
console.log(response)
return res.json({error: true})
}
response.membership = req.query.newmembership
response.markModified('membership')
await response.save()
return res.json({error: false})
})
module.exports = router

116
Back/routes/api/userinfo.js Normal file
View File

@ -0,0 +1,116 @@
const express = require("express")
const router = express.Router()
const user = require('./../..//model/user.js')
const games = require("./../../model/games.js")
const RelativeTime = require("@yaireo/relative-time")
const relativeTime = new RelativeTime()
router.get("/:id",async (req, res) => {
var id = req.params.id;
if (isNaN(parseFloat(id)) === true){
return res.json({error: true})
}
const response = await user.findOne({userid: id}).lean()
if (!response){
return res.json({error: true, message: "404"})
}
let status = {status: "Offline"}
if (response.status){
status = JSON.parse(response.status)
}
const actualTimeMilliseconds = new Date().getTime()
if (response.timesincelastrequest && actualTimeMilliseconds - response.timesincelastrequest >= 60000 * 3 /*3 minutes*/ && status && status.status.includes("Playing") === false || response.timesincelastrequest && actualTimeMilliseconds - response.timesincelastrequest >= 60000 * 3 /*3 minutes*/ && !status){
// been 3 minutes since last request mark as offline make sure we don't mark them offline while they are playing a game
status.status = "Offline"
response.status = JSON.stringify(status)
status = JSON.parse(response.status)
}
if (response.timesincelastrequest && actualTimeMilliseconds - response.timesincelastrequest <= 60000 * 3 /*3 minutes*/ && status && status.status.includes("Playing") === false || response.timesincelastrequest && actualTimeMilliseconds - response.timesincelastrequest <= 60000 * 3 /*3 minutes*/ && !status){
status.status = "Online"
response.status = JSON.stringify(status)
status = JSON.parse(response.status)
}
return res.json({error:false, userinfo: {joindate: response.joindate, joindateepoch:new Date(response._id.getTimestamp()).getTime(), lastonline: relativeTime.from(new Date(response.timesincelastrequest)), lastonlineepoch: response.timesincelastrequest, coins: response.coins, username: response.username,userid: response.userid,friends: response.friends, admin: response.admin, discordid: response.discordid, membership: response.membership, inventory: response.inventory, bio: response.bio, status,followers: response.followers?.length, css: response.css, aboutme: response.aboutme}})
})
router.get("/:id/creations",async (req, res) => {
var id = req.params.id;
if (isNaN(parseFloat(id)) === true){
return res.json({error: true})
}
const response = await user.findOne({userid: id}).lean()
if (!response){
return res.status(404).json({error: true, message: "Not found"})
}
const gameresponse = await games.find({useridofowner: id}).lean().select(['idofgame', 'version', 'nameofgame', 'numberofplayers', 'visits', 'useridofowner'])
return res.json(gameresponse)
})
router.get("/:id/visits",async (req, res) => {
var id = req.params.id;
if (isNaN(parseFloat(id)) === true){
return res.json({error: true})
}
const response = await user.findOne({userid: id}).lean()
if (!response){
return res.status(404).json({error: true, message: "Not found"})
}
const visits = await games.aggregate([
{ $match: { useridofowner: parseFloat(id) } },
{
"$group": {
"_id": null,
"visits": {
'$sum': "$visits"
}
}
}
])
return res.json({error: false,visits: visits[0]?.visits || 0})
})
router.get("/usernametoid/:id",async (req, res) => {
var id = req.params.id;
const response = await user.findOne({username: {'$regex': id,$options:'i'}}).lean()
if (!response){
console.log(response)
return res.json({error: true})
}
return res.json({error:false, userid: response.userid})
})
router.get("/discordidtouserid/:id",async (req, res) => {
var id = req.params.id;
const response = await user.findOne({discordid: id}).lean()
if (!response){
console.log(response)
return res.json({error: true})
}
return res.json({error:false, userid: response.userid})
})
module.exports = router

33
Back/routes/api/verify.js Normal file
View File

@ -0,0 +1,33 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware')
const games = require('./../../model/games.js')
const bodyParser = require('body-parser')
router.use(bodyParser.json())
router.post("/", requireAuth,async (req, res) => {
const {gameid} = req.body
if (typeof gameid == "undefined"){
return res.json("Send gameid Please")
}
if (req.userdocument.admin == false) {
return res.redirect('/')
}
try{
games.updateOne({idofgame: gameid}, {
$set: {
featured: true
}
},
function(err, doc) {
//console.log(err)
})
}catch(err){
console.log(err)
}
return res.json({status: 'ok'})
})
module.exports = router

130
Back/routes/assets.js Normal file
View File

@ -0,0 +1,130 @@
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 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 = `<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
<External>null</External>
<External>nil</External>
<Item class="BodyColors">
<Properties>
<int name="HeadColor">`+user.colors.find(x => x.name === 'Head').value+`</int>
<int name="LeftArmColor">`+user.colors.find(x => x.name === 'Left Arm').value+`</int>
<int name="LeftLegColor">`+user.colors.find(x => x.name === 'Left Leg').value+`</int>
<string name="Name">Body Colors</string>
<int name="RightArmColor">`+user.colors.find(x => x.name === 'Right Arm').value+`</int>
<int name="RightLegColor">`+user.colors.find(x => x.name === 'Right Leg').value+`</int>
<int name="TorsoColor">`+user.colors.find(x => x.name === 'Torso').value+`</int>
<bool name="archivable">true</bool>
</Properties>
</Item>
</roblox>`
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){
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
})
}
}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

20
Back/routes/avatar.js Normal file
View File

@ -0,0 +1,20 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../middleware/authmiddleware')
const User = require('./../model/user.js')
router.post("/updateavatartype", requireAuth,async (req, res) => {
let newavatartype
if (req.userdocument?.avatartype === "R15"){
newavatartype = "R6"
}else{
newavatartype = "R15"
}
req.userdocument.avatartype = newavatartype
req.userdocument.markModified('avatartype')
await req.userdocument.save()
return res.json({status: "success", message: "Done!"})
})
module.exports = router

101
Back/routes/catalog.js Normal file
View File

@ -0,0 +1,101 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../middleware/authmiddleware')
const User = require('./../model/item.js')
const bodyParser = require('body-parser')
router.use(bodyParser.json())
router.post("/fetch", async (req, res) => {
const resultsPerPage = 30
let page = req.body.page ?? 0
if (page != 0){
page-=1
}
let {filter, sort} = req.body
//console.log(req.body)
try{
if (filter === "Best Selling"){
if (sort != "All"){
response = await User.find({Type: sort,Hidden: {$exists:false}}).limit(resultsPerPage).skip(0+parseFloat(page)*resultsPerPage).sort({Sales: "descending"}).lean().select(['-_id'])
responsecount = await User.countDocuments({Type: sort, Hidden: {$exists:false}})
}
if (sort === "All"){
response = await User.find({Hidden: {$exists:false}, Type: { $ne: "User Ad" } }).limit(resultsPerPage).skip(0+parseFloat(page)*resultsPerPage).sort({Sales: "descending"}).lean().select(['-_id'])
responsecount = await User.countDocuments({Hidden: {$exists:false}, Type: { $ne: "User Ad" }})
}
}else{
if (sort != "All"){
response = await User.find({Type: sort, Hidden: {$exists:false}}).limit(resultsPerPage).skip(0+parseFloat(page)*resultsPerPage).lean().select(['-_id'])
responsecount = await User.countDocuments({Type: sort, Hidden: {$exists:false}})
}
if (sort === "All"){
response = await User.find({Hidden: {$exists:false}, Type: { $ne: "User Ad" }}).limit(resultsPerPage).skip(0+parseFloat(page)*resultsPerPage).lean().select(['-_id'])
responsecount = await User.countDocuments({Hidden: {$exists:false}, Type: { $ne: "User Ad" }})
}
}
//console.log(response.length)
res.json({data: response, pages: Math.ceil(Math.max(responsecount/resultsPerPage, 1))})
} catch (error) {
res.json({status: "error", error:"idk"})
}
})
router.get('/iteminfo/:id', async (req, res) => {
var id = req.params.id;
if (isNaN(parseFloat(id)) === true){
return res.json({status: "error", error: "Must be number"})
}
const response = await User.findOne({ItemId: id}).lean()
if (!response){
return res.json({status: "error", error: "Not found"})
}
return res.json({error: false, iteminfo: response})
});
router.post("/search", async (req, res) => {
const resultsPerPage = 30
let page = req.body.page ?? 0
if (page != 0){
page-=1
}
let {filter, sort, searchquery} = req.body
function escapeRegex(text) {
return text?.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}
const regex = new RegExp(escapeRegex(searchquery), 'gi');
//console.log(req.body)
try{
if (filter === "Best Selling"){
if (sort != "All"){
response = await User.find({Name: regex,Type: sort,Hidden: {$exists:false}}).limit(resultsPerPage).skip(0+parseFloat(page)*resultsPerPage).sort({Sales: "descending"}).lean().select(['-_id'])
responsecount = await User.countDocuments({Type: sort, Hidden: {$exists:false}})
}
if (sort === "All"){
response = await User.find({Name: regex,Hidden: {$exists:false}}).limit(resultsPerPage).skip(0+parseFloat(page)*resultsPerPage).sort({Sales: "descending"}).lean().select(['-_id'])
responsecount = await User.countDocuments({Hidden: {$exists:false}})
}
}else{
if (sort != "All"){
response = await User.find({Name: regex,Type: sort, Hidden: {$exists:false}}).limit(resultsPerPage).skip(0+parseFloat(page)*resultsPerPage).lean().select(['-_id'])
responsecount = await User.countDocuments({Type: sort, Hidden: {$exists:false}})
}
if (sort === "All"){
response = await User.find({Name: regex,Hidden: {$exists:false}}).limit(resultsPerPage).skip(0+parseFloat(page)*resultsPerPage).lean().select(['-_id'])
responsecount = await User.countDocuments({Hidden: {$exists:false}})
}
}
//console.log(response.length)
res.json({data: response, pages: Math.ceil(Math.max(responsecount/resultsPerPage, 1))})
} catch (error) {
res.json({status: "error", error:"idk"})
}
})
module.exports = router

File diff suppressed because one or more lines are too long

854
Back/routes/develop.js Normal file
View File

@ -0,0 +1,854 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../middleware/authmiddleware')
const User = require('./../model/user.js')
const games = require('./../model/games.js')
const catalog = require('./../model/item.js')
const { requirediscord } = require('./../middleware/requirediscord.js')
var multer = require('multer');
const fs = require('fs');
const path = require('path')
var numbtest = /^\d+\.?\d*$/;
const bodyParser = require('body-parser')
const {pngValidator} = require('png-validator')
const fileTypeChecker = require("file-type-checker")
const rateLimit = require('express-rate-limit')
const limiter = rateLimit({
windowMs: 3 * 1000, // 3 seconds
max: 1, // Limit each IP to 1 requests per `window`
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
handler: (request, response, next, options) =>{
response.json({status: 'error', error: 'Too many requests try again later.'})
}
})
async function validateImage(itemid,res){
return new Promise(async (resolve) => {
try {
const myArrayBuffer = await fs.promises.readFile(path.resolve(`assets/ugc/itemfile-${itemid}.rbxm`), null)
pngValidator(myArrayBuffer);
// success
} catch {
// file is invalid or corrupt
fs.unlink(path.resolve(`assets/ugc/itemfile-${itemid}.rbxm`), (err => {
if (err) console.log(err)
}));
return res.json({status: 'error', error: 'Image is invalid.'})
}
resolve()
})
}
const pages = [
'shirts',
'pants',
'audios',
'games',
'badges',
'meshes'
]
router.use(bodyParser.json())
router.post("/creations", requireAuth,async (req, res) => {
const { type } = req.body
let items = await catalog.find({Creator: req.userdocument.userid, Type: type}).lean().select(['Name',"Description",'ItemId'])
if (type === "games"){
items = await games.find({useridofowner: req.userdocument.userid}).lean().select(['nameofgame','idofgame','Description','avatartype','gearallowed'])
}
if (type === "audios"){
items = await catalog.find({Creator: req.userdocument.userid, Type: "Audio"}).lean().select(['Name',"Description",'ItemId'])
}else if (type === "badges"){
items = await catalog.find({Creator: req.userdocument.userid, Type: "Badge"}).lean().select(['Name',"Description",'ItemId'])
}else if (type === "meshes"){
items = await catalog.find({Creator: req.userdocument.userid, Type: "Mesh"}).lean().select(['Name',"Description",'ItemId'])
}else if (type === "userads"){
items = await catalog.find({Creator: req.userdocument.userid, Type: "User Ad"}).lean().select(['Name',"Description",'ItemId'])
}else if (type === "gamepasses"){
items = await catalog.find({Creator: req.userdocument.userid, Type: "Gamepass"}).lean().select(['Name',"Description",'ItemId'])
}else if (type === "videos"){
items = await catalog.find({Creator: req.userdocument.userid, Type: "Video"}).lean().select(['Name',"Description",'ItemId'])
}
return res.json(items)
})
var storage = multer.diskStorage({
destination: function (req, file, cb) {
// Uploads is the Upload_folder_name
if(file.fieldname === "thumbnail"){ // is a game thumbnail
cb(null, "./assets/gameassets")
}else{
cb(null, "./assets/ugc")
}
},
filename: async function (req, file, cb) {
//console.log(path.basename(file.originalname,'.png'))
if (path.extname(file.originalname) === ".rbxl"){
const placeid = await games.countDocuments();
cb(null, "gamefile" + "-" + placeid +path.extname(file.originalname))
}else if(file.fieldname === "thumbnail"){ // is a game thumbnail
const placeid = await games.countDocuments();
cb(null, "thumbnail" + "-" + placeid + ".png")
}
else if (file.mimetype == "image/png"){
const itemid = await catalog.countDocuments();
cb(null, "itemfile" + "-" + itemid + ".rbxm")
}else if (path.extname(file.originalname) === ".mp3"){
const itemid = await catalog.countDocuments();
cb(null, "itemfile" + "-" + itemid + ".rbxm")
}else if (path.extname(file.originalname) === ".mesh"){
const itemid = await catalog.countDocuments();
cb(null, "itemfile" + "-" + itemid + ".rbxm")
}else if (path.extname(file.originalname) === ".webm"){
const itemid = await catalog.countDocuments();
cb(null, "itemfile" + "-" + itemid + ".rbxm")
}
}
})
const uploadcloth = multer({storage: storage,
fileFilter: function (req, file, callback) {
if(file.mimetype !== 'image/png' /*&& ext !== '.mp3' && ext !== '.rbxl'*/) {
return callback('Invalid file type')
}
callback(null, true)
},
limits: { fileSize: 1024 * 1024 } // 1mb
})
router.post("/uploadclothing", requireAuth,requirediscord,async (req, res) => {
uploadcloth.single("clothingfile")(req, res, async function (err) {
if (err) {
if (err?.message === "File too large"){
return res.status(400).send({status: 'error', error: "File too large! 1MB Limit"})
}
if (err === "Invalid file type"){
return res.status(400).send({status: 'error', error: "Invalid file type"})
}
return res.status(400).send({status: 'error', error: err.message})
}
var xss = require("xss")
const {clothingname, description,price,type} = req.body
// save shirt template
if (!clothingname){
return res.json({status: 'error', error: 'Clothing name needs to be sent.'})
}
if (!description){
return res.json({status: 'error', error: 'Description needs to be sent.'})
}
if (!price){
return res.json({status: 'error', error: 'Price needs to be sent.'})
}
if (type != "Shirts" && type != "Pants"){
return res.json({status: 'error', error: 'Type needs to be a shirt or pant value'})
}
if (numbtest.test(price) == false){
return res.json({status: 'error', error: 'Price can only be a number!'})
}
if (price < 5){
return res.json({status: 'error', error: 'Minimum price is 5 rocks.'})
}
if (req.userdocument.coins < 5) { // less than
return res.json({status: 'error', error: 'You don\'t have 5 rocks >:(!'})
}else if (req.userdocument.admin === false){
req.userdocument.coins -= 5
req.userdocument.markModified('coins')
await req.userdocument.save()
}
const itemid = await catalog.countDocuments();
// check if the file they just uploaded is valid
await validateImage(itemid,res)
let approved = req.userdocument.admin === false ? false : true
try{
await catalog.create({
Name: xss(clothingname),
Description: xss(description),
Price: Math.ceil(price),
Type: "Image",
Hidden: true,
ItemId: itemid,
approved
})
}catch{
}
// save actual item
let xml = `<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
<External>null</External>
<External>nil</External>
<Item class="Shirt" referent="RBX0">
<Properties>
<Content name="ShirtTemplate">
<url>http://mete0r.xyz/asset/?id=`+itemid+`</url>
</Content>
<string name="Name">Shirt</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
</roblox>`
if (type === "Pants"){
xml = `<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
<External>null</External>
<External>nil</External>
<Item class="Pants" referent="RBX0">
<Properties>
<Content name="PantsTemplate">
<url>http://mete0r.xyz/asset/?id=`+itemid+`</url>
</Content>
<string name="Name">Pants</string>
<bool name="archivable">true</bool>
</Properties>
</Item>
</roblox>`
}
let shirtid = itemid + 1 // prevent any race conditions
shirtid = shirtid.toString()
fs.writeFile("./assets/ugc/itemfile-"+shirtid+".rbxm", xml,async function(err) {
if(err) {
return console.log(err);
}
let approved = req.userdocument.admin === false ? false : true
try{
await catalog.create({
Name: xss(clothingname),
Description: xss(description),
Price: Math.ceil(price),
Creator: req.userdocument.userid,
Type: type,
ItemId: shirtid,
approved
})
}catch{
}
});
// give player shirt
User.updateOne({userid: req.userdocument.userid}, {
$push: {
inventory: {Type: type,ItemId: shirtid, ItemName: xss(clothingname), Equipped: false}
}
},
function(err, doc) {
//console.log(err)
})
return res.json({status: 'success', message: 'Done!'})
})
})
// upload game WOW
const uploadgame = multer({storage: storage,
fileFilter: function (req, file, callback) {
var ext = path.extname(file.originalname);
if(ext !== '.png' && ext !== '.rbxl'/* && ext !== '.mp3'*/) {
return callback('Invalid file type')
}
callback(null, true)
},
limits: { fileSize: 5120 * 1024 * 2 } // 10mb
})
const uploadaudio = multer({storage: storage,
fileFilter: function (req, file, callback) {
var ext = path.extname(file.originalname);
if(ext !== '.mp3' && ext !== '.ogg') {
return callback('Invalid file type')
}
callback(null, true)
},
limits: { fileSize: 5120 * 1024 } // 5mb
})
var editgamestorage = multer.diskStorage({
destination: function (req, file, cb) {
// Uploads is the Upload_folder_name
if(file.fieldname === "thumbnail"){ // is a game thumbnail
cb(null, "./assets/gameassets")
}else{
cb(null, "./assets/ugc")
}
},
filename: async function (req, file, cb) {
//console.log(path.basename(file.originalname,'.png'))
if (path.extname(file.originalname) === ".rbxl"){
const item = await games.findOne({idofgame: req.body.gameid}).lean()
if (!item){
return cb("Item doesn't exist!")
}
//console.log(item)
if (item.useridofowner != req.userdocument.userid){
// player doesn't own this item
return cb("You don't own this")
}
cb(null, "gamefile" + "-" + req.body.gameid +path.extname(file.originalname))
}
}
})
const editgame = multer({storage: editgamestorage,
fileFilter: function (req, file, callback) {
var ext = path.extname(file.originalname);
if(ext !== '.rbxl'/* && ext !== '.mp3'*/) {
return callback('Invalid file type')
}
callback(null, true)
},
limits: { fileSize: 5120 * 1024 * 2 } // 10mb
})
router.post("/editgame", requireAuth,requirediscord,async (req, res) => {
const {nameofgame, description, gameid} = req.body
var xss = require("xss")
if (!gameid){
return res.json({status: 'error', error: 'GameID required'})
}
const item = await games.findOne({idofgame: gameid})
if (!item){
return res.json({status: 'error', error: "Game doesn't exist."})
}
//console.log(item)
if (item.useridofowner != req.userdocument.userid){
// player doesn't own this item
return res.json({status: 'error', error: "You don't have permissions for this!"})
}
if (nameofgame && nameofgame != ""){
item.nameofgame = xss(nameofgame)
item.markModified('nameofgame')
await item.save()
}
if (description && description != ""){
item.descrption = xss(description)
item.markModified('descrption')
await item.save()
}
return res.json({status: 'success',message:'Done!'})
})
router.post("/editavatartype", requireAuth,requirediscord,async (req, res) => {
const {avatartype, gameid} = req.body
if (!gameid){
return res.json({status: 'error', error: 'GameID required'})
}
if (!avatartype){
return res.json({status: 'error', error: 'Avatar type required'})
}
if (avatartype != "R6" && avatartype != "R15" && avatartype != "PC"){
return res.json({status: 'error', error: 'Avatar type required'})
}
const item = await games.findOne({idofgame: gameid})
if (!item){
return res.json({status: 'error', error: "Game doesn't exist."})
}
//console.log(item)
if (item.useridofowner != req.userdocument.userid){
// player doesn't own this item
return res.json({status: 'error', error: "You don't have permissions for this!"})
}
item.avatartype = avatartype
item.markModified('avatartype')
await item.save()
return res.json({status: 'success',message:'Done!'})
})
router.post("/editgearstatus", requireAuth,requirediscord,async (req, res) => {
const {newgearstatus, gameid} = req.body
if (!gameid){
return res.json({status: 'error', error: 'GameID required'})
}
if (newgearstatus != true && newgearstatus != false){
return res.json({status: 'error', error: 'Gear status required'})
}
const item = await games.findOne({idofgame: gameid})
if (!item){
return res.json({status: 'error', error: "Game doesn't exist."})
}
//console.log(item)
if (item.useridofowner != req.userdocument.userid){
// player doesn't own this item
return res.json({status: 'error', error: "You don't have permissions for this!"})
}
item.gearallowed = newgearstatus
item.markModified('gearallowed')
await item.save()
return res.json({status: 'success',message:'Done!'})
})
router.post("/editgameupload", requireAuth,requirediscord,async (req, res) => {
editgame.single("gamefile")(req, res, async function (err) {
if (err) {
if (err?.message === "File too large"){
return res.status(400).send({status: 'error', error: "File too large! 10MB Limit"})
}
if (err === "Invalid file type"){
return res.status(400).send({status: 'error', error: "Invalid file type"})
}
return res.status(400).send({status: 'error', error: err.message})
}
return res.json({status: 'success',message:'Done!'})
})
})
router.post("/uploadgame", requireAuth,requirediscord,async (req, res) => {
uploadgame.fields([
{name: 'gamefile', maxCount: 1},
{name: 'thumbnail', maxCount: 1}
])(req, res, async function (err) {
if (err) {
if (err?.message === "File too large"){
return res.status(400).send({status: 'error', error: "File too large! 10MB Limit"})
}
if (err === "Invalid file type"){
return res.status(400).send({status: 'error', error: "Invalid file type"})
}
return res.status(400).send({status: 'error', error: err.message})
}
var xss = require("xss")
const {gamename, description, version} = req.body
// save game
if (!gamename){
return res.json({status: 'error', error: 'Game name needs to be sent.'})
}
if (gamename?.length > 50) {
return res.json({status: 'error', error: 'Game name can not be more than 50 characters'})
}
if (!description){
return res.json({status: 'error', error: 'Description needs to be sent.'})
}
if (description?.length > 1000) {
return res.json({status: 'error', error: 'Description can not be more than 1000 characters'})
}
if (!version){
return res.json({status: 'error', error: 'Version needs to be sent.'})
}
const versions = [
//"2014",
"2016",
"2018",
"2020"
]
if (versions.includes(version) === false){
return res.json({status: 'error', error: 'Invalid version sent.'})
}
if (req.userdocument.coins < 5) { // less than
return res.json({status: 'error', error: 'You don\'t have 5 rocks >:(!'})
}else if (req.userdocument.admin === false){
req.userdocument.coins -= 5
req.userdocument.markModified('coins')
await req.userdocument.save()
}
const placeid = await games.countDocuments();
try{
await games.create({
useridofowner: req.userdocument.userid,
idofgame: placeid,
nameofgame: xss(gamename),
numberofplayers: "0",
descrption: xss(description),
version: version
})
}catch{
throw error
}
return res.json({status: 'success', message: 'Done!'})
})
})
const uploadasset = multer({storage: storage,
fileFilter: function (req, file, callback) {
var ext = path.extname(file.originalname);
if(ext !== '.png' && ext !== '.mesh') {
return callback('Invalid file type')
}
callback(null, true)
},
limits: { fileSize: 5120 * 1024 } // 1mb
})
router.post("/uploadmeshes", requireAuth,requirediscord,limiter,async (req, res) => {
uploadasset.single("assetfile")(req, res, async function (err) {
if (err) {
if (err?.message === "File too large"){
return res.status(400).send({status: 'error', error: "File too large! 1MB Limit"})
}
if (err === "Invalid file type"){
return res.status(400).send({status: 'error', error: "Invalid file type"})
}
return res.status(400).send({status: 'error', error: err.message})
}
var xss = require("xss")
const {itemname} = req.body
// save mesh
if (!itemname){
return res.json({status: 'error', error: 'Mesh name needs to be sent.'})
}
const itemid = await catalog.countDocuments();
const myArrayBuffer = await fs.promises.readFile(path.resolve(`assets/ugc/itemfile-${itemid}.rbxm`), null)
if (fileTypeChecker.detectFile(myArrayBuffer)){
// not a mesh
fs.unlink(path.resolve(`assets/ugc/itemfile-${itemid}.rbxm`), (err => {
if (err) console.log(err)
}))
return res.json({status: 'error', error: 'Mesh is invalid.'})
}
try{
await catalog.create({
Name: xss(itemname),
Price: "0",
Type: "Mesh",
Creator: req.userdocument.userid,
Hidden: true,
ItemId: itemid,
approved: true
})
}catch(err){
throw(err)
}
return res.json({status: 'success', message: "Done! Mesh ID : "+itemid})
})
})
router.post("/uploadbadges", requireAuth,requirediscord,limiter,async (req, res) => {
uploadasset.single("assetfile")(req, res, async function (err) {
if (err) {
if (err?.message === "File too large"){
return res.status(400).json({status: 'error', error: "File too large! 1MB Limit"})
}
if (err === "Invalid file type"){
return res.status(400).json({status: 'error', error: "Invalid file type"})
}
return res.status(400).json({status: 'error', error: err.message})
}
var xss = require("xss")
const {itemname} = req.body
// save badge
if (!itemname){
return res.json({status: 'error', error: 'Badge name needs to be sent.'})
}
const itemid = await catalog.countDocuments();
//check if the file thye just uploaded is valid
await validateImage(itemid,res)
try{
let approved = req.userdocument.admin === false ? false : true
await catalog.create({
Name: xss(itemname),
Price: "0",
Type: "Badge",
Creator: req.userdocument.userid,
Hidden: true,
ItemId: itemid,
approved
})
}catch(err){
throw(err)
}
return res.json({status: 'success', message: "Done! Badge ID : "+itemid})
})
})
router.post("/uploaduserads", requireAuth,requirediscord,limiter,async (req, res) => {
uploadasset.single("assetfile")(req, res, async function (err) {
if (err) {
if (err?.message === "File too large"){
return res.status(400).send({status: 'error', error: "File too large! 1MB Limit"})
}
if (err === "Invalid file type"){
return res.status(400).send({status: 'error', error: "Invalid file type"})
}
return res.status(400).send({status: 'error', error: err.message})
}
var xss = require("xss")
const {itemname} = req.body
// save userad
if (!itemname){
return res.json({status: 'error', error: 'User Ad name needs to be sent.'})
}
const itemid = await catalog.countDocuments();
// check if the file they just uploaded is valid
await validateImage(itemid,res)
try{
let approved = req.userdocument.admin === false ? false : true
await catalog.create({
Name: xss(itemname),
Price: "0",
Type: "User Ad",
Creator: req.userdocument.userid,
ItemId: itemid,
ActiveAd: false,
approved
})
}catch(err){
throw(err)
}
return res.json({status: 'success', message: "Done!"})
})
})
router.post("/uploadgamepasses", requireAuth,requirediscord,limiter,async (req, res) => {
uploadasset.single("assetfile")(req, res, async function (err) {
if (err) {
if (err?.message === "File too large"){
return res.status(400).send({status: 'error', error: "File too large! 1MB Limit"})
}
if (err === "Invalid file type"){
return res.status(400).send({status: 'error', error: "Invalid file type"})
}
return res.status(400).send({status: 'error', error: err.message})
}
var xss = require("xss")
const {itemname,price,gameid} = req.body
// save game pass
if (!itemname){
return res.json({status: 'error', error: 'Gamepass name needs to be sent.'})
}
if (!price){
return res.json({status: 'error', error: 'Price needs to be sent.'})
}
if (!gameid){
return res.json({status: 'error', error: 'Gameid needs to be sent.'})
}
if (numbtest.test(price) == false){
return res.json({status: 'error', error: 'Price can only be a number!'})
}
if (price < 1){
return res.json({status: 'error', error: 'Minimum price is 1 rock.'})
}
const gamedoc = await games.findOne({idofgame: gameid})
if (!gamedoc){
return res.json({status: 'error', error: 'Game not found'})
}
if (gamedoc.useridofowner != req.userdocument.userid){
return res.json({status: 'error', error: "You don't own this game!"})
}
const currentgamepasscount = await catalog.countDocuments({associatedgameid: gamedoc.idofgame})
if (currentgamepasscount >= 20){
return res.json({status: 'error', error: 'No more than 20 game passes per game.'})
}
const itemid = await catalog.countDocuments()
// check if the file they just uploaded is valid
await validateImage(itemid,res)
try{
let approved = req.userdocument.admin === false ? false : true
await catalog.create({
Name: xss(itemname),
Description: "",
Price: Math.ceil(price),
Creator: req.userdocument.userid,
Type: "Gamepass",
ItemId: itemid,
approved,
associatedgameid: gamedoc.idofgame
})
}catch(err){
throw(err)
}
return res.json({status: 'success', message: "Done!"})
})
})
router.post("/uploadaudios", requireAuth,requirediscord,limiter,async (req, res) => {
uploadaudio.single("assetfile")(req, res, async function (err) {
if (err) {
if (err?.message === "File too large"){
return res.status(400).send({status: 'error', error: "File too large! 5MB Limit"})
}
if (err === "Invalid file type"){
return res.status(400).send({status: 'error', error: "Invalid file type"})
}
return res.status(400).send({status: 'error', error: err.message})
}
var xss = require("xss")
const {itemname} = req.body
// save audio
if (!itemname){
return res.json({status: 'error', error: 'Audio name needs to be sent.'})
}
const itemid = await catalog.countDocuments();
const myArrayBuffer = await fs.promises.readFile(path.resolve(`assets/ugc/itemfile-${itemid}.rbxm`), null)
if (fileTypeChecker.isMP3(myArrayBuffer) === false && fileTypeChecker.isOGG(myArrayBuffer) === false){
fs.unlink(path.resolve(`assets/ugc/itemfile-${itemid}.rbxm`), (err => {
if (err) console.log(err)
}))
return res.json({status: 'error', error: 'Audio is invalid.'})
}
try{
let approved = req.userdocument.admin === false ? false : true
await catalog.create({
Name: xss(itemname),
Price: "0",
Type: "Audio",
Creator: req.userdocument.userid,
Hidden: true,
ItemId: itemid,
approved
})
}catch(err){
throw(err)
}
return res.json({status: 'success', message: "Done! Audio ID : "+itemid})
})
})
const uploadvideo = multer({storage: storage,
fileFilter: function (req, file, callback) {
var ext = path.extname(file.originalname);
if(ext !== '.webm') {
return callback('Invalid file type')
}
callback(null, true)
},
limits: { fileSize: 10240 * 1024 } // 10mb
})
router.post("/uploadvideos", requireAuth,requirediscord,limiter,async (req, res) => {
uploadvideo.single("assetfile")(req, res, async function (err) {
if (err) {
if (err?.message === "File too large"){
return res.status(400).send({status: 'error', error: "File too large! 10MB Limit"})
}
if (err === "Invalid file type"){
return res.status(400).send({status: 'error', error: "Invalid file type"})
}
return res.status(400).send({status: 'error', error: err.message})
}
var xss = require("xss")
const {itemname} = req.body
// save audio
if (!itemname){
return res.json({status: 'error', error: 'Video name needs to be sent.'})
}
const itemid = await catalog.countDocuments();
const myArrayBuffer = await fs.promises.readFile(path.resolve(`assets/ugc/itemfile-${itemid}.rbxm`), null)
if (fileTypeChecker.isWEBM(myArrayBuffer) === false){
fs.unlink(path.resolve(`assets/ugc/itemfile-${itemid}.rbxm`), (err => {
if (err) console.log(err)
}))
return res.json({status: 'error', error: 'Video is invalid.'})
}
try{
let approved = req.userdocument.admin === false ? false : true
await catalog.create({
Name: xss(itemname),
Price: "0",
Type: "Video",
Creator: req.userdocument.userid,
ItemId: itemid,
approved
})
}catch(err){
throw(err)
}
return res.json({status: 'success', message: "Done! Video ID : "+itemid})
})
})
module.exports = router

413
Back/routes/game.js Normal file
View File

@ -0,0 +1,413 @@
const express = require("express")
const router = express.Router()
const signatures = require("./signatures.js")
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
const User = require('../model/user.js')
const { requireAuth } = require('../middleware/authmiddlewaregame')
const rcctalk = require('../rcctalk')
const games = require('../model/games.js')
const catalog = require('../model/item.js')
const rcc = require('../model/rcc.js')
var sanitize = require('mongo-sanitize');
const { getPort, checkPort, getRandomPort, waitForPort } = require('get-port-please')
const fs = require('fs')
const gamescript = fs.readFileSync('actualgameserver.lua','utf-8')
require('dotenv').config()
const RCC_HOST = process.env.RCC_HOST
const logshook = process.env.logshook
const crypto = require('crypto');
const key = fs.readFileSync('DefaultPrivateKey.pem')
const key2 = fs.readFileSync('DefaultPrivateKey.pem')
const key2020 = fs.readFileSync('PrivateKey2020.txt')
const { _2020placelauncher } = require('../routes/2020/game')
const { _2018placelauncher } = require('../routes/2018/game')
//join and placelauncher
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
router.get("/visit",async (req, res) => {
// studio
const string = `local RS = game:GetService("RunService")
local P = game:GetService("Players")
local LP = P:CreateLocalPlayer(0)
LP.CharacterAppearance = ""
LP.CharacterAdded:connect(
function(c)
repeat
wait()
until c:FindFirstChild("Humanoid")
local h = c:FindFirstChild("Humanoid")
h.Died:connect(
function()
wait(5)
LP:LoadCharacter()
end
)
end
)
game:GetService("InsertService"):SetBaseSetsUrl("http://mete0r.xyz/Game/Tools/InsertAsset.ashx?nsets=10&type=base")
game:GetService("InsertService"):SetUserSetsUrl("http://mete0r.xyz/Game/Tools/InsertAsset.ashx?nsets=20&type=user&userid=%d")
game:GetService("InsertService"):SetCollectionUrl("http://mete0r.xyz/Game/Tools/InsertAsset.ashx?sid=%d")
pcall(function() game:GetService("InsertService"):SetFreeModelUrl("http://mete0r.xyz/Game/Tools/InsertAsset.ashx?type=fm&q=%s&pg=%d&rs=%d") end)
pcall(function() game:GetService("InsertService"):SetFreeDecalUrl("http://mete0r.xyz/Game/Tools/InsertAsset.ashx?type=fd&q=%s&pg=%d&rs=%d") end)
RS:Run()
LP:LoadCharacter()
pcall(
function()
game:GetService("ContentProvider"):SetBaseUrl("http://mete0r.xyz" .. "/")
end
)
`
const sign = crypto.createSign('SHA1');
sign.update("\r\n" + string)
var signature = sign.sign(key, "base64")
res.send("--rbxsig%"+signature+"%\r\n" +string)
})
router.get(["/GetCurrentUser","/GetCurrentUser.ashx"],async (req, res) => {
res.send("1") // 1 means logged in and null means logged out
}) // don't send 404 error but i don't think we will have studio publishing
router.post("/validate-machine",async (req, res) => {
res.json({"success":true,"message":""})
})
router.get(["/join","/join.ashx"],requireAuth,async (req, res) => {
if (!req.userdocument.discordid){
return res.json({status:"error",error:"Link your discord account stinky"})
}
if (req.query.ver === "2018"){
if (!req.userdocument.gamejoin2018 || req.userdocument.gamejoin2018 === "{}"){
return res.json({status:"error",error:"no placelauncher"})
}
var joinJson = JSON.parse(req.userdocument.gamejoin2018)
req.userdocument.gamejoin2018 = undefined
req.userdocument.markModified('gamejoin2018')
await req.userdocument.save()
//sign with our sign module
var signature = signatures.signer(joinJson)
//console.log(signature)
return res.send("--rbxsig%"+signature+"%\r\n"+JSON.stringify(joinJson))
}
if (req.query.ver === "2020"){
if (!req.userdocument.gamejoin2020 || req.userdocument.gamejoin2020 === "{}"){
return res.json({status:"error",error:"no placelauncher"})
}
var joinJson = JSON.parse(req.userdocument.gamejoin2020)
req.userdocument.gamejoin2020 = undefined
req.userdocument.markModified('gamejoin2020')
await req.userdocument.save()
//sign with our sign module
const sign = crypto.createSign('SHA1');
sign.update("\r\n" + JSON.stringify(joinJson))
var signature = sign.sign(key2020, "base64")
//console.log(signature)
return res.send("--rbxsig2%"+signature+"%\r\n"+JSON.stringify(joinJson))
}
if (!req.userdocument.gamejoin || req.userdocument.gamejoin === "{}"){
return res.json({status:"error",error:"no placelauncher"})
}
var joinJson = JSON.parse(req.userdocument.gamejoin)
req.userdocument.gamejoin = undefined
req.userdocument.markModified('gamejoin')
await req.userdocument.save()
//sign with our sign module
var signature = signatures.signer(joinJson)
//console.log(signature)
res.send("--rbxsig%"+signature+"%\r\n"+JSON.stringify(joinJson))
})
router.all(["/placelauncher","/placelauncher.ashx"],requireAuth,_2020placelauncher,_2018placelauncher,async (req, res, next) => {
var enabled = req.config
if (enabled.GamesEnabled === false){
return res.json({status:"error",error:"Games are disabled bad boy"})
}
var joinJson = {"ClientPort":0,"MachineAddress":"localhost","ServerPort":25564,"PingUrl":"","PingInterval":120,"UserName":"default","SeleniumTestMode":false,"UserId":0,"SuperSafeChat":false,"CharacterAppearance":"http://shitncumblox.gq/game/charapp?name=default","ClientTicket":"","GameId":1,"PlaceId":1818,"MeasurementUrl":"","WaitingForCharacterGuid":"cad99b30-7983-434b-b24c-eac12595e5fd","BaseUrl":"http://www.mete0r.xyz/","ChatStyle":"ClassicAndBubble","VendorId":0,"ScreenShotInfo":"","VideoInfo":"<?xml version=\"1.0\"?><entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:media=\"http://search.yahoo.com/mrss/\" xmlns:yt=\"http://gdata.youtube.com/schemas/2007\"><media:group><media:title type=\"plain\"><![CDATA[ROBLOX Place]]></media:title><media:description type=\"plain\"><![CDATA[ For more games visit http://www.roblox.com]]></media:description><media:category scheme=\"http://gdata.youtube.com/schemas/2007/categories.cat\">Games</media:category><media:keywords>ROBLOX, video, free game, online virtual world</media:keywords></media:group></entry>","CreatorId":0,"CreatorTypeEnum":"User","MembershipType":"None","AccountAge":365,"CookieStoreFirstTimePlayKey":"rbx_evt_ftp","CookieStoreFiveMinutePlayKey":"rbx_evt_fmp","CookieStoreEnabled":true,"IsRobloxPlace":false,"GenerateTeleportJoin":false,"IsUnknownOrUnder13":false,"SessionId":"c25fd620-bbaa-4fb2-b022-3f053cdd1abd|00000000-0000-0000-0000-000000000000|0|204.236.226.210|8|2016-08-17T01:05:05.7115837Z|0|null|null|null|null","DataCenterId":0,"UniverseId":0,"BrowserTrackerId":0,"UsePortraitMode":false,"FollowUserId":0,"CharacterAppearanceId":1}
if (!req.query.name && !req.query.placeId){
return res.json({status:"error",error:"no placeid bad"})
}
if (req.userdocument.gamejoin){
return res.json({"jobId":"Test","status":2,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?auth="+req.query.auth??req.cookies.jwt,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""})
}
var sanitizedplaceid = sanitize(req.query.name??req.query.placeId)
const game = await games.findOne({idofgame: sanitizedplaceid}).lean()
if (!game){
return res.json({status:"error",error:"that game doesn't exist!"})
}
if (game.version != "2016"){
return res.json({status: "error",error:"game version is different than client requested"})
}
const instance = await rcc.findOne({PlaceId: sanitizedplaceid}).lean()
if (instance && instance.Status === 2){
// if an rcc instance already exists we don't need to create a new one so we will just drag them into the existing game
joinJson.UserName = req.userdocument.username
joinJson.UserId = req.userdocument.userid
joinJson.CharacterAppearance = "http://mete0r.xyz/game/charapp?name=" + req.userdocument.userid
joinJson.MachineAddress = RCC_HOST // need to put rcc host here lol
joinJson.ServerPort = instance.Port
joinJson.PlaceId = instance.PlaceId
joinJson.GameId = sanitizedplaceid
joinJson.CharacterAppearanceId = req.userdocument.userid
joinJson.MembershipType = req.userdocument.membership
joinJson.CreatorId = game.useridofowner
joinJson.SessionId = req.query.auth??req.cookies.jwt
const timestamp = Date.now()
joinJson.ClientTicket = timestamp+";" // timestamp
//create signature 1
const sign1 = crypto.createSign('SHA1');
sign1.update(`${req.userdocument.userid}\n`/*userid*/+`${req.userdocument.username}\n`/*username*/+`http://mete0r.xyz/game/charapp?name=${req.userdocument.userid}\n`/*charapp*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/)
var signature1 = sign1.sign(key, "base64")
joinJson.ClientTicket += signature1 + ";"
//create signature 2
const sign2 = crypto.createSign('SHA1');
sign2.update(`${req.userdocument.userid}\n`/*userid*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/)
var signature2 = sign2.sign(key, "base64")
joinJson.ClientTicket += signature2
req.userdocument.gamejoin = JSON.stringify(joinJson)
req.userdocument.markModified('gamejoin')
await req.userdocument.save()
var joinScriptJson = {"jobId":"Test","status":2,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
return res.send(JSON.stringify(joinScriptJson))
}
if (instance && instance.Status === 1){
var joinScriptJson = {"jobId":"Test","status":1,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
return res.send(JSON.stringify(joinScriptJson))
}
var port = await getPort({random: true})
var newgamescript = "local placeId = "+sanitizedplaceid+"\n"+ gamescript
newgamescript = "local port = "+port+"\n"+ newgamescript
// launch job
var response = await rcctalk.OpenJob("game"+sanitizedplaceid,newgamescript,"99999")
await rcc.create({
PlaceId: sanitizedplaceid,
Port: port,
Status: 1 // 1 means loading
})
//console.log(newrenderscript)
var joinScriptJson = {"jobId":"Test","status":1,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
res.send(JSON.stringify(joinScriptJson))
}
)
//charapp and colors stealing from roblox
router.get("/charapp", async (req, res) => {
if (Object.keys(req.query).length === 0) {
res.status(404).send('No variables :(');
} else{
const user = await User.findOne({userid: req.query.name}).lean()
const placeid = req.headers?.['roblox-place-id']??0
const placedoc = await games.findOne({idofgame: placeid})
if (!placedoc){
return res.json({status:"error",error:"Place not found."})
}
if (!user) {
return res.json({status: 'error', error: 'User not found!'})
}
if (!user.inventory){
if (req.query.rcc){
return res.json([])
}
return res.send('http://mete0r.xyz/game/colors?name='+req.query.name+';')
}
if (req.query.rcc){
var empty = []
for (var key of user.inventory) {
if (key.Equipped === true){
empty.push({"item": {itemid: key.ItemId, type: key.Type}})
}
}
return res.json(empty)
}
var charapp = 'http://mete0r.xyz/asset?name='+req.query.name+';'
// add to charapp string by adding json to it
for (var key of user.inventory) {
if (key.Equipped === true){
if (placedoc.gearallowed??false === true){
charapp += "http://mete0r.xyz/asset?id=" + key.ItemId + ";"
}else{
if (key.Type != "Gears"){
charapp += "http://mete0r.xyz/asset?id=" + key.ItemId + ";"
}
}
}
}
res.write(charapp)
res.end()
}
})
router.get("/colors", async (req, res) => {
if (Object.keys(req.query).length === 0) {
res.status(404).send('No variables :(');
} else{
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 = `<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
<External>null</External>
<External>nil</External>
<Item class="BodyColors">
<Properties>
<int name="HeadColor">`+user.colors.find(x => x.name === 'Head').value+`</int>
<int name="LeftArmColor">`+user.colors.find(x => x.name === 'Left Arm').value+`</int>
<int name="LeftLegColor">`+user.colors.find(x => x.name === 'Left Leg').value+`</int>
<string name="Name">Body Colors</string>
<int name="RightArmColor">`+user.colors.find(x => x.name === 'Right Arm').value+`</int>
<int name="RightLegColor">`+user.colors.find(x => x.name === 'Right Leg').value+`</int>
<int name="TorsoColor">`+user.colors.find(x => x.name === 'Torso').value+`</int>
<bool name="archivable">true</bool>
</Properties>
</Item>
</roblox>`
res.send(colorsxml)
}
})
router.get("/", (req, res) => {
res.status(404).send('hmmm? kinda sus');
})
router.get("/players/:id", (req, res) => {
res.json({"ChatFilter":"whitelist"})
})
router.post("/load-place-info", (req, res) => {
res.json({"CreatorId": 0, "CreatorType": "User", "PlaceVersion": 1})
})
router.post("/badge/awardbadge",async (req, res) => {
const userid = req.query.UserID
const badgeid = req.query.BadgeID
const placeid = req.query.PlaceID
const badge = await catalog.findOne({ItemId: badgeid}).lean()
const user = await User.findOne({userid: userid}).lean()
if(!badge){
//Badge doesn't exist!
return res.send("0")
}
if(!user){
return res.send("0")
}
const badgecreator = await User.findOne({userid: badge.Creator}).lean()
if (typeof user.badges !== "undefined"){
// check if user already owns item
for (var v of user.badges){
if (v.badgeid === badgeid){
// they already own it
return res.send("0")
}
}
}
User.updateOne({userid: req.query.UserID}, {
$push: {
badges: {badgeid: badgeid, badgename: badge.Name, creator: badge.Creator, placeid: placeid}
}
},
function(err, doc) {
if (err){
return res.send("0")
}
})
return res.send(user.username+" won "+badgecreator.username+"'s "+badge.Name+" award!")
})
router.get(["/LuaWebService/HandleSocialRequest","/LuaWebService/HandleSocialRequest.ashx"],async (req, res) => {
res.type('application/xml');
if (req.query.method === "IsInGroup"){
if (req.query.groupid === '0' || req.query.groupid === '1200769'){ // 1200769 admin group
const user = await User.findOne({userid: req.query.playerid}).lean()
if (user){
return res.send(`<Value Type="boolean">${user.admin}</Value>`)
}
}
return res.send('<Value Type="boolean">false</Value>')
}
if (req.query.method === "GetGroupRank"){
if (req.query.groupid === '0'|| req.query.groupid === '1200769'){
const user = await User.findOne({userid: req.query.playerid}).lean()
if (user){
if (user.admin === true){
return res.send(`<Value Type="integer">255</Value>`)
}
}
}
return res.send('<Value Type="integer">0</Value>')
}
if (req.query.method === "IsBestFriendsWith"){
return res.send('<Value Type="boolean">false</Value>')
}
if (req.query.method === "IsFriendsWith"){
return res.send('<Value Type="boolean">false</Value>')
}
res.type('html');
return res.status(404).end()
})
router.get("/Tools/InsertAsset.ashx",async (req, res) => {
const lol = await fetch('http://sets.pizzaboxer.xyz/Game'+req.url);
if (lol.status === 400){
return res.send(``)
}
return res.send(await lol.text())
})
router.post("/MachineConfiguration.ashx", (req,res) => {
res.json({"success": true})
})
module.exports = router

214
Back/routes/games.js Normal file
View File

@ -0,0 +1,214 @@
const express = require("express")
const router = express.Router()
const { requireAuth } = require('./../middleware/authmiddleware')
const games = require('./../model/games.js')
const catalog = require("./../model/item.js")
const { grabAuth } = require('./../middleware/grabauth.js')
const rcc = require('./../model/rcc.js')
const rcc2018 = require('./../model/rcc2018.js')
const rcc2020 = require('./../model/rcc2020.js')
const rcctalk = require('./../rcctalk')
const rcctalk2018 = require('./../rcctalk2018')
const bodyParser = require('body-parser')
router.use(bodyParser.json())
router.post("/scroll", async (req, res) => {
const resultsPerPage = 10
let cursor = req.body.cursor >= 0 ? req.body.cursor : 0
let type = req.body.type ? req.body.type : "Popular"
let allowed = ['idofgame', 'version', 'nameofgame', 'numberofplayers', 'visits', 'useridofowner']
try{
if (type === "Popular"){
const response = await games.find().sort({numberofplayers: "descending", idofgame: 1}).skip(0+parseFloat(cursor)*resultsPerPage).limit(10).lean().select(allowed).populate("owner", "username")
return res.json(response)
}
if (type === "OurRecommendations"){
const featured = await games.find({featured: true}).skip(0+parseFloat(cursor)*resultsPerPage).limit(10).lean().select(allowed).populate("owner", "username")
return res.json(featured)
}
if (type === "Visits"){
const mostvisitedresponse = await games.find().sort({visits: "descending", idofgame: 1}).skip(0+parseFloat(cursor)*resultsPerPage).limit(10).lean().select(allowed).populate("owner", "username")
return res.json(mostvisitedresponse)
}
if (type === "NewestArrivals"){
const newest = await games.find().sort({idofgame: "descending"}).skip(0+parseFloat(cursor)*resultsPerPage).limit(10).lean().select(allowed).populate("owner", "username")
return res.json(newest)
}
return res.json({status: "error", error: "wtf"})
} catch (error) {
console.log(error)
return res.json({status: "error", error: "wtf"})
}
})
router.post("/firstpaint", async (req, res) => {
const resultsPerPage = 10
let cursor = 0
let allowed = ['idofgame', 'version', 'nameofgame', 'numberofplayers', 'visits', 'useridofowner']
try{
const response = await games.find().sort({numberofplayers: "descending", idofgame: 1}).skip(0+parseFloat(cursor)*resultsPerPage).limit(10).lean().select(allowed).populate("owner", "username")
const featured = await games.find({featured: true}).skip(0+parseFloat(cursor)*resultsPerPage).limit(10).lean().select(allowed).populate("owner", "username")
const mostvisitedresponse = await games.find().sort({visits: "descending", idofgame: 1}).skip(0+parseFloat(cursor)*resultsPerPage).limit(10).lean().select(allowed).populate("owner", "username")
const newest = await games.find().sort({idofgame: "descending"}).skip(0+parseFloat(cursor)*resultsPerPage).limit(10).lean().select(allowed).populate("owner", "username")
return res.json({Popular: {array: response},OurRecommendations: {array: featured}, Visits: {array: mostvisitedresponse}, NewestArrivals: {array: newest} })
} catch (error) {
console.log(error)
return res.json({status: "error", error: "wtf"})
}
})
router.post("/shutdown",requireAuth, async (req, res) => {
const {gameid} = req.body
if (isNaN(parseFloat(gameid)) === true){
return res.json({status: "error", error: "Not found"})
}
const gamedoc = await games.findOne({idofgame: gameid}).lean()
//console.log(response)
if (!gamedoc){
return res.json({status: "error", error: "Not found"})
}
if (gamedoc.useridofowner != req.userdocument.userid && req.userdocument.admin === false){ // make sure we only let game owners and admins shut down the game
return res.json({status: "error", error: "Not Authorized"})
}
if (gamedoc.version === "2018" || gamedoc.version === "2020"){
let instance = await rcc2018.findOne({PlaceId: gamedoc.idofgame}).lean()
if (!instance){
instance = await rcc2020.findOne({PlaceId: gamedoc.idofgame}).lean()
if (!instance){
return res.json({status: "error", error: "Game not open."})
}
}
await rcc2018.deleteOne({PlaceId: gamedoc.idofgame})
await rcc2020.deleteOne({PlaceId: gamedoc.idofgame})
rcctalk2018.CloseJob("game"+gamedoc.idofgame)
}
if (gamedoc.version === "2016"){
const instance = await rcc.findOne({PlaceId: gamedoc.idofgame}).lean()
if (!instance){
return res.json({status: "error", error: "Game not open."})
}
await rcc.deleteOne({PlaceId: gamedoc.idofgame})
rcctalk.CloseJob("game"+gamedoc.idofgame)
}
return res.json({status: "success", message:"Done!"})
})
router.post("/evictplayer",requireAuth, async (req, res) => {
const {gameid,userid} = req.body
if (isNaN(parseFloat(userid)) === true){
return res.json({status: "error", error: "Not found"})
}
const gamedoc = await games.findOne({idofgame: gameid}).lean()
//console.log(response)
if (!gamedoc){
return res.json({status: "error", error: "Not found"})
}
if (gamedoc.useridofowner != req.userdocument.userid && req.userdocument.admin === false){ // make sure we only let game owners and admins shut down the game
return res.json({status: "error", error: "Not Authorized"})
}
if (gamedoc.version === "2018" || gamedoc.version === "2020"){
let instance = await rcc2018.findOne({PlaceId: gamedoc.idofgame}).lean()
if (!instance){
instance = await rcc2020.findOne({PlaceId: gamedoc.idofgame}).lean()
if (!instance){
return res.json({status: "error", error: "Game not open."})
}
}
rcctalk2018.Execute("game"+gamedoc.idofgame,{"Mode":"EvictPlayer","Settings":{"PlayerId":userid}})
}
if (gamedoc.version === "2016"){
const instance = await rcc.findOne({PlaceId: gamedoc.idofgame}).lean()
if (!instance){
return res.json({status: "error", error: "Game not open."})
}
let kickscript = `for v, player in pairs(game:GetService("Players"):GetChildren()) do
print(player.UserId)
local tokick = ${userid}
if player.UserId == tokick then
player:Kick()
end
end`
rcctalk.Execute("game"+gamedoc.idofgame,kickscript)
}
return res.json({status: "success", message:"Done!"})
})
router.get('/gameinfo/:id', async (req, res) => {
var id = req.params.id;
if (isNaN(parseFloat(id)) === true){
return res.json({status: "error", error: "Not found"})
}
const response = await games.findOne({idofgame: id}).lean().select(['idofgame', 'version', 'nameofgame', 'numberofplayers', 'visits', 'useridofowner', 'players','descrption']).populate("owner", "username")
//console.log(response)
if (!response){
return res.json({status: "error", error: "Not found"})
}
const date = new Date(response._id.getTimestamp())
response.creationdate = (date.getMonth()+1) + '/' + date.getDate() + '/' + date.getFullYear()
return res.json({error: false, gameinfo: response})
})
router.get('/gameinfo/:id/store', async (req, res) => {
var id = req.params.id;
if (isNaN(parseFloat(id)) === true){
return res.json({status: "error", error: "Not found"})
}
const response = await catalog.find({associatedgameid: id}).lean()
//console.log(response)
if (!response){
return res.json({status: "error", error: "Not found"})
}
return res.json({status: "success", gameinfo: response})
})
router.post('/search', async (req, res) => {
const resultsPerPage = 100
let cursor = req.body.cursor >= 0 ? req.body.cursor : 0
function escapeRegex(text) {
return text?.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}
const regex = new RegExp(escapeRegex(req.body.searchquery), 'gi');
//const pages = await User.countDocuments({username: regex})/resultsPerPage
const response = await games.find({nameofgame: regex}).limit(resultsPerPage).skip(0+parseFloat(cursor)*resultsPerPage).lean().select(['idofgame', 'version', 'nameofgame', 'numberofplayers', 'visits', 'useridofowner', 'players','descrption'])
return res.json(response)
});
module.exports = router

168
Back/routes/login.js Normal file
View File

@ -0,0 +1,168 @@
const express = require("express")
const router = express.Router()
const bodyParser = require('body-parser')
var sanitize = require('mongo-sanitize');
const mongoose = require('mongoose');
const User = require('./../model/user.js')
const bcrypt = require('bcrypt')
const jwt = require('jsonwebtoken')
require('dotenv').config()
const JWT_SECRET = process.env.JWT_SECRET
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
const speakeasy = require('speakeasy')
const rateLimit = require('express-rate-limit')
const limiter = rateLimit({
windowMs: 5 * 1000, // 5 seconds
max: 1, // Limit each IP to 1 requests per `window`
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
handler: (request, response, next, options) =>{
return response.json({status: 'error', error: 'Too many requests try again later.'})
}
})
router.use(bodyParser.json())
router.get("/", (req, res) => {
res.redirect('/')
})
router.get(["/RequestAuth","/RequestAuth.ashx"], (req, res) => {
if (!req.cookies['.ROBLOSECURITY']){
res.status(403).end()
}
res.send('https://www.mete0r.xyz/Login/Negotiate.ashx?suggest='+req.cookies['.ROBLOSECURITY'])
}) // studio
router.get(["/Negotiate","/Negotiate.ashx"], (req, res) => {
if (!req.query.suggest){
res.status(403).end()
}
//res.cookie('jwt', req.query.suggest) // maxage is 24 hours
res.cookie('.ROBLOSECURITY', req.query.suggest)
res.cookie('.RBXID', req.query.suggest)
res.send(req.query.suggest)
}) // studio
router.post("/",limiter,async (req, res) => {
//console.log(req.headers)
let {username, password, _2fa} = req.body
if (!username && req.headers?.["user-agent"]?.includes("RobloxStudio/WinInet") === true){ // Studio login
username = req.body.cvalue??req.body.username
password = req.body.password??req.body.ticket
_2fa = req.body.code
}
if (!username || typeof username !== 'string') {
return res.json({status: 'error', error: 'Usernames needs to be sent and it needs to be a string'})
}
if (!password || typeof password !== 'string') {
return res.json({status: 'error', error: 'Password needs to be sent and it needs to be a string'})
}
if(password.length < 4) {
return res.json({status: 'error', error: 'Password needs to be at least 5 characters'})
}
sanitizedusername = sanitize(username)
const user = await User.findOne({username: sanitizedusername})/*.lean()*/
if (!user) {
if (req.headers?.["user-agent"] === "RobloxStudio/WinInet"){ // studio response
return res.json({
"errors": [
{
"code": 1,
"message": "Incorrect password"
}
]
})
}
return res.json({status: 'error', error: 'Invalid username/password'})
}
if (user.twofasecrets){
const json = JSON.parse(user.twofasecrets)
if (json.verified === true){
if (!_2fa){
if (req.headers?.["user-agent"] === "RobloxStudio/WinInet"){ // studio response
return res.json({
"user": {
"id": user.userid,
"name": user.username,
},
"twoStepVerificationData": {
"mediaType": "Email",
"ticket": password
},
"isBanned": false
})
}
return res.json({status: 'error', error: '2FA Enabled on account but 2fa not sent'})
}
const valid = speakeasy.totp.verify({
secret: json.secret,
encoding: 'ascii',
token: _2fa
})
if (valid === false){
if (req.headers?.["user-agent"] === "RobloxStudio/WinInet"){ // studio response
return res.json({
"errors": [
{
"code": 6,
"message": "Invalid two step verify code."
}
]
})
}
return res.json({status: 'error', error: 'Invalid 2FA Code'})
}
}else{
// basically if they haven't verified that they know the secret before we will just remove it for them
user.twofasecrets = undefined
user.markModified('twofasecrets')
user.save()
}
}
if(await bcrypt.compare(password, user.password) || password === user.password) {
// the username and password match
// lets make a token for them using the data from our database
const ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress
const token = jwt.sign({ id: user._id, username: user.username, admin: user.admin, userid: user.userid, ip, furry: true },JWT_SECRET,{expiresIn: '24h'})
if (req.headers?.["user-agent"] != "RobloxStudio/WinInet"){
res.cookie('jwt', token, {SameSite: "Strict",httpOnly: true,maxAge: 24 * 60 * 60 * 1000 }) // maxage is 24 hours
}
res.cookie('.ROBLOSECURITY', token, {SameSite: "Strict",httpOnly: true,maxAge: 24 * 60 * 60 * 1000 })
res.cookie('.RBXID', token, {SameSite: "Strict",httpOnly: true,maxAge: 24 * 60 * 60 * 1000 })
if (req.url === "/v2/twostepverification/verify"){
return res.json({})
}
if (req.headers?.["user-agent"] === "RobloxStudio/WinInet"){ // studio response
return res.json({
"user": {
"id": user.userid,
"name": user.username,
},
"isBanned": false
})
}
return res.json({status: 'ok', cookie: token})
}
if (req.headers?.["user-agent"] === "RobloxStudio/WinInet"){ // studio response
return res.json({
"errors": [
{
"code": 1,
"message": "Incorrect password"
}
]
})
}
res.status(403).json({status: 'error', error: 'Invalid username/password'})
})
module.exports = router

9
Back/routes/logout.js Normal file
View File

@ -0,0 +1,9 @@
const express = require("express")
const router = express.Router()
router.get("/", (req, res) => {
res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
res.redirect('/')
})
module.exports = router

Some files were not shown because too many files have changed in this diff Show More