Install dependencies with pnpm and format files with Prettier

This commit is contained in:
Lewin Kelly 2023-09-10 02:02:20 +01:00
parent 24e44a3b50
commit e61816bd6d
No known key found for this signature in database
GPG Key ID: C103AD9C84014FD7
144 changed files with 40063 additions and 20038 deletions

9
.prettierrc Normal file
View File

@ -0,0 +1,9 @@
{
"semi": false,
"arrowParens": "avoid",
"printWidth": 80,
"tabWidth": 4,
"useTabs": true,
"bracketSameLine": true,
"htmlWhitespaceSensitivity": "ignore"
}

View File

@ -1,4 +1,5 @@
# SushiBlox-Website # SushiBlox-Website
Website for sushiblox I guess. Website for sushiblox I guess.
~~Private for now might open source.~~ ~~Private for now might open source.~~
@ -8,13 +9,15 @@ The setup is ~~easy install required node modules and setup a nginx reverse prox
Uses MongoDB for datastorage. Redis for special things Uses MongoDB for datastorage. Redis for special things
# Advice # Advice
~~This uses hardcoded domain names in the code~~ and relies on cloudflare headers for IP configs. so yeahhhhhhhhhhhhhhhhhhhhhhhhhh ~~This uses hardcoded domain names in the code~~ and relies on cloudflare headers for IP configs. so yeahhhhhhhhhhhhhhhhhhhhhhhhhh
# Redis # Redis
idk set it up nerd idk set it up nerd
# setup # setup
easy enough easy enough
# Example # Example

View File

@ -1,65 +1,86 @@
const jwt = require('jsonwebtoken') const jwt = require("jsonwebtoken")
require('dotenv').config() require("dotenv").config()
const JWT_SECRET = process.env.JWT_SECRET const JWT_SECRET = process.env.JWT_SECRET
const atob = require("atob"); const atob = require("atob")
const model = require("./../model/user.js") const model = require("./../model/user.js")
const requireAuth = (req,res,next) => { const requireAuth = (req, res, next) => {
if (!req.cookies && req.headers['authorization']) { if (!req.cookies && req.headers["authorization"]) {
return res.json({status: "error", error: "Unauthorized"}) return res.json({ status: "error", error: "Unauthorized" })
} }
let token = req.cookies.jwt??req.cookies['.ROBLOSECURITY']??req.headers['authorization']??req.headers['roblox-session-id'] let token =
req.cookies.jwt ??
req.cookies[".ROBLOSECURITY"] ??
req.headers["authorization"] ??
req.headers["roblox-session-id"]
if (!token) { if (!token) {
return res.status(401).json({status: "error", error: "Unauthorized"}) 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()
}
jwt.verify(token,JWT_SECRET, (err,decodedtoken) => { if (moderationstatus.status !== "ok") {
if (err){ // if they are moderated then we invalidate the cookie and proceed
res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 }) //res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
return res.status(401).json({status: "error", error: "Unauthorized"}) //return res.send("You have been moderated for "+moderationstatus.Reason+" expires at"+moderationstatus.ExpiresIn+" Moderated by "+moderationstatus.BannedBy )
}else{ var date = Date.parse(moderationstatus.ExpiresIn)
var tokendata = decodedtoken var datetime = new Date()
var name = tokendata.userid var datetime2 = Date.parse(datetime)
try { /*if (date <= datetime2){
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 // they have served there time
model.updateOne({userid: doc.userid}, { model.updateOne({userid: doc.userid}, {
@ -73,17 +94,19 @@ const requireAuth = (req,res,next) => {
return next() return next()
}*/ }*/
return res.json({status: "error", error:"Moderated", moderationstatus}) return res.json({
} status: "error",
next() error: "Moderated",
})/*.lean() rip*/} moderationstatus,
catch (error) { })
console.error(error); }
} next()
}) /*.lean() rip*/
} } catch (error) {
console.error(error)
}) }
}
})
} }
module.exports = {requireAuth} module.exports = { requireAuth }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

17620
Back/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

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

5145
Back/pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,320 +1,373 @@
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const fetch = (...args) =>
let controller = new AbortController(); import("node-fetch").then(({ default: fetch }) => fetch(...args))
require('dotenv').config() let controller = new AbortController()
require("dotenv").config()
const RCC_HOST = process.env.RCC_HOST const RCC_HOST = process.env.RCC_HOST
const url = 'http://'+RCC_HOST+':64989'; // change this to rcc soap const url = "http://" + RCC_HOST + ":64989" // change this to rcc soap
var convert = require('xml-js'); var convert = require("xml-js")
const sampleHeaders = { const sampleHeaders = {
'Content-Type': 'text/xml;charset=UTF-8', "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 { async function OpenJob(jobid, script, expiration) {
const result = await fetch(url, { method: 'POST', body }) return new Promise(async (resolve, reject) => {
const data = await result.text() // this is all boilerplate because soap sucks
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) var xml = {
return resolve( _declaration: {
convertedData _attributes: { version: "1.0", encoding: "UTF-8" },
) },
} catch (error) { "SOAP-ENV:Envelope": {
return reject(error) _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() { async function GetAllJobs() {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const xmlData = (xml = { const xmlData = (xml = {
_declaration: { _declaration: {
_attributes: { version: '1.0', encoding: 'UTF - 8' }, _attributes: { version: "1.0", encoding: "UTF - 8" },
}, },
'SOAP-ENV:Envelope': { "SOAP-ENV:Envelope": {
_attributes: { _attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', "xmlns:SOAP-ENV":
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/', "http://schemas.xmlsoap.org/soap/envelope/",
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', "xmlns:SOAP-ENC":
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema', "http://schemas.xmlsoap.org/soap/encoding/",
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap', "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
'xmlns:ns1': 'http://roblox.com/', "xmlns:xsd": "http://www.w3.org/2001/XMLSchema",
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12', "xmlns:ns2": "http://roblox.com/RCCServiceSoap",
}, "xmlns:ns1": "http://roblox.com/",
'SOAP-ENV:Body': { 'ns1:GetAllJobsEx': {} }, "xmlns:ns3": "http://roblox.com/RCCServiceSoap12",
}, },
}) "SOAP-ENV:Body": { "ns1:GetAllJobsEx": {} },
},
})
const body = convert.js2xml(xmlData, { compact: true, spaces: 4 }) const body = convert.js2xml(xmlData, { compact: true, spaces: 4 })
try { try {
const result = await fetch(url, { method: 'POST', body }) const result = await fetch(url, { method: "POST", body })
const data = await result.text() const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) const convertedData = convert.xml2js(data, {
return resolve( compact: true,
convertedData['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:GetAllJobsExResponse']['ns1:GetAllJobsExResult'] spaces: 4,
) })
} catch (error) { return resolve(
return reject(error) 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 {
async function Execute(jobid,script) { const result = await fetch(url, { method: "POST", body })
return new Promise(async (resolve, reject) => { const data = await result.text()
var xml = { const convertedData = convert.xml2js(data, {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF - 8' } }, compact: true,
'SOAP-ENV:Envelope': { spaces: 4,
_attributes: { })
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', return resolve(convertedData)
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/', } catch (error) {
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', return reject(error)
'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) { async function CloseJob(jobid) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
var xml = { var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF - 8' } }, _declaration: {
'SOAP-ENV:Envelope': { _attributes: { version: "1.0", encoding: "UTF - 8" },
_attributes: { },
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', "SOAP-ENV:Envelope": {
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/', _attributes: {
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', "xmlns:SOAP-ENV":
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema', "http://schemas.xmlsoap.org/soap/envelope/",
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap', "xmlns:SOAP-ENC":
'xmlns:ns1': 'http://roblox.com/', "http://schemas.xmlsoap.org/soap/encoding/",
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12' "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
}, "xmlns:xsd": "http://www.w3.org/2001/XMLSchema",
'SOAP-ENV:Body': { "xmlns:ns2": "http://roblox.com/RCCServiceSoap",
'ns1:CloseJob': { "xmlns:ns1": "http://roblox.com/",
'ns1:jobID': { _text: 'Test' } "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 }) },
},
}
xml["SOAP-ENV:Envelope"]["SOAP-ENV:Body"]["ns1:CloseJob"][
"ns1:jobID"
]._text = jobid
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try { try {
const result = await fetch(url, { method: 'POST', body }) const result = await fetch(url, { method: "POST", body })
const data = await result.text() const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) const convertedData = convert.xml2js(data, {
return resolve( compact: true,
convertedData spaces: 4,
) })
} catch (error) { return resolve(convertedData)
return reject(error) } 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 })
async function RenewLease(jobid,expiration) { try {
return new Promise(async (resolve, reject) => { const result = await fetch(url, { method: "POST", body })
var xml = { const data = await result.text()
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } }, const convertedData = convert.xml2js(data, {
'SOAP-ENV:Envelope': { compact: true,
_attributes: { spaces: 4,
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', })
'xmlns:ns1': 'http://roblox.com/', return resolve(convertedData)
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance' } catch (error) {
}, return reject(error)
'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){ async function GetExpiration(jobid) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
var xml = { var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } }, _declaration: {
'SOAP-ENV:Envelope': { _attributes: { version: "1.0", encoding: "UTF-8" },
_attributes: { },
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', "SOAP-ENV:Envelope": {
'xmlns:ns1': 'http://roblox.com/' _attributes: {
}, "xmlns:SOAP-ENV":
'SOAP-ENV:Body': { 'ns1:GetExpiration': { 'ns1:jobID': { _text: 'Test' } } } "http://schemas.xmlsoap.org/soap/envelope/",
} "xmlns:ns1": "http://roblox.com/",
} },
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:GetExpiration']['ns1:jobID']._text = jobid "SOAP-ENV:Body": {
const body = convert.js2xml(xml, { compact: true, spaces: 4 }) "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 { try {
const result = await fetch(url, { method: 'POST', body }) const result = await fetch(url, { method: "POST", body })
const data = await result.text() const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) const convertedData = convert.xml2js(data, {
return resolve( compact: true,
convertedData spaces: 4,
) })
} catch (error) { return resolve(convertedData)
return reject(error) } catch (error) {
} return reject(error)
}) }
})
} }
//var gameservertxt = fs.readFileSync('actualgameserver.txt','utf-8') //var gameservertxt = fs.readFileSync('actualgameserver.txt','utf-8')
//gameservertxt = gameservertxt.replace('function start(placeId, port, url)','function start(1111, port)') //gameservertxt = gameservertxt.replace('function start(placeId, port, url)','function start(1111, port)')
async function CloseExpiredJobs(){ async function CloseExpiredJobs() {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
var xml = xml = { var xml = (xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } }, _declaration: {
'SOAP-ENV:Envelope': { _attributes: { version: "1.0", encoding: "UTF-8" },
_attributes: { },
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', "SOAP-ENV:Envelope": {
'xmlns:ns1': 'http://roblox.com/' _attributes: {
}, "xmlns:SOAP-ENV":
'SOAP-ENV:Body': { 'ns1:CloseExpiredJobs': {} } "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 }) const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try { try {
const result = await fetch(url, { method: 'POST', body }) const result = await fetch(url, { method: "POST", body })
const data = await result.text() const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) const convertedData = convert.xml2js(data, {
return resolve( compact: true,
convertedData spaces: 4,
) })
} catch (error) { return resolve(convertedData)
return reject(error) } catch (error) {
} return reject(error)
}) }
})
} }
async function CloseAllJobs(){ async function CloseAllJobs() {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
var xml = xml = { var xml = (xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } }, _declaration: {
'SOAP-ENV:Envelope': { _attributes: { version: "1.0", encoding: "UTF-8" },
_attributes: { },
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', "SOAP-ENV:Envelope": {
'xmlns:ns1': 'http://roblox.com/' _attributes: {
}, "xmlns:SOAP-ENV":
'SOAP-ENV:Body': { 'ns1:CloseAllJobs': {} } "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 }) const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try { try {
const result = await fetch(url, { method: 'POST', body }) const result = await fetch(url, { method: "POST", body })
const data = await result.text() const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) const convertedData = convert.xml2js(data, {
return resolve( compact: true,
convertedData spaces: 4,
) })
} catch (error) { return resolve(convertedData)
return reject(error) } catch (error) {
} return reject(error)
}) }
})
} }
module.exports = {
module.exports = {OpenJob, GetAllJobs,Execute,CloseJob,RenewLease,GetExpiration,CloseExpiredJobs,CloseAllJobs} OpenJob,
GetAllJobs,
Execute,
CloseJob,
RenewLease,
GetExpiration,
CloseExpiredJobs,
CloseAllJobs,
}

View File

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

View File

