Initialise repository with SushiDesigner/Meteor-Front and SushiDesigner/Meteor-back
|
|
@ -0,0 +1,7 @@
|
|||
JWT_SECRET=
|
||||
RCC_HOST=
|
||||
logshook=
|
||||
PROD=true
|
||||
LOCALCERTIFICATEPATH=
|
||||
LOCALREDISCONNECTION=
|
||||
DB_PASSWORD=
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
node_modules/
|
||||
assets/release.zip
|
||||
assets/hash.txt
|
||||
|
|
@ -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-----
|
||||
|
|
@ -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-----
|
||||
|
|
@ -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
|
||||
```
|
||||
|
|
@ -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);
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 301 KiB |
|
|
@ -0,0 +1 @@
|
|||
3b5f1470aa859d3782f72ba07c72ed7d7bc2e461f5f85bb9fd007bf66349d5ee
|
||||
|
|
@ -0,0 +1 @@
|
|||
4cd4d51885b3127d72cf4bbc3e889ec4afa5c4bd725dfba4beab239c2d51b7c5
|
||||
|
|
@ -0,0 +1 @@
|
|||
ecfbc1e4cadd0167cddf1c9920adadf7183f690d7101c1b84d51616a35fada55
|
||||
|
|
@ -0,0 +1 @@
|
|||
d650fafa3e969e786d874def30f32208dc1ebe57d051fc719fe8a0e75af339eb
|
||||
|
|
@ -0,0 +1 @@
|
|||
f13b90a25b1d1d3ff7dfc0628d6fe554cb3b4eb809fe7289632e41670effb197
|
||||
|
|
@ -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 |
|
|
@ -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 |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 195 KiB |
|
After Width: | Height: | Size: 16 MiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
|
@ -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>
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
|
@ -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)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
7c9f615b-8535-4e9c-96d0-dff4cecabdd1
|
||||
|
|
@ -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}
|
||||
|
|
@ -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}
|
||||
|
|
@ -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}
|
||||
|
|
@ -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}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import { Schema } from 'redis-om'
|
||||
|
||||
const ipWhiteListSchema = new Schema('ipWhiteListSchema', {
|
||||
ip: { type: 'string' },
|
||||
})
|
||||
|
||||
export default ipWhiteListSchema
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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}
|
||||
|
|
@ -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}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||