@ -1,110 +1,212 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const { requireAuth } = require('../../middleware/authmiddlewaregame') const { requireAuth } = require("../../middleware/authmiddlewaregame")
const crypto = require('crypto'); const crypto = require("crypto")
const fs = require('fs') const fs = require("fs")
const key = fs.readFileSync('DefaultPrivateKey.pem') const key = fs.readFileSync("DefaultPrivateKey.pem")
const { getPort, checkPort, getRandomPort, waitForPort } = require('get-port-please') const {
getPort,
checkPort,
getRandomPort,
waitForPort,
} = require("get-port-please")
const RCC_HOST = process.env.RCC_HOST const RCC_HOST = process.env.RCC_HOST
var sanitize = require('mongo-sanitize'); var sanitize = require("mongo-sanitize")
const games = require('./../../model/games.js') const games = require("./../../model/games.js")
const signatures = require("./../signatures.js") const signatures = require("./../signatures.js")
const rcc = require('../../model/rcc2018.js') const rcc = require("../../model/rcc2018.js")
const rcctalk = require('../../rcctalk2018') const rcctalk = require("../../rcctalk2018")
const User = require('../../model/user.js') const User = require("../../model/user.js")
function sleep(ms) { function sleep(ms) {
return new Promise((resolve) => { return new Promise(resolve => {
setTimeout(resolve, ms); setTimeout(resolve, ms)
}); })
} }
const _2018placelauncher = async(req,res,next) => { const _2018placelauncher = async (req, res, next) => {
var enabled = req.config var enabled = req.config
if (enabled.GamesEnabled === false){ if (enabled.GamesEnabled === false) {
return res.json({status:"error",error:"Games are disabled bad boy"}) return res.json({
} status: "error",
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} error: "Games are disabled bad boy",
if (!req.query.name && !req.query.placeId && !req.query.placeid){ })
return res.json({status:"error",error:"no placeid bad"}) }
} var joinJson = {
if (req.userdocument.gamejoin2018){ ClientPort: 0,
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":""}) MachineAddress: "localhost",
} ServerPort: 25564,
var sanitizedplaceid = sanitize(req.query.name??req.query.placeId??req.query.placeid) PingUrl: "",
const game = await games.findOne({idofgame: sanitizedplaceid}).lean() PingInterval: 120,
if (!game){ UserName: "default",
return res.json({status:"error",error:"that game doesn't exist!"}) SeleniumTestMode: false,
} UserId: 0,
if (game.version != "2018"){ SuperSafeChat: false,
return next() CharacterAppearance: "http://shitncumblox.gq/game/charapp?name=default",
} ClientTicket: "",
let instance = await rcc.findOne({PlaceId: sanitizedplaceid}).lean() GameId: 1,
if (instance && instance.Status === 2){ 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 + ";"
// 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 //create signature 2
joinJson.UserName = req.userdocument.username const sign2 = crypto.createSign("SHA1")
joinJson.UserId = req.userdocument.userid sign2.update(
joinJson.CharacterAppearance = "http://mete0r.xyz/v1.1/avatar-fetch?userId" + req.userdocument.userid `${req.userdocument.userid}\n` /*userid*/ +
joinJson.MachineAddress = RCC_HOST // need to put rcc host here lol `game${sanitizedplaceid}\n` /*jobid*/ +
joinJson.ServerPort = instance.Port timestamp /*timestamp*/,
joinJson.PlaceId = instance.PlaceId )
joinJson.GameId = sanitizedplaceid var signature2 = sign2.sign(key, "base64")
joinJson.CharacterAppearanceId = req.userdocument.userid joinJson.ClientTicket += signature2
joinJson.MembershipType = req.userdocument.membership
joinJson.CreatorId = game.useridofowner
joinJson.SessionId = req.query.auth??req.cookies.jwt
const timestamp = Date.now() req.userdocument.gamejoin2018 = JSON.stringify(joinJson)
joinJson.ClientTicket = timestamp+";" // timestamp req.userdocument.markModified("gamejoin2018")
//create signature 1 await req.userdocument.save()
const sign1 = crypto.createSign('SHA1'); var joinScriptJson = {
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*/) jobId: "Test",
var signature1 = sign1.sign(key, "base64") status: 2,
joinJson.ClientTicket += signature1 + ";" joinScriptUrl:
"http://mete0r.xyz/game/join.ashx?ver=2018&auth=" +
joinJson.SessionId,
authenticationUrl: "http://mete0r.xyz/Login/Negotiate.ashx",
authenticationTicket: "SomeTicketThatDosentCrash",
message: "",
}
//create signature 2 return res.send(JSON.stringify(joinScriptJson))
const sign2 = crypto.createSign('SHA1'); }
sign2.update(`${req.userdocument.userid}\n`/*userid*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/) if (instance && instance.Status === 1) {
var signature2 = sign2.sign(key, "base64") var joinScriptJson = {
joinJson.ClientTicket += signature2 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))
}
req.userdocument.gamejoin2018 = JSON.stringify(joinJson) var port = await getPort({ random: true })
req.userdocument.markModified('gamejoin2018') // launch job
await req.userdocument.save() rcctalk.OpenGame(
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":""} "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
})
return res.send(JSON.stringify(joinScriptJson)) //console.log(newrenderscript)
}
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 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))
}
var port = await getPort({random: true}) router.all("/2018/join", requireAuth, _2018placelauncher, async (req, res) => {
// launch job return res.json({
rcctalk.OpenGame("game"+sanitizedplaceid,port,RCC_HOST,sanitizedplaceid,game.useridofowner) status: "error",
//console.dir(response,{ depth: null }) error: "Version different than client requested.",
//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') //rcctalk.CloseJob('game2')
module.exports = {router: router, _2018placelauncher:_2018placelauncher} module.exports = { router: router, _2018placelauncher: _2018placelauncher }

View File

@ -1,207 +1,327 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const { requireAuth } = require('../../middleware/authmiddlewaregame') const { requireAuth } = require("../../middleware/authmiddlewaregame")
const crypto = require('crypto'); const crypto = require("crypto")
const fs = require('fs') const fs = require("fs")
const key = fs.readFileSync('PrivateKey2020.txt') const key = fs.readFileSync("PrivateKey2020.txt")
const { getPort, checkPort, getRandomPort, waitForPort } = require('get-port-please') const {
getPort,
checkPort,
getRandomPort,
waitForPort,
} = require("get-port-please")
const RCC_HOST = process.env.RCC_HOST const RCC_HOST = process.env.RCC_HOST
var sanitize = require('mongo-sanitize'); var sanitize = require("mongo-sanitize")
const games = require('./../../model/games.js') const games = require("./../../model/games.js")
const signatures = require("./../signatures.js") const signatures = require("./../signatures.js")
const rcc = require('../../model/rcc2020.js') const rcc = require("../../model/rcc2020.js")
const rcctalk = require('../../rcctalk2018') const rcctalk = require("../../rcctalk2018")
const User = require('../../model/user.js') const User = require("../../model/user.js")
const bodyParser = require('body-parser') const bodyParser = require("body-parser")
router.use(bodyParser.json()) router.use(bodyParser.json())
function sleep(ms) { function sleep(ms) {
return new Promise((resolve) => { return new Promise(resolve => {
setTimeout(resolve, ms); 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) => { const _2020placelauncher = async (req, res, next) => {
return res.json({status:"error",error:"Version different than client requested."}) 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') //rcctalk.CloseJob('game2')
module.exports = {router: router, _2020placelauncher:_2020placelauncher} module.exports = { router: router, _2020placelauncher: _2020placelauncher }

View File

@ -1,188 +1,284 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
var path = require('path') var path = require("path")
const { requireAuth } = require('./../middleware/authmiddleware') const { requireAuth } = require("./../middleware/authmiddleware")
var multer = require('multer'); var multer = require("multer")
const bodyParser = require('body-parser') const bodyParser = require("body-parser")
router.use(bodyParser.json()) router.use(bodyParser.json())
const User = require('./../model/games.js') const User = require("./../model/games.js")
const ActualUser = require('./../model/user.js') const ActualUser = require("./../model/user.js")
const catalog = require('./../model/item.js') const catalog = require("./../model/item.js")
const games = require('./../model/games.js') const games = require("./../model/games.js")
const rcc = require('./../model/rcc.js') const rcc = require("./../model/rcc.js")
var numbtest = /^\d+\.?\d*$/; var numbtest = /^\d+\.?\d*$/
const rcctalk = require('./../rcctalk') const rcctalk = require("./../rcctalk")
require('dotenv').config() require("dotenv").config()
const RCCDIR = process.env.RCC_Content const RCCDIR = process.env.RCC_Content
var thisistheplaceid = "1" var thisistheplaceid = "1"
var storage = multer.diskStorage({ var storage = multer.diskStorage({
destination: function (req, file, cb) { destination: function (req, file, cb) {
// Uploads is the Upload_folder_name // Uploads is the Upload_folder_name
if (file.mimetype == "image/png"){ if (file.mimetype == "image/png") {
cb(null, "./assets/gameassets") cb(null, "./assets/gameassets")
}else{ } else {
cb(null, "./assets/ugc") cb(null, "./assets/ugc")
} }
},
}, filename: async function (req, file, cb) {
filename: async function (req, file, cb) { if (path.extname(file.originalname) === ".rbxl") {
if (path.extname(file.originalname) === ".rbxl"){ const placeid = await User.countDocuments()
const placeid = await User.countDocuments(); cb(
cb(null, file.fieldname + "-" + placeid +path.extname(file.originalname)) null,
}else if (file.mimetype == "image/png"){ file.fieldname +
const placeid = await User.countDocuments(); "-" +
cb(null, file.fieldname + "-" + placeid +path.extname(file.originalname)) placeid +
path.extname(file.originalname),
}else if (file.mimetype == "application/octet-stream"){ )
const itemid = await catalog.countDocuments(); } else if (file.mimetype == "image/png") {
cb(null, file.fieldname + "-" + itemid +path.extname(file.originalname)) const placeid = await User.countDocuments()
} cb(
null,
} file.fieldname +
}) "-" +
const upload = multer({storage: storage, placeid +
fileFilter: function (req, file, callback) { path.extname(file.originalname),
var ext = path.extname(file.originalname); )
if(ext !== '.png' && ext !== '.png' && ext !== '.rbxl') { } else if (file.mimetype == "application/octet-stream") {
return callback('Only pngs and rbxl are allowed') const itemid = await catalog.countDocuments()
} cb(
callback(null, true) null,
}, file.fieldname + "-" + itemid + path.extname(file.originalname),
}) )
}
},
const itemupload = multer({storage: storage, })
fileFilter: function (req, file, callback) { const upload = multer({
var ext = path.extname(file.originalname); storage: storage,
if (req.userdocument.admin === "false"){ fileFilter: function (req, file, callback) {
return callback('LEAVE') var ext = path.extname(file.originalname)
} if (ext !== ".png" && ext !== ".png" && ext !== ".rbxl") {
if(ext !== '.png' && ext !== '.png' && ext !== '.rbxm') { return callback("Only pngs and rbxl are allowed")
return callback('Only pngs and rbxm are allowed') }
} callback(null, true)
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."})
}) })
const itemupload = multer({
router.post("/moderateuser", requireAuth,async (req, res) => { storage: storage,
if (req.userdocument.admin == false) { fileFilter: function (req, file, callback) {
return res.redirect('/') var ext = path.extname(file.originalname)
} if (req.userdocument.admin === "false") {
let {userid, reason, unbantime,Type} = req.body return callback("LEAVE")
}
if (numbtest.test(userid) == false){ if (ext !== ".png" && ext !== ".png" && ext !== ".rbxm") {
return res.json({status: "error", error: "Userid can only be a number!"}) return callback("Only pngs and rbxm are allowed")
} }
callback(null, true)
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) => { router.post(
if (req.userdocument.admin == false) { "/uploaditem",
return res.redirect('/') requireAuth,
} itemupload.single("itemfile"),
const {userid,username} = req.body async (req, res) => {
const whitelist = ["username","coins","userid","admin","moderation","colors","inventory","joindate","lastclaimofcurrency","membership","friendrequests","friends","badges","status","timesincelastrequest","avatartype","discordid","moderationhistory"] if (
if (numbtest.test(userid) == false && !username){ req.userdocument.admin == false &&
return res.json({status: "error", error: "Userid can only be a number!"}) 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!",
})
}
let lookupuser 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." })
},
)
if (userid != ""){ router.post("/moderateuser", requireAuth, async (req, res) => {
lookupuser = await ActualUser.findOne({userid: userid}).lean().select(whitelist) if (req.userdocument.admin == false) {
}else if (username){ return res.redirect("/")
lookupuser = await ActualUser.findOne({username: username}).lean().select(whitelist) }
} let { userid, reason, unbantime, Type } = req.body
if (!lookupuser) { if (numbtest.test(userid) == false) {
return res.json({status: "error", error: "User not found reenter"}) return res.json({
} status: "error",
return res.json({status: "success", data: lookupuser}) 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("/queue", requireAuth,async (req, res) => { router.post("/moderateuserlookup", requireAuth, async (req, res) => {
if (req.userdocument.admin == false) { if (req.userdocument.admin == false) {
return res.redirect('/') return res.redirect("/")
} }
const resultsPerPage = 30 const { userid, username } = req.body
let page = req.body.page ?? 0 const whitelist = [
if (page != 0){ "username",
page-=1 "coins",
} "userid",
let {sort} = req.body "admin",
let response "moderation",
let responsecount "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!",
})
}
if (sort != "All"){ let lookupuser
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}})
}
if (userid != "") {
lookupuser = await ActualUser.findOne({ userid: userid })
.lean()
.select(whitelist)
} else if (username) {
lookupuser = await ActualUser.findOne({ username: username })
.lean()
.select(whitelist)
}
return res.json({data: response, pages: Math.ceil(Math.max(responsecount/resultsPerPage, 1)), count: responsecount }) 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 module.exports = router

View File

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

View File

@ -1,80 +1,152 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware') const { requireAuth } = require("./../../middleware/authmiddleware")
const bodyParser = require('body-parser') const bodyParser = require("body-parser")
const User = require('./../../model/user.js') const User = require("./../../model/user.js")
router.use(bodyParser.json()) router.use(bodyParser.json())
function selectKeys(obj, keysArray) { function selectKeys(obj, keysArray) {
let result = {}; let result = {}
for (let i = 0; i < keysArray.length; i++) { for (let i = 0; i < keysArray.length; i++) {
if (keysArray[i] in obj === true) { if (keysArray[i] in obj === true) {
result[keysArray[i]] = obj[keysArray[i]]; result[keysArray[i]] = obj[keysArray[i]]
} }
} }
return result; 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) 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 module.exports = router

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,188 +1,241 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware') const { requireAuth } = require("./../../middleware/authmiddleware")
const games = require('./../../model/games.js') const games = require("./../../model/games.js")
const User = require('./../../model/user.js') const User = require("./../../model/user.js")
const bodyParser = require('body-parser') const bodyParser = require("body-parser")
router.use(bodyParser.json()) router.use(bodyParser.json())
router.post("/request-friendship", requireAuth,async (req, res) => { router.post("/request-friendship", requireAuth, async (req, res) => {
const tofriend = req.body.recipientUserId const tofriend = req.body.recipientUserId
if (!tofriend){ if (!tofriend) {
return res.json({status:"error",error:"Recipent not sent!"}) return res.json({ status: "error", error: "Recipent not sent!" })
} }
const usertofriend = await User.findOne({userid: tofriend}).lean() const usertofriend = await User.findOne({ userid: tofriend }).lean()
if (!usertofriend){ if (!usertofriend) {
return res.json({status:"error",error:"Can't find Recipent!"}) 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
if (usertofriend.friends){ const bothwantobefriends = req.userdocument.friendrequests.some(
const friends = usertofriend.friends.some(word => word.userid == req.userdocument.userid) word => word.userid == usertofriend.userid,
if (friends === true){ )
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) {},
)
return res.json({status:"error",error:"You are already friends!"}) User.updateOne(
} { userid: tofriend },
// already friends {
} $push: {
if (req.userdocument.friendrequests){ friends: {
// 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 userid: req.userdocument.userid,
username: req.userdocument.username,
const bothwantobefriends = req.userdocument.friendrequests.some(word => word.userid == usertofriend.userid) },
if (bothwantobefriends === true){ },
console.log(tofriend) $pull: {
User.updateOne({userid: req.userdocument.userid}, { friendrequests: {
$push: { userid: req.userdocument.userid,
friends: {userid: usertofriend.userid, username: usertofriend.username} username: req.userdocument.username,
}, },
$pull: { },
friendrequests: {userid: usertofriend.userid, username: usertofriend.username} },
} function (err, doc) {},
}, )
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!"})
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) => { router.post("/decline-friend-request", requireAuth, async (req, res) => {
const tounfriend = req.body.recipientUserId const tounfriend = req.body.recipientUserId
//console.log(tounfriend+" nerd") //console.log(tounfriend+" nerd")
if (!tounfriend){ if (!tounfriend) {
return res.json({status:"error",error:"Recipent not sent!"}) return res.json({ status: "error", error: "Recipent not sent!" })
} }
const usertofriend = await User.findOne({userid: tounfriend}).lean() const usertofriend = await User.findOne({ userid: tounfriend }).lean()
if (!usertofriend){ if (!usertofriend) {
return res.json({status:"error",error:"Can't find Recipent!"}) return res.json({ status: "error", error: "Can't find Recipent!" })
} }
const alreadyfriends = req.userdocument?.friends?.some(word => word.userid == tounfriend ) const alreadyfriends = req.userdocument?.friends?.some(
if (alreadyfriends === true){ word => word.userid == tounfriend,
// already friends with the person so they want ro remove their friend )
User.updateOne({userid: tounfriend}, { if (alreadyfriends === true) {
$pull: { // already friends with the person so they want ro remove their friend
friends: {userid: req.userdocument.userid, username: req.userdocument.username} User.updateOne(
} { userid: tounfriend },
}, {
function(err, doc) { $pull: {
//console.log(err) friends: {
}) userid: req.userdocument.userid,
User.updateOne({userid: req.userdocument.userid}, { username: req.userdocument.username,
$pull: { },
friends: {userid:usertofriend.userid, username: usertofriend.username} },
} },
}, function (err, doc) {
function(err, doc) { //console.log(err)
//console.log(err) },
}) )
return res.json({status:"error",error:"Unfriended friend!"}) User.updateOne(
} { userid: req.userdocument.userid },
{
$pull: {
friends: {
//otherwise the user isn't friends but still declines the friend request userid: usertofriend.userid,
username: usertofriend.username,
User.updateOne({userid: tounfriend}, { },
$pull: { },
friendrequests: {userid: req.userdocument.userid, username: req.userdocument.username} },
} function (err, doc) {
}, //console.log(err)
function(err, doc) { },
//console.log(err) )
}) return res.json({ status: "error", error: "Unfriended friend!" })
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!"})
//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) => { router.post("/has-sent-request", requireAuth, async (req, res) => {
const tofriend = req.body.recipientUserId const tofriend = req.body.recipientUserId
if (!tofriend){ if (!tofriend) {
return res.json({status:"error",error:"Recipent not sent!"}) return res.json({ status: "error", error: "Recipent not sent!" })
} }
const usertofriend = await User.findOne({userid: tofriend}).lean() const usertofriend = await User.findOne({ userid: tofriend }).lean()
if (!usertofriend){ if (!usertofriend) {
return res.json({status:"error",error:"Can't find Recipent!"}) return res.json({ status: "error", error: "Can't find Recipent!" })
} }
const friends = usertofriend?.friends?.some(word => word.userid == req.userdocument.userid) const friends = usertofriend?.friends?.some(
if (friends === true){ word => word.userid == req.userdocument.userid,
)
if (friends === true) {
return res.json({ status: "error", error: "You are already friends!" })
}
// already friends
return res.json({status:"error",error:"You are already friends!"}) const alreadyrequested = usertofriend?.friendrequests?.some(
} word => word.userid == req.userdocument.userid,
// 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 })
}
// already friend requested const bothwantobefriends = req.userdocument?.friendrequests?.some(
if (alreadyrequested === true){ 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:true}) return res.json({ status: "success", message: false })
}
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) => {
router.post('/friend-requests',requireAuth, async (req, res) => { res.json({ data: req.userdocument?.friendrequests })
res.json({data: req.userdocument?.friendrequests}) })
});
module.exports = router module.exports = router

View File

@ -1,49 +1,48 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware') const { requireAuth } = require("./../../middleware/authmiddleware")
const bodyParser = require('body-parser') const bodyParser = require("body-parser")
const keys = require('./../../model/keys.js') const keys = require("./../../model/keys.js")
router.use(bodyParser.json()) 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? // 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) { function stringGen(len) {
var text = ""; var text = ""
var charset = "abcdefghijklmnopqrstuvwxyz0123456789"; var charset = "abcdefghijklmnopqrstuvwxyz0123456789"
for (var i = 0; i < len; i++) for (var i = 0; i < len; i++)
text += charset.charAt(Math.floor(Math.random() * charset.length)); text += charset.charAt(Math.floor(Math.random() * charset.length))
return text; return text
} }
router.post("/",requireAuth,async (req, res) => { router.post("/", requireAuth, async (req, res) => {
if (req.userdocument.admin === true){ if (req.userdocument.admin === true) {
var key = stringGen(10) var key = stringGen(10)
const response = await keys.create({ const response = await keys.create({
Creator: req.userdocument.username, Creator: req.userdocument.username,
Key: key, Key: key,
Used: false Used: false,
}) })
return res.redirect(req.get('referer')); return res.redirect(req.get("referer"))
} }
if (req.userdocument.coins >= 100){ if (req.userdocument.coins >= 100) {
// they have enough // they have enough
req.userdocument.coins -= 100 req.userdocument.coins -= 100
req.userdocument.markModified('coins') req.userdocument.markModified("coins")
await req.userdocument.save() await req.userdocument.save()
var key = stringGen(10) var key = stringGen(10)
const response = await keys.create({ const response = await keys.create({
Creator: req.userdocument.username, Creator: req.userdocument.username,
Key: key, Key: key,
Used: false Used: false,
}) })
return res.redirect(req.get('referer')); return res.redirect(req.get("referer"))
}
} return res.redirect(req.get("referer"))
return res.redirect(req.get('referer'));
}) })
module.exports = router module.exports = router

View File

@ -1,182 +1,238 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware') const { requireAuth } = require("./../../middleware/authmiddleware")
const bodyParser = require('body-parser') const bodyParser = require("body-parser")
const groups = require('./../../model/groups.js') const groups = require("./../../model/groups.js")
var multer = require('multer'); var multer = require("multer")
const fs = require('fs'); const fs = require("fs")
const path = require('path') const path = require("path")
router.use(bodyParser.json()) router.use(bodyParser.json())
router.post("/", requireAuth,async (req, res) => { router.post("/", requireAuth, async (req, res) => {
let mygroups = await groups.find({"members.userId": req.userdocument.userid}).lean().select(["Name","Description","Public","groupid","ownerid","memberscount"]) let mygroups = await groups
return res.json(mygroups) .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) => { router.post("/:id", requireAuth, async (req, res) => {
const groupid = parseInt(req.params.id) const groupid = parseInt(req.params.id)
if (isNaN(groupid)){ if (isNaN(groupid)) {
return res.json({status: "error", error: "Not found"}) 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"]}) let groupresponse = await groups
.findOne({ groupid })
.lean()
.select([
"Name",
"Description",
"Public",
"groupid",
"ownerid",
"memberscount",
"currentshout",
])
.populate({ path: "owner", select: ["username", "userid"] })
if (!groupresponse){ if (!groupresponse) {
return res.json({status: "error", error: "Not found"}) return res.json({ status: "error", error: "Not found" })
} }
return res.json({status: "success", data: groupresponse}) return res.json({ status: "success", data: groupresponse })
}) })
router.post("/:id/members", requireAuth,async (req, res) => { router.post("/:id/members", requireAuth, async (req, res) => {
const groupid = parseInt(req.params.id) const groupid = parseInt(req.params.id)
const {rank} = req.body const { rank } = req.body
if (!rank){ if (!rank) {
return res.json({status: "error", error: "Rank not sent"}) return res.json({ status: "error", error: "Rank not sent" })
} }
const resultsPerPage = 5 const resultsPerPage = 5
let page = req.body.page ?? 0 let page = req.body.page ?? 0
if (page != 0){ if (page != 0) {
page-=1 page -= 1
} }
let skip = 0+parseFloat(page)*resultsPerPage let skip = 0 + parseFloat(page) * resultsPerPage
if (isNaN(groupid)){ if (isNaN(groupid)) {
return res.json({status: "error", error: "Not found"}) 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"]}) let groupresponse = await groups
.findOne({ groupid })
.lean()
.select({ members: { $slice: [skip, resultsPerPage] } })
.populate({ path: "memberspoly", select: ["username", "userid"] })
if (!groupresponse){ if (!groupresponse) {
return res.json({status: "error", error: "Not found"}) return res.json({ status: "error", error: "Not found" })
} }
return res.json({status: "success", data: groupresponse.memberspoly}) return res.json({ status: "success", data: groupresponse.memberspoly })
}) })
async function validateImage(groupid,res){ async function validateImage(groupid, res) {
return new Promise(async (resolve) => { 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)
},
)
try { return res.json({ status: "error", error: "Image is invalid." })
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()
} })
resolve()
})
} }
var storage = multer.diskStorage({ var storage = multer.diskStorage({
destination: function (req, file, cb) { destination: function (req, file, cb) {
// Uploads is the Upload_folder_name // Uploads is the Upload_folder_name
cb(null, "./assets/groupicons") cb(null, "./assets/groupicons")
},
}, filename: async function (req, file, cb) {
filename: async function (req, file, cb) { const groupid = await groups.countDocuments()
const groupid = await groups.countDocuments(); cb(null, "icon-" + groupid + ".png")
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!"})
}) })
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("/editgroup", requireAuth,async (req, res) => { 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("/postshout", requireAuth,async (req, res) => { router.post("/editgroup", requireAuth, async (req, res) => {})
router.post("/postshout", requireAuth, async (req, res) => {})
}) router.post("/joingroup", 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) => {})
})
router.post("/leavegroup", requireAuth,async (req, res) => {
})
router.post("/exile", requireAuth,async (req, res) => {
})
module.exports = router module.exports = router

View File

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

View File

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

View File

@ -1,83 +1,99 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const { requireAuth } = require('./../../middleware/authmiddleware') const { requireAuth } = require("./../../middleware/authmiddleware")
const bodyParser = require('body-parser') const bodyParser = require("body-parser")
var numbtest = /^\d+\.?\d*$/; var numbtest = /^\d+\.?\d*$/
const items = require('./../../model/item.js') const items = require("./../../model/item.js")
const User = require('./../../model/user.js') const User = require("./../../model/user.js")
router.use(bodyParser.json()) router.use(bodyParser.json())
router.post("/", requireAuth,async (req, res) => { router.post("/", requireAuth, async (req, res) => {
if (!req.userdocument.discordid) { if (!req.userdocument.discordid) {
return res.json({status: "error", error: "Discord link required for purchasing. Link your discord in the settings panel."}) return res.json({
} status: "error",
const {itemid} = req.body error: "Discord link required for purchasing. Link your discord in the settings panel.",
if (typeof itemid == "undefined"){ })
return res.json({status: "error", error: "You need sum itemids bozo"}) }
} const { itemid } = req.body
if (numbtest.test(itemid) == false){ if (typeof itemid == "undefined") {
return res.json({status: "error", error: "You need sum itemids bozo"}) 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." })
}
const itemdoc = await items.findOne({ItemId: itemid})//.lean() if (itemdoc.Hidden) {
if (typeof req.userdocument.inventory !== "undefined"){ return res.json({ status: "error", error: "You can't buy this." })
// 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){ if (req.userdocument.coins >= itemdoc.Price) {
return res.json({status: 'error', error: "You can't buy this."}) // has enough money to purcahse item
} try {
User.updateOne(
{ userid: req.userdocument.userid },
if (req.userdocument.coins >= itemdoc.Price){ {
// has enough money to purcahse item $set: {
try{ coins: req.userdocument.coins - itemdoc.Price,
User.updateOne({userid: req.userdocument.userid}, { },
$set: { $push: {
coins: req.userdocument.coins - itemdoc.Price inventory: {
}, Type: itemdoc.Type,
$push: { ItemId: itemdoc.ItemId,
inventory: {Type: itemdoc.Type,ItemId: itemdoc.ItemId, ItemName: itemdoc.Name, Equipped: false} ItemName: itemdoc.Name,
} Equipped: false,
}, },
function(err, doc) { },
//console.log(err) },
}) function (err, doc) {
// give owner cash //console.log(err)
User.updateOne({userid: itemdoc.Creator}, { },
$inc: { )
coins: itemdoc.Price // give owner cash
} User.updateOne(
}, { userid: itemdoc.Creator },
function(err, doc) { {
//console.log(err) $inc: {
}) coins: itemdoc.Price,
},
itemdoc.Sales += 1 },
if (!itemdoc.Sales){ function (err, doc) {
itemdoc.Sales = 1 //console.log(err)
} },
//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"})
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 module.exports = router

View File

@ -1,249 +1,292 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const rcctalk = require('./../../thumbnailrcctalk') const rcctalk = require("./../../thumbnailrcctalk")
const rcctalk2018 = require('./../../rcctalk2018') const rcctalk2018 = require("./../../rcctalk2018")
const fs = require('fs') const fs = require("fs")
const assetrenderscript = fs.readFileSync('assetthumbnailrenderer.lua','utf-8') const assetrenderscript = fs.readFileSync("assetthumbnailrenderer.lua", "utf-8")
var path = require("path"); var path = require("path")
const User = require('./../../model/user.js') const User = require("./../../model/user.js")
const item = require('./../../model/item.js') const item = require("./../../model/item.js")
var rgx = /^[0-9]*\.?[0-9]*$/; var rgx = /^[0-9]*\.?[0-9]*$/
router.use(express.json({limit: '200mb'})); router.use(express.json({ limit: "200mb" }))
const { requireAuth } = require('./../../middleware/authmiddleware.js') const { requireAuth } = require("./../../middleware/authmiddleware.js")
const { grabAuth } = require('./../../middleware/grabauth.js') const { grabAuth } = require("./../../middleware/grabauth.js")
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const fetch = (...args) =>
require('dotenv').config() import("node-fetch").then(({ default: fetch }) => fetch(...args))
require("dotenv").config()
const RCC_HOST = process.env.RCC_HOST const RCC_HOST = process.env.RCC_HOST
const rateLimit = require('express-rate-limit') const rateLimit = require("express-rate-limit")
const limiter = rateLimit({ const limiter = rateLimit({
windowMs: 2 * 1000, // 5 seconds windowMs: 2 * 1000, // 5 seconds
max: 1, // Limit each IP to 1 requests per `window` max: 1, // Limit each IP to 1 requests per `window`
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers legacyHeaders: false, // Disable the `X-RateLimit-*` headers
handler: (request, response, next, options) =>{ handler: (request, response, next, options) => {
return response.sendFile(path.resolve("./assets/default.png")) return response.sendFile(path.resolve("./assets/default.png"))
} },
}) })
router.get("/",grabAuth,async (req, res) => { router.get("/", grabAuth, async (req, res) => {
if (!req.query.id && !req.query.userId) { if (!req.query.id && !req.query.userId) {
return res.status(400) return res.status(400)
} }
let headshot = false let headshot = false
if (req.query.type === "headshot"){ if (req.query.type === "headshot") {
headshot = true headshot = true
} }
let id = req.query.id??req.query.userId let id = req.query.id ?? req.query.userId
var sanitizedid = id.match(rgx) var sanitizedid = id.match(rgx)
const user = await User.findOne({userid: sanitizedid}).lean() const user = await User.findOne({ userid: sanitizedid }).lean()
if (!user) { if (!user) {
return res.json({status: 'error', error: 'User does not exist'}) 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",
)
}
// lets get our file path with sanitized id fs.access(path2, fs.F_OK, async err => {
let path2=path.resolve(__dirname, "../../assets/userthumbnails/"+sanitizedid+".png") if (err) {
if (headshot === true){ let newrender = await rcctalk2018.OpenRender(sanitizedid, headshot)
path2=path.resolve(__dirname, "../../assets/userthumbnailsheadshots/"+sanitizedid+".png") 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
fs.access(path2, fs.F_OK,async (err) => { res.writeHead(200, { "Content-Type": "image/png" })
if (err) {
fs.writeFile(path2, newrender, "base64", function (err) {
if (err) {
console.log("error")
}
})
return res.end(Buffer.from(newrender, "base64"))
let newrender = await rcctalk2018.OpenRender(sanitizedid,headshot) // if this timeouts and rcc doesn't return the image feor some reason then send the default fallback
if (newrender.error){ //return res.sendFile(path.resolve("./assets/default.png"))
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'}) //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)
}
fs.writeFile(path2,newrender,'base64',function(err){ let newrender = await rcctalk2018.OpenRender(
if (err) { sanitizedid,
console.log("error") 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" })
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
}
})
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) => { router.post("/rcc", (req, res) => {
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress var ip = req.headers["cf-connecting-ip"] || req.socket.remoteAddress
if (ip == RCC_HOST || ip == "::ffff:"+RCC_HOST) { if (ip == RCC_HOST || ip == "::ffff:" + RCC_HOST) {
const {player, thumbnail} = req.body const { player, thumbnail } = req.body
let path2=path.resolve(__dirname, "../../assets/userthumbnails/"+player+".png") let path2 = path.resolve(
fs.writeFile(path2,thumbnail,'base64',function(err){ __dirname,
if (err) { "../../assets/userthumbnails/" + player + ".png",
console.log("error") )
// if writing fails we can still fallback fs.writeFile(path2, thumbnail, "base64", function (err) {
return res.sendFile(path.resolve("./../../assets/default.png")) if (err) {
} console.log("error")
// if it succeeds then we can send the userthumbnail // if writing fails we can still fallback
// close the job after return res.sendFile(path.resolve("./../../assets/default.png"))
rcctalk.CloseJob("Thumbnailfor"+player) }
}) // 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"),
)
}
}
router.get(["/asset","/asset.ashx"],grabAuth,async (req, res) => { // lets get our file path with sanitized id
if (!req.query.id && !req.query.assetid) { let path2 = path.resolve(
return res.status(400) __dirname,
} "../../assets/ugc/asset-" + sanitizedid + ".png",
let id = req.query.id??req.query.assetid )
var sanitizedid = id.match(rgx) 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()
const user = await item.findOne({ItemId: sanitizedid}).lean() // if this timeouts and rcc doesn't return the image feor some reason then send the default fallback
if (!user) { return res.sendFile(path.resolve("./assets/default.png"))
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
})
res.sendFile(path.resolve(path2))
return
})
}) })
router.post("/rccasset", (req, res) => { router.post("/rccasset", (req, res) => {
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress var ip = req.headers["cf-connecting-ip"] || req.socket.remoteAddress
if (ip == RCC_HOST || ip == "::ffff:"+RCC_HOST) { if (ip == RCC_HOST || ip == "::ffff:" + RCC_HOST) {
const {asset, thumbnail} = req.body const { asset, thumbnail } = req.body
console.log(asset) console.log(asset)
let path2=path.resolve(__dirname, "../../assets/ugc/asset-"+asset+".png") let path2 = path.resolve(
fs.writeFile(path2,thumbnail,'base64',function(err){ __dirname,
if (err) { "../../assets/ugc/asset-" + asset + ".png",
console.log("error") )
// if writing fails we can still fallback fs.writeFile(path2, thumbnail, "base64", function (err) {
return res.sendFile(path.resolve("./../../assets/default.png")) if (err) {
} console.log("error")
// if it succeeds then we can send the userthumbnail // if writing fails we can still fallback
// close the job after return res.sendFile(path.resolve("./../../assets/default.png"))
rcctalk.CloseJob("Thumbnailforasset"+asset) }
}) // if it succeeds then we can send the userthumbnail
} // close the job after
rcctalk.CloseJob("Thumbnailforasset" + asset)
})
}
}) })
module.exports = router module.exports = router

View File

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

View File

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

View File

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

View File

@ -1,116 +1,162 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const user = require('./../..//model/user.js') const user = require("./../..//model/user.js")
const games = require("./../../model/games.js") const games = require("./../../model/games.js")
const RelativeTime = require("@yaireo/relative-time") const RelativeTime = require("@yaireo/relative-time")
const relativeTime = new RelativeTime() const relativeTime = new RelativeTime()
router.get("/:id",async (req, res) => { router.get("/:id", async (req, res) => {
var id = req.params.id; var id = req.params.id
if (isNaN(parseFloat(id)) === true){ if (isNaN(parseFloat(id)) === true) {
return res.json({error: true}) return res.json({ error: true })
} }
const response = await user.findOne({userid: id}).lean() const response = await user.findOne({ userid: id }).lean()
if (!response){ if (!response) {
return res.json({error: true, message: "404"}) 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}})
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) => { router.get("/:id/creations", async (req, res) => {
var id = req.params.id; var id = req.params.id
if (isNaN(parseFloat(id)) === true){ if (isNaN(parseFloat(id)) === true) {
return res.json({error: true}) return res.json({ error: true })
} }
const response = await user.findOne({userid: id}).lean() const response = await user.findOne({ userid: id }).lean()
if (!response){ if (!response) {
return res.status(404).json({error: true, message: "Not found"}) 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)
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) => { router.get("/:id/visits", async (req, res) => {
var id = req.params.id; var id = req.params.id
if (isNaN(parseFloat(id)) === true){ if (isNaN(parseFloat(id)) === true) {
return res.json({error: true}) return res.json({ error: true })
} }
const response = await user.findOne({userid: id}).lean() const response = await user.findOne({ userid: id }).lean()
if (!response){ if (!response) {
return res.status(404).json({error: true, message: "Not found"}) 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})
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
router.get("/usernametoid/:id",async (req, res) => { const response = await user
.findOne({ username: { $regex: id, $options: "i" } })
.lean()
var id = req.params.id; if (!response) {
console.log(response)
return res.json({ error: true })
}
const response = await user.findOne({username: {'$regex': id,$options:'i'}}).lean() return res.json({ error: false, userid: response.userid })
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) => { router.get("/discordidtouserid/:id", async (req, res) => {
var id = req.params.id
var id = req.params.id; const response = await user.findOne({ discordid: id }).lean()
const response = await user.findOne({discordid: id}).lean() if (!response) {
console.log(response)
return res.json({ error: true })
}
if (!response){ return res.json({ error: false, userid: response.userid })
console.log(response)
return res.json({error: true})
}
return res.json({error:false, userid: response.userid})
}) })
module.exports = router module.exports = router

View File

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

View File

@ -1,130 +1,190 @@
const { response } = require("express") const { response } = require("express")
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const fs = require('fs') const fs = require("fs")
var path = require('path'); var path = require("path")
const crypto = require('crypto'); const crypto = require("crypto")
require('dotenv').config() require("dotenv").config()
const RCC_HOST = process.env.RCC_HOST const RCC_HOST = process.env.RCC_HOST
const User = require('../model/user.js') const User = require("../model/user.js")
const catalog = require("../model/item") const catalog = require("../model/item")
const games = require('./../model/games.js') const games = require("./../model/games.js")
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const fetch = (...args) =>
import("node-fetch").then(({ default: fetch }) => fetch(...args))
//redirect hmmmm //redirect hmmmm
var rgx = /^[0-9]*\.?[0-9]*$/; var rgx = /^[0-9]*\.?[0-9]*$/
router.get("/",async (req, res) => { router.get("/", async (req, res) => {
if (req.query.name){ if (req.query.name) {
const user = await User.findOne({userid: req.query.name}).lean() const user = await User.findOne({ userid: req.query.name }).lean()
if (!user) { if (!user) {
return res.json({status: 'error', error: 'User not found!'}) return res.json({ status: "error", error: "User not found!" })
} }
if (req.query.rcc){ if (req.query.rcc) {
var empty = [] var empty = []
for (var key of user.colors) { for (var key of user.colors) {
empty.push(key.value) empty.push(key.value)
} }
return res.json(empty) return res.json(empty)
} }
res.type("application/xml")
res.type('application/xml'); var colorsxml =
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"> `<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>null</External>
<External>nil</External> <External>nil</External>
<Item class="BodyColors"> <Item class="BodyColors">
<Properties> <Properties>
<int name="HeadColor">`+user.colors.find(x => x.name === 'Head').value+`</int> <int name="HeadColor">` +
<int name="LeftArmColor">`+user.colors.find(x => x.name === 'Left Arm').value+`</int> user.colors.find(x => x.name === "Head").value +
<int name="LeftLegColor">`+user.colors.find(x => x.name === 'Left Leg').value+`</int> `</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> <string name="Name">Body Colors</string>
<int name="RightArmColor">`+user.colors.find(x => x.name === 'Right Arm').value+`</int> <int name="RightArmColor">` +
<int name="RightLegColor">`+user.colors.find(x => x.name === 'Right Leg').value+`</int> user.colors.find(x => x.name === "Right Arm").value +
<int name="TorsoColor">`+user.colors.find(x => x.name === 'Torso').value+`</int> `</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> <bool name="archivable">true</bool>
</Properties> </Properties>
</Item> </Item>
</roblox>` </roblox>`
return res.send(colorsxml) return res.send(colorsxml)
} }
if (req.query.method || /*req.headers?.["requester"] === "Server" &&*/ req.headers?.["assettype"] === "Place"){ if (
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress req.query.method ||
console.log(ip) /*req.headers?.["requester"] === "Server" &&*/ req.headers?.[
var sanitizedid = req.query.id.match(rgx) "assettype"
if (ip === RCC_HOST || ip === "::ffff:"+RCC_HOST){ ] === "Place"
fs.access("./assets/ugc/gamefile-"+sanitizedid+".rbxl", fs.F_OK, (err) => { ) {
if (err) { var ip = req.headers["cf-connecting-ip"] || req.socket.remoteAddress
console.log(ip)
res.status(404).send("not found") var sanitizedid = req.query.id.match(rgx)
return if (ip === RCC_HOST || ip === "::ffff:" + RCC_HOST) {
} fs.access(
"./assets/ugc/gamefile-" + sanitizedid + ".rbxl",
fs.F_OK,
//file exists err => {
res.sendFile(path.resolve("./assets/ugc/gamefile-"+sanitizedid+".rbxl")) if (err) {
return res.status(404).send("not found")
}) 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
})
}
//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 module.exports = router

View File

@ -1,20 +1,19 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const { requireAuth } = require('./../middleware/authmiddleware') const { requireAuth } = require("./../middleware/authmiddleware")
const User = require('./../model/user.js') 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!"})
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 module.exports = router

View File

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

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +1,43 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const signatures = require("./signatures.js") const signatures = require("./signatures.js")
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const fetch = (...args) =>
const User = require('../model/user.js') import("node-fetch").then(({ default: fetch }) => fetch(...args))
const { requireAuth } = require('../middleware/authmiddlewaregame') const User = require("../model/user.js")
const rcctalk = require('../rcctalk') const { requireAuth } = require("../middleware/authmiddlewaregame")
const games = require('../model/games.js') const rcctalk = require("../rcctalk")
const catalog = require('../model/item.js') const games = require("../model/games.js")
const rcc = require('../model/rcc.js') const catalog = require("../model/item.js")
var sanitize = require('mongo-sanitize'); const rcc = require("../model/rcc.js")
const { getPort, checkPort, getRandomPort, waitForPort } = require('get-port-please') var sanitize = require("mongo-sanitize")
const fs = require('fs') const {
const gamescript = fs.readFileSync('actualgameserver.lua','utf-8') getPort,
require('dotenv').config() 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 RCC_HOST = process.env.RCC_HOST
const logshook = process.env.logshook const logshook = process.env.logshook
const crypto = require('crypto'); const crypto = require("crypto")
const key = fs.readFileSync('DefaultPrivateKey.pem') const key = fs.readFileSync("DefaultPrivateKey.pem")
const key2 = fs.readFileSync('DefaultPrivateKey.pem') const key2 = fs.readFileSync("DefaultPrivateKey.pem")
const key2020 = fs.readFileSync('PrivateKey2020.txt') const key2020 = fs.readFileSync("PrivateKey2020.txt")
const { _2020placelauncher } = require('../routes/2020/game') const { _2020placelauncher } = require("../routes/2020/game")
const { _2018placelauncher } = require('../routes/2018/game') const { _2018placelauncher } = require("../routes/2018/game")
//join and placelauncher //join and placelauncher
function sleep(ms) { function sleep(ms) {
return new Promise((resolve) => { return new Promise(resolve => {
setTimeout(resolve, ms); setTimeout(resolve, ms)
}); })
} }
router.get("/visit",async (req, res) => { router.get("/visit", async (req, res) => {
// studio // studio
const string = `local RS = game:GetService("RunService") const string = `local RS = game:GetService("RunService")
local P = game:GetService("Players") local P = game:GetService("Players")
local LP = P:CreateLocalPlayer(0) local LP = P:CreateLocalPlayer(0)
LP.CharacterAppearance = "" LP.CharacterAppearance = ""
@ -65,349 +71,501 @@ pcall(function() game:GetService("InsertService"):SetFreeDecalUrl("http://mete0r
` `
const sign = crypto.createSign('SHA1'); const sign = crypto.createSign("SHA1")
sign.update("\r\n" + string) sign.update("\r\n" + string)
var signature = sign.sign(key, "base64") var signature = sign.sign(key, "base64")
res.send("--rbxsig%"+signature+"%\r\n" +string) 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) => { router.get(["/GetCurrentUser", "/GetCurrentUser.ashx"], async (req, res) => {
var enabled = req.config res.send("1") // 1 means logged in and null means logged out
if (enabled.GamesEnabled === false){ }) // don't send 404 error but i don't think we will have studio publishing
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() router.post("/validate-machine", async (req, res) => {
joinJson.ClientTicket = timestamp+";" // timestamp res.json({ success: true, message: "" })
//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 router.get(["/join", "/join.ashx"], requireAuth, async (req, res) => {
const sign2 = crypto.createSign('SHA1'); if (!req.userdocument.discordid) {
sign2.update(`${req.userdocument.userid}\n`/*userid*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/) return res.json({
var signature2 = sign2.sign(key, "base64") status: "error",
joinJson.ClientTicket += signature2 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)
req.userdocument.gamejoin = JSON.stringify(joinJson) return res.send(
req.userdocument.markModified('gamejoin') "--rbxsig%" + signature + "%\r\n" + JSON.stringify(joinJson),
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":""} }
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(JSON.stringify(joinScriptJson)) return res.send(
} "--rbxsig2%" + signature + "%\r\n" + JSON.stringify(joinJson),
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)) 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))
})
var port = await getPort({random: true}) router.all(
var newgamescript = "local placeId = "+sanitizedplaceid+"\n"+ gamescript ["/placelauncher", "/placelauncher.ashx"],
newgamescript = "local port = "+port+"\n"+ newgamescript requireAuth,
// launch job _2020placelauncher,
var response = await rcctalk.OpenJob("game"+sanitizedplaceid,newgamescript,"99999") _2018placelauncher,
await rcc.create({ async (req, res, next) => {
PlaceId: sanitizedplaceid, var enabled = req.config
Port: port, if (enabled.GamesEnabled === false) {
Status: 1 // 1 means loading 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
//console.log(newrenderscript) 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 + ";"
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":""} //create signature 2
res.send(JSON.stringify(joinScriptJson)) 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 //charapp and colors stealing from roblox
router.get("/charapp", async (req, res) => { router.get("/charapp", async (req, res) => {
if (Object.keys(req.query).length === 0) { if (Object.keys(req.query).length === 0) {
res.status(404).send('No variables :('); res.status(404).send("No variables :(")
} else{ } else {
const user = await User.findOne({userid: req.query.name}).lean() const user = await User.findOne({ userid: req.query.name }).lean()
const placeid = req.headers?.['roblox-place-id']??0 const placeid = req.headers?.["roblox-place-id"] ?? 0
const placedoc = await games.findOne({idofgame: placeid}) const placedoc = await games.findOne({ idofgame: placeid })
if (!placedoc){ if (!placedoc) {
return res.json({status:"error",error:"Place not found."}) return res.json({ status: "error", error: "Place not found." })
} }
if (!user) { if (!user) {
return res.json({status: 'error', error: 'User not found!'}) return res.json({ status: "error", error: "User not found!" })
} }
if (!user.inventory){ if (!user.inventory) {
if (req.query.rcc){ if (req.query.rcc) {
return res.json([]) return res.json([])
} }
return res.send('http://mete0r.xyz/game/colors?name='+req.query.name+';') return res.send(
} "http://mete0r.xyz/game/colors?name=" + req.query.name + ";",
)
}
if (req.query.rcc){ if (req.query.rcc) {
var empty = [] var empty = []
for (var key of user.inventory) { for (var key of user.inventory) {
if (key.Equipped === true){ if (key.Equipped === true) {
empty.push({"item": {itemid: key.ItemId, type: key.Type}}) empty.push({ item: { itemid: key.ItemId, type: key.Type } })
} }
} }
return res.json(empty) 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 + ";"
}
}
}
}
var charapp = 'http://mete0r.xyz/asset?name='+req.query.name+';' res.write(charapp)
// add to charapp string by adding json to it res.end()
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) => { router.get("/colors", async (req, res) => {
if (Object.keys(req.query).length === 0) { if (Object.keys(req.query).length === 0) {
res.status(404).send('No variables :('); res.status(404).send("No variables :(")
} else{ } else {
const user = await User.findOne({userid: req.query.name}).lean() const user = await User.findOne({ userid: req.query.name }).lean()
if (!user) { if (!user) {
return res.json({status: 'error', error: 'User not found!'}) return res.json({ status: "error", error: "User not found!" })
} }
if (req.query.rcc){ if (req.query.rcc) {
var empty = [] var empty = []
for (var key of user.colors) { for (var key of user.colors) {
empty.push(key.value) empty.push(key.value)
} }
return res.json(empty) return res.json(empty)
} }
res.type("application/xml")
res.type('application/xml'); var colorsxml =
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"> `<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>null</External>
<External>nil</External> <External>nil</External>
<Item class="BodyColors"> <Item class="BodyColors">
<Properties> <Properties>
<int name="HeadColor">`+user.colors.find(x => x.name === 'Head').value+`</int> <int name="HeadColor">` +
<int name="LeftArmColor">`+user.colors.find(x => x.name === 'Left Arm').value+`</int> user.colors.find(x => x.name === "Head").value +
<int name="LeftLegColor">`+user.colors.find(x => x.name === 'Left Leg').value+`</int> `</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> <string name="Name">Body Colors</string>
<int name="RightArmColor">`+user.colors.find(x => x.name === 'Right Arm').value+`</int> <int name="RightArmColor">` +
<int name="RightLegColor">`+user.colors.find(x => x.name === 'Right Leg').value+`</int> user.colors.find(x => x.name === "Right Arm").value +
<int name="TorsoColor">`+user.colors.find(x => x.name === 'Torso').value+`</int> `</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> <bool name="archivable">true</bool>
</Properties> </Properties>
</Item> </Item>
</roblox>` </roblox>`
res.send(colorsxml) res.send(colorsxml)
}
}
}) })
router.get("/", (req, res) => { router.get("/", (req, res) => {
res.status(404).send('hmmm? kinda sus'); res.status(404).send("hmmm? kinda sus")
}) })
router.get("/players/:id", (req, res) => { router.get("/players/:id", (req, res) => {
res.json({"ChatFilter":"whitelist"}) res.json({ ChatFilter: "whitelist" })
}) })
router.post("/load-place-info", (req, res) => { router.post("/load-place-info", (req, res) => {
res.json({"CreatorId": 0, "CreatorType": "User", "PlaceVersion": 1}) res.json({ CreatorId: 0, CreatorType: "User", PlaceVersion: 1 })
}) })
router.post("/badge/awardbadge",async (req, res) => { router.post("/badge/awardbadge", async (req, res) => {
const userid = req.query.UserID const userid = req.query.UserID
const badgeid = req.query.BadgeID const badgeid = req.query.BadgeID
const placeid = req.query.PlaceID const placeid = req.query.PlaceID
const badge = await catalog.findOne({ItemId: badgeid}).lean() const badge = await catalog.findOne({ ItemId: badgeid }).lean()
const user = await User.findOne({userid: userid}).lean() const user = await User.findOne({ userid: userid }).lean()
if(!badge){ if (!badge) {
//Badge doesn't exist! //Badge doesn't exist!
return res.send("0") return res.send("0")
} }
if(!user){ if (!user) {
return res.send("0") return res.send("0")
} }
const badgecreator = await User.findOne({userid: badge.Creator}).lean() const badgecreator = await User.findOne({ userid: badge.Creator }).lean()
if (typeof user.badges !== "undefined"){ if (typeof user.badges !== "undefined") {
// check if user already owns item // check if user already owns item
for (var v of user.badges){ for (var v of user.badges) {
if (v.badgeid === badgeid){ if (v.badgeid === badgeid) {
// they already own it // they already own it
return res.send("0") return res.send("0")
} }
} }
} }
User.updateOne({userid: req.query.UserID}, { User.updateOne(
$push: { { userid: req.query.UserID },
badges: {badgeid: badgeid, badgename: badge.Name, creator: badge.Creator, placeid: placeid} {
} $push: {
}, badges: {
function(err, doc) { badgeid: badgeid,
if (err){ badgename: badge.Name,
return res.send("0") 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!") 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(["/LuaWebService/HandleSocialRequest","/LuaWebService/HandleSocialRequest.ashx"],async (req, res) => { router.get("/Tools/InsertAsset.ashx", async (req, res) => {
res.type('application/xml'); const lol = await fetch("http://sets.pizzaboxer.xyz/Game" + req.url)
if (req.query.method === "IsInGroup"){ if (lol.status === 400) {
if (req.query.groupid === '0' || req.query.groupid === '1200769'){ // 1200769 admin group return res.send(``)
const user = await User.findOne({userid: req.query.playerid}).lean() }
if (user){ return res.send(await lol.text())
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) => { router.post("/MachineConfiguration.ashx", (req, res) => {
const lol = await fetch('http://sets.pizzaboxer.xyz/Game'+req.url); res.json({ success: true })
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 module.exports = router

View File

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

View File

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

View File

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

View File

@ -1,260 +1,327 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const games = require('./../model/games.js') const games = require("./../model/games.js")
const User = require('./../model/user.js') const User = require("./../model/user.js")
const item = require("./../model/item.js") const item = require("./../model/item.js")
const { requireAuth } = require("../middleware/authmiddleware.js") const { requireAuth } = require("../middleware/authmiddleware.js")
var rgx = /^[0-9]*\.?[0-9]*$/; var rgx = /^[0-9]*\.?[0-9]*$/
router.get("/marketplace/productinfo", async (req, res) => { router.get("/marketplace/productinfo", async (req, res) => {
const sanitizedid = req.query.assetId.match(rgx) const sanitizedid = req.query.assetId.match(rgx)
let json = {"TargetId":5009,"ProductType":"User Product","AssetId":93722443,"ProductId":13831621,"Name":"rrr","Description":"","AssetTypeId":19,"Creator":{"Id":1,"Name":"","CreatorType":"User","CreatorTargetId":1},"IconImageAssetId":0,"Created":"2012-09-28T01:09:47.077Z","Updated":"2017-01-03T00:25:45.8813192Z","PriceInRobux":null,"PriceInTickets":null,"Sales":0,"IsNew":false,"IsForSale":true,"IsPublicDomain":false,"IsLimited":false,"IsLimitedUnique":false,"Remaining":null,"MinimumMembershipLevel":0,"ContentRatingTypeId":0} let json = {
TargetId: 5009,
ProductType: "User Product",
AssetId: 93722443,
ProductId: 13831621,
Name: "rrr",
Description: "",
AssetTypeId: 19,
Creator: { Id: 1, Name: "", CreatorType: "User", CreatorTargetId: 1 },
IconImageAssetId: 0,
Created: "2012-09-28T01:09:47.077Z",
Updated: "2017-01-03T00:25:45.8813192Z",
PriceInRobux: null,
PriceInTickets: null,
Sales: 0,
IsNew: false,
IsForSale: true,
IsPublicDomain: false,
IsLimited: false,
IsLimitedUnique: false,
Remaining: null,
MinimumMembershipLevel: 0,
ContentRatingTypeId: 0,
}
let response = await games
.findOne({ idofgame: parseFloat(sanitizedid) })
.lean()
if (!response) {
response = await item
.findOne({ ItemId: parseFloat(sanitizedid) })
.lean()
json.PriceInRobux = parseFloat(response.Price)
json.AssetTypeId = 34
json.IconImageAssetId = parseFloat(req.query.assetId)
if (!response) {
return res.status(404).end()
}
}
let response = await games.findOne({idofgame: parseFloat(sanitizedid)}).lean() const creator = await User.findOne({
if (!response){ userid: parseFloat(response.useridofowner ?? response.Creator),
response = await item.findOne({ItemId: parseFloat(sanitizedid)}).lean() }).lean()
json.PriceInRobux = parseFloat(response.Price) json.AssetId = parseFloat(req.query.assetId)
json.AssetTypeId = 34 json.ProductId = parseFloat(req.query.assetId)
json.IconImageAssetId = parseFloat(req.query.assetId) json.TargetId = parseFloat(req.query.assetId)
if (!response){ json.Name = response.nameofgame ?? response.Name
return res.status(404).end() json.Description = response.descrption ?? ""
} json.Creator.Id = parseFloat(response.useridofowner ?? response.Creator)
} json.Creator.Name = creator.username
json.Creator.CreatorTargetId = parseFloat(
const creator = await User.findOne({userid: parseFloat(response.useridofowner??response.Creator)}).lean() response.useridofowner ?? response.Creator,
json.AssetId = parseFloat(req.query.assetId) )
json.ProductId = parseFloat(req.query.assetId) res.json(json)
json.TargetId = parseFloat(req.query.assetId)
json.Name = response.nameofgame??response.Name
json.Description = response.descrption??""
json.Creator.Id = parseFloat(response.useridofowner??response.Creator)
json.Creator.Name = creator.username
json.Creator.CreatorTargetId = parseFloat(response.useridofowner??response.Creator)
res.json(json)
}) })
router.post("/marketplace/purchase",requireAuth, async (req, res) => { router.post("/marketplace/purchase", requireAuth, async (req, res) => {
const productId = parseInt(req.body.productId) const productId = parseInt(req.body.productId)
if (!productId){ if (!productId) {
res.json({success: false,status: "Error",receipt: ""}) res.json({ success: false, status: "Error", receipt: "" })
} }
const itemdoc = await item.findOne({ ItemId: productId }) //.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." })
}
const itemdoc = await item.findOne({ItemId: productId})//.lean() if (itemdoc.Hidden) {
if (typeof req.userdocument.inventory !== "undefined"){ return res.json({ success: false, status: "Error", receipt: "" })
// 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){ if (req.userdocument.coins >= itemdoc.Price) {
return res.json({success: false,status: "Error",receipt: ""}) // has enough money to purcahse item
} try {
User.updateOne(
{ userid: req.userdocument.userid },
if (req.userdocument.coins >= itemdoc.Price){ {
// has enough money to purcahse item $set: {
try{ coins: req.userdocument.coins - itemdoc.Price,
User.updateOne({userid: req.userdocument.userid}, { },
$set: { $push: {
coins: req.userdocument.coins - itemdoc.Price inventory: {
}, Type: itemdoc.Type,
$push: { ItemId: itemdoc.ItemId,
inventory: {Type: itemdoc.Type,ItemId: itemdoc.ItemId, ItemName: itemdoc.Name, Equipped: false} ItemName: itemdoc.Name,
} Equipped: false,
}, },
function(err, doc) { },
//console.log(err) },
}) function (err, doc) {
// give owner cash //console.log(err)
User.updateOne({userid: itemdoc.Creator}, { },
$inc: { )
coins: itemdoc.Price // give owner cash
} User.updateOne(
}, { userid: itemdoc.Creator },
function(err, doc) { {
//console.log(err) $inc: {
}) coins: itemdoc.Price,
},
itemdoc.Sales += 1 },
if (!itemdoc.Sales){ function (err, doc) {
itemdoc.Sales = 1 //console.log(err)
} },
//console.log(itemdoc.Sales) )
itemdoc.markModified('Sales')
await itemdoc.save()
}catch{
}
return res.json(({success: true,status: "Bought",receipt: ""}))
}
// too poor
return res.json({success: false,status: "Error",receipt: ""})
itemdoc.Sales += 1
if (!itemdoc.Sales) {
itemdoc.Sales = 1
}
//console.log(itemdoc.Sales)
itemdoc.markModified("Sales")
await itemdoc.save()
} catch {}
return res.json({ success: true, status: "Bought", receipt: "" })
}
// too poor
return res.json({ success: false, status: "Error", receipt: "" })
}) })
router.get('/ownership/hasasset',async (req, res) => { router.get("/ownership/hasasset", async (req, res) => {
const userid = req.query?.userId const userid = req.query?.userId
const assetId = req.query?.assetId const assetId = req.query?.assetId
const doc = await User.findOne({userid: userid}) const doc = await User.findOne({ userid: userid })
const itemdoc = await item.findOne({ItemId: assetId}) const itemdoc = await item.findOne({ ItemId: assetId })
if (!doc){ if (!doc) {
return res.send("false") return res.send("false")
} }
if (!itemdoc){ if (!itemdoc) {
return res.send("false") return res.send("false")
} }
if (typeof doc.inventory !== "undefined"){ if (typeof doc.inventory !== "undefined") {
// check if user already owns item // check if user already owns item
for (var v of doc.inventory){ for (var v of doc.inventory) {
if (v.ItemId === itemdoc.ItemId){ if (v.ItemId === itemdoc.ItemId) {
// they already own it // they already own it
return res.send("true") return res.send("true")
} }
} }
} }
return res.send("false") return res.send("false")
}) })
router.get('/v1/users/:userId/items/gamepass/:assetId',async (req, res) => { router.get("/v1/users/:userId/items/gamepass/:assetId", async (req, res) => {
const userid = req.params?.userId const userid = req.params?.userId
const assetId = req.params?.assetId const assetId = req.params?.assetId
const doc = await User.findOne({userid: userid}) const doc = await User.findOne({ userid: userid })
const itemdoc = await item.findOne({ItemId: assetId}) const itemdoc = await item.findOne({ ItemId: assetId })
let data = {"previousPageCursor":null,"nextPageCursor":null,"data":[]} let data = { previousPageCursor: null, nextPageCursor: null, data: [] }
if (!doc){ if (!doc) {
return res.json(data) return res.json(data)
} }
if (!itemdoc){ if (!itemdoc) {
return res.json(data) return res.json(data)
} }
if (typeof doc.inventory !== "undefined"){ if (typeof doc.inventory !== "undefined") {
// check if user already owns item // check if user already owns item
for (var v of doc.inventory){ for (var v of doc.inventory) {
if (v.ItemId === itemdoc.ItemId){ if (v.ItemId === itemdoc.ItemId) {
// they already own it // they already own it
data.data.push({"type": "GamePass","id": req.params?.assetId,"name": itemdoc.Name,"instanceId": null}) data.data.push({
return res.json(data) type: "GamePass",
} id: req.params?.assetId,
} name: itemdoc.Name,
} instanceId: null,
})
return res.json(data)
}
}
}
return res.json(data) return res.json(data)
}) })
router.post('/v1/purchases/products/:assetId',requireAuth,async (req, res) => { router.post(
const assetId = req.params?.assetId "/v1/purchases/products/:assetId",
const itemdoc = await item.findOne({ItemId: assetId}) requireAuth,
let error = { async (req, res) => {
"purchased": false, const assetId = req.params?.assetId
"reason": "InsufficientFunds", const itemdoc = await item.findOne({ ItemId: assetId })
"productId": 15194787, let error = {
"statusCode": 500, purchased: false,
"title": "Not Enough Robux", reason: "InsufficientFunds",
"errorMsg": "You do not have enough Robux to purchase this item.", productId: 15194787,
"showDivId": "InsufficientFundsView", statusCode: 500,
"shortfallPrice": 29, title: "Not Enough Robux",
"balanceAfterSale": -29, errorMsg: "You do not have enough Robux to purchase this item.",
"expectedPrice": 150, showDivId: "InsufficientFundsView",
"currency": 1, shortfallPrice: 29,
"price": 150, balanceAfterSale: -29,
"assetId": 106690045 expectedPrice: 150,
} currency: 1,
price: 150,
assetId: 106690045,
}
if (!itemdoc){ if (!itemdoc) {
error.productId = assetId error.productId = assetId
error.title = "Not found" error.title = "Not found"
return res.json(error) return res.json(error)
} }
error.price = itemdoc.Price error.price = itemdoc.Price
error.productId = assetId error.productId = assetId
error.assetId = assetId error.assetId = assetId
error.expectedPrice = itemdoc.Price error.expectedPrice = itemdoc.Price
error.balanceAfterSale = req.userdocument.coins - itemdoc.Price error.balanceAfterSale = req.userdocument.coins - itemdoc.Price
error.shortfallPrice = Math.abs(req.userdocument.coins - itemdoc.Price) error.shortfallPrice = Math.abs(req.userdocument.coins - itemdoc.Price)
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 (typeof req.userdocument.inventory !== "undefined"){ if (itemdoc.Hidden) {
// check if user already owns item return res.json({ status: "error", error: "You can't buy this!" })
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){ if (req.userdocument.coins >= itemdoc.Price) {
return res.json({status: 'error', error: "You can't buy this!"}) // 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)
},
)
if (req.userdocument.coins >= itemdoc.Price){ itemdoc.Sales += 1
// has enough money to purcahse item if (!itemdoc.Sales) {
try{ itemdoc.Sales = 1
User.updateOne({userid: req.userdocument.userid}, { }
$set: { //console.log(itemdoc.Sales)
coins: req.userdocument.coins - itemdoc.Price itemdoc.markModified("Sales")
}, await itemdoc.save()
$push: { } catch {}
inventory: {Type: itemdoc.Type,ItemId: itemdoc.ItemId, ItemName: itemdoc.Name, Equipped: false} return res.json({
} purchased: true,
}, reason: "Success",
function(err, doc) { productId: assetId,
//console.log(err) currency: 1,
}) price: itemdoc.Price,
// give owner cash assetId: assetId,
User.updateOne({userid: itemdoc.Creator}, { assetName: itemdoc.Name,
$inc: { assetType: "Gamepass",
coins: itemdoc.Price assetTypeDisplayName: "Gamepass",
} assetIsWearable: false,
}, sellerName: "Robloxxx",
function(err, doc) { transactionVerb: "bought",
//console.log(err) isMultiPrivateSale: false,
}) })
}
itemdoc.Sales += 1 return res.json(error)
if (!itemdoc.Sales){ },
itemdoc.Sales = 1 )
}
//console.log(itemdoc.Sales)
itemdoc.markModified('Sales')
await itemdoc.save()
}catch{
}
return res.json({
"purchased": true,
"reason": "Success",
"productId": assetId,
"currency": 1,
"price": itemdoc.Price,
"assetId": assetId,
"assetName": itemdoc.Name,
"assetType": "Gamepass",
"assetTypeDisplayName": "Gamepass",
"assetIsWearable": false,
"sellerName": "Robloxxx",
"transactionVerb": "bought",
"isMultiPrivateSale": false
})
}
return res.json(error)
})
module.exports = router module.exports = router

View File

@ -1,44 +1,42 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
router.get('/check-app-version',async (req, res) => { router.get("/check-app-version", async (req, res) => {
return res.json({Response: {"data":{"UpgradeAction":"NotRequired"}}}) return res.json({ Response: { data: { UpgradeAction: "NotRequired" } } })
}) })
router.post('/login',async (req, res) => { router.post("/login", async (req, res) => {
return res.json({ return res.json({
"Status":"OK", Status: "OK",
"UserInfo": { UserInfo: {
"UserName":"meteorite", UserName: "meteorite",
"RobuxBalance":"69420", RobuxBalance: "69420",
"TicketsBalance":"69420", TicketsBalance: "69420",
"IsAnyBuildersClubMember":false, IsAnyBuildersClubMember: false,
"ThumbnailUrl":"http://www.mete0r.xyz/", ThumbnailUrl: "http://www.mete0r.xyz/",
"UserID":1 UserID: 1,
} },
}) })
}) })
router.get("/userinfo", async (req, res) => {
return res.json({
router.get('/userinfo',async (req, res) => { Status: "OK",
return res.json({ UserInfo: {
"Status":"OK", UserName: "meteorite",
"UserInfo": { RobuxBalance: "69420",
"UserName":"meteorite", TicketsBalance: "69420",
"RobuxBalance":"69420", IsAnyBuildersClubMember: false,
"TicketsBalance":"69420", ThumbnailUrl: "http://www.mete0r.xyz/",
"IsAnyBuildersClubMember":false, UserID: 1,
"ThumbnailUrl":"http://www.mete0r.xyz/", },
"UserID":1 })
}
})
}) })
router.all('/logout',async (req, res) => { router.all("/logout", async (req, res) => {
res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 }) res.cookie("jwt", "", { SameSite: "Strict", maxAge: 1 })
res.cookie('.ROBLOSECURITY', "", {SameSite: "Strict",maxAge: 1 }) res.cookie(".ROBLOSECURITY", "", { SameSite: "Strict", maxAge: 1 })
return res.json({}) return res.json({})
}) })
module.exports = router module.exports = router

View File

@ -1,209 +1,319 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const bodyParser = require('body-parser') const bodyParser = require("body-parser")
const games = require('./../model/games.js') const games = require("./../model/games.js")
require('dotenv').config() require("dotenv").config()
const RCC_HOST = process.env.RCC_HOST const RCC_HOST = process.env.RCC_HOST
router.use(bodyParser.text({limit: '100mb'})) router.use(bodyParser.text({ limit: "100mb" }))
router.use(async function (req, res, next) { router.use(async function (req, res, next) {
var ip = req.headers['cf-connecting-ip'] || req.socket.remoteAddress.replace(/^.*:/, '') var ip =
console.log(ip) req.headers["cf-connecting-ip"] ||
req.socket.remoteAddress.replace(/^.*:/, "")
console.log(ip)
if (ip === RCC_HOST || ip == "::ffff:"+RCC_HOST){ if (ip === RCC_HOST || ip == "::ffff:" + RCC_HOST) {
return next() return next()
} }
return res.status(403) return res.status(403)
}) })
router.post('/getV2', async (req, res)=>{ router.post("/getV2", async (req, res) => {
const placeid = req.query.placeId const placeid = req.query.placeId
const scope = req.query.scope const scope = req.query.scope
const game = await games.findOne({idofgame: placeid}).lean() const game = await games.findOne({ idofgame: placeid }).lean()
if (!game.datastore){ if (!game.datastore) {
return res.json({"data": [{"Key": {"Scope": req.body.qkeys[0], "Target": "KEY", "Key": req.body.qkeys[1]}, "Value": "nil"}]}) return res.json({
} data: [
const datastore = JSON.parse(game.datastore) {
// first make sure database exists then make sure scope exists finally make sure key exists inside scope Key: {
if (datastore[req.body.qkeys[2]] && datastore[req.body.qkeys[2]][req.body.qkeys[0]] && datastore[req.body.qkeys[2]][req.body.qkeys[0]][req.body.qkeys[1]]){ Scope: req.body.qkeys[0],
Target: "KEY",
Key: req.body.qkeys[1],
},
Value: "nil",
},
],
})
}
const datastore = JSON.parse(game.datastore)
// first make sure database exists then make sure scope exists finally make sure key exists inside scope
if (
datastore[req.body.qkeys[2]] &&
datastore[req.body.qkeys[2]][req.body.qkeys[0]] &&
datastore[req.body.qkeys[2]][req.body.qkeys[0]][req.body.qkeys[1]]
) {
// 2 = database name
// 1 = Key name
// 0 = scope
// 2 = database name var wow = {
// 1 = Key name data: [
// 0 = scope {
Key: {
Scope: req.body.qkeys[0],
Target: "KEY",
Key: req.body.qkeys[1],
},
Value: datastore[req.body.qkeys[2]][req.body.qkeys[0]][
req.body.qkeys[1]
].value,
},
],
}
//console.log(req.body)
var wow = {"data": [{"Key": {"Scope": req.body.qkeys[0], "Target": "KEY", "Key": req.body.qkeys[1]}, "Value": datastore[req.body.qkeys[2]][req.body.qkeys[0]][req.body.qkeys[1]].value}]}; console.dir(wow, { depth: null })
//console.log(req.body)
console.dir(wow,{ depth: null }) return res.json(wow)
}
return res.json({
data: [
{
Key: {
Scope: req.body.qkeys[0],
Target: "KEY",
Key: req.body.qkeys[1],
},
Value: "nil",
},
],
})
})
router.post("/set", async (req, res) => {
const placeid = req.query.placeId
const game = await games.findOne({ idofgame: placeid }).lean()
if (!game) {
return res.sendStatus(404)
}
let currentdatastore
if (!game.datastore) {
try {
await games.updateOne(
{ idofgame: placeid },
{
$set: {
datastore: JSON.stringify({
[req.query.key]: {
[req.query.scope]: {
[req.query.target]: {
value: req.body.value,
},
},
type: req.query.type,
},
}),
},
},
function (err, doc) {
//console.log(err)
},
)
} catch {}
return res.json({
data: [
{
Key: {
Scope: req.query.key,
Target: "KEY",
Key: [req.query.target],
},
Value: req.body.value,
},
],
})
}
currentdatastore = JSON.parse(game.datastore)
return res.json(wow) if (currentdatastore[req.query.key]) {
} // if database name already exists
console.log("1")
if (currentdatastore[req.query.key][[req.query.scope]]) {
// if database scope already exists
return res.json({"data": [{"Key": {"Scope": req.body.qkeys[0], "Target": "KEY", "Key": req.body.qkeys[1]}, "Value": "nil"}]}) console.log("2")
if (
currentdatastore[req.query.key][req.query.scope][
}); req.query.target
router.post('/set', async (req, res)=>{ ]
const placeid = req.query.placeId ) {
const game = await games.findOne({idofgame: placeid}).lean() // key already stored overwrite it
if (!game){ console.log("3")
return res.sendStatus(404) currentdatastore[req.query.key][req.query.scope][
} req.query.target
] = { value: req.body.value }
let currentdatastore } else {
if (!game.datastore){ console.log("4")
try{ currentdatastore[req.query.key][req.query.scope][
await games.updateOne({idofgame: placeid}, { req.query.target
$set: { ] = { value: req.body.value } // database scope exists but key doesn't so generate it
datastore: JSON.stringify({[req.query.key]: {[req.query.scope]: {[req.query.target]: {value: req.body.value}},type: req.query.type}}) }
} } else {
}, currentdatastore[req.query.key][req.query.scope] = {
function(err, doc) { [req.query.target]: { value: req.body.value },
//console.log(err) } // scope doesn't exist
}) }
}catch{ } else {
currentdatastore[req.query.key] = {
} [req.query.scope]: {
return res.json({"data": [{"Key": {"Scope": req.query.key, "Target": "KEY", "Key": [req.query.target]}, "Value": req.body.value}]}) [req.query.target]: { value: req.body.value },
} },
currentdatastore = JSON.parse(game.datastore) type: req.query.type,
} // database doesn't exist make sure to pass database type as well
if (currentdatastore[req.query.key]){ // if database name already exists }
console.log('1')
if (currentdatastore[req.query.key][[req.query.scope]]){ // if database scope already exists
console.log('2')
if (currentdatastore[req.query.key][req.query.scope][req.query.target]){ // key already stored overwrite it
console.log('3')
currentdatastore[req.query.key][req.query.scope][req.query.target] = {value: req.body.value}
}else{
console.log('4')
currentdatastore[req.query.key][req.query.scope][req.query.target] = {value: req.body.value} // database scope exists but key doesn't so generate it
}
}else{
currentdatastore[req.query.key][req.query.scope] = {[req.query.target]: {value: req.body.value}} // scope doesn't exist
}
}else{
currentdatastore[req.query.key] = {[req.query.scope]: {[req.query.target]: {value: req.body.value}},type: req.query.type} // database doesn't exist make sure to pass database type as well
}
try{
await games.updateOne({idofgame: placeid}, {
$set: {
datastore: JSON.stringify(currentdatastore)
}
},
function(err, doc) {
//console.log(err)
})
}catch{
}
//console.log(req.body)
res.json({"data": [{"Key": {"Scope": req.query.key, "Target": "KEY", "Key": [req.query.target]}, "Value": req.body.value}]})
})
try {
await games.updateOne(
{ idofgame: placeid },
{
$set: {
datastore: JSON.stringify(currentdatastore),
},
},
function (err, doc) {
//console.log(err)
},
)
} catch {}
//console.log(req.body)
res.json({
data: [
{
Key: {
Scope: req.query.key,
Target: "KEY",
Key: [req.query.target],
},
Value: req.body.value,
},
],
})
})
router.post("/increment", async (req, res) => { router.post("/increment", async (req, res) => {
const placeid = req.query.placeId const placeid = req.query.placeId
const game = await games.findOne({idofgame: placeid}).lean() const game = await games.findOne({ idofgame: placeid }).lean()
if (!game){ if (!game) {
return res.sendStatus(404) return res.sendStatus(404)
} }
let currentdatastore let currentdatastore
if (!game.datastore){ if (!game.datastore) {
res.json({"data": {}}) res.json({ data: {} })
} }
currentdatastore = JSON.parse(game.datastore) currentdatastore = JSON.parse(game.datastore)
if (currentdatastore[req.query.key] && currentdatastore[req.query.key][req.query.scope] && currentdatastore[req.query.key][req.query.scope][req.query.target]){
let value = parseFloat(currentdatastore[req.query.key][req.query.scope][req.query.target].value)
if (!isNaN(parseFloat(value)) === true){
// is number
let newvalue = value += parseFloat(req.query.value)
currentdatastore[req.query.key][req.query.scope][req.query.target].value = newvalue.toString()
try{
await games.updateOne({idofgame: placeid}, {
$set: {
datastore: JSON.stringify(currentdatastore)
}
},
function(err, doc) {
//console.log(err)
})
}catch{
}
//console.log(req.body)
return res.json({"data": [{"Key": {"Scope": req.query.key, "Target": "KEY", "Key": [req.query.target]}, "Value": parseFloat(currentdatastore[req.query.key][req.query.scope][req.query.target].value)}]})
}
}
res.json({"data": {}})
if (
currentdatastore[req.query.key] &&
currentdatastore[req.query.key][req.query.scope] &&
currentdatastore[req.query.key][req.query.scope][req.query.target]
) {
let value = parseFloat(
currentdatastore[req.query.key][req.query.scope][req.query.target]
.value,
)
if (!isNaN(parseFloat(value)) === true) {
// is number
let newvalue = (value += parseFloat(req.query.value))
currentdatastore[req.query.key][req.query.scope][
req.query.target
].value = newvalue.toString()
try {
await games.updateOne(
{ idofgame: placeid },
{
$set: {
datastore: JSON.stringify(currentdatastore),
},
},
function (err, doc) {
//console.log(err)
},
)
} catch {}
//console.log(req.body)
return res.json({
data: [
{
Key: {
Scope: req.query.key,
Target: "KEY",
Key: [req.query.target],
},
Value: parseFloat(
currentdatastore[req.query.key][req.query.scope][
req.query.target
].value,
),
},
],
})
}
}
res.json({ data: {} })
}) })
router.post("/getSortedValues", async (req, res) => { router.post("/getSortedValues", async (req, res) => {
const placeid = req.query.placeId const placeid = req.query.placeId
const game = await games.findOne({idofgame: placeid}).lean() const game = await games.findOne({ idofgame: placeid }).lean()
if (!game){ if (!game) {
return res.sendStatus(404) return res.sendStatus(404)
} }
if (!game.datastore){ if (!game.datastore) {
return res.json({"data":{"Entries":[],"ExclusiveStartKey":null}}) return res.json({ data: { Entries: [], ExclusiveStartKey: null } })
} }
const datastore = JSON.parse(game.datastore) const datastore = JSON.parse(game.datastore)
// first make sure database exists then make sure scope exists // first make sure database exists then make sure scope exists
if (datastore[req.query.key] && datastore[req.query.key][req.query.scope]){ if (datastore[req.query.key] && datastore[req.query.key][req.query.scope]) {
function paginate(array, page_size, page_number) {
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
return array.slice(
(page_number - 1) * page_size,
page_number * page_size,
)
}
function paginate(array, page_size, page_number) { let wow = { data: { Entries: [], ExclusiveStartKey: null } }
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
return array.slice((page_number - 1) * page_size, page_number * page_size);
}
//console.log(datastore[req.query.key][req.query.scope])
let wow = {"data":{"Entries":[],"ExclusiveStartKey":null}} const pageNumber = req.query.exclusiveStartKey ?? 1
//console.log(datastore[req.query.key][req.query.scope]) for (const [key, value] of Object.entries(
datastore[req.query.key][req.query.scope],
)) {
wow.data.Entries.push({ Target: key, Value: value.value })
}
const pageNumber = req.query.exclusiveStartKey??1 if (req.query.ascending === "False") {
// descending order
wow.data.Entries.sort((a, b) => a.Value - b.Value).reverse()
} else {
//ascending
wow.data.Entries.sort((a, b) => a.Value - b.Value)
}
for (const [key, value] of Object.entries(datastore[req.query.key][req.query.scope])) { wow.data.Entries = paginate(
wow.data.Entries.push({Target: key,Value: value.value}) wow.data.Entries,
} req.query.pageSize,
pageNumber,
)
if (req.query.ascending === "False"){ if (
// descending order Object.entries(datastore[req.query.key][req.query.scope]).length >
wow.data.Entries.sort((a, b) => a.Value - b.Value).reverse(); pageNumber * req.query.pageSize
}else{ ) {
//ascending // if the next page exists fill the exclusivestartkey
wow.data.Entries.sort((a, b) => a.Value - b.Value) wow.data.ExclusiveStartKey = (parseFloat(pageNumber) + 1).toString()
} }
wow.data.Entries = paginate(wow.data.Entries,req.query.pageSize,pageNumber) //console.log(req.body)
if (Object.entries(datastore[req.query.key][req.query.scope]).length > pageNumber * req.query.pageSize ){ // if the next page exists fill the exclusivestartkey //console.dir(wow,{ depth: null })
wow.data.ExclusiveStartKey = (parseFloat(pageNumber) + 1).toString()
}
//console.log(req.body)
//console.dir(wow,{ depth: null })
return res.json(wow)
}
return res.json({"data":{"Entries":[],"ExclusiveStartKey":null}})
return res.json(wow)
}
return res.json({ data: { Entries: [], ExclusiveStartKey: null } })
}) })
module.exports = router module.exports = router

View File

@ -1,142 +1,189 @@
const { response } = require("express") const { response } = require("express")
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const bodyParser = require('body-parser') const bodyParser = require("body-parser")
const mongoose = require('mongoose'); const mongoose = require("mongoose")
const User = require('./../model/user.js') const User = require("./../model/user.js")
const keys = require('./../model/keys.js') const keys = require("./../model/keys.js")
const bcrypt = require('bcrypt') const bcrypt = require("bcrypt")
var sanitize = require('mongo-sanitize'); var sanitize = require("mongo-sanitize")
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const fetch = (...args) =>
import("node-fetch").then(({ default: fetch }) => fetch(...args))
var xss = require("xss") var xss = require("xss")
function isAlphaNumeric(str) { function isAlphaNumeric(str) {
var code, i, len; var code, i, len
for (i = 0, len = str.length; i < len; i++) { for (i = 0, len = str.length; i < len; i++) {
code = str.charCodeAt(i); code = str.charCodeAt(i)
if (!(code > 47 && code < 58) && // numeric (0-9) if (
!(code > 64 && code < 91) && // upper alpha (A-Z) !(code > 47 && code < 58) && // numeric (0-9)
!(code === 95) && // underscore !(code > 64 && code < 91) && // upper alpha (A-Z)
!(code > 96 && code < 123)) { // lower alpha (a-z) !(code === 95) && // underscore
return false; !(code > 96 && code < 123)
} ) {
} // lower alpha (a-z)
return true; return false
} }
}
return true
}
router.use(bodyParser.json()) router.use(bodyParser.json())
router.post("/",async (req, res) => { router.post("/", async (req, res) => {
//console.log(req.body) //console.log(req.body)
let {username, password: plainTextPassword} = req.body let { username, password: plainTextPassword } = req.body
if (!req.body.captcha) { if (!req.body.captcha) {
return res.json({status: 'error', error: 'Need a valid captcha bozo'}) return res.json({ status: "error", error: "Need a valid captcha bozo" })
} }
if (!username || typeof username !== 'string') { if (!username || typeof username !== "string") {
return res.json({status: 'error', error: 'Usernames needs to be sent and it needs to be a string'}) return res.json({
} status: "error",
if (!plainTextPassword || typeof plainTextPassword !== 'string') { error: "Usernames needs to be sent and it needs to be a string",
return res.json({status: 'error', error: 'Password needs to be sent and it needs to be a string'}) })
} }
if (!plainTextPassword || typeof plainTextPassword !== "string") {
return res.json({
status: "error",
error: "Password needs to be sent and it needs to be a string",
})
}
if(plainTextPassword.length < 4) { if (plainTextPassword.length < 4) {
return res.json({status: 'error', error: 'Password needs to be at least 5 characters'}) return res.json({
} status: "error",
error: "Password needs to be at least 5 characters",
})
}
if(username.length > 20) { if (username.length > 20) {
return res.json({status: 'error', error: 'Username can not be more than 20 characters'}) return res.json({
} status: "error",
error: "Username can not be more than 20 characters",
})
}
if (isAlphaNumeric(username) === false){ if (isAlphaNumeric(username) === false) {
return res.json({status: 'error', error: 'Usernames can not have special symbols except for underscores'}) return res.json({
} status: "error",
// verify our captcha error: "Usernames can not have special symbols except for underscores",
var captchaverifyreq = await fetch('https://hcaptcha.com/siteverify', { })
method: 'POST', }
headers:{ // verify our captcha
'Content-Type': 'application/x-www-form-urlencoded' var captchaverifyreq = await fetch("https://hcaptcha.com/siteverify", {
}, method: "POST",
body: new URLSearchParams({ headers: {
'secret': '0xE05AB1CFB83252696175FA69E526a3048547Cf0d', "Content-Type": "application/x-www-form-urlencoded",
'response': req.body.captcha, },
'sitekey': '30f6dee1-f765-42d0-ae34-29697c4aa623' body: new URLSearchParams({
}) secret: "0xE05AB1CFB83252696175FA69E526a3048547Cf0d",
}); response: req.body.captcha,
var captcha = await captchaverifyreq.json() sitekey: "30f6dee1-f765-42d0-ae34-29697c4aa623",
if (captcha.success == false) { }),
return res.json({status: 'error', error: 'Invalid Captcha. Try again.'}) })
} var captcha = await captchaverifyreq.json()
if (captcha.success == false) {
return res.json({
status: "error",
error: "Invalid Captcha. Try again.",
})
}
// check if keys are enabled // check if keys are enabled
var registration = req.config var registration = req.config
if (registration.RegistrationEnabled === false){ if (registration.RegistrationEnabled === false) {
return res.json({status: 'error', error: 'Registration has been temporarily disabled. Please join our discord.'}) return res.json({
} status: "error",
if (registration.KeysEnabled === true){ error: "Registration has been temporarily disabled. Please join our discord.",
})
}
if (registration.KeysEnabled === true) {
if (!req.body.invitekey) {
return res.json({
status: "error",
error: "Invite key needs to be sent.",
})
}
if (!req.body.invitekey){ sanitizedkey = sanitize(req.body.invitekey)
return res.json({status: 'error', error: 'Invite key needs to be sent.'}) const key = await keys.findOne({ Key: sanitizedkey }).lean()
}
sanitizedkey = sanitize(req.body.invitekey) if (!key) {
const key = await keys.findOne({Key: sanitizedkey}).lean() // key is invalid
return res.json({ status: "error", error: "Invalid Key." })
}
if (!key){ if (key.Used === true) {
// key is invalid // key has been used already
return res.json({status: 'error', error: 'Invalid Key.'}) return res.json({
} status: "error",
error: "Key has been used already.",
})
}
if (key.Used === true){ keys.updateOne(
// key has been used already { Key: sanitizedkey },
return res.json({status: 'error', error: 'Key has been used already.'}) {
} $set: {
Used: true,
UsedBy: username,
},
},
function (err, doc) {
//console.log(err)
},
)
}
keys.updateOne({Key: sanitizedkey}, { // if all checks above have succceeded we can proceed with registering in our database
$set: { username = xss(username) // stop anyone doing anything silly :)
Used: true, try {
UsedBy: username const password = await bcrypt.hash(plainTextPassword, 10)
} const userid = await User.countDocuments()
}, var datetime = new Date()
function(err, doc) { var datetimeepoch = new Date().getTime()
//console.log(err) const response = await User.create({
}) username,
} password,
admin: false,
coins: 15,
userid,
moderation: JSON.stringify({
status: "ok",
Reason: "None",
ExpiresIn: "None",
}),
joindate: datetime.toISOString().slice(0, 10),
colors: [
{ name: "Head", value: 1001 },
{ name: "Torso", value: 1001 },
{ name: "Left Arm", value: 1001 },
{ name: "Right Arm", value: 1001 },
{ name: "Left Leg", value: 1001 },
{ name: "Right Leg", value: 1001 },
],
lastclaimofcurrency: datetimeepoch,
membership: "None",
timesincelastrequest: datetimeepoch,
})
//console.log(response)
} catch (error) {
if (error.code === 11000) {
return res.json({
status: "error",
error: "Username already in use",
})
} else if (error.errors.username.kind === "unique") {
return res.json({
status: "error",
error: "Username already in use",
})
}
throw error
}
res.json({ status: "ok" })
// if all checks above have succceeded we can proceed with registering in our database
username = xss(username) // stop anyone doing anything silly :)
try{
const password = (await bcrypt.hash(plainTextPassword, 10))
const userid = await User.countDocuments();
var datetime = new Date()
var datetimeepoch = new Date().getTime()
const response = await User.create({
username,
password,
admin: false,
coins: 15,
userid,
moderation: JSON.stringify({status: "ok", Reason: "None", ExpiresIn: "None"}),
joindate: datetime.toISOString().slice(0,10),
colors: [{name: "Head",value: 1001 },{name: "Torso",value: 1001 },{name: "Left Arm",value: 1001 },{name: "Right Arm",value: 1001 },{name: "Left Leg",value: 1001 },{name: "Right Leg",value: 1001 }],
lastclaimofcurrency: datetimeepoch,
membership: "None",
timesincelastrequest: datetimeepoch
})
//console.log(response)
}catch(error){
if (error.code === 11000) {
return res.json({status: 'error', error: 'Username already in use'})
}else if (error.errors.username.kind === "unique") {
return res.json({status: 'error', error: 'Username already in use'})
}
throw error
}
res.json({status: 'ok'})
}) })
module.exports = router module.exports = router

View File

@ -1,67 +1,71 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const { requireAuth } = require('./../middleware/authmiddleware') const { requireAuth } = require("./../middleware/authmiddleware")
const clientid = "1008206768989544449" const clientid = "1008206768989544449"
const secret = "M2ixbjumSA6o1Qgt7KvCNcPb_giJHyp3" const secret = "M2ixbjumSA6o1Qgt7KvCNcPb_giJHyp3"
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const fetch = (...args) =>
const User = require('./../model/user.js') import("node-fetch").then(({ default: fetch }) => fetch(...args))
const speakeasy = require('speakeasy') const User = require("./../model/user.js")
const qrcode = require('qrcode') const speakeasy = require("speakeasy")
const bodyParser = require('body-parser') const qrcode = require("qrcode")
const xss = require('xss') const bodyParser = require("body-parser")
const xss = require("xss")
router.use(bodyParser.json()) router.use(bodyParser.json())
router.get('/authenticate',requireAuth,async function(req,rep){ router.get("/authenticate", requireAuth, async function (req, rep) {
const code = req.query.code const code = req.query.code
//console.log(code) //console.log(code)
if (code){ if (code) {
const response = await fetch("https://discord.com/api/oauth2/token",{ const response = await fetch("https://discord.com/api/oauth2/token", {
body: new URLSearchParams({ body: new URLSearchParams({
client_id: clientid, client_id: clientid,
client_secret: secret, client_secret: secret,
code, code,
grant_type: 'authorization_code', grant_type: "authorization_code",
redirect_uri: `http://mete0r.xyz/settings/authenticate`, redirect_uri: `http://mete0r.xyz/settings/authenticate`,
scope: 'identify', scope: "identify",
}), }),
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/x-www-form-urlencoded" "Content-Type": "application/x-www-form-urlencoded",
} },
}) })
const son = await response.json() const son = await response.json()
//console.log(son) //console.log(son)
//console.log(son["access_token"]) //console.log(son["access_token"])
const resp2 = await fetch("https://discord.com/api/users/@me",{ const resp2 = await fetch("https://discord.com/api/users/@me", {
headers: { headers: {
"authorization": `${son["token_type"]} ${son["access_token"]}` authorization: `${son["token_type"]} ${son["access_token"]}`,
} },
}) })
const final = await resp2.json() const final = await resp2.json()
const dcid = final.id const dcid = final.id
//console.log(dcid) //console.log(dcid)
const user = await User.findOne({discordid: dcid})/*.lean()*/ const user = await User.findOne({ discordid: dcid }) /*.lean()*/
if (user) { if (user) {
return rep.redirect("/settings?error=alreadyused") return rep.redirect("/settings?error=alreadyused")
} }
const milliseconds = BigInt(dcid) >> 22n const milliseconds = BigInt(dcid) >> 22n
if (new Date(Number(milliseconds) + 1420070400000)> Date.now() - (1000 * 60 * 60 * 24 * 7 * 4) === true){ // 1 month if (
return rep.redirect("/settings?error=toonew") new Date(Number(milliseconds) + 1420070400000) >
} Date.now() - 1000 * 60 * 60 * 24 * 7 * 4 ===
req.userdocument.discordid = dcid.toString() true
req.userdocument.markModified('discordid') ) {
await req.userdocument.save() // 1 month
return rep.redirect("/settings?error=toonew")
}
req.userdocument.discordid = dcid.toString()
req.userdocument.markModified("discordid")
await req.userdocument.save()
rep.redirect('/settings') rep.redirect("/settings")
}
}
}) })
/*router.get("/unlink", requireAuth,async (req, res) => { /*router.get("/unlink", requireAuth,async (req, res) => {
req.userdocument.discordid = undefined req.userdocument.discordid = undefined
req.userdocument.markModified('discordid') req.userdocument.markModified('discordid')
@ -69,101 +73,107 @@ router.get('/authenticate',requireAuth,async function(req,rep){
res.redirect('/settings') res.redirect('/settings')
})*/ })*/
router.get("/2fa", requireAuth,async (req, res) => { router.get("/2fa", requireAuth, async (req, res) => {
if (req.userdocument.twofasecrets){ if (req.userdocument.twofasecrets) {
const json = JSON.parse(req.userdocument.twofasecrets) const json = JSON.parse(req.userdocument.twofasecrets)
if (json.verified === true){ if (json.verified === true) {
return res.json({status: "success", message: "2FA already set sorry."}) return res.json({
}else{ status: "success",
// basically if they haven't verified that they know the secret before we will just remove it for them message: "2FA already set sorry.",
req.userdocument.twofasecrets = undefined })
req.userdocument.markModified('twofasecrets') } else {
req.userdocument.save() // basically if they haven't verified that they know the secret before we will just remove it for them
} req.userdocument.twofasecrets = undefined
} req.userdocument.markModified("twofasecrets")
const secret = speakeasy.generateSecret({ req.userdocument.save()
name: "Meteorite" }
}) }
qrcode.toDataURL(secret.otpauth_url, function(err, data) { const secret = speakeasy.generateSecret({
name: "Meteorite",
req.userdocument.twofasecrets = JSON.stringify({secret: secret.ascii, verified: false}) })
req.userdocument.markModified('twofasecrets') qrcode.toDataURL(secret.otpauth_url, function (err, data) {
req.userdocument.save() req.userdocument.twofasecrets = JSON.stringify({
return res.json({status: "success", message: "2FA set please verify to complete.", qrcode: data}) secret: secret.ascii,
}); verified: false,
})
req.userdocument.markModified("twofasecrets")
req.userdocument.save()
return res.json({
status: "success",
message: "2FA set please verify to complete.",
qrcode: data,
})
})
}) })
router.post("/verify2fa", requireAuth, async (req, res) => {
router.post("/verify2fa", requireAuth,async (req, res) => { const { code } = req.body
const {code} = req.body if (req.userdocument.twofasecrets) {
if (req.userdocument.twofasecrets){ const json = JSON.parse(req.userdocument.twofasecrets)
const json = JSON.parse(req.userdocument.twofasecrets) if (json.verified === true) {
if (json.verified === true){ return res.json({
return res.json({status: "success", message: "2FA already set sorry."}) status: "success",
}else{ message: "2FA already set sorry.",
})
const valid = speakeasy.totp.verify({ } else {
secret: json.secret, const valid = speakeasy.totp.verify({
encoding: 'ascii', secret: json.secret,
token: code encoding: "ascii",
}) token: code,
if (valid === false){ })
return res.json({status: 'error', error: 'Invalid 2FA Code'}) if (valid === false) {
}else{ return res.json({ status: "error", error: "Invalid 2FA Code" })
json.verified = true } else {
req.userdocument.twofasecrets = JSON.stringify(json) json.verified = true
req.userdocument.markModified('twofasecrets') req.userdocument.twofasecrets = JSON.stringify(json)
req.userdocument.save() req.userdocument.markModified("twofasecrets")
return res.json({status: "success", message:"2FA verified."}) req.userdocument.save()
} return res.json({ status: "success", message: "2FA verified." })
}
}
} }
}
}) })
router.post("/setbio", requireAuth,async (req, res) => { router.post("/setbio", requireAuth, async (req, res) => {
const { bio } = req.body const { bio } = req.body
if (typeof bio !== 'string'){ if (typeof bio !== "string") {
return res.json({status: 'error', error: 'Bio not sent'}) return res.json({ status: "error", error: "Bio not sent" })
} }
if (bio.length>100){ if (bio.length > 100) {
return res.json({status: 'error', error: 'Length over 100.'}) return res.json({ status: "error", error: "Length over 100." })
} }
req.userdocument.bio = xss(bio) req.userdocument.bio = xss(bio)
req.userdocument.markModified('bio') req.userdocument.markModified("bio")
req.userdocument.save() req.userdocument.save()
return res.json({status: "success", message:"Done."}) return res.json({ status: "success", message: "Done." })
}) })
router.post("/changecss", requireAuth,async (req, res) => { router.post("/changecss", requireAuth, async (req, res) => {
const { customcss } = req.body const { customcss } = req.body
if (typeof customcss !== 'string'){ if (typeof customcss !== "string") {
return res.json({status: 'error', error: 'Bio not sent'}) return res.json({ status: "error", error: "Bio not sent" })
} }
if (customcss.length>5000){ if (customcss.length > 5000) {
return res.json({status: 'error', error: 'Length over 5000.'}) return res.json({ status: "error", error: "Length over 5000." })
} }
req.userdocument.css = xss(customcss) req.userdocument.css = xss(customcss)
req.userdocument.markModified('css') req.userdocument.markModified("css")
req.userdocument.save() req.userdocument.save()
return res.json({status: "success", message:"Done."}) return res.json({ status: "success", message: "Done." })
}) })
router.post("/aboutme", requireAuth,async (req, res) => { router.post("/aboutme", requireAuth, async (req, res) => {
const { about } = req.body const { about } = req.body
if (typeof about !== 'string'){ if (typeof about !== "string") {
return res.json({status: 'error', error: 'Bio not sent'}) return res.json({ status: "error", error: "Bio not sent" })
} }
if (about.length>200){ if (about.length > 200) {
return res.json({status: 'error', error: 'Length over 200.'}) return res.json({ status: "error", error: "Length over 200." })
} }
req.userdocument.aboutme = xss(about) req.userdocument.aboutme = xss(about)
req.userdocument.markModified('aboutme') req.userdocument.markModified("aboutme")
req.userdocument.save() req.userdocument.save()
return res.json({status: "success", message:"Done."}) return res.json({ status: "success", message: "Done." })
}) })
module.exports = router module.exports = router

View File

@ -1,14 +1,14 @@
const crypto = require('crypto'); const crypto = require("crypto")
const fs = require('fs') const fs = require("fs")
const key = fs.readFileSync('DefaultPrivateKey.pem') const key = fs.readFileSync("DefaultPrivateKey.pem")
// signature API for roblos , used to bless scripts from site to client/rcc/studio and will grant // signature API for roblos , used to bless scripts from site to client/rcc/studio and will grant
// FULL Lua permissions to scripts, and allow CoreGui access. // FULL Lua permissions to scripts, and allow CoreGui access.
function signer(wow){ function signer(wow) {
const sign = crypto.createSign('SHA1'); const sign = crypto.createSign("SHA1")
sign.update("\r\n" + JSON.stringify(wow)) sign.update("\r\n" + JSON.stringify(wow))
var signature_b64 = sign.sign(key, "base64") var signature_b64 = sign.sign(key, "base64")
//console.log(signature_b64) //console.log(signature_b64)
return(signature_b64) return signature_b64
} }
module.exports = {signer} module.exports = { signer }

View File

@ -1,257 +1,303 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const User = require('./../model/user.js') const User = require("./../model/user.js")
var bodyParser = require('body-parser'); var bodyParser = require("body-parser")
router.use(bodyParser.json()); // support json encoded bodies router.use(bodyParser.json()) // support json encoded bodies
router.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies router.use(bodyParser.urlencoded({ extended: true })) // support encoded bodies
router.use(bodyParser.text()); // support encoded bodies router.use(bodyParser.text()) // support encoded bodies
const JWT_SECRET = process.env.JWT_SECRET const JWT_SECRET = process.env.JWT_SECRET
const jwt = require('jsonwebtoken') const jwt = require("jsonwebtoken")
const jwtverify = (req,res,next) => { const jwtverify = (req, res, next) => {
jwt.verify(req.headers['roblox-session-id'],JWT_SECRET, (err,decodedtoken) => { jwt.verify(
if (err){ req.headers["roblox-session-id"],
return res.status(403).end() JWT_SECRET,
}else{ (err, decodedtoken) => {
var tokendata = decodedtoken if (err) {
var name = tokendata.username return res.status(403).end()
try { } else {
User.findOne({username: new RegExp('^'+name+'$', "i")}, function(err, doc) { var tokendata = decodedtoken
var name = tokendata.username
req.userdocument = doc try {
next() User.findOne(
{ username: new RegExp("^" + name + "$", "i") },
})/*.lean()*/} function (err, doc) {
catch (error) { req.userdocument = doc
console.error(error); next()
} },
) /*.lean()*/
} } catch (error) {
console.error(error)
}) }
}
}; },
)
}
// below is follow code // below is follow code
router.get("/user/following-exists",async (req, res) => { router.get("/user/following-exists", async (req, res) => {
//console.log("My userid"+req.query.userId) //console.log("My userid"+req.query.userId)
//console.log("their userid"+req.query.followerUserId) //console.log("their userid"+req.query.followerUserId)
const user = await User.findOne({userid: req.query.userId}).lean() const user = await User.findOne({ userid: req.query.userId }).lean()
if(!user){ if (!user) {
return res.json({isFollowing:"false"}) return res.json({ isFollowing: "false" })
} }
if (!user.followers){ if (!user.followers) {
return res.json({isFollowing:"false"}) return res.json({ isFollowing: "false" })
} }
const follower = user.followers.some(word => word.userid == req.query.followerUserId ) const follower = user.followers.some(
word => word.userid == req.query.followerUserId,
)
if (follower === false){ if (follower === false) {
return res.json({isFollowing:"false"}) return res.json({ isFollowing: "false" })
} }
res.json({success:"true",isFollowing:"true"}) res.json({ success: "true", isFollowing: "true" })
}) })
router.post("/user/follow",jwtverify,async (req, res) => { router.post("/user/follow", jwtverify, async (req, res) => {
const tofollow = req.body.followedUserId const tofollow = req.body.followedUserId
if (!tofollow){ if (!tofollow) {
return res.json({isFollowing:"false"}) return res.json({ isFollowing: "false" })
} }
let follower = false let follower = false
if (req.userdocument.followers){ if (req.userdocument.followers) {
follower = req.userdocument.followers.some(word => word.userid == req.query.followerUserId ) follower = req.userdocument.followers.some(
} word => word.userid == req.query.followerUserId,
)
}
if (follower === true){
// already following
res.json({success:"true",isFollowing:"true"})
}
User.updateOne({userid: tofollow}, {
$push: {
followers: {userid: req.userdocument.userid, username: req.userdocument.username}
}
},
function(err, doc) {
//console.log(err)
})
res.json({success:"true",isFollowing:"true"})
if (follower === true) {
// already following
res.json({ success: "true", isFollowing: "true" })
}
User.updateOne(
{ userid: tofollow },
{
$push: {
followers: {
userid: req.userdocument.userid,
username: req.userdocument.username,
},
},
},
function (err, doc) {
//console.log(err)
},
)
res.json({ success: "true", isFollowing: "true" })
}) })
router.post("/user/unfollow",jwtverify,async (req, res) => { router.post("/user/unfollow", jwtverify, async (req, res) => {
const tofollow = req.body.followedUserId const tofollow = req.body.followedUserId
if (!tofollow){ if (!tofollow) {
return res.json({isFollowing:"false"}) return res.json({ isFollowing: "false" })
} }
User.updateOne({userid: tofollow}, {
$pull: {
followers: {userid: req.userdocument.userid, username: req.userdocument.username}
}
},
function(err, doc) {
//console.log(err)
})
res.json({success:"true",isFollowing:"false"})
User.updateOne(
{ userid: tofollow },
{
$pull: {
followers: {
userid: req.userdocument.userid,
username: req.userdocument.username,
},
},
},
function (err, doc) {
//console.log(err)
},
)
res.json({ success: "true", isFollowing: "false" })
}) })
//below is friend code //below is friend code
router.get("/user/get-friendship-count",async (req, res) => { router.get("/user/get-friendship-count", async (req, res) => {
// this is used to limit friends on the client but since we won't have friends limits we can leave it here // this is used to limit friends on the client but since we won't have friends limits we can leave it here
res.json({success:"true",count:1}) res.json({ success: "true", count: 1 })
}) })
router.post("/user/request-friendship",jwtverify,async (req, res) => { router.post("/user/request-friendship", jwtverify, async (req, res) => {
const tofriend = req.query.recipientUserId const tofriend = req.query.recipientUserId
if (!tofriend){ if (!tofriend) {
return res.json({isFollowing:"false"}) return res.json({ isFollowing: "false" })
} }
const usertofriend = await User.findOne({userid: tofriend}).lean() const usertofriend = await User.findOne({ userid: tofriend }).lean()
if (!usertofriend){ if (!usertofriend) {
return res.json({success:"true",isFollowing:"true"}) return res.json({ success: "true", isFollowing: "true" })
} }
if (usertofriend.friends) {
const friends = usertofriend.friends.some(
word => word.userid == req.userdocument.userid,
)
if (friends === true) {
return res.json({ success: "true", isFollowing: "true" })
}
// 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
if (usertofriend.friends){ const bothwantobefriends = req.userdocument.friendrequests.some(
const friends = usertofriend.friends.some(word => word.userid == req.userdocument.userid) word => word.userid == usertofriend.userid,
if (friends === true){ )
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) {},
)
return res.json({success:"true",isFollowing:"true"}) User.updateOne(
} { userid: tofriend },
// already friends {
} $push: {
if (req.userdocument.friendrequests){ friends: {
// 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 userid: req.userdocument.userid,
username: req.userdocument.username,
},
},
$pull: {
friendrequests: {
userid: req.userdocument.userid,
username: req.userdocument.username,
},
},
},
function (err, doc) {},
)
const bothwantobefriends = req.userdocument.friendrequests.some(word => word.userid == usertofriend.userid) return res.json({ success: "true", isFollowing: "true" })
if (bothwantobefriends === true){ }
console.log(tofriend) }
User.updateOne({userid: req.userdocument.userid}, { if (usertofriend.friendrequests) {
$push: { const alreadyrequested = usertofriend.friendrequests.some(
friends: {userid: usertofriend.userid, username: usertofriend.username} word => word.userid == req.userdocument.userid,
}, )
$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({success:"true",isFollowing:"true"})
}
}
if (usertofriend.friendrequests){
const alreadyrequested = usertofriend.friendrequests.some(word => word.userid == req.userdocument.userid)
// already friend requested
if (alreadyrequested === true){
return res.json({success:"true",isFollowing:"true"})
}
}
User.updateOne({userid: usertofriend.userid}, {
$push: {
friendrequests: {userid: req.userdocument.userid, username: req.userdocument.username}
}
},
function(err, doc) {
})
res.json({success:"true",isFollowing:"true"})
// already friend requested
if (alreadyrequested === true) {
return res.json({ success: "true", isFollowing: "true" })
}
}
User.updateOne(
{ userid: usertofriend.userid },
{
$push: {
friendrequests: {
userid: req.userdocument.userid,
username: req.userdocument.username,
},
},
},
function (err, doc) {},
)
res.json({ success: "true", isFollowing: "true" })
}) })
router.post("/user/decline-friend-request",jwtverify,async (req, res) => { router.post("/user/decline-friend-request", jwtverify, async (req, res) => {
const tounfriend = req.query.requesterUserId const tounfriend = req.query.requesterUserId
//console.log(tounfriend+" nerd") //console.log(tounfriend+" nerd")
if (!tounfriend){ if (!tounfriend) {
return res.json({isFollowing:"false"}) return res.json({ isFollowing: "false" })
} }
const usertofriend = await User.findOne({userid: tounfriend}).lean() const usertofriend = await User.findOne({ userid: tounfriend }).lean()
if (!usertofriend){ if (!usertofriend) {
return res.json({success:"true",isFollowing:"true"}) return res.json({ success: "true", isFollowing: "true" })
} }
const alreadyfriends = req.userdocument.friends.some(word => word.userid == tounfriend ) const alreadyfriends = req.userdocument.friends.some(
if (alreadyfriends === true){ word => word.userid == tounfriend,
// already friends with the person so they want ro remove their friend )
User.updateOne({userid: tounfriend}, { if (alreadyfriends === true) {
$pull: { // already friends with the person so they want ro remove their friend
friends: {userid: req.userdocument.userid, username: req.userdocument.username} User.updateOne(
} { userid: tounfriend },
}, {
function(err, doc) { $pull: {
//console.log(err) friends: {
}) userid: req.userdocument.userid,
User.updateOne({userid: req.userdocument.userid}, { username: req.userdocument.username,
$pull: { },
friends: {userid:usertofriend.userid, username: usertofriend.username} },
} },
}, function (err, doc) {
function(err, doc) { //console.log(err)
//console.log(err) },
}) )
return res.json({success:"true",isFollowing:"true"}) User.updateOne(
} { userid: req.userdocument.userid },
{
$pull: {
friends: {
//otherwise the user isn't friends but still declines the friend request userid: usertofriend.userid,
username: usertofriend.username,
User.updateOne({userid: tounfriend}, { },
$pull: { },
friendrequests: {userid: req.userdocument.userid, username: req.userdocument.username} },
} function (err, doc) {
}, //console.log(err)
function(err, doc) { },
//console.log(err) )
}) return res.json({ success: "true", isFollowing: "true" })
User.updateOne({userid: req.userdocument.userid}, { }
$pull: {
friendrequests: {userid: usertofriend.userid, username: usertofriend.username}
}
},
function(err, doc) {
//console.log(err)
})
res.json({success:"true",isFollowing:"true"})
//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)
},
)
res.json({ success: "true", isFollowing: "true" })
}) })
module.exports = router module.exports = router

View File

@ -1,49 +1,64 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const { requireAuth } = require('./../middleware/authmiddleware') const { requireAuth } = require("./../middleware/authmiddleware")
const User = require('./../model/user.js') const User = require("./../model/user.js")
const games = require('./../model/games.js') const games = require("./../model/games.js")
const bodyParser = require('body-parser') const bodyParser = require("body-parser")
router.use(bodyParser.json()) router.use(bodyParser.json())
router.post('/api/users/search', async (req, res) => { router.post("/api/users/search", async (req, res) => {
const resultsPerPage = 12 const resultsPerPage = 12
let page = req.body.page ?? 0 let page = req.body.page ?? 0
if (page != 0){ if (page != 0) {
page-=1 page -= 1
} }
let {searchquery} = req.body let { searchquery } = req.body
function escapeRegex(text) { function escapeRegex(text) {
return text?.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); return text?.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
} }
const regex = new RegExp(escapeRegex(searchquery), 'gi'); const regex = new RegExp(escapeRegex(searchquery), "gi")
//const pages = await User.countDocuments({username: regex})/resultsPerPage //const pages = await User.countDocuments({username: regex})/resultsPerPage
const response = await User.find({username: regex}).limit(resultsPerPage).skip(0+parseFloat(page)*resultsPerPage).select(['userid','username']).lean() const response = await User.find({ username: regex })
let responsecount = await User.countDocuments({username: regex}) .limit(resultsPerPage)
.skip(0 + parseFloat(page) * resultsPerPage)
.select(["userid", "username"])
.lean()
let responsecount = await User.countDocuments({ username: regex })
res.json({data: response, pages: Math.ceil(Math.max(responsecount/resultsPerPage, 1))}) res.json({
}); data: response,
pages: Math.ceil(Math.max(responsecount / resultsPerPage, 1)),
})
})
router.get(['/users/:userid/canmanage/:gameid','//users/:userid/canmanage/:gameid'], async (req, res) => { router.get(
["/users/:userid/canmanage/:gameid", "//users/:userid/canmanage/:gameid"],
async (req, res) => {
const user = await User.findOne({
userid: req.params.userid,
}) /*.lean()*/
if (!user) {
return res.json({ Success: false, CanManage: false })
}
const user = await User.findOne({userid: req.params.userid})/*.lean()*/ const game = await games.findOne({ idofgame: req.params.gameid }).lean()
if (!user) { if (!game) {
return res.json({"Success":false,"CanManage":false}) return res.json({ Success: false, CanManage: false })
} }
const game = await games.findOne({idofgame: req.params.gameid}).lean() if (
if (!game) { game.useridofowner === user.userid ||
return res.json({"Success":false,"CanManage":false}) user.userid === 0 ||
} user.userid === 18
) {
return res.json({ Success: true, CanManage: true })
}
if (game.useridofowner === user.userid || user.userid === 0 || user.userid === 18){ return res.json({ Success: true, CanManage: false })
return res.json({"Success":true,"CanManage":true}) },
} )
return res.json({"Success":true,"CanManage":false})
});
module.exports = router module.exports = router

View File

@ -10,7 +10,7 @@ const router = express.Router()
//}) //})
router.get("/universes/validate-place-join", async (req, res) => { router.get("/universes/validate-place-join", async (req, res) => {
res.send("true") res.send("true")
}) })
module.exports = router module.exports = router

File diff suppressed because one or more lines are too long

View File

@ -1,319 +1,372 @@
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); const fetch = (...args) =>
let controller = new AbortController(); import("node-fetch").then(({ default: fetch }) => fetch(...args))
require('dotenv').config() let controller = new AbortController()
require("dotenv").config()
const RCC_HOST = process.env.RCC_HOST const RCC_HOST = process.env.RCC_HOST
const url = 'http://'+RCC_HOST+':64990'; // change this to rcc soap const url = "http://" + RCC_HOST + ":64990" // change this to rcc soap
var convert = require('xml-js'); var convert = require("xml-js")
const sampleHeaders = { const sampleHeaders = {
'Content-Type': 'text/xml;charset=UTF-8', "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 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() { async function GetAllJobs() {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const xmlData = (xml = { const xmlData = (xml = {
_declaration: { _declaration: {
_attributes: { version: '1.0', encoding: 'UTF - 8' }, _attributes: { version: "1.0", encoding: "UTF - 8" },
}, },
'SOAP-ENV:Envelope': { "SOAP-ENV:Envelope": {
_attributes: { _attributes: {
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', "xmlns:SOAP-ENV":
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/', "http://schemas.xmlsoap.org/soap/envelope/",
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', "xmlns:SOAP-ENC":
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema', "http://schemas.xmlsoap.org/soap/encoding/",
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap', "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
'xmlns:ns1': 'http://roblox.com/', "xmlns:xsd": "http://www.w3.org/2001/XMLSchema",
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12', "xmlns:ns2": "http://roblox.com/RCCServiceSoap",
}, "xmlns:ns1": "http://roblox.com/",
'SOAP-ENV:Body': { 'ns1:GetAllJobsEx': {} }, "xmlns:ns3": "http://roblox.com/RCCServiceSoap12",
}, },
}) "SOAP-ENV:Body": { "ns1:GetAllJobsEx": {} },
},
})
const body = convert.js2xml(xmlData, { compact: true, spaces: 4 }) const body = convert.js2xml(xmlData, { compact: true, spaces: 4 })
try { try {
const result = await fetch(url, { method: 'POST', body }) const result = await fetch(url, { method: "POST", body })
const data = await result.text() const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) const convertedData = convert.xml2js(data, {
return resolve( compact: true,
convertedData['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:GetAllJobsExResponse']['ns1:GetAllJobsExResult'] spaces: 4,
) })
} catch (error) { return resolve(
return reject(error) convertedData["SOAP-ENV:Envelope"]["SOAP-ENV:Body"][
} "ns1:GetAllJobsExResponse"
}) ]["ns1:GetAllJobsExResult"],
)
} catch (error) {
return reject(error)
}
})
} }
async function Execute(jobid,script) { async function Execute(jobid, script) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
var xml = { var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF - 8' } }, _declaration: {
'SOAP-ENV:Envelope': { _attributes: { version: "1.0", encoding: "UTF - 8" },
_attributes: { },
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', "SOAP-ENV:Envelope": {
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/', _attributes: {
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', "xmlns:SOAP-ENV":
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema', "http://schemas.xmlsoap.org/soap/envelope/",
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap', "xmlns:SOAP-ENC":
'xmlns:ns1': 'http://roblox.com/', "http://schemas.xmlsoap.org/soap/encoding/",
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12' "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
}, "xmlns:xsd": "http://www.w3.org/2001/XMLSchema",
'SOAP-ENV:Body': { "xmlns:ns2": "http://roblox.com/RCCServiceSoap",
'ns1:ExecuteEx': { "xmlns:ns1": "http://roblox.com/",
'ns1:jobID': { _text: 'Test' }, "xmlns:ns3": "http://roblox.com/RCCServiceSoap12",
'ns1:script': { },
'ns1:name': { _text: 'Script' }, "SOAP-ENV:Body": {
'ns1:script': { _text: 'print("no")' }, "ns1:ExecuteEx": {
'ns1:arguments': { _text: '' } "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 { xml["SOAP-ENV:Envelope"]["SOAP-ENV:Body"]["ns1:ExecuteEx"][
const result = await fetch(url, { method: 'POST', body }) "ns1:jobID"
const data = await result.text() ]._text = jobid
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) xml["SOAP-ENV:Envelope"]["SOAP-ENV:Body"]["ns1:ExecuteEx"][
return resolve( "ns1:script"
convertedData ]["ns1:script"]._text = script
) const body = convert.js2xml(xml, { compact: true, spaces: 4 })
} catch (error) {
return reject(error)
}
})
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) { async function CloseJob(jobid) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
var xml = { var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF - 8' } }, _declaration: {
'SOAP-ENV:Envelope': { _attributes: { version: "1.0", encoding: "UTF - 8" },
_attributes: { },
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', "SOAP-ENV:Envelope": {
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/', _attributes: {
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', "xmlns:SOAP-ENV":
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema', "http://schemas.xmlsoap.org/soap/envelope/",
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap', "xmlns:SOAP-ENC":
'xmlns:ns1': 'http://roblox.com/', "http://schemas.xmlsoap.org/soap/encoding/",
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12' "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
}, "xmlns:xsd": "http://www.w3.org/2001/XMLSchema",
'SOAP-ENV:Body': { "xmlns:ns2": "http://roblox.com/RCCServiceSoap",
'ns1:CloseJob': { "xmlns:ns1": "http://roblox.com/",
'ns1:jobID': { _text: 'Test' } "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 }) },
},
}
xml["SOAP-ENV:Envelope"]["SOAP-ENV:Body"]["ns1:CloseJob"][
"ns1:jobID"
]._text = jobid
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try { try {
const result = await fetch(url, { method: 'POST', body }) const result = await fetch(url, { method: "POST", body })
const data = await result.text() const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) const convertedData = convert.xml2js(data, {
return resolve( compact: true,
convertedData spaces: 4,
) })
} catch (error) { return resolve(convertedData)
return reject(error) } 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 })
async function RenewLease(jobid,expiration) { try {
return new Promise(async (resolve, reject) => { const result = await fetch(url, { method: "POST", body })
var xml = { const data = await result.text()
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } }, const convertedData = convert.xml2js(data, {
'SOAP-ENV:Envelope': { compact: true,
_attributes: { spaces: 4,
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', })
'xmlns:ns1': 'http://roblox.com/', return resolve(convertedData)
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance' } catch (error) {
}, return reject(error)
'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){ async function GetExpiration(jobid) {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
var xml = { var xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } }, _declaration: {
'SOAP-ENV:Envelope': { _attributes: { version: "1.0", encoding: "UTF-8" },
_attributes: { },
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', "SOAP-ENV:Envelope": {
'xmlns:ns1': 'http://roblox.com/' _attributes: {
}, "xmlns:SOAP-ENV":
'SOAP-ENV:Body': { 'ns1:GetExpiration': { 'ns1:jobID': { _text: 'Test' } } } "http://schemas.xmlsoap.org/soap/envelope/",
} "xmlns:ns1": "http://roblox.com/",
} },
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:GetExpiration']['ns1:jobID']._text = jobid "SOAP-ENV:Body": {
const body = convert.js2xml(xml, { compact: true, spaces: 4 }) "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 { try {
const result = await fetch(url, { method: 'POST', body }) const result = await fetch(url, { method: "POST", body })
const data = await result.text() const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) const convertedData = convert.xml2js(data, {
return resolve( compact: true,
convertedData spaces: 4,
) })
} catch (error) { return resolve(convertedData)
return reject(error) } catch (error) {
} return reject(error)
}) }
})
} }
//var gameservertxt = fs.readFileSync('actualgameserver.txt','utf-8') //var gameservertxt = fs.readFileSync('actualgameserver.txt','utf-8')
//gameservertxt = gameservertxt.replace('function start(placeId, port, url)','function start(1111, port)') //gameservertxt = gameservertxt.replace('function start(placeId, port, url)','function start(1111, port)')
async function CloseExpiredJobs(){ async function CloseExpiredJobs() {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
var xml = xml = { var xml = (xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } }, _declaration: {
'SOAP-ENV:Envelope': { _attributes: { version: "1.0", encoding: "UTF-8" },
_attributes: { },
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', "SOAP-ENV:Envelope": {
'xmlns:ns1': 'http://roblox.com/' _attributes: {
}, "xmlns:SOAP-ENV":
'SOAP-ENV:Body': { 'ns1:CloseExpiredJobs': {} } "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 }) const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try { try {
const result = await fetch(url, { method: 'POST', body }) const result = await fetch(url, { method: "POST", body })
const data = await result.text() const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) const convertedData = convert.xml2js(data, {
return resolve( compact: true,
convertedData spaces: 4,
) })
} catch (error) { return resolve(convertedData)
return reject(error) } catch (error) {
} return reject(error)
}) }
})
} }
async function CloseAllJobs(){ async function CloseAllJobs() {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
var xml = xml = { var xml = (xml = {
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } }, _declaration: {
'SOAP-ENV:Envelope': { _attributes: { version: "1.0", encoding: "UTF-8" },
_attributes: { },
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/', "SOAP-ENV:Envelope": {
'xmlns:ns1': 'http://roblox.com/' _attributes: {
}, "xmlns:SOAP-ENV":
'SOAP-ENV:Body': { 'ns1:CloseAllJobs': {} } "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 }) const body = convert.js2xml(xml, { compact: true, spaces: 4 })
try { try {
const result = await fetch(url, { method: 'POST', body }) const result = await fetch(url, { method: "POST", body })
const data = await result.text() const data = await result.text()
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 }) const convertedData = convert.xml2js(data, {
return resolve( compact: true,
convertedData spaces: 4,
) })
} catch (error) { return resolve(convertedData)
return reject(error) } catch (error) {
} return reject(error)
}) }
})
} }
module.exports = {
module.exports = {OpenJob, GetAllJobs,Execute,CloseJob,RenewLease,GetExpiration,CloseExpiredJobs,CloseAllJobs} OpenJob,
GetAllJobs,
Execute,
CloseJob,
RenewLease,
GetExpiration,
CloseExpiredJobs,
CloseAllJobs,
}

View File

@ -1,93 +1,121 @@
<style type="text/css"> <style type="text/css">
html { html {
height: 100%; height: 100%;
} }
body { body {
background-color: #000; background-color: #000;
color: #fff; color: #fff;
font-family: 'Source Sans Pro', sans-serif; font-family: "Source Sans Pro", sans-serif;
font-size: 24px; font-size: 24px;
font-weight: 300; font-weight: 300;
height: auto; height: auto;
line-height: 24px; line-height: 24px;
margin: 0; margin: 0;
min-width: 320px; min-width: 320px;
text-align: center; text-align: center;
overflow: hidden; overflow: hidden;
} }
.header { .header {
padding: 50px 0 20px; padding: 50px 0 20px;
} }
p{ p {
font-weight: bold; font-weight: bold;
} }
</style>
<audio id="my-audio" loop autoplay>
<source
src="https://cdn.mete0r.xyz/file/meteorite/bittersweet.m4a"
type="audio/x-m4a" />
</audio>
<script type="text/javascript">
var isAudioPlayed = false
function playAudio() {
isAudioPlayed = true
const myAudio = document.getElementById("my-audio")
myAudio.play()
}
</style> document.body.onclick = () => {
<audio id="my-audio" loop autoplay> if (isAudioPlayed) return
<source src="https://cdn.mete0r.xyz/file/meteorite/bittersweet.m4a" type="audio/x-m4a"> playAudio()
</audio> }
<script type="text/javascript"> </script>
var isAudioPlayed = false;
function playAudio() {
isAudioPlayed = true;
const myAudio = document.getElementById("my-audio");
myAudio.play();
}
document.body.onclick = ()=>{
if(isAudioPlayed) return ;
playAudio();
}
</script>
<div class="header"> <div class="header">
<h1>What happened to Meteorite?</h1> <h1>What happened to Meteorite?</h1>
<p>In short I had lost motivation to keep it open. Now let me give you some reasons why.</p> <p>
<br> In short I had lost motivation to keep it open. Now let me give you some
<ul> reasons why.
<li>it was a massive money bleed ranging $60-400 a month to run.</li> </p>
<br> <br />
<li>The staff I hired didn't do the best job which is partially my fault. I didn't do enough to keep them doing their best. This resulted in some accidents over the course of Meteorite's 1 year life which I don't condone and infighting. I didn't tell my staff to censor or hide any criticism though I should of been more proactive about what my staff were doing.</li> <ul>
<br> <li>it was a massive money bleed ranging $60-400 a month to run.</li>
<li>I wanted a break which is why updates slowed down but obviously the website/discord was not in a state to leave. This also upset some staff members which I apologize for.</li> <br />
</ul> <li>
The staff I hired didn't do the best job which is partially my
fault. I didn't do enough to keep them doing their best. This
resulted in some accidents over the course of Meteorite's 1 year
life which I don't condone and infighting. I didn't tell my staff to
censor or hide any criticism though I should of been more proactive
about what my staff were doing.
</li>
<br />
<li>
I wanted a break which is why updates slowed down but obviously the
website/discord was not in a state to leave. This also upset some
staff members which I apologize for.
</li>
</ul>
<br> <br />
<p>To clear some things up of accusations against me since I know there is a lot of noise.</p> <p>
<br> To clear some things up of accusations against me since I know there is
<h5>First of all, I had already decided to shut down before the <a href="https://docs.google.com/document/d/1GHwiaTWezaIRUSKgR7XG4VDB_tw88Zz2FCb40RI47yY/edit">document</a> even came out. It didn't influence this decision in any way. Now, we will skip over criticisms of the website itself as that doesn't matter. Two problematic individuals in the community were a result of my bad management and staff favoritism over members. Security of Meteorite was compromised from a lazy config error but I did my best to minimize the damage and as far as I'm aware only around 70 places leaked on the internet.</h5> a lot of noise.
<br> </p>
<h5>Thanks, sushi. it's been fun. Maybe we meet again <a href="/assets/2020.zip">2020 RCC</a></h5> <br />
<h5>
<input id="real" type="text" maxlength="56"> First of all, I had already decided to shut down before the
<button onclick="real(1)"></button> <a
<button onclick="real(2)"></button> href="https://docs.google.com/document/d/1GHwiaTWezaIRUSKgR7XG4VDB_tw88Zz2FCb40RI47yY/edit">
<button onclick="real(3)"></button> document
<button onclick="real(4)"></button> </a>
<button onclick="real(5)"></button> even came out. It didn't influence this decision in any way. Now, we
<button onclick="real(6)"></button> will skip over criticisms of the website itself as that doesn't matter.
<button onclick="real(7)"></button> Two problematic individuals in the community were a result of my bad
<button onclick="real(8)"></button> management and staff favoritism over members. Security of Meteorite was
<button onclick="real(9)"></button> compromised from a lazy config error but I did my best to minimize the
<button onclick="real(0)"></button> damage and as far as I'm aware only around 70 places leaked on the
<button onclick="real(11)"></button> internet.
<button onclick="real(111)"></button> </h5>
<button onclick="real(1111)"></button> <br />
<script> <h5>
function real(num){ Thanks, sushi. it's been fun. Maybe we meet again
document.cookie = "real="+num+document.getElementById('real').value; <a href="/assets/2020.zip">2020 RCC</a>
document.location.reload() </h5>
}
</script>
<input id="real" type="text" maxlength="56" />
<button onclick="real(1)"></button>
<button onclick="real(2)"></button>
<button onclick="real(3)"></button>
<button onclick="real(4)"></button>
<button onclick="real(5)"></button>
<button onclick="real(6)"></button>
<button onclick="real(7)"></button>
<button onclick="real(8)"></button>
<button onclick="real(9)"></button>
<button onclick="real(0)"></button>
<button onclick="real(11)"></button>
<button onclick="real(111)"></button>
<button onclick="real(1111)"></button>
<script>
function real(num) {
document.cookie =
"real=" + num + document.getElementById("real").value
document.location.reload()
}
</script>
</div> </div>

View File

@ -18,6 +18,8 @@
"@tailwindcss/typography": "^0.5.8", "@tailwindcss/typography": "^0.5.8",
"autoprefixer": "^10.4.13", "autoprefixer": "^10.4.13",
"postcss": "^8.4.21", "postcss": "^8.4.21",
"prettier": "^3.0.3",
"prettier-plugin-svelte": "^3.0.3",
"svelte": "^3.56.0", "svelte": "^3.56.0",
"svelte-check": "^3.0.3", "svelte-check": "^3.0.3",
"svelte-feather-icons": "^4.0.0", "svelte-feather-icons": "^4.0.0",

1674
Front/pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

1
Front/src/app.d.ts vendored
View File

@ -2,7 +2,6 @@
// for information about these interfaces // for information about these interfaces
// and what to do when importing types // and what to do when importing types
declare namespace App { declare namespace App {
interface Locals { interface Locals {
user: User | null user: User | null
jwt: cookie | null jwt: cookie | null

View File

@ -1,4 +1,4 @@
<!DOCTYPE html > <!doctype html>
<html lang="en" class="dark"> <html lang="en" class="dark">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
@ -7,6 +7,8 @@
%sveltekit.head% %sveltekit.head%
</head> </head>
<body data-sveltekit-preload-data="hover" data-theme="crimson"> <body data-sveltekit-preload-data="hover" data-theme="crimson">
<div style="display: contents" class="h-full overflow-hidden">%sveltekit.body%</div> <div style="display: contents" class="h-full overflow-hidden">
%sveltekit.body%
</div>
</body> </body>
</html> </html>

View File

@ -1,2 +1,5 @@
/*place global styles here */ /*place global styles here */
html, body { @apply h-full overflow-hidden; } html,
body {
@apply h-full overflow-hidden;
}

View File

@ -1,78 +1,93 @@
<script lang="ts"> <script lang="ts">
import Itemcard from "../itemcard.svelte"; import Itemcard from "../itemcard.svelte"
let currentPage = 1
let maxiumumPage = 1
let currentCategory = "All"
let queuecount = 0
let currentPage = 1; export let jwt: string
let maxiumumPage = 1;
let currentCategory = "All"
let queuecount = 0
export let jwt:string let items: []
async function updateItems() {
let items: []; const response = await fetch("admin/queue", {
async function updateItems(){ method: "POST",
body: JSON.stringify({ sort: currentCategory, page: currentPage }),
const response = await fetch('admin/queue',{method: "POST", body: JSON.stringify({sort: currentCategory,page: currentPage}),headers: {"content-type": "application/json",'Authorization': jwt,}}); headers: { "content-type": "application/json", Authorization: jwt },
const data = await response.json() })
if (!data.error){ const data = await response.json()
if (items){ if (!data.error) {
items.length = 0 if (items) {
items = items items.length = 0
} items = items
items = data.data }
items = items items = data.data
maxiumumPage = data.pages items = items
queuecount = data.count maxiumumPage = data.pages
} queuecount = data.count
}
}
} function setPage(value: number) {
function setPage(value: number){ if (currentPage - value >= 1 && currentPage - value <= maxiumumPage) {
if (currentPage-value >= 1 && currentPage-value <= maxiumumPage){ currentPage -= value
currentPage -= value updateItems()
updateItems() }
} }
} function setCategory(event: any) {
function setCategory(event: any){ currentCategory = event.target.innerText
currentCategory = event.target.innerText currentPage = 1
currentPage = 1 updateItems()
updateItems() }
} async function moderateaction(action: any, itemid: Number) {
async function moderateaction(action: any,itemid: Number){ console.log(action)
console.log(action) console.log(itemid)
console.log(itemid) const itemactionresult = await fetch("/api/moderate/queue", {
const itemactionresult = await fetch('/api/moderate/queue', { method: "POST",
method: 'POST', headers: {
headers: { "Content-Type": "application/json",
'Content-Type': 'application/json', Authorization: jwt,
'Authorization': jwt, },
}, body: JSON.stringify({
body: JSON.stringify({ action,
action, itemid,
itemid }),
}) })
}) const itemaction = await itemactionresult.json()
const itemaction = await itemactionresult.json() updateItems()
updateItems() }
updateItems()
}
updateItems()
</script> </script>
<div class="grow"> <div class="grow">
<h2 class="">Queue Count: {queuecount} </h2> <h2 class="">Queue Count: {queuecount}</h2>
<div class="flex flex-col flex-wrap md:grid sm:grid-cols-6 sm:grid-rows-5 gap-2"> <div
{#if items} class="flex flex-col flex-wrap md:grid sm:grid-cols-6 sm:grid-rows-5 gap-2">
{#each items as {Name, ItemId, Creator, Type}} {#if items}
<Itemcard itemname={Name} itemid={ItemId} moderation={true} type={Type} moderate={moderateaction}/> {#each items as { Name, ItemId, Creator, Type }}
{/each} <Itemcard
{/if} itemname={Name}
</div> itemid={ItemId}
<div class="flex flex-row space-x-2 justify-center"> moderation={true}
<button on:click={() => {setPage(1)}} class="btn btn-sm bg-surface-600 rounded-md">&lt;</button> type={Type}
<h5 class="">{currentPage} / {maxiumumPage}</h5> moderate={moderateaction} />
<button on:click={() => {setPage(-1)}} class="btn btn-sm bg-surface-600 rounded-md">&gt;</button> {/each}
</div> {/if}
</div>
<div class="flex flex-row space-x-2 justify-center">
<button
on:click={() => {
setPage(1)
}}
class="btn btn-sm bg-surface-600 rounded-md">
&lt;
</button>
<h5 class="">{currentPage} / {maxiumumPage}</h5>
<button
on:click={() => {
setPage(-1)
}}
class="btn btn-sm bg-surface-600 rounded-md">
&gt;
</button>
</div>
</div> </div>

View File

@ -1,58 +1,71 @@
<script lang="ts"> <script lang="ts">
let disabled = false let disabled = false
let message = {error: false, message: ""} let message = { error: false, message: "" }
let userid : any
let username : any
export let jwt: string
export let data
async function searchuser(){
const response = await fetch("admin/moderateuserlookup", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': jwt,
},
body: JSON.stringify({
userid: userid??"",
username: username??""
})
})
const responsejson = await response.json()
if (!responsejson.error){
message.message = "woo"
message.error = false
data = responsejson.data
}else{
message.message = responsejson.error
message.error = true
}
}
$:if (!userid && !username){
disabled = true
message.message = "Enter userid or username"
message.error = true
}else if(userid && username){
disabled = true
message.message = "You can only search userid or username dummy"
message.error = true
}
else{
disabled = false
message.message = ""
message.error = false
}
let userid: any
let username: any
export let jwt: string
export let data
async function searchuser() {
const response = await fetch("admin/moderateuserlookup", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: jwt,
},
body: JSON.stringify({
userid: userid ?? "",
username: username ?? "",
}),
})
const responsejson = await response.json()
if (!responsejson.error) {
message.message = "woo"
message.error = false
data = responsejson.data
} else {
message.message = responsejson.error
message.error = true
}
}
$: if (!userid && !username) {
disabled = true
message.message = "Enter userid or username"
message.error = true
} else if (userid && username) {
disabled = true
message.message = "You can only search userid or username dummy"
message.error = true
} else {
disabled = false
message.message = ""
message.error = false
}
</script> </script>
<div class="flex flex-wrap space-y-2"> <div class="flex flex-wrap space-y-2">
<input
<input type="text" bind:value={userid} placeholder="UserID" class="input input-bordered input-primary w-full rounded-md"> type="text"
<div class="w-full !text-xs">or</div> bind:value={userid}
<input type="text" bind:value={username} placeholder="Username" class="input input-bordered input-primary w-full rounded-md"> placeholder="UserID"
<div class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</div> class="input input-bordered input-primary w-full rounded-md" />
<button type="submit" on:click={searchuser} class="btn variant-filled-primary btn-sm w-full rounded-md" disabled={disabled}>Search</button> <div class="w-full !text-xs">or</div>
<input
type="text"
bind:value={username}
placeholder="Username"
class="input input-bordered input-primary w-full rounded-md" />
<div
class="!text-xs mt-6 {message.error === true
? 'text-error-600'
: 'text-success-600'}">
{message.message ?? ""}
</div>
<button
type="submit"
on:click={searchuser}
class="btn variant-filled-primary btn-sm w-full rounded-md"
{disabled}>
Search
</button>
</div> </div>

View File

@ -1,144 +1,198 @@
<script lang="ts"> <script lang="ts">
import { Avatar } from "@skeletonlabs/skeleton"; import { Avatar } from "@skeletonlabs/skeleton"
export let lookupdata:any export let lookupdata: any
export let jwt:string export let jwt: string
let lookupaction = "Banned" let lookupaction = "Banned"
let banreason: string let banreason: string
let expirationdate: string let expirationdate: string
let disabled = false let disabled = false
let message = {error: false, message: ""} let message = { error: false, message: "" }
$:if (!banreason || banreason === ""){ $: if (!banreason || banreason === "") {
disabled = true disabled = true
message.message = "Enter ban reason" message.message = "Enter ban reason"
message.error = true message.error = true
}else if(!expirationdate && lookupaction === "Banned"){ } else if (!expirationdate && lookupaction === "Banned") {
disabled = true disabled = true
message.message = "Date required" message.message = "Date required"
message.error = true message.error = true
}else{ } else {
disabled = false disabled = false
message.message = "" message.message = ""
message.error = false message.error = false
} }
async function submitaction(){
const response = await fetch("admin/moderateuser", {
method: 'POST',
body: JSON.stringify({userid: lookupdata.userid,reason:banreason,unbantime:expirationdate??"0",Type:lookupaction}),
headers: {
'Content-Type': 'application/json',
'Authorization': jwt,
}
})
const json = await response.json()
if (!json.error){
message.message = json.message
message.error = false
}else{
message.message = json.error
message.error = true
}
}
async function submitaction() {
const response = await fetch("admin/moderateuser", {
method: "POST",
body: JSON.stringify({
userid: lookupdata.userid,
reason: banreason,
unbantime: expirationdate ?? "0",
Type: lookupaction,
}),
headers: {
"Content-Type": "application/json",
Authorization: jwt,
},
})
const json = await response.json()
if (!json.error) {
message.message = json.message
message.error = false
} else {
message.message = json.error
message.error = true
}
}
</script> </script>
<div class="w-full flex flex-row gap-6"> <div class="w-full flex flex-row gap-6">
<div>
<h5>Action:</h5>
<div> <label>
<input type="radio" bind:group={lookupaction} value="Banned" />
Ban
</label>
<h5>Action:</h5> <label>
<input
type="radio"
bind:group={lookupaction}
value="Permanent Ban" />
Permanent Ban
</label>
<label> <label>
<input type=radio bind:group={lookupaction} value="Banned"> <input type="radio" bind:group={lookupaction} value="Warning" />
Ban Warning
</label> </label>
<label> {#if lookupaction === "Banned"}
<input type=radio bind:group={lookupaction} value="Permanent Ban"> <input bind:value={expirationdate} type="date" />
Permanent Ban {/if}
</label> </div>
<label> <div class="flex flex-col gap-y-1">
<input type=radio bind:group={lookupaction} value="Warning"> <h5>Auto Fill:</h5>
Warning <button
</label> type="submit"
on:click={() => {
{#if lookupaction === "Banned"} banreason = "real"
<input bind:value={expirationdate} type="date" /> }}
{/if} class="btn variant-filled-primary btn-sm w-full rounded-md">
Exploiting
</div> </button>
<button
<div class="flex flex-col gap-y-1"> type="submit"
on:click={() => {
<h5>Auto Fill: </h5> banreason =
<button type="submit" on:click={()=> {banreason="real"}} class="btn variant-filled-primary btn-sm w-full rounded-md" >Exploiting</button> "Adult content is not allowed on Meteorite. You are not allowed to create new accounts."
<button type="submit" on:click={()=> {banreason="Adult content is not allowed on Meteorite. You are not allowed to create new accounts."}} class="btn variant-filled-primary btn-sm w-full rounded-md" >NSFW</button> }}
</div> class="btn variant-filled-primary btn-sm w-full rounded-md">
NSFW
<div class="grow space-y-2"> </button>
<h5>Moderator Note:</h5> </div>
<textarea bind:value={banreason} class="input input-bordered input-primary w-full rounded-md h-32"></textarea>
<div class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</div>
<div class="flex flex-row justify-around gap-4">
<button type="submit" on:click={submitaction} class="btn variant-filled-primary btn-base grow rounded-md"disabled={disabled} >Submit</button>
<button type="submit" on:click={() => {lookupdata = null}} class="btn variant-filled-primary btn-base rounded-md" >Close</button>
</div>
</div>
<div class="grow space-y-2">
<h5>Moderator Note:</h5>
<textarea
bind:value={banreason}
class="input input-bordered input-primary w-full rounded-md h-32">
</textarea>
<div
class="!text-xs mt-6 {message.error === true
? 'text-error-600'
: 'text-success-600'}">
{message.message ?? ""}
</div>
<div class="flex flex-row justify-around gap-4">
<button
type="submit"
on:click={submitaction}
class="btn variant-filled-primary btn-base grow rounded-md"
{disabled}>
Submit
</button>
<button
type="submit"
on:click={() => {
lookupdata = null
}}
class="btn variant-filled-primary btn-base rounded-md">
Close
</button>
</div>
</div>
</div> </div>
<div class="flex flex-row justify-around w-full border-none gap-8"> <div class="flex flex-row justify-around w-full border-none gap-8">
<div class="w-96 flex flex-wrap flex-row bg-surface-700 rounded-md p-4 border-none divide-y"> <div
<div class="flex flex-row w-full"> class="w-96 flex flex-wrap flex-row bg-surface-700 rounded-md p-4 border-none divide-y">
<h5 class="font-bold grow">{lookupdata.username}</h5> <div class="flex flex-row w-full">
</div> <h5 class="font-bold grow">{lookupdata.username}</h5>
</div>
<div class="flex flex-row w-full grow"> <div class="flex flex-row w-full grow">
<a class="unstyled" href="/users/{lookupdata.userid}"><Avatar src="/api/thumbnailrender/?id={lookupdata.userid}" background="" width="w-32" /></a> <a class="unstyled" href="/users/{lookupdata.userid}">
<Avatar
src="/api/thumbnailrender/?id={lookupdata.userid}"
background=""
width="w-32" />
</a>
<div> <div>
{#if JSON.parse(lookupdata.moderation).status.toUpperCase() != "OK"}
{#if JSON.parse(lookupdata.moderation).status.toUpperCase() != "OK"} <h5 class="!text-sm flex flex-row gap-1">
<h5 class="!text-sm flex flex-row gap-1">Moderation Status: <h5 class="!text-sm text-error-600">{JSON.parse(lookupdata.moderation).status}</h5></h5> Moderation Status: <h5 class="!text-sm text-error-600">
{:else} {JSON.parse(lookupdata.moderation).status}
<h5 class="!text-sm flex flex-row gap-1">Moderation Status: <h5 class="!text-sm text-success-600">{JSON.parse(lookupdata.moderation).status}</h5></h5> </h5>
{/if} </h5>
<h5 class="!text-sm">Rocks: {lookupdata.coins}</h5> {:else}
<h5 class="!text-sm">Discord ID: {lookupdata.discordid??"Not Linked"}</h5> <h5 class="!text-sm flex flex-row gap-1">
<a><h5 class="!text-sm">View Screenshots</h5></a> Moderation Status: <h5
<a><h5 class="!text-sm">View Identity</h5></a> class="!text-sm text-success-600">
</div> {JSON.parse(lookupdata.moderation).status}
</h5>
</div> </h5>
{/if}
<h5 class="!text-sm">Rocks: {lookupdata.coins}</h5>
</div> <h5 class="!text-sm">
<div class="table-container rounded-none h-52"> Discord ID: {lookupdata.discordid ?? "Not Linked"}
<h5>Moderation History</h5> </h5>
<table class="table table-hover"> <a><h5 class="!text-sm">View Screenshots</h5></a>
<thead> <a><h5 class="!text-sm">View Identity</h5></a>
<tr> </div>
<th>Type</th> </div>
<th>Reason</th> </div>
<th>BannedBy</th> <div class="table-container rounded-none h-52">
<th>Date</th> <h5>Moderation History</h5>
</tr> <table class="table table-hover">
</thead> <thead>
<tbody> <tr>
{#if lookupdata.moderationhistory} <th>Type</th>
{#each lookupdata.moderationhistory as {status, Reason, BannedBy, Date}} <th>Reason</th>
<tr> <th>BannedBy</th>
<td>{status}</td> <th>Date</th>
<td style="white-space: nowrap; text-overflow:ellipsis; overflow: hidden; max-width:1px;">{Reason}</td> </tr>
<td>{BannedBy}</td> </thead>
<td>{Date}</td> <tbody>
</tr> {#if lookupdata.moderationhistory}
{/each} {#each lookupdata.moderationhistory as { status, Reason, BannedBy, Date }}
{/if} <tr>
</tbody> <td>{status}</td>
</table> <td
</div> style="white-space: nowrap; text-overflow:ellipsis; overflow: hidden; max-width:1px;">
{Reason}
</td>
<td>{BannedBy}</td>
<td>{Date}</td>
</tr>
{/each}
{/if}
</tbody>
</table>
</div>
</div> </div>

View File

@ -1,58 +1,69 @@
<script lang="ts"> <script lang="ts">
let message = {error: false, message: ""} let message = { error: false, message: "" }
let disabled = false let disabled = false
let AdId = "" let AdId = ""
export let jwt: string export let jwt: string
export let itemid: string export let itemid: string
export let type: string export let type: string
async function advertise(){ async function advertise() {
const result = await fetch('/api/advertise', { const result = await fetch("/api/advertise", {
method: 'POST', method: "POST",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
'Authorization': jwt, Authorization: jwt,
}, },
body: JSON.stringify({ body: JSON.stringify({
itemid, itemid,
AdId, AdId,
type type,
}) }),
}) })
const advertiseresult = await result.json() const advertiseresult = await result.json()
if (!advertiseresult.error){ if (!advertiseresult.error) {
message.message = advertiseresult.message message.message = advertiseresult.message
message.error = false message.error = false
}else{ } else {
message.message = advertiseresult.error message.message = advertiseresult.error
message.error = true message.error = true
} }
} }
$:if (!AdId){ $: if (!AdId) {
disabled = true disabled = true
message.message = "Ad ID not inputted" message.message = "Ad ID not inputted"
message.error = true message.error = true
}else{ } else {
disabled = false disabled = false
message.message = "" message.message = ""
message.error = false message.error = false
} }
</script> </script>
<h5>Advertise</h5> <h5>Advertise</h5>
<div class="p-2 space-y-2"> <div class="p-2 space-y-2">
<label class="label"> <label class="label">
<span>Ad ID</span> <span>Ad ID</span>
<input type="number" bind:value={AdId} class="input input-bordered input-primary w-full rounded-md" required> <input
</label> type="number"
bind:value={AdId}
<div> class="input input-bordered input-primary w-full rounded-md"
required />
<h5 class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</h5> </label>
<button on:click={advertise} class="btn variant-filled-primary btn-base w-full rounded-md" disabled={disabled}>
Advertise for 10 Rocks (For 24 hours)
</button>
</div> <div>
<h5
class="!text-xs mt-6 {message.error === true
? 'text-error-600'
: 'text-success-600'}">
{message.message ?? ""}
</h5>
<button
on:click={advertise}
class="btn variant-filled-primary btn-base w-full rounded-md"
{disabled}>
Advertise for 10 Rocks (For 24 hours)
</button>
</div>
</div> </div>

File diff suppressed because it is too large Load Diff

View File

@ -1,110 +1,141 @@
<script lang="ts"> <script lang="ts">
import { Avatar } from "@skeletonlabs/skeleton"; import { Avatar } from "@skeletonlabs/skeleton"
import RelativeTime from '@yaireo/relative-time' import RelativeTime from "@yaireo/relative-time"
import { url } from "$lib/url" import { url } from "$lib/url"
const relativeTime = new RelativeTime() const relativeTime = new RelativeTime()
export let width: String; export let width: String
export let PostText = "Post Comment" export let PostText = "Post Comment"
export let PlaceholderText = "Write a comment!" export let PlaceholderText = "Write a comment!"
export let disabled = true export let disabled = true
export let AssociatedAssetType: String export let AssociatedAssetType: String
export let AssociatedAssetId: String export let AssociatedAssetId: String
export let jwt: string export let jwt: string
let comment: String let comment: String
let currentPage = 1; let currentPage = 1
let maxiumumPage = 1; let maxiumumPage = 1
//export let type:string //export let type:string
let loading = true let loading = true
let comments: any let comments: any
$:if (!comment){ $: if (!comment) {
disabled = true disabled = true
}else{ } else {
disabled = false disabled = false
} }
async function postComment(){ async function postComment() {
const response = await fetch("/api/comments/post", { const response = await fetch("/api/comments/post", {
method: 'POST', method: "POST",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
'Authorization': jwt, Authorization: jwt,
}, },
body: JSON.stringify({ body: JSON.stringify({
comment, comment,
AssociatedAssetType, AssociatedAssetType,
AssociatedAssetId AssociatedAssetId,
}) }),
}) })
const responsedata = await response.json() const responsedata = await response.json()
if (!responsedata.error){ if (!responsedata.error) {
loadComments() loadComments()
}else{ } else {
}
}
} async function loadComments() {
} const res = await fetch(url + "/api/comments/get", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: jwt,
},
body: JSON.stringify({
AssociatedAssetType,
AssociatedAssetId,
page: currentPage,
}),
})
comments = await res.json()
if (comments.error) {
comments = []
}
maxiumumPage = comments.pages
loading = false
}
loadComments()
async function loadComments(){ function setPage(value: number) {
const res = await fetch(url+"/api/comments/get", { if (currentPage - value >= 1 && currentPage - value <= maxiumumPage) {
method: 'POST', currentPage -= value
headers: { loadComments()
'Content-Type': 'application/json', }
'Authorization': jwt, }
},
body: JSON.stringify({
AssociatedAssetType,
AssociatedAssetId,
page: currentPage
})
})
comments = await res.json()
if (comments.error){
comments = []
}
maxiumumPage = comments.pages
loading = false
}
loadComments()
function setPage(value: number){
if (currentPage-value >= 1 && currentPage-value <= maxiumumPage){
currentPage -= value
loadComments()
}
}
</script> </script>
<div class="bg-surface-700 p-4 space-x-4 space-y-4 flex flex-row flex-wrap max-w-[{width}px] m-0 m-auto">
<div class="flex flex-row w-full space-x-4">
<textarea class="rounded-md grow input input-bordered input-primary" maxlength={200} bind:value={comment} placeholder={PlaceholderText} />
<button on:click={postComment} class="btn mt-6 variant-filled-primary rounded-md "disabled={disabled}>{PostText}</button>
</div>
<div class="w-full"> <div
{#if loading === true} class="bg-surface-700 p-4 space-x-4 space-y-4 flex flex-row flex-wrap max-w-[{width}px] m-0 m-auto">
<p>Loading...</p> <div class="flex flex-row w-full space-x-4">
{:else if loading === false && comments.data.length === 0} <textarea
<p>No comments found.</p> class="rounded-md grow input input-bordered input-primary"
{:else if loading === false} maxlength={200}
bind:value={comment}
placeholder={PlaceholderText} />
<button
on:click={postComment}
class="btn mt-6 variant-filled-primary rounded-md"
{disabled}>
{PostText}
</button>
</div>
{#each comments.data as {content, posterid, date, poster}} <div class="w-full">
<div class="flex flex-row gap-x-6"> {#if loading === true}
<a class="unstyled" href="/users/{posterid}"><Avatar src={"/api/thumbnailrender/?id="+posterid+"&type=headshot"} width="w-14" /></a> <p>Loading...</p>
<div> {:else if loading === false && comments.data.length === 0}
<a class='truncate !text-base' href="/users/{posterid}">{poster.username}</a> <p>No comments found.</p>
<h5 class="!text-base whitespace-pre-line overflow-hidden">"{content}"</h5> {:else if loading === false}
<h5 class="!text-xs">Posted {relativeTime.from(new Date(date))}</h5> {#each comments.data as { content, posterid, date, poster }}
</div> <div class="flex flex-row gap-x-6">
</div> <a class="unstyled" href="/users/{posterid}">
<Avatar
{/each} src={"/api/thumbnailrender/?id=" +
<div class="flex flex-row gap-x-2 justify-center"> posterid +
<button on:click={() => {setPage(1)}} class="btn btn-sm bg-surface-600 rounded-md">&lt;</button> "&type=headshot"}
<h5 class="">{currentPage} / {maxiumumPage}</h5> width="w-14" />
<button on:click={() => {setPage(-1)}} class="btn btn-sm bg-surface-600 rounded-md">&gt;</button> </a>
</div> <div>
<a class="truncate !text-base" href="/users/{posterid}">
{/if} {poster.username}
</div> </a>
<h5
</div> class="!text-base whitespace-pre-line overflow-hidden">
"{content}"
</h5>
<h5 class="!text-xs">
Posted {relativeTime.from(new Date(date))}
</h5>
</div>
</div>
{/each}
<div class="flex flex-row gap-x-2 justify-center">
<button
on:click={() => {
setPage(1)
}}
class="btn btn-sm bg-surface-600 rounded-md">
&lt;
</button>
<h5 class="">{currentPage} / {maxiumumPage}</h5>
<button
on:click={() => {
setPage(-1)
}}
class="btn btn-sm bg-surface-600 rounded-md">
&gt;
</button>
</div>
{/if}
</div>
</div>

View File

@ -1,91 +1,105 @@
<script lang="ts"> <script lang="ts">
let message = {error: false, message: ""} let message = { error: false, message: "" }
let disabled = false let disabled = false
let itemname: string let itemname: string
let itemdesc: string let itemdesc: string
let files: FileList; let files: FileList
let price:string let price: string
let creations: any[] = [] let creations: any[] = []
$:if (!itemname || !price){ $: if (!itemname || !price) {
disabled = true disabled = true
message.message = "Item name and price required." message.message = "Item name and price required."
message.error = true message.error = true
}else if (!files){ } else if (!files) {
disabled = true disabled = true
message.message = "File required." message.message = "File required."
message.error = true message.error = true
}else{ } else {
disabled = false disabled = false
message.message = "" message.message = ""
message.error = false message.error = false
} }
export let type:string export let type: string
export let jwt: string export let jwt: string
async function upload(){ async function upload() {
const formData = new FormData(); const formData = new FormData()
formData.append("itemfile", files[0]) formData.append("itemfile", files[0])
formData.append("itemname", itemname) formData.append("itemname", itemname)
formData.append("description", itemdesc??"No Description") formData.append("description", itemdesc ?? "No Description")
formData.append("price", price) formData.append("price", price)
formData.append("Type", type) formData.append("Type", type)
const req = await fetch("/admin/uploaditem", { const req = await fetch("/admin/uploaditem", {
method: "post", method: "post",
body: formData, body: formData,
headers: { headers: {
'Authorization': jwt, Authorization: jwt,
}, },
}); })
const res = await req.json(); const res = await req.json()
if (!res.error){
message.message = "Done!"
message.error = false
}else{
message.message = res.error
message.error = true
}
}
if (!res.error) {
message.message = "Done!"
message.error = false
} else {
message.message = res.error
message.error = true
}
}
</script> </script>
<div class="space-y-2 grow"> <div class="space-y-2 grow">
<h3>{type}</h3> <h3>{type}</h3>
<label class="input-label"> <label class="input-label">
<span class="pt-3">Find your rbxm:</span>
<span class="pt-3">Find your rbxm:</span> <input class="w-fit" accept=".rbxm" bind:files type="file" />
</label>
<label class="input-label gap-8">
<span class="pt-3">{type} Name:</span>
<input
bind:value={itemname}
type="text"
class="input input-bordered input-primary w-full max-w-md rounded-md"
required />
</label>
<input class="w-fit" accept=".rbxm" bind:files type="file" /> <label class="input-label gap-8">
<span class="pt-3">Description:</span>
<input
bind:value={itemdesc}
type="text"
class="input input-bordered input-primary w-full max-w-md rounded-md"
required />
</label>
</label> <label class="input-label gap-8">
<label class="input-label gap-8"> <span class="pt-3">Price:</span>
<span class="pt-3">{type} Name:</span> <input
<input bind:value={itemname} type="text" class="input input-bordered input-primary w-full max-w-md rounded-md" required> bind:value={price}
</label> type="number"
class="input input-bordered input-primary w-full max-w-md rounded-md"
required />
</label>
<label class="input-label gap-8"> <h5
<span class="pt-3">Description:</span> class="!text-xs mt-6 {message.error === true
<input bind:value={itemdesc} type="text" class="input input-bordered input-primary w-full max-w-md rounded-md" required> ? 'text-error-600'
</label> : 'text-success-600'}">
{message.message ?? ""}
<label class="input-label gap-8"> </h5>
<span class="pt-3">Price:</span>
<input bind:value={price} type="number" class="input input-bordered input-primary w-full max-w-md rounded-md" required>
</label>
<h5 class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</h5>
<button on:click={upload} type="submit" class="btn variant-filled-primary btn-sm text-base rounded-md" disabled={disabled}>Upload for 0 Rocks</button>
<div class="pt-8 space-y-4">
<button
on:click={upload}
type="submit"
class="btn variant-filled-primary btn-sm text-base rounded-md"
{disabled}>
Upload for 0 Rocks
</button>
</div> <div class="pt-8 space-y-4"></div>
</div> </div>

View File

@ -1,95 +1,109 @@
<script lang="ts"> <script lang="ts">
let message = {error: false, message: ""} let message = { error: false, message: "" }
let disabled = false let disabled = false
let itemname: string let itemname: string
let itemdesc: string let itemdesc: string
let files: FileList; let files: FileList
let price:string let price: string
let creations: any[] = [] let creations: any[] = []
$:if (!itemname || !price){ $: if (!itemname || !price) {
disabled = true disabled = true
message.message = "Item name and price required." message.message = "Item name and price required."
message.error = true message.error = true
}else if (!files){ } else if (!files) {
disabled = true disabled = true
message.message = "File required." message.message = "File required."
message.error = true message.error = true
}else{ } else {
disabled = false disabled = false
message.message = "" message.message = ""
message.error = false message.error = false
} }
export let type:string export let type: string
export let jwt: string export let jwt: string
async function upload(){ async function upload() {
const formData = new FormData(); const formData = new FormData()
formData.append("itemfile", files[0]) formData.append("itemfile", files[0])
formData.append("itemname", itemname) formData.append("itemname", itemname)
formData.append("description", itemdesc) formData.append("description", itemdesc)
formData.append("price", price) formData.append("price", price)
formData.append("Type", type) formData.append("Type", type)
const req = await fetch("/admin/uploaditem", { const req = await fetch("/admin/uploaditem", {
method: "post", method: "post",
body: formData, body: formData,
headers: { headers: {
'Authorization': jwt, Authorization: jwt,
}, },
}); })
const res = await req.json(); const res = await req.json()
if (!res.error){
message.message = "Done!"
message.error = false
}else{
message.message = res.error
message.error = true
}
}
if (!res.error) {
message.message = "Done!"
message.error = false
} else {
message.message = res.error
message.error = true
}
}
</script> </script>
<div class="space-y-2 grow"> <div class="space-y-2 grow">
{#if type === "Packages"} {#if type === "Packages"}
<h3>Create a Package</h3> <h3>Create a Package</h3>
{/if} {/if}
<label class="input-label"> <label class="input-label">
<span class="pt-3">Find your rbxm:</span>
<span class="pt-3">Find your rbxm:</span> <input class="w-fit" accept=".rbxm" bind:files type="file" />
</label>
<label class="input-label gap-8">
{#if type === "Packages"}
<span class="pt-3">{type} Name:</span>
{/if}
<input
bind:value={itemname}
type="text"
class="input input-bordered input-primary w-full max-w-md rounded-md"
required />
</label>
<input class="w-fit" accept=".rbxm" bind:files type="file" /> <label class="input-label gap-8">
<span class="pt-3">Description:</span>
<input
bind:value={itemdesc}
type="text"
class="input input-bordered input-primary w-full max-w-md rounded-md"
required />
</label>
</label> <label class="input-label gap-8">
<label class="input-label gap-8"> <span class="pt-3">Price:</span>
{#if type === "Packages"} <input
<span class="pt-3">{type} Name:</span> bind:value={price}
{/if} type="number"
<input bind:value={itemname} type="text" class="input input-bordered input-primary w-full max-w-md rounded-md" required> class="input input-bordered input-primary w-full max-w-md rounded-md"
</label> required />
</label>
<label class="input-label gap-8"> <h5
<span class="pt-3">Description:</span> class="!text-xs mt-6 {message.error === true
<input bind:value={itemdesc} type="text" class="input input-bordered input-primary w-full max-w-md rounded-md" required> ? 'text-error-600'
</label> : 'text-success-600'}">
{message.message ?? ""}
<label class="input-label gap-8"> </h5>
<span class="pt-3">Price:</span>
<input bind:value={price} type="number" class="input input-bordered input-primary w-full max-w-md rounded-md" required>
</label>
<h5 class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</h5>
<button on:click={upload} type="submit" class="btn variant-filled-primary btn-sm text-base rounded-md" disabled={disabled}>Upload for 0 Rocks</button>
<div class="pt-8 space-y-4">
<button
on:click={upload}
type="submit"
class="btn variant-filled-primary btn-sm text-base rounded-md"
{disabled}>
Upload for 0 Rocks
</button>
</div> <div class="pt-8 space-y-4"></div>
</div> </div>

View File

@ -1,168 +1,189 @@
<script lang="ts"> <script lang="ts">
import Createditems from "../develop/createditems.svelte" import Createditems from "../develop/createditems.svelte"
import { url } from "$lib/url" import { url } from "$lib/url"
let message = {error: false, message: ""} let message = { error: false, message: "" }
let disabled = false let disabled = false
let itemname: string let itemname: string
let files: FileList; let files: FileList
let price:string let price: string
let associatedgameid:string let associatedgameid: string
let creations: any[] = [] let creations: any[] = []
$:if (!itemname){ $: if (!itemname) {
disabled = true disabled = true
message.message = "Item name required." message.message = "Item name required."
message.error = true message.error = true
}else if (!files){ } else if (!files) {
disabled = true disabled = true
message.message = "File required." message.message = "File required."
message.error = true message.error = true
}else if (type === "gamepasses" && (!price || !associatedgameid)){ } else if (type === "gamepasses" && (!price || !associatedgameid)) {
disabled = true disabled = true
message.message = "Price and associated game id required." message.message = "Price and associated game id required."
message.error = true message.error = true
} } else {
else{ disabled = false
disabled = false message.message = ""
message.message = "" message.error = false
message.error = false }
}
export let type:string export let type: string
export let jwt: string export let jwt: string
async function updatecreations(){ async function updatecreations() {
const response = await fetch(url+'/develop/creations',{method: "POST", body: JSON.stringify({type}),headers: {"content-type": "application/json", 'Authorization': jwt,}}); const response = await fetch(url + "/develop/creations", {
const data = await response.json() method: "POST",
if (!data.error){ body: JSON.stringify({ type }),
creations = data headers: { "content-type": "application/json", Authorization: jwt },
//console.log(creations) })
} const data = await response.json()
} if (!data.error) {
updatecreations() creations = data
//console.log(creations)
}
}
updatecreations()
async function upload(){ async function upload() {
const formData = new FormData(); const formData = new FormData()
formData.append("assetfile", files[0]) formData.append("assetfile", files[0])
formData.append("itemname", itemname) formData.append("itemname", itemname)
formData.append("price", price) formData.append("price", price)
formData.append("gameid", associatedgameid) formData.append("gameid", associatedgameid)
const req = await fetch("/develop/upload"+type, { const req = await fetch("/develop/upload" + type, {
method: "post", method: "post",
body: formData, body: formData,
headers: { headers: {
'Authorization': jwt, Authorization: jwt,
}, },
}); })
const res = await req.json(); const res = await req.json()
if (!res.error){ if (!res.error) {
message.message = "Done!" message.message = "Done!"
message.error = false message.error = false
updatecreations() updatecreations()
}else{ } else {
message.message = res.error message.message = res.error
message.error = true message.error = true
} }
}
$: type, updatecreations() // if type variable changes run updatecreations again
}
$:type,updatecreations() // if type variable changes run updatecreations again
</script> </script>
<div class="space-y-2 grow"> <div class="space-y-2 grow">
{#if type === "audios"} {#if type === "audios"}
<h3>Create a Audio</h3> <h3>Create a Audio</h3>
{:else if type === "badges"} {:else if type === "badges"}
<h3>Create a Badge</h3> <h3>Create a Badge</h3>
{:else if type === "meshes"} {:else if type === "meshes"}
<h3>Create a Mesh</h3> <h3>Create a Mesh</h3>
{:else if type === "userads"} {:else if type === "userads"}
<h3>Create a User Ad</h3> <h3>Create a User Ad</h3>
{:else if type === "gamepasses"} {:else if type === "gamepasses"}
<h3>Create a Gamepass</h3> <h3>Create a Gamepass</h3>
{:else if type === "videos"} {:else if type === "videos"}
<h3>Create a Video</h3> <h3>Create a Video</h3>
{/if} {/if}
<label class="input-label"> <label class="input-label">
{#if type === "badges" || type === "userads" || type === "gamepasses"} {#if type === "badges" || type === "userads" || type === "gamepasses"}
<span class="pt-3">Find your image:</span> <span class="pt-3">Find your image:</span>
{:else if type === "meshes"} {:else if type === "meshes"}
<span class="pt-3">Find your mesh:</span> <span class="pt-3">Find your mesh:</span>
{:else if type === "audios"} {:else if type === "audios"}
<span class="pt-3">Find your audio:</span> <span class="pt-3">Find your audio:</span>
{:else if type === "videos"} {:else if type === "videos"}
<span class="pt-3">Find your video:</span> <span class="pt-3">Find your video:</span>
{/if} {/if}
{#if type === "audios"} {#if type === "audios"}
<input class="w-fit" accept="audio/mp3" bind:files type="file" /> <input class="w-fit" accept="audio/mp3" bind:files type="file" />
{:else if type === "meshes"} {:else if type === "meshes"}
<input class="w-fit" accept=".mesh" bind:files type="file" /> <input class="w-fit" accept=".mesh" bind:files type="file" />
{:else if type === "badges" || type === "userads" || type === "gamepasses"} {:else if type === "badges" || type === "userads" || type === "gamepasses"}
<input class="w-fit" accept="image/png" bind:files type="file" /> <input class="w-fit" accept="image/png" bind:files type="file" />
{:else if type === "videos"} {:else if type === "videos"}
<input class="w-fit" accept=".webm" bind:files type="file" /> <input class="w-fit" accept=".webm" bind:files type="file" />
{/if} {/if}
</label>
<label class="input-label gap-8">
{#if type === "audios"}
<span class="pt-3">Audio Name:</span>
{:else if type === "badges"}
<span class="pt-3">Badge Name:</span>
{:else if type === "meshes"}
<span class="pt-3">Mesh Name:</span>
{:else if type === "userads"}
<span class="pt-3">Ad Name:</span>
{:else if type === "gamepasses"}
<span class="pt-3">Gamepass Name:</span>
{:else if type === "videos"}
<span class="pt-3">Video Name:</span>
{/if}
<input
bind:value={itemname}
type="text"
class="input input-bordered input-primary w-full max-w-md rounded-md"
required />
</label>
</label> {#if type === "gamepasses"}
<label class="input-label gap-8"> <label class="input-label gap-8">
{#if type === "audios"} <span class="pt-3">Price:</span>
<span class="pt-3">Audio Name:</span> <input
{:else if type === "badges"} bind:value={price}
<span class="pt-3">Badge Name:</span> type="number"
{:else if type === "meshes"} class="input input-bordered input-primary w-full max-w-md rounded-md"
<span class="pt-3">Mesh Name:</span> required />
{:else if type === "userads"} </label>
<span class="pt-3">Ad Name:</span> {/if}
{:else if type === "gamepasses"}
<span class="pt-3">Gamepass Name:</span>
{:else if type === "videos"}
<span class="pt-3">Video Name:</span>
{/if}
<input bind:value={itemname} type="text" class="input input-bordered input-primary w-full max-w-md rounded-md" required>
</label>
{#if type === "gamepasses"} {#if type === "gamepasses"}
<label class="input-label gap-8"> <label class="input-label gap-8">
<span class="pt-3">Price:</span> <span class="pt-3">Associated game id:</span>
<input bind:value={price} type="number" class="input input-bordered input-primary w-full max-w-md rounded-md" required> <input
</label> bind:value={associatedgameid}
{/if} type="number"
class="input input-bordered input-primary w-full max-w-md rounded-md"
required />
</label>
{/if}
{#if type === "gamepasses"} <h5
<label class="input-label gap-8"> class="!text-xs mt-6 {message.error === true
<span class="pt-3">Associated game id:</span> ? 'text-error-600'
<input bind:value={associatedgameid} type="number" class="input input-bordered input-primary w-full max-w-md rounded-md" required> : 'text-success-600'}">
</label> {message.message ?? ""}
{/if} </h5>
<h5 class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</h5> <button
on:click={upload}
type="submit"
class="btn variant-filled-primary btn-sm text-base rounded-md"
{disabled}>
Upload for 0 Rocks
</button>
<button on:click={upload} type="submit" class="btn variant-filled-primary btn-sm text-base rounded-md" disabled={disabled}>Upload for 0 Rocks</button> <div class="pt-8 space-y-4">
{#if type === "audios"}
<div class="pt-8 space-y-4"> <h3>Audios</h3>
{#if type === "audios"} {:else if type === "badges"}
<h3>Audios</h3> <h3>Badges</h3>
{:else if type === "badges"} {:else if type === "meshes"}
<h3>Badges</h3> <h3>Meshes</h3>
{:else if type === "meshes"} {:else if type === "userads"}
<h3>Meshes</h3> <h3>User Ads</h3>
{:else if type === "userads"} {:else if type === "gamepasses"}
<h3>User Ads</h3> <h3>Gamepasses</h3>
{:else if type === "gamepasses"} {:else if type === "videos"}
<h3>Gamepasses</h3> <h3>Videos</h3>
{:else if type === "videos"} {/if}
<h3>Videos</h3>
{/if}
{#each creations as {Name, ItemId, Description}}
<Createditems itemname={Name} itemid={ItemId} type={type} />
{/each}
</div>
{#each creations as { Name, ItemId, Description }}
<Createditems itemname={Name} itemid={ItemId} {type} />
{/each}
</div>
</div> </div>

View File

@ -1,122 +1,143 @@
<script lang="ts"> <script lang="ts">
import { coinstore } from "$lib/coinstore" import { coinstore } from "$lib/coinstore"
import Createditems from "../develop/createditems.svelte" import Createditems from "../develop/createditems.svelte"
import { url } from "$lib/url" import { url } from "$lib/url"
let message = {error: false, message: ""} let message = { error: false, message: "" }
let disabled = false let disabled = false
let itemname: string let itemname: string
let itemdesc: string let itemdesc: string
let files: FileList; let files: FileList
let price:string let price: string
let creations: any[] = [] let creations: any[] = []
$:if (!itemname || !price){ $: if (!itemname || !price) {
disabled = true disabled = true
message.message = "Item name and price required." message.message = "Item name and price required."
message.error = true message.error = true
}else if (parseFloat(price) < 5){ } else if (parseFloat(price) < 5) {
disabled = true disabled = true
message.message = "Minimum price is 5 rocks." message.message = "Minimum price is 5 rocks."
message.error = true message.error = true
}else if (!files){ } else if (!files) {
disabled = true disabled = true
message.message = "File required." message.message = "File required."
message.error = true message.error = true
} } else {
else{ disabled = false
disabled = false message.message = ""
message.message = "" message.error = false
message.error = false }
}
export let type:string export let type: string
export let jwt: string export let jwt: string
async function updatecreations(){ async function updatecreations() {
const response = await fetch(url+'/develop/creations',{method: "POST", body: JSON.stringify({type}),headers: {"content-type": "application/json", 'Authorization': jwt,}}); const response = await fetch(url + "/develop/creations", {
const data = await response.json() method: "POST",
if (!data.error){ body: JSON.stringify({ type }),
creations = data headers: { "content-type": "application/json", Authorization: jwt },
//console.log(creations) })
} const data = await response.json()
} if (!data.error) {
updatecreations() creations = data
//console.log(creations)
}
}
updatecreations()
async function upload() {
const formData = new FormData()
formData.append("clothingfile", files[0])
formData.append("clothingname", itemname)
formData.append("description", itemdesc ?? "...")
formData.append("price", price)
formData.append("type", type)
async function upload(){ const req = await fetch("develop/uploadclothing", {
const formData = new FormData(); method: "post",
formData.append("clothingfile", files[0]) body: formData,
formData.append("clothingname", itemname) headers: {
formData.append("description", itemdesc??"...") Authorization: jwt,
formData.append("price", price) },
formData.append("type",type) })
const res = await req.json()
const req = await fetch("develop/uploadclothing", { if (!res.error) {
method: "post", message.message = "Done!"
body: formData, message.error = false
headers: { coinstore.update(n => n - 5)
'Authorization': jwt, updatecreations()
}, } else {
}); message.message = res.error
message.error = true
}
}
const res = await req.json(); $: type, updatecreations() // if type variable changes run updatecreations again
if (!res.error){
message.message = "Done!"
message.error = false
coinstore.update(n => n - 5)
updatecreations()
}else{
message.message = res.error
message.error = true
}
}
$:type,updatecreations() // if type variable changes run updatecreations again
</script> </script>
<div class="space-y-2 grow"> <div class="space-y-2 grow">
{#if type === "Shirts"} {#if type === "Shirts"}
<h3>Create a Shirt</h3> <h3>Create a Shirt</h3>
{:else if type === "Pants"} {:else if type === "Pants"}
<h3>Create a Pant</h3> <h3>Create a Pant</h3>
{/if} {/if}
<label class="input-label"> <label class="input-label">
<span class="pt-3">Find your image:</span> <span class="pt-3">Find your image:</span>
<input class="w-fit" accept="image/png" bind:files type="file" /> <input class="w-fit" accept="image/png" bind:files type="file" />
</label> </label>
<label class="input-label gap-8"> <label class="input-label gap-8">
{#if type === "Shirts"} {#if type === "Shirts"}
<span class="pt-3">Shirt Name:</span> <span class="pt-3">Shirt Name:</span>
{:else if type === "Pants"} {:else if type === "Pants"}
<span class="pt-3">Pant Name:</span> <span class="pt-3">Pant Name:</span>
{/if} {/if}
<input bind:value={itemname} type="text" class="input input-bordered input-primary w-full max-w-md rounded-md" required> <input
</label> bind:value={itemname}
type="text"
class="input input-bordered input-primary w-full max-w-md rounded-md"
required />
</label>
<label class="input-label gap-8"> <label class="input-label gap-8">
<span class="pt-3">Description:</span> <span class="pt-3">Description:</span>
<input bind:value={itemdesc} type="text" class="input input-bordered input-primary w-full max-w-md rounded-md" required> <input
</label> bind:value={itemdesc}
type="text"
class="input input-bordered input-primary w-full max-w-md rounded-md"
required />
</label>
<label class="input-label gap-8"> <label class="input-label gap-8">
<span class="pt-3">Price:</span> <span class="pt-3">Price:</span>
<input bind:value={price} type="number" class="input input-bordered input-primary w-full max-w-md rounded-md" required> <input
</label> bind:value={price}
type="number"
class="input input-bordered input-primary w-full max-w-md rounded-md"
required />
</label>
<h5 class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</h5> <h5
class="!text-xs mt-6 {message.error === true
? 'text-error-600'
: 'text-success-600'}">
{message.message ?? ""}
</h5>
<button on:click={upload} type="submit" class="btn variant-filled-primary btn-sm text-base rounded-md" disabled={disabled}>Upload for 5 Rocks</button> <button
on:click={upload}
type="submit"
class="btn variant-filled-primary btn-sm text-base rounded-md"
{disabled}>
Upload for 5 Rocks
</button>
<div class="pt-8 space-y-4"> <div class="pt-8 space-y-4">
<h3>{type}</h3> <h3>{type}</h3>
{#each creations as {Name, ItemId, Description}}
<Createditems itemname={Name} itemid={ItemId}/>
{/each}
</div>
{#each creations as { Name, ItemId, Description }}
<Createditems itemname={Name} itemid={ItemId} />
{/each}
</div>
</div> </div>

View File

@ -1,44 +1,62 @@
<script lang="ts"> <script lang="ts">
export let itemname: string
export let itemid: string
export let avatartype: string
export let gearallowed: boolean
export let itemname: string import { Modal, modalStore } from "@skeletonlabs/skeleton"
export let itemid: string import type { ModalSettings, ModalComponent } from "@skeletonlabs/skeleton"
export let avatartype: string import Editgamemodal from "./modals/editgamemodal.svelte"
export let gearallowed: boolean import type { PageData } from "../../routes/$types"
import { Modal, modalStore } from '@skeletonlabs/skeleton';
import type { ModalSettings, ModalComponent } from '@skeletonlabs/skeleton';
import Editgamemodal from './modals/editgamemodal.svelte';
import type { PageData } from '../../routes/$types';
export let data: PageData;
function triggerCustomModal(itemid: string): void {
const modalComponent: ModalComponent = {
// Pass a reference to your custom component
ref: Editgamemodal,
// Add your props as key/value pairs
props: { jwt: data.jwt, gameid: itemid, avatartype, gearallowed},
};
const d: ModalSettings = {
type: 'component',
// NOTE: title, body, response, etc are supported!
component: modalComponent,
modalClasses: 'w-full max-w-[700px] p-8'
};
modalStore.trigger(d);
}
export let data: PageData
function triggerCustomModal(itemid: string): void {
const modalComponent: ModalComponent = {
// Pass a reference to your custom component
ref: Editgamemodal,
// Add your props as key/value pairs
props: { jwt: data.jwt, gameid: itemid, avatartype, gearallowed },
}
const d: ModalSettings = {
type: "component",
// NOTE: title, body, response, etc are supported!
component: modalComponent,
modalClasses: "w-full max-w-[700px] p-8",
}
modalStore.trigger(d)
}
</script> </script>
<div class="flex flex-row gap-4 justify-around w-full"> <div class="flex flex-row gap-4 justify-around w-full">
<div class="flex flex-row grow gap-2">
<div class="flex flex-row grow gap-2"> <img
<img alt={itemname} class="w-16 aspect-video" src="assets/gameassets/thumbnail-{itemid}.png#"/> alt={itemname}
<a href="/games/{itemid}"><h5 class="!text-sm">{itemname}</h5></a> class="w-16 aspect-video"
</div> src="assets/gameassets/thumbnail-{itemid}.png#" />
<svg fill="none" on:click={()=> {triggerCustomModal(itemid)}} stroke="currentColor" height="24" width="24" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z"></path><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path></svg> <a href="/games/{itemid}"><h5 class="!text-sm">{itemname}</h5></a>
</div>
</div> <svg
fill="none"
on:click={() => {
triggerCustomModal(itemid)
}}
stroke="currentColor"
height="24"
width="24"
stroke-width="1.5"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z">
</path>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z">
</path>
</svg>
</div>

View File

@ -1,19 +1,40 @@
<script lang="ts"> <script lang="ts">
export let itemname: string
export let itemname: string export let itemid: string
export let itemid: string export let type = ""
export let type = ""
</script> </script>
<div class="flex flex-row gap-4 justify-around w-full"> <div class="flex flex-row gap-4 justify-around w-full">
<div class="flex flex-row grow gap-2">
<div class="flex flex-row grow gap-2"> <img
<img alt={itemname} class="w-16" src="/api/thumbnailrender/asset/?id={itemid}"/> alt={itemname}
<a href="/catalog/{itemid}/{itemname.replace(/[^a-zA-Z ]/g, "").replaceAll(' ', '-')}"><h5 class="!text-sm">{itemname}</h5></a> class="w-16"
</div> src="/api/thumbnailrender/asset/?id={itemid}" />
<svg fill="none" stroke="currentColor" height="24" width="24" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z"></path><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path></svg> <a
href="/catalog/{itemid}/{itemname
.replace(/[^a-zA-Z ]/g, '')
.replaceAll(' ', '-')}">
<h5 class="!text-sm">{itemname}</h5>
</a>
</div>
<svg
fill="none"
stroke="currentColor"
height="24"
width="24"
stroke-width="1.5"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z">
</path>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z">
</path>
</svg>
</div> </div>

View File

@ -1,121 +1,147 @@
<script lang="ts"> <script lang="ts">
import { coinstore } from "$lib/coinstore" import { coinstore } from "$lib/coinstore"
import type { PageData } from "../../routes/$types"; import type { PageData } from "../../routes/$types"
import Createdgames from "../develop/createdgames.svelte" import Createdgames from "../develop/createdgames.svelte"
import { url } from "$lib/url" import { url } from "$lib/url"
export let data: PageData; export let data: PageData
let message = {error: false, message: ""} let message = { error: false, message: "" }
let disabled = false let disabled = false
let itemname: string let itemname: string
let itemdesc: string let itemdesc: string
let files: FileList; let files: FileList
let gamefiles: FileList; let gamefiles: FileList
let version: string let version: string
let creations: any[] = [] let creations: any[] = []
$:if (!itemname){ $: if (!itemname) {
disabled = true disabled = true
message.message = "Game name required." message.message = "Game name required."
message.error = true message.error = true
}else if (!files || !gamefiles){ } else if (!files || !gamefiles) {
disabled = true disabled = true
message.message = "File required." message.message = "File required."
message.error = true message.error = true
} } else {
else{ disabled = false
disabled = false message.message = ""
message.message = "" message.error = false
message.error = false }
}
export let type:string export let type: string
export let jwt: string export let jwt: string
async function updatecreations(){ async function updatecreations() {
const response = await fetch(url+'/develop/creations',{method: "POST", body: JSON.stringify({type: "games"}),headers: {"content-type": "application/json", 'Authorization': jwt,}}); const response = await fetch(url + "/develop/creations", {
const data = await response.json() method: "POST",
if (!data.error){ body: JSON.stringify({ type: "games" }),
creations = data headers: { "content-type": "application/json", Authorization: jwt },
//console.log(creations) })
} const data = await response.json()
} if (!data.error) {
updatecreations() creations = data
//console.log(creations)
}
}
updatecreations()
async function upload() {
const formData = new FormData()
formData.append("gamefile", gamefiles[0])
formData.append("thumbnail", files[0])
formData.append("gamename", itemname)
formData.append("description", itemdesc ?? "...")
formData.append("version", version)
async function upload(){ const req = await fetch("/develop/uploadgame", {
const formData = new FormData(); method: "post",
formData.append("gamefile", gamefiles[0]) body: formData,
formData.append("thumbnail", files[0]) headers: {
formData.append("gamename", itemname) Authorization: jwt,
formData.append("description", itemdesc??"...") },
formData.append("version",version) })
const res = await req.json()
const req = await fetch("/develop/uploadgame", { if (!res.error) {
method: "post", message.message = "Done!"
body: formData, message.error = false
headers: { coinstore.update(n => n - 5)
'Authorization': jwt, updatecreations()
}, } else {
}); message.message = res.error
message.error = true
}
}
const res = await req.json(); $: type, updatecreations() // if type variable changes run updatecreations again
if (!res.error){
message.message = "Done!"
message.error = false
coinstore.update(n => n - 5)
updatecreations()
}else{
message.message = res.error
message.error = true
}
}
$:type,updatecreations() // if type variable changes run updatecreations again
</script> </script>
<div class="space-y-2 grow"> <div class="space-y-2 grow">
<h3>Create a Game</h3> <h3>Create a Game</h3>
<label class="input-label"> <label class="input-label">
<span class="pt-3">Thumbnail :</span> <span class="pt-3">Thumbnail :</span>
<input class="w-fit" accept="image/png" bind:files type="file" /> <input class="w-fit" accept="image/png" bind:files type="file" />
</label> </label>
<label class="input-label"> <label class="input-label">
<span class="pt-3">Game File :</span> <span class="pt-3">Game File :</span>
<input class="w-fit" accept=".rbxl" bind:files={gamefiles} type="file" /> <input
</label> class="w-fit"
<label class="input-label gap-6"> accept=".rbxl"
<span class="pt-3">Game Name:</span> bind:files={gamefiles}
<input bind:value={itemname} type="text" class="input input-bordered input-primary w-full max-w-md rounded-md" required> type="file" />
</label> </label>
<label class="input-label gap-6">
<span class="pt-3">Game Name:</span>
<input
bind:value={itemname}
type="text"
class="input input-bordered input-primary w-full max-w-md rounded-md"
required />
</label>
<label class="input-label gap-8"> <label class="input-label gap-8">
<span class="pt-3">Description:</span> <span class="pt-3">Description:</span>
<textarea bind:value={itemdesc} class="input input-bordered input-primary w-full max-w-md rounded-md" required></textarea> <textarea
</label> bind:value={itemdesc}
class="input input-bordered input-primary w-full max-w-md rounded-md"
required>
</textarea>
</label>
<label class="input-label gap-14"> <label class="input-label gap-14">
<span class="pt-3">Version:</span> <span class="pt-3">Version:</span>
<select bind:value={version} class="select w-full max-w-md"> <select bind:value={version} class="select w-full max-w-md">
<option value="2020">2020</option> <option value="2020">2020</option>
<option value="2018">2018</option> <option value="2018">2018</option>
<option value="2016">2016</option> <option value="2016">2016</option>
</select> </select>
</label> </label>
<h5 class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</h5> <h5
class="!text-xs mt-6 {message.error === true
? 'text-error-600'
: 'text-success-600'}">
{message.message ?? ""}
</h5>
<button on:click={upload} type="submit" class="btn variant-filled-primary btn-sm text-base rounded-md" disabled={disabled}>Upload for 5 Rocks</button> <button
on:click={upload}
type="submit"
class="btn variant-filled-primary btn-sm text-base rounded-md"
{disabled}>
Upload for 5 Rocks
</button>
<div class="pt-8 space-y-4"> <div class="pt-8 space-y-4">
<h3>Games</h3> <h3>Games</h3>
{#each creations as {nameofgame, idofgame, Description, avatartype, gearallowed}}
<Createdgames itemname={nameofgame} itemid={idofgame} data={data} avatartype={avatartype} gearallowed={gearallowed}/>
{/each}
</div>
{#each creations as { nameofgame, idofgame, Description, avatartype, gearallowed }}
<Createdgames
itemname={nameofgame}
itemid={idofgame}
{data}
{avatartype}
{gearallowed} />
{/each}
</div>
</div> </div>

View File

@ -1,192 +1,239 @@
<script lang="ts"> <script lang="ts">
let title:string; let title: string
let description:string let description: string
let files: FileList; let files: FileList
let disabled = false let disabled = false
let disabledupload = false let disabledupload = false
let message = {error: false, message: ""} let message = { error: false, message: "" }
let messageupload = {error: false, message: ""} let messageupload = { error: false, message: "" }
let allowmeshes = false let allowmeshes = false
import { RadioGroup, RadioItem } from '@skeletonlabs/skeleton'; import { RadioGroup, RadioItem } from "@skeletonlabs/skeleton"
export let jwt: string; export let jwt: string
export let gameid:string export let gameid: string
export let avatartype = "PC" export let avatartype = "PC"
export let gearallowed = false export let gearallowed = false
$:if (!title && !description){ $: if (!title && !description) {
disabled = true disabled = true
message.message = "Enter new title or new description." message.message = "Enter new title or new description."
message.error = true message.error = true
}else{ } else {
disabled = false disabled = false
message.message = "" message.message = ""
message.error = false message.error = false
} }
$:if (!files){ $: if (!files) {
disabledupload = true disabledupload = true
messageupload.message = "Choose a file." messageupload.message = "Choose a file."
messageupload.error = true messageupload.error = true
}else{ } else {
disabledupload = false disabledupload = false
messageupload.message = "" messageupload.message = ""
messageupload.error = false messageupload.error = false
} }
async function updategame() {
const updategameresp = await fetch("/develop/editgame", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: jwt,
},
body: JSON.stringify({
nameofgame: title,
description: description,
gameid: gameid.toString(),
}),
})
const updategamejson = await updategameresp.json()
console.log(updategamejson)
if (!updategamejson.error) {
message.message = updategamejson.message
message.error = false
} else {
message.message = updategamejson.error
message.error = true
}
}
async function uploadnew() {
const formData = new FormData()
formData.append("gameid", gameid.toString())
formData.append("gamefile", files[0])
async function updategame(){ const req = await fetch("/develop/editgameupload", {
const updategameresp = await fetch("/develop/editgame", { method: "post",
method: 'POST', body: formData,
headers: {
Authorization: jwt,
},
})
const res = await req.json()
console.log(res)
if (!res.error) {
messageupload.message = res.message
messageupload.error = false
} else {
messageupload.message = res.error
messageupload.error = true
}
}
async function updateAvatarType(newavatartype: string) {
if (avatartype != newavatartype) {
avatartype = newavatartype
const updateAvatarType = await fetch("/develop/editavatartype", {
method: "POST",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
'Authorization': jwt, Authorization: jwt,
}, },
body: JSON.stringify({ body: JSON.stringify({
nameofgame: title, avatartype,
description: description, gameid: gameid.toString(),
gameid: gameid.toString() }),
})
}) })
const updategamejson = await updategameresp.json() const updateAvatarTypejson = await updateAvatarType.json()
console.log(updategamejson) console.log(updateAvatarTypejson)
if (!updategamejson.error){ }
message.message = updategamejson.message }
message.error = false
}else{
message.message = updategamejson.error
message.error = true
}
} async function updateGearStatus(newgearstatus: boolean) {
if (allowmeshes != newgearstatus) {
async function uploadnew(){ allowmeshes = newgearstatus
const formData = new FormData(); const updateGearStatus = await fetch("/develop/editgearstatus", {
formData.append("gameid", gameid.toString()) method: "POST",
formData.append("gamefile", files[0])
const req = await fetch("/develop/editgameupload", {
method: "post",
body: formData,
headers: {
'Authorization': jwt,
},
});
const res = await req.json();
console.log(res)
if (!res.error){
messageupload.message = res.message
messageupload.error = false
}else{
messageupload.message = res.error
messageupload.error = true
}
}
async function updateAvatarType(newavatartype: string){
if (avatartype != newavatartype){
avatartype = newavatartype
const updateAvatarType = await fetch("/develop/editavatartype", {
method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
'Authorization': jwt, Authorization: jwt,
}, },
body: JSON.stringify({ body: JSON.stringify({
avatartype, newgearstatus,
gameid: gameid.toString() gameid: gameid.toString(),
}) }),
}) })
const updateAvatarTypejson = await updateAvatarType.json() const updateGearStatusjson = await updateGearStatus.json()
console.log(updateAvatarTypejson) console.log(updateGearStatusjson)
} }
} }
</script>
async function updateGearStatus(newgearstatus: boolean){ <div class="space-y-2 flex flex-row flex-wrap justify-center">
if (allowmeshes != newgearstatus){ <div class="w-full flex flex-row gap-4">
allowmeshes = newgearstatus <div class="space-y-4 w-full">
const updateGearStatus = await fetch("/develop/editgearstatus", { <h5 class="m-auto tex t-center w-full">Edit Game</h5>
method: 'POST', <label class="label">
headers: { <span>Title</span>
'Content-Type': 'application/json', <input
'Authorization': jwt, type="text"
}, bind:value={title}
body: JSON.stringify({ class="input input-bordered input-primary w-full rounded-md"
newgearstatus, required />
gameid: gameid.toString() </label>
}) <label class="label">
}) <span>Description</span>
const updateGearStatusjson = await updateGearStatus.json() <textarea
console.log(updateGearStatusjson) bind:value={description}
} class="input input-bordered input-primary w-full rounded-md"
} required>
</textarea>
</label>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="label">
<span>Avatar Type</span>
<RadioGroup
rounded="rounded-md"
display="flex flex-row flex-wrap">
<RadioItem
bind:group={avatartype}
on:click={() => {
updateAvatarType("R15")
}}
value="R15">
R15
</RadioItem>
<RadioItem
bind:group={avatartype}
on:click={() => {
updateAvatarType("R6")
}}
value="R6">
R6
</RadioItem>
<RadioItem
bind:group={avatartype}
on:click={() => {
updateAvatarType("PC")
}}
value="PC">
Player Choice
</RadioItem>
</RadioGroup>
</label>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="label">
<span>Allow Gear</span>
<RadioGroup
rounded="rounded-md"
display="flex flex-row flex-wrap">
<RadioItem
bind:group={gearallowed}
on:click={() => {
updateGearStatus(true)
}}
value={true}>
Yes
</RadioItem>
<RadioItem
bind:group={gearallowed}
on:click={() => {
updateGearStatus(false)
}}
value={false}>
No
</RadioItem>
</RadioGroup>
</label>
<h5
class="!text-xs mt-6 {message.error === true
? 'text-error-600'
: 'text-success-600'}">
{message.message ?? ""}
</h5>
</div>
</script> <div class="space-y-4 w-full h-full">
<h5 class="m-auto tex t-center w-full">Edit File</h5>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="label">
<span>RBXL File</span>
<input class="w-full" accept=".rbxl" bind:files type="file" />
</label>
<h5
class="!text-xs {messageupload.error === true
? 'text-error-600'
: 'text-success-600'}">
{messageupload.message ?? ""}
</h5>
</div>
</div>
<div class="space-y-2 flex flex-row flex-wrap justify-center"> <div class="flex flex-row w-full gap-4">
<button
on:click={updategame}
class="btn variant-filled-primary btn-base w-full"
{disabled}>
Update
</button>
<button
on:click={uploadnew}
<div class="w-full flex flex-row gap-4"> class="btn variant-filled-primary btn-base w-full"
disabled={disabledupload}>
<div class="space-y-4 w-full"> Upload
<h5 class="m-auto tex t-center w-full">Edit Game</h5> </button>
<label class="label"> </div>
<span>Title</span>
<input type="text" bind:value={title} class="input input-bordered input-primary w-full rounded-md" required>
</label>
<label class="label">
<span>Description</span>
<textarea bind:value={description} class="input input-bordered input-primary w-full rounded-md" required></textarea>
</label>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="label">
<span>Avatar Type</span>
<RadioGroup rounded="rounded-md" display="flex flex-row flex-wrap">
<RadioItem bind:group={avatartype} on:click={() => {updateAvatarType("R15")}} value="R15">R15</RadioItem>
<RadioItem bind:group={avatartype} on:click={() => {updateAvatarType("R6")}} value="R6">R6</RadioItem>
<RadioItem bind:group={avatartype} on:click={() => {updateAvatarType("PC")}} value="PC">Player Choice</RadioItem>
</RadioGroup>
</label>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="label">
<span>Allow Gear</span>
<RadioGroup rounded="rounded-md" display="flex flex-row flex-wrap">
<RadioItem bind:group={gearallowed} on:click={() => {updateGearStatus(true)}} value={true}>Yes</RadioItem>
<RadioItem bind:group={gearallowed} on:click={() => {updateGearStatus(false)}} value={false}>No</RadioItem>
</RadioGroup>
</label>
<h5 class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</h5>
</div>
<div class="space-y-4 w-full h-full">
<h5 class="m-auto tex t-center w-full">Edit File</h5>
<!-- svelte-ignore a11y-label-has-associated-control -->
<label class="label">
<span>RBXL File</span>
<input class="w-full" accept=".rbxl" bind:files type="file" />
</label>
<h5 class="!text-xs {messageupload.error === true ? 'text-error-600' : 'text-success-600'}">{messageupload.message??""}</h5>
</div>
</div>
<div class="flex flex-row w-full gap-4">
<button on:click={updategame} class="btn variant-filled-primary btn-base w-full" disabled={disabled}>
Update
</button>
<button on:click={uploadnew} class="btn variant-filled-primary btn-base w-full" disabled={disabledupload}>
Upload
</button>
</div> </div>
</div>

View File

@ -1,61 +1,109 @@
<script lang="ts"> <script lang="ts">
import { Avatar } from "@skeletonlabs/skeleton"; import { Avatar } from "@skeletonlabs/skeleton"
import { onMount } from "svelte"; import { onMount } from "svelte"
export let gamename= ""; export let gamename = ""
export let playercount = ""; export let playercount = ""
export let idofgame: String; export let idofgame: String
export let version = ""; export let version = ""
export let visits= ""; export let visits = ""
export let useridofowner = ""; export let useridofowner = ""
export let useragent:string export let useragent: string
export let username = "" export let username = ""
let imageloading = true let imageloading = true
const onload = (node:HTMLImageElement, callback: VoidFunction) => { const onload = (node: HTMLImageElement, callback: VoidFunction) => {
if(node.complete) { if (node.complete) {
imageloading = false imageloading = false
} else { } else {
node.addEventListener('load', callback) node.addEventListener("load", callback)
return { return {
destroy() { destroy() {
node.removeEventListener('load', callback) node.removeEventListener("load", callback)
}, },
} }
} }
} }
</script>
</script> {#if useragent.includes("Android") === true || useragent.includes("iPhone") === true}
{#if useragent.includes("Android") === true || useragent.includes("iPhone") === true} <!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-click-events-have-key-events --> <div
<div class="unstyled group" on:click={()=> {document.location.href="/games/"+idofgame+"/"+gamename.replace(/[^a-zA-Z ]/g, "").replaceAll(' ', '-')}}> class="unstyled group"
<div class="card rounded-md card-glass-surface snap-center card-hover w-20 sm:w-40 relative"> on:click={() => {
{#if imageloading} document.location.href =
<div class="w-20 h-20 sm:w-40 sm:h-40 rounded-none placeholder animate-pulse"></div> "/games/" +
{/if} idofgame +
<img alt="" class="avatar-image w-20 h-20 sm:w-40 sm:h-40 object-cover {imageloading === true ? 'hidden' : ''} " use:onload={()=> imageloading=false} src="/assets/gameassets/thumbnail-{idofgame}.png#" /> "/" +
<p class="truncate w-auto">{gamename}</p> gamename.replace(/[^a-zA-Z ]/g, "").replaceAll(" ", "-")
<div class="!text-sm">{playercount} Playing</div> }}>
<div class="btn h-2 w-6 sm:w-14 variant-filled-surface rounded-none absolute top-0 right-0 ">{version}</div> <div
<div class="hidden group-hover:block hover:block absolute top-32 sm:top-52"> class="card rounded-md card-glass-surface snap-center card-hover w-20 sm:w-40 relative">
<div class="!text-xs">By <a href="/users/{useridofowner}">{username}</a></div> {#if imageloading}
<div class="!text-xs">{visits??"0"} Visits</div> <div
</div> class="w-20 h-20 sm:w-40 sm:h-40 rounded-none placeholder animate-pulse">
</div> </div>
</div> {/if}
{:else} <img
<a class="unstyled group" href="/games/{idofgame}/{gamename.replace(/[^a-zA-Z ]/g, "").replaceAll(' ', '-')}"> alt=""
<div class="card rounded-md card-glass-surface snap-center card-hover w-20 sm:w-40 relative"> class="avatar-image w-20 h-20 sm:w-40 sm:h-40 object-cover {imageloading ===
{#if imageloading} true
<div class="w-20 h-20 sm:w-40 sm:h-40 rounded-none placeholder animate-pulse"></div> ? 'hidden'
{/if} : ''} "
<img alt="" class="avatar-image w-20 h-20 sm:w-40 sm:h-40 object-cover {imageloading === true ? 'hidden' : ''} " use:onload={()=> imageloading=false} src="/assets/gameassets/thumbnail-{idofgame}.png#" /> use:onload={() => (imageloading = false)}
<p class="truncate w-auto">{gamename}</p> src="/assets/gameassets/thumbnail-{idofgame}.png#" />
<div class="!text-sm">{playercount} Playing</div> <p class="truncate w-auto">{gamename}</p>
<div class="btn h-2 w-6 sm:w-14 variant-filled-surface rounded-none absolute top-0 right-0 ">{version}</div> <div class="!text-sm">{playercount} Playing</div>
{#if username}<div class="hidden group-hover:block hover:block absolute top-32 sm:top-52"> <div
<div class="!text-xs flex flex-row">By <div class="text-primary-700 dark:text-primary-500 hover:brightness-110 underline truncate w-20 sm:w-40">{username}</div></div> <!-- not using anchor links here because it breaks styling in certain instances --> class="btn h-2 w-6 sm:w-14 variant-filled-surface rounded-none absolute top-0 right-0">
<div class="!text-xs">{visits??"0"} Visits</div> {version}
</div>{/if} </div>
</div> <div
</a> class="hidden group-hover:block hover:block absolute top-32 sm:top-52">
{/if} <div class="!text-xs">
By <a href="/users/{useridofowner}">{username}</a>
</div>
<div class="!text-xs">{visits ?? "0"} Visits</div>
</div>
</div>
</div>
{:else}
<a
class="unstyled group"
href="/games/{idofgame}/{gamename
.replace(/[^a-zA-Z ]/g, '')
.replaceAll(' ', '-')}">
<div
class="card rounded-md card-glass-surface snap-center card-hover w-20 sm:w-40 relative">
{#if imageloading}
<div
class="w-20 h-20 sm:w-40 sm:h-40 rounded-none placeholder animate-pulse">
</div>
{/if}
<img
alt=""
class="avatar-image w-20 h-20 sm:w-40 sm:h-40 object-cover {imageloading ===
true
? 'hidden'
: ''} "
use:onload={() => (imageloading = false)}
src="/assets/gameassets/thumbnail-{idofgame}.png#" />
<p class="truncate w-auto">{gamename}</p>
<div class="!text-sm">{playercount} Playing</div>
<div
class="btn h-2 w-6 sm:w-14 variant-filled-surface rounded-none absolute top-0 right-0">
{version}
</div>
{#if username}<div
class="hidden group-hover:block hover:block absolute top-32 sm:top-52">
<div class="!text-xs flex flex-row">
By <div
class="text-primary-700 dark:text-primary-500 hover:brightness-110 underline truncate w-20 sm:w-40">
{username}
</div>
</div>
<!-- not using anchor links here because it breaks styling in certain instances -->
<div class="!text-xs">{visits ?? "0"} Visits</div>
</div>{/if}
</div>
</a>
{/if}

View File

@ -1,9 +1,21 @@
<script lang="ts"> <script lang="ts">
import { ProgressBar } from '@skeletonlabs/skeleton'; import { ProgressBar } from "@skeletonlabs/skeleton"
</script> </script>
<div class="flex flex-wrap flex-row justify-center gap-y-6"> <div class="flex flex-wrap flex-row justify-center gap-y-6">
<div class="w-full"><img alt="meteorite" class="h-32 m-auto" src="/assets/images/logosmall.png"></div> <div class="w-full">
<h5 class="text-base">Do you have Meteorite Installed? If not install now!</h5> <img
<ProgressBar meter="variant-filled-primary" /> alt="meteorite"
<a href="https://cdn.discordapp.com/attachments/1015311856744792104/1087210604273606766/Meteorite_0.5.0_x64_en-US.msi" class="btn variant-filled-primary btn-base rounded-md">Download</a> class="h-32 m-auto"
src="/assets/images/logosmall.png" />
</div>
<h5 class="text-base">
Do you have Meteorite Installed? If not install now!
</h5>
<ProgressBar meter="variant-filled-primary" />
<a
href="https://cdn.discordapp.com/attachments/1015311856744792104/1087210604273606766/Meteorite_0.5.0_x64_en-US.msi"
class="btn variant-filled-primary btn-base rounded-md">
Download
</a>
</div> </div>

View File

@ -1,6 +1,29 @@
<div class="flex flex-wrap flex-row justify-center gap-y-6"> <div class="flex flex-wrap flex-row justify-center gap-y-6">
<svg xmlns="http://www.w3.org/2000/svg" width="44" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-full"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg> <svg
<h5>Hi! In order to play games here at Meteorite you must link your discord account.</h5> xmlns="http://www.w3.org/2000/svg"
<h5 class="!text-sm m-auto w-full">Thank you...</h5> width="44"
<a href="https://discord.com/api/oauth2/authorize?client_id=1008206768989544449&redirect_uri=http%3A%2F%2Fmete0r.xyz%2Fsettings%2Fauthenticate&response_type=code&scope=identify" class="btn variant-filled-primary btn-base rounded-md">Link</a> height="64"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="w-full">
<path
d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z">
</path>
<line x1="12" y1="9" x2="12" y2="13"></line>
<line x1="12" y1="17" x2="12.01" y2="17"></line>
</svg>
<h5>
Hi! In order to play games here at Meteorite you must link your discord
account.
</h5>
<h5 class="!text-sm m-auto w-full">Thank you...</h5>
<a
href="https://discord.com/api/oauth2/authorize?client_id=1008206768989544449&redirect_uri=http%3A%2F%2Fmete0r.xyz%2Fsettings%2Fauthenticate&response_type=code&scope=identify"
class="btn variant-filled-primary btn-base rounded-md">
Link
</a>
</div> </div>

View File

@ -1,27 +1,35 @@
<script lang="ts"> <script lang="ts">
import { Avatar } from "@skeletonlabs/skeleton"; import { Avatar } from "@skeletonlabs/skeleton"
export let selectedgroup:string export let selectedgroup: string
export let grouplist: array export let grouplist: array
</script> </script>
<div class="hidden sm:block"> <div class="hidden sm:block">
<div class="flex flex-col"> <div class="flex flex-col">
<h2 class="font-bold">Groups</h2> <h2 class="font-bold">Groups</h2>
{#if grouplist} {#if grouplist}
{#each grouplist as {Name, groupid}} {#each grouplist as { Name, groupid }}
<a class="unstyled group" href="/groups/{groupid}"> <a class="unstyled group" href="/groups/{groupid}">
<div class="flex flex-row bg-surface-700 p-4 gap-2 shadow-[inset_4px_0_0_0_white]" > <div
class="flex flex-row bg-surface-700 p-4 gap-2 shadow-[inset_4px_0_0_0_white]">
<Avatar
width="w-8"
rounded="rounded-none"
src="/assets/groupicons/icon-0.png" />
<h5
class="!text-xs truncate w-48 m-auto group-hover:text-white">
{Name}
</h5>
</div>
</a>
{/each}
{/if}
<Avatar width="w-8" rounded="rounded-none" src="/assets/groupicons/icon-0.png" /> <a
<h5 class="!text-xs truncate w-48 m-auto group-hover:text-white">{Name}</h5> href="/groups/create"
</div> class="btn variant-ringed-surface rounded-md w-full btn-sm">
</a> Create Group
{/each} </a>
{/if} </div>
<a href="/groups/create" class="btn variant-ringed-surface rounded-md w-full btn-sm">Create Group</a>
</div>
</div> </div>

View File

@ -1,92 +1,134 @@
<script lang="ts"> <script lang="ts">
import { Avatar } from "@skeletonlabs/skeleton"; import { Avatar } from "@skeletonlabs/skeleton"
import Rocks from '../components/rocks.svelte'; import Rocks from "../components/rocks.svelte"
export let itemname: String; export let itemname: String
export let price:any = undefined export let price: any = undefined
export let itemid: String; export let itemid: String
export let sales:any = undefined export let sales: any = undefined
export let type = "" export let type = ""
export let width = "w-36" export let width = "w-36"
export let interact = "false" export let interact = "false"
export let moderation = false export let moderation = false
export let equipped = false export let equipped = false
export let action = () => {} export let action = () => {}
export let moderate = () => {} export let moderate = () => {}
let imageloading = true let imageloading = true
const onload = (node:HTMLImageElement, callback: VoidFunction) => { const onload = (node: HTMLImageElement, callback: VoidFunction) => {
if(node.complete) { if (node.complete) {
imageloading = false imageloading = false
} else { } else {
node.addEventListener('load', callback) node.addEventListener("load", callback)
return { return {
destroy() { destroy() {
node.removeEventListener('load', callback) node.removeEventListener("load", callback)
}, },
} }
} }
} }
</script>
</script> <div
class="card rounded-md card-glass-surface snap-center card-hover {width} relative hidden sm:block">
<a
class="unstyled hidden sm:block"
href="/catalog/{itemid}/{itemname
.replace(/[^a-zA-Z ]/g, '')
.replaceAll(' ', '-')}">
{#if type != "Audio" && type != "Video"}
{#if imageloading}
<div class="w-36 h-36 rounded-none placeholder animate-pulse">
</div>
{/if}
<img
alt=""
class="avatar-image bg-surface-400-500-token w-full h-full flex aspect-square object-cover {imageloading ===
true
? 'hidden'
: ''} "
use:onload={() => (imageloading = false)}
src="/api/thumbnailrender/asset/?id={itemid}{moderation ===
false
? ''
: '&nonapproved=true'}" />
{/if}
</a>
<div class="card rounded-md card-glass-surface snap-center card-hover {width} relative hidden sm:block"> {#if type === "Audio"}
<a class="unstyled hidden sm:block" href="/catalog/{itemid}/{itemname.replace(/[^a-zA-Z ]/g, "").replaceAll(' ', '-')}"> <audio class="block" controls>
{#if type != "Audio" && type != "Video"} <source
{#if imageloading} src="/asset?id={itemid}&nonapproved=true"
<div class="w-36 h-36 rounded-none placeholder animate-pulse"></div> type="audio/mp3" />
{/if} </audio>
<img alt="" class="avatar-image bg-surface-400-500-token w-full h-full flex aspect-square object-cover {imageloading === true ? 'hidden' : ''} " use:onload={()=> imageloading=false} src="/api/thumbnailrender/asset/?id={itemid}{moderation === false ? "": "&nonapproved=true"}" /> {/if}
{/if}
</a>
{#if type === "Audio"} {#if type === "Video"}
<audio class="block" controls> <!-- svelte-ignore a11y-media-has-caption -->
<source src="/asset?id={itemid}&nonapproved=true" type="audio/mp3"> <video controls>
</audio> <source
{/if} src="/asset?id={itemid}&nonapproved=true"
type="video/webm" />
</video>
{/if}
{#if type === "Video"} {#if interact === "true"}
<!-- svelte-ignore a11y-media-has-caption --> {#if equipped === true}
<video controls> <button
<source src="/asset?id={itemid}&nonapproved=true" type="video/webm"> on:click={() => {
</video> action("remove", parseFloat({ itemid }.itemid))
{/if} }}
class="btn variant-filled-primary rounded-md btn-sm absolute right-0 top-0">
Remove
</button>
{:else}
<button
on:click={() => {
action("wear", parseFloat({ itemid }.itemid))
}}
class="btn variant-filled-primary rounded-md btn-sm absolute right-0 top-0">
Wear
</button>
{/if}
{/if}
<p class="truncate w-28">{itemname}</p>
{#if sales}
<div class="!text-xs">{sales ?? "0"} Sales</div>
{/if}
{#if interact === "true"} {#if moderation === true}
{#if equipped === true} <p class="!text-xs">{type}</p>
<button on:click={() => {action('remove',parseFloat({itemid}.itemid))}} class="btn variant-filled-primary rounded-md btn-sm absolute right-0 top-0">Remove</button> <div class="flex flex-col gap-y-1">
{:else} <div class="flex flex-row gap-x-2">
<button on:click={() => {action('wear',parseFloat({itemid}.itemid))}} class="btn variant-filled-primary rounded-md btn-sm absolute right-0 top-0">Wear</button> <button
{/if} on:click={() => {
{/if} moderate("deny", parseFloat({ itemid }.itemid))
<p class="truncate w-28">{itemname}</p> }}
{#if sales} class="btn variant-filled-primary rounded-md btn-sm grow">
<div class="!text-xs">{sales??"0"} Sales</div> Deny
{/if} </button>
<button
on:click={() => {
moderate("approve", parseFloat({ itemid }.itemid))
}}
class="btn variant-filled-primary rounded-md btn-sm grow">
Approve
</button>
</div>
<!--<button on:click={() => {}} class="btn variant-filled-primary rounded-md btn-sm w-full">Download</button>-->
</div>
{/if}
{#if moderation === true} {#if price}
<p class="!text-xs">{type}</p> <div class="flex flex-row">
<div class="flex flex-col gap-y-1"> <Rocks width="w-5" />
<div class="flex flex-row gap-x-2"> <div class="!text-sm">{price}</div>
<button on:click={() => {moderate('deny',parseFloat({itemid}.itemid))}} class="btn variant-filled-primary rounded-md btn-sm grow">Deny</button> </div>
<button on:click={() => {moderate('approve',parseFloat({itemid}.itemid))}} class="btn variant-filled-primary rounded-md btn-sm grow">Approve</button> {/if}
</div> </div>
<!--<button on:click={() => {}} class="btn variant-filled-primary rounded-md btn-sm w-full">Download</button>-->
</div>
{/if}
{#if price}
<div class="flex flex-row ">
<Rocks width="w-5"/>
<div class="!text-sm">{price}</div>
</div>
{/if}
</div>

View File

@ -1,82 +1,101 @@
<script lang="ts"> <script lang="ts">
import { toastStore, type ToastSettings } from "@skeletonlabs/skeleton"; import { toastStore, type ToastSettings } from "@skeletonlabs/skeleton"
let message = { error: false, message: "" }
let disabled = false
let message = {error: false, message: ""} let _2fa: number
let disabled = false
let _2fa: number; export let username: string
export let password: string
export let username: string $: if (!_2fa) {
export let password:string disabled = true
message.message = "2FA code not inputted"
message.error = true
} else {
disabled = false
message.message = ""
message.error = false
}
$:if (!_2fa){ const t: ToastSettings = {
disabled = true message: "resp",
message.message = "2FA code not inputted"
message.error = true
}else{
disabled = false
message.message = ""
message.error = false
}
const t: ToastSettings = {
message: 'resp',
// Optional: Presets for primary | secondary | tertiary | warning // Optional: Presets for primary | secondary | tertiary | warning
preset: 'error', preset: "error",
// Optional: The auto-hide settings // Optional: The auto-hide settings
autohide: true, autohide: true,
timeout: 2000 timeout: 2000,
}; }
async function retrylogin(){
if (username && password){
const loginresp = await fetch('/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include',
body: JSON.stringify({
username,
password,
_2fa
})
})
const login = await loginresp.json()
if (!login.error){
t.preset = 'success'
t.message = 'Logged in!'
toastStore.trigger(t)
document.location = '/home'
}else{
t.message = login.error
toastStore.trigger(t)
}
async function retrylogin() {
if (username && password) {
const loginresp = await fetch("/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
body: JSON.stringify({
username,
password,
_2fa,
}),
})
const login = await loginresp.json()
if (!login.error) {
t.preset = "success"
t.message = "Logged in!"
toastStore.trigger(t)
document.location = "/home"
} else {
t.message = login.error
toastStore.trigger(t)
}
} }
} }
</script> </script>
<div class="space-y-2 flex flex-row flex-wrap justify-center"> <div class="space-y-2 flex flex-row flex-wrap justify-center">
<h5 class="m-auto text-center w-full">Confirm 2FA</h5>
<h5 class="m-auto text-center w-full">Confirm 2FA</h5> <svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="w-32">
<path
d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4">
</path>
</svg>
<h5 class="m-auto text-center w-full">
Enter the code generated by your authenticator app.
</h5>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-32"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"></path></svg> <div class="space-y-4 w-full">
<input
<h5 class="m-auto text-center w-full">Enter the code generated by your authenticator app.</h5> type="number"
bind:value={_2fa}
<div class="space-y-4 w-full"> placeholder="Input 2FA"
<input type="number" bind:value={_2fa} placeholder="Input 2FA" class="input input-bordered input-primary w-full rounded-md" required> class="input input-bordered input-primary w-full rounded-md"
<h5 class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</h5> required />
</div> <h5
class="!text-xs mt-6 {message.error === true
? 'text-error-600'
: 'text-success-600'}">
<button on:click={retrylogin} class="btn variant-filled-primary btn-base rounded-md" disabled={disabled}> {message.message ?? ""}
Confirm </h5>
</button> </div>
<button
on:click={retrylogin}
class="btn variant-filled-primary btn-base rounded-md"
{disabled}>
Confirm
</button>
</div> </div>

View File

@ -1,72 +1,89 @@
<script> <script>
import { tweened } from 'svelte/motion'; import { tweened } from "svelte/motion"
import { cubicOut } from 'svelte/easing'; import { cubicOut } from "svelte/easing"
import { navigating } from '$app/stores'; import { navigating } from "$app/stores"
import { fade } from 'svelte/transition'; import { fade } from "svelte/transition"
// progress bar value // progress bar value
const p = tweened(0, { const p = tweened(0, {
duration: 200, duration: 200,
easing: cubicOut easing: cubicOut,
}); })
let isVisible = false; let isVisible = false
function increase(){ function increase() {
if ($p >= 0 && $p < 0.2) { p.update(_ => _ + 0.04); } if ($p >= 0 && $p < 0.2) {
else if ($p >= 0.2 && $p < 0.5) { p.update(_ => _ + 0.02); } p.update(_ => _ + 0.04)
else if ($p >= 0.5 && $p < 0.8) { p.update(_ => _ + 0.002); } } else if ($p >= 0.2 && $p < 0.5) {
else if ($p >= 0.8 && $p < 0.99) { p.update(_ => _ + 0.0005); } p.update(_ => _ + 0.02)
else { p.set(0) } } else if ($p >= 0.5 && $p < 0.8) {
p.update(_ => _ + 0.002)
} else if ($p >= 0.8 && $p < 0.99) {
p.update(_ => _ + 0.0005)
} else {
p.set(0)
}
if($navigating){ if ($navigating) {
const rand = Math.round(Math.random() * (300 - 50)) + 50; const rand = Math.round(Math.random() * (300 - 50)) + 50
setTimeout(function() { setTimeout(function () {
increase(); increase()
}, rand); }, rand)
} }
} }
$: { $: {
if($navigating){ if ($navigating) {
increase(); increase()
isVisible = true; isVisible = true
} }
if(!$navigating){ if (!$navigating) {
p.update(_ => _ + 0.3); p.update(_ => _ + 0.3)
setTimeout(function() { setTimeout(function () {
p.set(1); p.set(1)
setTimeout(function() { setTimeout(function () {
isVisible = false; isVisible = false
p.set(0); p.set(0)
}, 100) }, 100)
}, 100) }, 100)
} }
} }
</script> </script>
{#if $p > 0 && $p < 1 && isVisible} {#if $p > 0 && $p < 1 && isVisible}
<progress value={$p} transition:fade={{duration: 300}} /> <progress value={$p} transition:fade={{ duration: 300 }} />
{/if} {/if}
<style> <style>
progress { progress {
--bar-color: rgba(255,255,255,0.3); --bar-color: rgba(255, 255, 255, 0.3);
--val-color: rgb(212 22 60); --val-color: rgb(212 22 60);
position: fixed; position: fixed;
top: 0; top: 0;
z-index: 99999; z-index: 99999;
left: 0; left: 0;
height: 2px; height: 2px;
width: 100vw; width: 100vw;
border-radius: 0; border-radius: 0;
} }
/* bar: */ /* bar: */
progress::-webkit-progress-bar {background-color: var(--bar-color); width: 100%;} progress::-webkit-progress-bar {
progress {background-color: var(--bar-color);} background-color: var(--bar-color);
width: 100%;
}
progress {
background-color: var(--bar-color);
}
/* value: */ /* value: */
progress::-webkit-progress-value {background-color: var(--val-color) !important;} progress::-webkit-progress-value {
progress::-moz-progress-bar {background-color: var(--val-color) !important;} background-color: var(--val-color) !important;
progress {color: var(--val-color);} }
progress::-moz-progress-bar {
background-color: var(--val-color) !important;
}
progress {
color: var(--val-color);
}
</style> </style>

View File

@ -1,4 +1,23 @@
<script lang="ts"> <script lang="ts">
export let width = "w-6" export let width = "w-6"
</script> </script>
<svg class={width} fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 18.657A8 8 0 016.343 7.343S7 9 9 10c0-2 .5-5 2.986-7C14 5 16.09 5.777 17.656 7.343A7.975 7.975 0 0120 13a7.975 7.975 0 01-2.343 5.657z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.879 16.121A3 3 0 1012.015 11L11 14H9c0 .768.293 1.536.879 2.121z"></path></svg>
<svg
class={width}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M17.657 18.657A8 8 0 016.343 7.343S7 9 9 10c0-2 .5-5 2.986-7C14 5 16.09 5.777 17.656 7.343A7.975 7.975 0 0120 13a7.975 7.975 0 01-2.343 5.657z">
</path>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9.879 16.121A3 3 0 1012.015 11L11 14H9c0 .768.293 1.536.879 2.121z">
</path>
</svg>

View File

@ -1,27 +1,28 @@
<script lang="ts"> <script lang="ts">
export let scrollDirection: String; export let scrollDirection: String
export let scrollElement: HTMLDivElement; export let scrollElement: HTMLDivElement
const scroll = async (node: HTMLDivElement, direction: String) => { const scroll = async (node: HTMLDivElement, direction: String) => {
if (direction === "right"){ if (direction === "right") {
if (window.matchMedia("(min-width: 640px)").matches === true){ if (window.matchMedia("(min-width: 640px)").matches === true) {
return node.scrollLeft += 800 return (node.scrollLeft += 800)
} }
node.scrollLeft += 200 node.scrollLeft += 200
}else{ } else {
if (window.matchMedia("(min-width: 640px)").matches === true){ if (window.matchMedia("(min-width: 640px)").matches === true) {
return node.scrollLeft -= 800 return (node.scrollLeft -= 800)
} }
node.scrollLeft -= 200 node.scrollLeft -= 200
} }
}
};
</script> </script>
<button class="btn btn-ringed btn-base w-3 rounded-md float-{scrollDirection} h-32 sm:h-52" on:click={() => scroll(scrollElement, scrollDirection)} style="transition: none !important;transform: none !important;">
{#if scrollDirection === "right"} <button
&gt; class="btn btn-ringed btn-base w-3 rounded-md float-{scrollDirection} h-32 sm:h-52"
{:else} on:click={() => scroll(scrollElement, scrollDirection)}
&lt; style="transition: none !important;transform: none !important;">
{/if} {#if scrollDirection === "right"}
&gt;
{:else}
&lt;
{/if}
</button> </button>

View File

@ -1,60 +1,66 @@
<script lang="ts"> <script lang="ts">
let _2facode: string let _2facode: string
let message = {error: false, message: ""} let message = { error: false, message: "" }
let disabled = false let disabled = false
export let jwt: string; export let jwt: string
export let qrcode: string; export let qrcode: string
$:if (!_2facode){ $: if (!_2facode) {
disabled = true disabled = true
message.message = "2FA code not inputted" message.message = "2FA code not inputted"
message.error = true message.error = true
}else{ } else {
disabled = false disabled = false
message.message = "" message.message = ""
message.error = false message.error = false
} }
async function verify2fa(){ async function verify2fa() {
const response = await fetch("/settings/verify2fa", { const response = await fetch("/settings/verify2fa", {
method: 'POST', method: "POST",
body: JSON.stringify({code: _2facode}), body: JSON.stringify({ code: _2facode }),
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
'Authorization': jwt, Authorization: jwt,
} },
}) })
const json = await response.json() const json = await response.json()
if (!json.error){ if (!json.error) {
message.message = "2FA Enabled" message.message = "2FA Enabled"
message.error = false message.error = false
document.location = '/settings' document.location = "/settings"
}else{ } else {
message.message = json.error message.message = json.error
message.error = true message.error = true
} }
}
</script>
} <div class="space-y-2 flex flex-row flex-wrap justify-center">
<h5 class="m-auto text-center w-full">Confirm 2FA</h5>
</script> <img alt={qrcode} class="w-64" src={qrcode} />
<div class="space-y-2 flex flex-row flex-wrap justify-center"> <div class="space-y-4 w-full">
<input
<h5 class="m-auto text-center w-full">Confirm 2FA</h5> type="text"
bind:value={_2facode}
<img alt={qrcode} class="w-64" src={qrcode}/> placeholder="Input 2FA"
class="input input-bordered input-primary w-full rounded-md"
<div class="space-y-4 w-full"> required />
<input type="text" bind:value={_2facode} placeholder="Input 2FA" class="input input-bordered input-primary w-full rounded-md" required> <h5
<h5 class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</h5> class="!text-xs mt-6 {message.error === true
</div> ? 'text-error-600'
: 'text-success-600'}">
{message.message ?? ""}
</h5>
<button on:click={verify2fa} class="btn variant-filled-primary btn-base rounded-md" disabled={disabled}> </div>
Confirm
</button>
</div>
<button
on:click={verify2fa}
class="btn variant-filled-primary btn-base rounded-md"
{disabled}>
Confirm
</button>
</div>

View File

@ -1,60 +1,78 @@
<script lang="ts"> <script lang="ts">
let currentp:string; let currentp: string
let newp:string; let newp: string
let confp:string; let confp: string
let disabled = false let disabled = false
let message = {error: false, message: ""} let message = { error: false, message: "" }
export let jwt: string; export let jwt: string
$:if (newp != confp || !newp && !confp){ $: if (newp != confp || (!newp && !confp)) {
disabled = true disabled = true
message.message = "New password and Confirm Password are not the same." message.message = "New password and Confirm Password are not the same."
message.error = true message.error = true
}else{ } else {
disabled = false disabled = false
message.message = "" message.message = ""
message.error = false message.error = false
} }
async function changepassword(){
const changepasswordresp = await fetch('/api/changepassword', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': jwt,
},
body: JSON.stringify({
oldpassword:currentp,
newpassword:confp
})
})
const changepassword = await changepasswordresp.json()
if (!changepassword.error){
message.message = changepassword.message
message.error = false
}else{
message.message = changepassword.error
message.error = true
}
}
async function changepassword() {
const changepasswordresp = await fetch("/api/changepassword", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: jwt,
},
body: JSON.stringify({
oldpassword: currentp,
newpassword: confp,
}),
})
const changepassword = await changepasswordresp.json()
if (!changepassword.error) {
message.message = changepassword.message
message.error = false
} else {
message.message = changepassword.error
message.error = true
}
}
</script> </script>
<div class="space-y-2 flex flex-row flex-wrap justify-center"> <div class="space-y-2 flex flex-row flex-wrap justify-center">
<h5 class="m-auto text-center">Change Password</h5>
<h5 class="m-auto text-center">Change Password</h5> <div class="space-y-4">
<input
<div class="space-y-4"> type="password"
<input type="password" bind:value={currentp} placeholder="Current Password" class="input input-bordered input-primary w-full rounded-md" required> bind:value={currentp}
<input type="password" bind:value={newp} placeholder="New Password" class="input input-bordered input-primary w-full rounded-md" required> placeholder="Current Password"
<input type="password" bind:value={confp} placeholder="Confirm Password" class="input input-bordered input-primary w-full rounded-md" required> class="input input-bordered input-primary w-full rounded-md"
<h5 class="!text-xs mt-6 {message.error === true ? 'text-error-600' : 'text-success-600'}">{message.message??""}</h5> required />
</div> <input
type="password"
bind:value={newp}
placeholder="New Password"
<button on:click={changepassword} class="btn variant-filled-primary btn-base" disabled={disabled}> class="input input-bordered input-primary w-full rounded-md"
Update required />
</button> <input
type="password"
bind:value={confp}
placeholder="Confirm Password"
class="input input-bordered input-primary w-full rounded-md"
required />
<h5
class="!text-xs mt-6 {message.error === true
? 'text-error-600'
: 'text-success-600'}">
{message.message ?? ""}
</h5>
</div>
<button
on:click={changepassword}
class="btn variant-filled-primary btn-base"
{disabled}>
Update
</button>
</div> </div>

View File

@ -1,28 +1,35 @@
<script lang="ts"> <script lang="ts">
import { url } from "$lib/url" import { url } from "$lib/url"
export let customclass: string
export let customMediaClass = "hidden lg:block"
let imageUrl = ""
let redirectUrl = "/games/0"
let loading = true
async function grabAd() {
const res = await fetch(url + `/api/requestad`)
export let customclass: string const data = await res.json()
export let customMediaClass = "hidden lg:block" imageUrl = data.imageUrl
let imageUrl = "" redirectUrl = data.redirectUrl
let redirectUrl = "/games/0" }
let loading = true grabAd()
async function grabAd(){
const res = await fetch(url+`/api/requestad`)
const data = await res.json()
imageUrl = data.imageUrl
redirectUrl = data.redirectUrl
}
grabAd()
</script> </script>
{#if loading} {#if loading}
<div class="hidden lg:block w-[160px] h-[600px] rounded-none placeholder animate-pulse {customclass}"></div> <div
class="hidden lg:block w-[160px] h-[600px] rounded-none placeholder animate-pulse {customclass}">
</div>
{/if} {/if}
<a on:click={grabAd} href={redirectUrl}><img class="w-[160px] h-[600px] rounded-none {customclass} {loading === true ? 'hidden' : customMediaClass}" on:load={() => {loading = false}} alt="Ad" src={imageUrl}/></a> <a on:click={grabAd} href={redirectUrl}>
<img
class="w-[160px] h-[600px] rounded-none {customclass} {loading === true
? 'hidden'
: customMediaClass}"
on:load={() => {
loading = false
}}
alt="Ad"
src={imageUrl} />
</a>

View File

@ -1,22 +1,29 @@
<script lang="ts"> <script lang="ts">
import { onMount } from "svelte"; import { onMount } from "svelte"
export let size: string
export let status = "Offline"
export let userid = "0"
export let gameid = "0"
export let offline = false
export let customclass = ""
$: if (status === "Offline") {
offline = true
}
</script>
export let size: string; {#if status === "Offline"}
export let status = "Offline" <div
export let userid = "0" class="{customclass} absolute bottom-2 right-5 w-{size} h-{size} bg-surface-300 rounded-full">
export let gameid = "0" </div>
export let offline = false
export let customclass = ""
$:if (status === "Offline"){
offline = true
}
</script>
{#if status === "Offline"}
<div class="{customclass} absolute bottom-2 right-5 w-{size} h-{size} bg-surface-300 rounded-full"></div>
{:else if status === "Online"} {:else if status === "Online"}
<div class="{customclass} absolute bottom-2 right-5 w-{size} h-{size} bg-blue-500 rounded-full"></div> <div
{:else if status.includes('Playing') === true} class="{customclass} absolute bottom-2 right-5 w-{size} h-{size} bg-blue-500 rounded-full">
<a class="unstyled" href="http://mete0r.xyz/games/{gameid}"><div class="{customclass} absolute bottom-2 right-5 w-{size} h-{size} bg-green-500 rounded-full"></div></a> </div>
{:else if status.includes("Playing") === true}
<a class="unstyled" href="http://mete0r.xyz/games/{gameid}">
<div
class="{customclass} absolute bottom-2 right-5 w-{size} h-{size} bg-green-500 rounded-full">
</div>
</a>
{/if} {/if}

View File

@ -1,69 +1,68 @@
<script lang="ts"> <script lang="ts">
import { Avatar } from "@skeletonlabs/skeleton"; import { Avatar } from "@skeletonlabs/skeleton"
export let userid: string export let userid: string
export let username: string export let username: string
export let friendRequest = false export let friendRequest = false
export let jwt = "" export let jwt = ""
export let refresh = async function(){ export let refresh = async function () {}
} async function ignore() {
const result = await fetch("/api/friends/decline-friend-request", {
async function ignore(){ method: "POST",
headers: {
const result = await fetch('/api/friends/decline-friend-request', { "Content-Type": "application/json",
method: 'POST', Authorization: jwt,
headers: { },
'Content-Type': 'application/json', body: JSON.stringify({
'Authorization': jwt, recipientUserId: userid.toString(),
}, }),
body: JSON.stringify({ })
recipientUserId: userid.toString() const requestresult = await result.json()
}) console.log(requestresult)
}) refresh()
const requestresult = await result.json() }
console.log(requestresult)
refresh()
}
async function accept(){
const result = await fetch('/api/friends/request-friendship', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': jwt,
},
body: JSON.stringify({
recipientUserId: userid.toString()
})
})
const requestresult = await result.json()
console.log(requestresult)
refresh()
}
async function accept() {
const result = await fetch("/api/friends/request-friendship", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: jwt,
},
body: JSON.stringify({
recipientUserId: userid.toString(),
}),
})
const requestresult = await result.json()
console.log(requestresult)
refresh()
}
</script> </script>
<div class="card rounded-md card-glass-surface snap-center card-hover group w-full lg:w-96 relative p-2"> <div
<a class="unstyled" href="/users/{userid}"> class="card rounded-md card-glass-surface snap-center card-hover group w-full lg:w-96 relative p-2">
<div class="flex flex-row gap-4"> <a class="unstyled" href="/users/{userid}">
<Avatar width="w-32" src="/api/thumbnailrender/?id={userid}#" /> <div class="flex flex-row gap-4">
<h5 class="truncate w-96">{username}</h5> <Avatar width="w-32" src="/api/thumbnailrender/?id={userid}#" />
</div> <h5 class="truncate w-96">{username}</h5>
</a> </div>
{#if friendRequest === true} </a>
{#if friendRequest === true}
<div class="flex flex-row gap-4 justify-around p-4">
<button
on:click={ignore}
type="submit"
class="btn variant-filled-primary btn-base rounded-md w-full">
Ignore
</button>
<div class="flex flex-row gap-4 justify-around p-4"> <button
on:click={accept}
<button on:click={ignore} type="submit" class="btn variant-filled-primary btn-base rounded-md w-full">Ignore</button> type="submit"
class="btn variant-filled-primary btn-base rounded-md w-full">
<button on:click={accept} type="submit" class="btn variant-filled-primary btn-base rounded-md w-full">Accept</button> Accept
</button>
</div> </div>
{/if}
{/if} </div>
</div>

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