diff --git a/api/accurateLeaderboard.js b/api/accurateLeaderboard.js index 47e1e63..a121f2f 100644 --- a/api/accurateLeaderboard.js +++ b/api/accurateLeaderboard.js @@ -30,7 +30,7 @@ module.exports = async (app, req, res) => { idArray.forEach((x, y) => { request.post(app.endpoint + 'getGJUserInfo20.php', { - form: {targetAccountID: x, secret: app.secret} + form: app.gdParams({targetAccountID: x}) }, function (err, resp, body) { if (err || !body || body == '-1') return res.send([]) diff --git a/api/analyze.js b/api/analyze.js index d1b8418..933f475 100644 --- a/api/analyze.js +++ b/api/analyze.js @@ -1,4 +1,4 @@ -const pako = require('pako') +const pako = require('zlib') const properties = require('../misc/objectProperties.json') const init = require('../misc/initialProperties.json') const colorStuff = require('../misc/colorProperties.json') @@ -16,7 +16,7 @@ if (unencrypted) rawData = level.data else { let buffer; - try { buffer = pako.inflate(levelString, {to:"string"}) } + try { buffer = zlib.gzipSync(levelString).toString() } catch(e) { return res.send("-1") } rawData = buffer.toString('utf8') } diff --git a/api/comments.js b/api/comments.js index 8421def..66b8b0a 100644 --- a/api/comments.js +++ b/api/comments.js @@ -1,24 +1,20 @@ const request = require('request') -module.exports = async (app, req, res, worstPage) => { +module.exports = async (app, req, res) => { if (app.offline) return res.send("-1") let count = +req.query.count || 10 if (count > 1000) count = 1000 - if (+req.query.worstPage) worstPage = +req.query.worstPage - let params = { + let params = app.gdParams({ userID : req.params.id, accountID : req.params.id, levelID: req.params.id, - page: worstPage ? worstPage - (+req.query.page || 0) - 1 : +req.query.page || 0, - secret: app.secret, + page: +req.query.page || 0, count, - gameVersion: app.gameVersion, - binaryVersion: app.binaryVersion, - mode: worstPage || req.query.hasOwnProperty("top") ? "1" : "0", - } + mode: req.query.hasOwnProperty("top") ? "1" : "0", + }) let path = "getGJComments21" if (req.query.type == "commentHistory") path = "getGJCommentHistory" @@ -38,11 +34,9 @@ module.exports = async (app, req, res, worstPage) => { let pages = body.split('#')[1].split(":") let lastPage = +Math.ceil(+pages[0] / +pages[2]); - if (path == "getGJComments21" && !worstPage && req.query.hasOwnProperty("worst")) return app.run.comments(app, req, res, lastPage) let commentArray = [] - if (worstPage) comments.reverse() comments.forEach((c, i) => { var x = c[0] //comment info @@ -74,7 +68,7 @@ module.exports = async (app, req, res, worstPage) => { if (i == 0 && req.query.type != "commentHistory") { comment.results = +pages[0]; comment.pages = lastPage; - comment.range = `${+pages[1] + 1} of ${Math.min(+pages[0], +pages[1] + +pages[2])}` + comment.range = `${+pages[1] + 1} to ${Math.min(+pages[0], +pages[1] + +pages[2])}` } commentArray.push(comment) diff --git a/api/download.js b/api/download.js index 08485b1..e377b46 100644 --- a/api/download.js +++ b/api/download.js @@ -15,12 +15,7 @@ module.exports = async (app, req, res, api, ID, analyze) => { else levelID = levelID.replace(/[^0-9]/g, "") request.post(app.endpoint + 'downloadGJLevel22.php', { - form: { - levelID, - gameVersion: app.gameVersion, - binaryVersion: app.binaryVersion, - secret: app.secret - } + form: app.gdParams({ levelID }) }, async function (err, resp, body) { if (err || !body || body == '-1' || body.startsWith(" { let level = new Level(levelInfo) request.post(app.endpoint + 'getGJUsers20.php', { - form: { str: level.authorID, secret: app.secret } + form: app.gdParams({ str: level.authorID }) }, function (err1, res1, b1) { let gdSearchResult = app.parseResponse(b1) request.post(app.endpoint + 'getGJUserInfo20.php', { - form: { targetAccountID: gdSearchResult[16], secret: app.secret } + form: app.gdParams({ targetAccountID: gdSearchResult[16] }) }, function (err2, res2, b2) { if (b2 != '-1') { let account = app.parseResponse(b2) @@ -51,10 +46,7 @@ module.exports = async (app, req, res, api, ID, analyze) => { } request.post(app.endpoint + 'getGJSongInfo.php', { - form: { - songID: level.customSong, - secret: app.secret - } + form: app.gdParams({ songID: level.customSong }) }, async function (err, resp, songRes) { if (songRes != '-1') { diff --git a/api/icon.js b/api/icon.js index 36017d9..719e741 100644 --- a/api/icon.js +++ b/api/icon.js @@ -361,19 +361,13 @@ module.exports = async (app, req, res) => { res.contentType('image/png'); request.post(app.endpoint + 'getGJUsers20.php', { - form: { - str: username, - secret: app.secret - } + form: app.gdParams({ str: username }) }, function (err1, res1, body1) { if (err1 || !body1 || body1 == "-1") return buildIcon() else result = app.parseResponse(body1); request.post(app.endpoint + 'getGJUserInfo20.php', { - form: { - targetAccountID: result[16], - secret: app.secret - } + form: app.gdParams({ targetAccountID: result[16] }) }, function (err2, res2, body2) { if (!err2 && body2 && body2 != '-1') return buildIcon(app.parseResponse(body2)); diff --git a/api/leaderboard.js b/api/leaderboard.js index b3fcc57..5a4ca40 100644 --- a/api/leaderboard.js +++ b/api/leaderboard.js @@ -11,13 +11,10 @@ module.exports = async (app, req, res) => { else amount = count; } - let params = { + let params = app.gdParams({ count: amount, - gameVersion: app.gameVersion, - binaryVersion: app.binaryVersion, - secret: app.secret, type: (req.query.hasOwnProperty("creator") || req.query.hasOwnProperty("creators")) ? "creators" : "top", - } + }) request.post(app.endpoint + 'getGJScores20.php', { form : params}, async function(err, resp, body) { diff --git a/api/leaderboardLevel.js b/api/leaderboardLevel.js index ff83d5a..a278366 100644 --- a/api/leaderboardLevel.js +++ b/api/leaderboardLevel.js @@ -11,13 +11,12 @@ module.exports = async (app, req, res) => { else amount = count; } - let params = { + let params = app.gdParams({ levelID: req.params.id, - secret: app.secret, accountID: app.id, gjp: app.gjp, type: req.query.hasOwnProperty("week") ? "2" : "1", - } + }) request.post(app.endpoint + 'getGJLevelScores211.php', { form : params, headers: {'x-forwarded-for': req.headers['x-real-ip']}}, async function(err, resp, body) { diff --git a/api/level.js b/api/level.js index b05e868..49a00e3 100644 --- a/api/level.js +++ b/api/level.js @@ -23,11 +23,10 @@ module.exports = async (app, req, res, api, analyze) => { if (analyze || req.query.hasOwnProperty("download")) return app.run.download(app, req, res, api, levelID, analyze) request.post(app.endpoint + 'getGJLevels21.php', { - form: { + form: app.gdParams({ str: levelID, - secret: app.secret, type: 0 - } + }) }, async function (err, resp, body) { if (err || !body || body == '-1' || body.startsWith(" { if (!req.body.accountID) return res.status(400).send("No account ID provided!") if (!req.body.password) return res.status(400).send("No password provided!") - let params = { + let params = app.gdParams({ accountID: req.body.accountID, targetAccountID: req.body.accountID, gjp: xor.encrypt(req.body.password, 37526), - secret: app.secret, - gameVersion: app.gameVersion, - binaryVersion: app.binaryVersion, - } + }) request.post(app.endpoint + 'getGJUserInfo20.php', { form: params, diff --git a/api/messages/deleteMessage.js b/api/messages/deleteMessage.js index 0c950cb..6316fe4 100644 --- a/api/messages/deleteMessage.js +++ b/api/messages/deleteMessage.js @@ -8,12 +8,11 @@ module.exports = async (app, req, res, api) => { if (!req.body.password) return res.status(400).send("No password provided!") if (!req.body.id) return res.status(400).send("No message ID(s) provided!") - let params = { + let params = app.gdParams({ accountID: req.body.accountID, gjp: xor.encrypt(req.body.password, 37526), messages: Array.isArray(req.body.id) ? req.body.id.map(x => x.trim()).join(",") : req.body.id, - secret: app.secret, - } + }) let deleted = params.messages.split(",").length diff --git a/api/messages/fetchMessage.js b/api/messages/fetchMessage.js index 4526150..25c3cd3 100644 --- a/api/messages/fetchMessage.js +++ b/api/messages/fetchMessage.js @@ -7,12 +7,11 @@ module.exports = async (app, req, res, api) => { if (!req.body.accountID) return res.status(400).send("No account ID provided!") if (!req.body.password) return res.status(400).send("No password provided!") - let params = { + let params = app.gdParams({ accountID: req.body.accountID, gjp: xor.encrypt(req.body.password, 37526), messageID: req.params.id, - secret: app.secret, - } + }) request.post(app.endpoint + 'downloadGJMessage20.php', { form: params, diff --git a/api/messages/getMessages.js b/api/messages/getMessages.js index f335498..e07e4d0 100644 --- a/api/messages/getMessages.js +++ b/api/messages/getMessages.js @@ -8,15 +8,12 @@ module.exports = async (app, req, res, api) => { if (!req.body.accountID) return res.status(400).send("No account ID provided!") if (!req.body.password) return res.status(400).send("No password provided!") - let params = { + let params = app.gdParams({ accountID: req.body.accountID, gjp: xor.encrypt(req.body.password, 37526), page: req.body.page || 0, - secret: app.secret, - gameVersion: app.gameVersion, - binaryVersion: app.binaryVersion, getSent: req.query.sent ? 1 : 0 - } + }) request.post(app.endpoint + 'getGJMessages20.php', { form: params, diff --git a/api/messages/sendMessage.js b/api/messages/sendMessage.js index e24c901..1bf3c98 100644 --- a/api/messages/sendMessage.js +++ b/api/messages/sendMessage.js @@ -12,13 +12,12 @@ module.exports = async (app, req, res, api) => { let subject = Buffer.from(req.body.subject ? (req.body.color ? "☆" : "") + (req.body.subject.slice(0, 50)) : (req.body.color ? "☆" : "") + "No subject").toString('base64').replace(/\//g, '_').replace(/\+/g, "-") let body = xor.encrypt(req.body.message.slice(0, 300), 14251) - let params = { + let params = app.gdParams({ accountID: req.body.accountID, gjp: xor.encrypt(req.body.password, 37526), toAccountID: req.body.targetID, subject, body, - secret: app.secret, - } + }) request.post(app.endpoint + 'uploadGJMessage20.php', { form: params, diff --git a/api/post/like.js b/api/post/like.js index 764ee74..85576fc 100644 --- a/api/post/like.js +++ b/api/post/like.js @@ -13,14 +13,11 @@ module.exports = async (app, req, res) => { if (!req.body.type) return res.status(400).send("No type provided! (1=level, 2=comment, 3=profile") if (!req.body.extraID) return res.status(400).send("No extra ID provided! (this should be a level ID, account ID, or '0' for levels") - let params = { - gameVersion: app.gameVersion, - binaryVersion: app.binaryVersion, - secret: app.secret, + let params = app.gdParams({ udid: '0', uuid: '0', rs: '8f0l0ClAN1' - } + }) params.itemID = req.body.ID.toString() params.gjp = xor.encrypt(req.body.password, 37526) diff --git a/api/post/postComment.js b/api/post/postComment.js index e854c21..979462d 100644 --- a/api/post/postComment.js +++ b/api/post/postComment.js @@ -24,12 +24,9 @@ module.exports = async (app, req, res) => { if (rateLimit[req.body.username]) return res.status(400).send(`Please wait ${getTime(rateLimit[req.body.username] + cooldown - Date.now())} seconds before posting another comment!`) - let params = { - gameVersion: app.gameVersion, - binaryVersion: app.binaryVersion, - secret: app.secret, + let params = app.gdParams({ percent: 0 - } + }) params.comment = Buffer.from(req.body.comment + (req.body.color ? "☆" : "")).toString('base64').replace(/\//g, '_').replace(/\+/g, "-") params.gjp = xor.encrypt(req.body.password, 37526) diff --git a/api/post/postProfileComment.js b/api/post/postProfileComment.js index 66e1d62..63e51c4 100644 --- a/api/post/postProfileComment.js +++ b/api/post/postProfileComment.js @@ -13,12 +13,9 @@ module.exports = async (app, req, res) => { if (req.body.comment.includes('\n')) return res.status(400).send("Profile posts cannot contain line breaks!") - let params = { - gameVersion: app.gameVersion, - binaryVersion: app.binaryVersion, - secret: app.secret, + let params = app.gdParams({ cType: '1' - } + }) params.comment = Buffer.from(req.body.comment.slice(0, 190) + (req.body.color ? "☆" : "")).toString('base64').replace(/\//g, '_').replace(/\+/g, "-") params.gjp = xor.encrypt(req.body.password, 37526) diff --git a/api/profile.js b/api/profile.js index 53ac198..502e14b 100644 --- a/api/profile.js +++ b/api/profile.js @@ -6,19 +6,13 @@ module.exports = async (app, req, res, api, getLevels) => { if (app.offline) return res.send("-1") request.post(app.endpoint + 'getGJUsers20.php', { - form: { - str: getLevels || req.params.id, - secret: app.secret, - } + form: app.gdParams({ str: getLevels || req.params.id }) }, function (err1, res1, b1) { let searchResult = (req.query.hasOwnProperty("account") || err1 || b1 == '-1' || b1.startsWith(" { else amount = count; } - let filters = { + let filters = app.gdParams({ str: req.params.text, diff: req.query.diff, @@ -35,10 +35,7 @@ module.exports = async (app, req, res) => { customSong: req.query.hasOwnProperty("customSong") ? 1 : 0, type: req.query.type || 0, - gameVersion: app.gameVersion, - binaryVersion: app.binaryVersion, - secret: app.secret - } + }) let foundPack = mapPacks[req.params.text.toLowerCase()] if (foundPack) filters.str = `${foundPack[0]},${foundPack[1]},${foundPack[2]}`; @@ -73,7 +70,7 @@ module.exports = async (app, req, res) => { request.post(app.endpoint + 'getGJLevels21.php', { form : filters}, async function(err, resp, body) { - + if (err || !body || body == '-1' || body.startsWith("Returns up to 10 comments or profile posts
Parameters (5)
+Parameters (4)
page: The page of the search
top: Whether or not to sort by most liked (comments only)
-worst: Whether or not to sort by most disliked (comments only)
-worstPage: The total number of pages, if you already know what it is. Optional, but speeds up disliked sorting
count: The number of comments/posts to list (default is 10, max is 1000)
type: The type of comments to fetch. Instead of a level ID, they require a player and account ID, respectively.
• commentHistory - All the comments from a player, if public on their profile
diff --git a/html/comments.html b/html/comments.html index fddb6ae..07d7254 100644 --- a/html/comments.html +++ b/html/comments.html @@ -59,12 +59,24 @@
${userName}
${modNumber > 0 ? `` : ""}${x.percent ? x.percent + "%" : ""}
@@ -259,7 +274,7 @@ fetch(`../api${!history ? window.location.pathname : "/comments/" + lvl.playerID${userName}
${modNumber > 0 ? `` : ""}${x.percent ? x.percent + "%" : ""}
@@ -284,9 +299,9 @@ fetch(`../api${!history ? window.location.pathname : "/comments/" + lvl.playerID }) $('.commentText').each(function() { - if ($(this).text().length > 100) { - let overflow = ($(this).text().length - 100) * 0.01 - $(this).css('font-size', (3.5 - (overflow)) + 'vh') + if ($(this).text().length > 100) { + let overflow = ($(this).text().length - 100) * 0.01 + $(this).css('font-size', (3.5 - (overflow)) + 'vh') } }); @@ -301,6 +316,7 @@ appendComments() $('#pageUp').click(function() {if (loadingComments) return; page += 1; appendComments()}) $('#pageDown').click(function() {if (loadingComments) return; page -= 1; appendComments()}) +$('#lastPage').click(function() {if (loadingComments || auto) return; page = lastPage - 1; appendComments()}) function resetSort() { page = 0 @@ -316,7 +332,6 @@ $('#topSort').click(function() { mode = "top"; $('#timeSort').attr('src', "../assets/sort-time.png") $('#topSort').attr('src', "../assets/sort-likes-on.png") - $('#worstSort').attr('src', "../assets/sort-dislikes.png") appendComments() }) @@ -326,24 +341,13 @@ $('#timeSort').click(function() { mode = "time"; $('#timeSort').attr('src', "../assets/sort-time-on.png") $('#topSort').attr('src', "../assets/sort-likes.png") - $('#worstSort').attr('src', "../assets/sort-dislikes.png") - appendComments() -}) - -$('#worstSort').click(function() { - if (mode == "worst" || loadingComments) return; - resetSort() - mode = "worst"; - $('#timeSort').attr('src', "../assets/sort-time.png") - $('#topSort').attr('src', "../assets/sort-likes.png") - $('#worstSort').attr('src', "../assets/sort-dislikes-on.png") appendComments() }) $('#compactMode').click(function() { if (loadingComments) return; compact = !compact - worstPage = 0; + lastPage = 0; page = 0; $('#compactMode').attr('src', `../assets/compact-${compact ? "on" : "off"}.png`) appendComments() @@ -356,13 +360,15 @@ $('#autoMode').click(function() { page = 0; $('#timeSort').attr('src', "../assets/sort-time-on.png") $('#topSort').attr('src', "../assets/sort-likes.png") - $('#worstSort').attr('src', "../assets/sort-dislikes.png") + if (auto) { + document.title = "[LIVE] " + document.title $('#liveText').show() $('#autoMode').attr('src', `../assets/stopbutton.png`) interval = setInterval(function() { appendComments(true) }, 2000) } else { + document.title = document.title.slice(6) $('#liveText').hide() $('#autoMode').attr('src', `../assets/playbutton.png`) clearInterval(interval) @@ -370,9 +376,9 @@ $('#autoMode').click(function() { appendComments(true) }) -$('#refresh').click(function() { +$(document).on('click', '.refreshBtn', function () { if (loadingComments) return - worstPage = 0; + lastPage = 0; page = 0; appendComments() }) diff --git a/html/filters.html b/html/filters.html index 1bfa81e..6bef5ed 100644 --- a/html/filters.html +++ b/html/filters.html @@ -117,7 +117,7 @@ let demonMode = false; $('#userSearch').click(function() { let query = encodeURIComponent($('#levelName').val()) - if (query) window.location.href = "./profile/" + query + if (query) window.location.href = "./u/" + query }) $('.levelSearch').click(function() { diff --git a/html/home.html b/html/home.html index 11f02bb..518d6fa 100644 --- a/html/home.html +++ b/html/home.html @@ -91,7 +91,7 @@ fetch(`./api/credits`).then(res => res.json()).then(res => { $('#credits').append(`${x.header}
-
${x.name}
+${x.name}
@@ -112,7 +112,7 @@ fetch(`./api/credits`).then(res => res.json()).then(res => { res.specialThanks.forEach((x, y) => { $('#specialthanks').append(`
${x}
+${x}
${x.username}
+${x.username}
${x.stars}
diff --git a/html/level.html b/html/level.html index 6ae9ccd..a53f47b 100644 --- a/html/level.html +++ b/html/level.html @@ -80,7 +80,7 @@By [[AUTHOR]]
+By [[AUTHOR]]
${x.username}
+${x.username}
${x.percent}% diff --git a/html/messages.html b/html/messages.html index fc78bf7..f445ad4 100644 --- a/html/messages.html +++ b/html/messages.html @@ -238,7 +238,7 @@ $('#msgList').append(`
@@ -285,7 +285,7 @@
targetUser = decodeURIComponent(targetUser[1])
fetch(`../api/profile/${targetUser}`).then(res => res.json()).then(res => {
if (res == "-1" || !res) return;
- $('#replyAuthor').html(`To: ${res.username}`)
+ $('#replyAuthor').html(`To: ${res.username}`)
messageStatus[res.accountID] = [res.messages, res.username]
authorID = res.accountID
if (res.messages == "all") $('#messageStatus').html(`${res.username} has messages enabled`)
diff --git a/html/search.html b/html/search.html
index e223f04..6a830ce 100644
--- a/html/search.html
+++ b/html/search.html
@@ -180,7 +180,7 @@ function Append(firstLoad) {
$('#searchBox').append(`
30 ? "3.5" : x.subject.length > 25 ? "3.75" : "4"}vh">${x.subject}${x.unread ? " !" : ""}
-From: ${x.author}
+From: ${x.author}
${x.date}
${x.name}
-${hasAuthor ? `By ${x.author}` : `By ${x.author}`}
${x.copiedID == '0' ? "" : ''}${x.large ? '' : ''}
+${hasAuthor ? `By ${x.author}` : `By ${x.author}`}
${x.copiedID == '0' ? "" : ''}${x.large ? '' : ''}
${x.songName.replace(/[^ -~]/g, "")}
${x.length} diff --git a/index.js b/index.js index 9005447..978f045 100644 --- a/index.js +++ b/index.js @@ -9,11 +9,15 @@ let useRateLimiting = true const app = express(); app.offline = false // set to true to go into "offline" mode (in case of ip ban from rob) -app.secret = 'Wmfd2893gb7' -app.gameVersion = '21' -app.binaryVersion = '35' -app.endpoint = 'http://boomlings.com/database/' +app.secret = "Wmfd2893gb7" // lol + app.config = require('./misc/gdpsConfig') // tweak settings in this file if you're using a GDPS +app.endpoint = app.config.endpoint // boomlings.com/database/ + +app.gdParams = function(obj={}) { + Object.keys(app.config.params).forEach(x => { if (!obj[x]) obj[x] = app.config.params[x] }) + return obj +} const RL = rateLimit({ windowMs: useRateLimiting ? 5 * 60 * 1000 : 0, @@ -137,23 +141,21 @@ app.get("/api/search/:text", function(req, res) { app.run.search(app, req, res) app.get("/icon", function(req, res) { res.redirect('/iconkit') }) app.get("/iconkit/:text", function(req, res) { res.redirect('/icon/' + req.params.text) }) app.get("/leaderboards/:id", function(req, res) { res.redirect('/leaderboard/' + req.params.id) }) +app.get("/profile/:id", function(req, res) { res.redirect('/u/' + req.params.id) }) +app.get("/p/:id", function(req, res) { res.redirect('/u/' + req.params.id) }) app.get("/l/:id", function(req, res) { res.redirect('/leaderboard/' + req.params.id) }) app.get("/a/:id", function(req, res) { res.redirect('/analyze/' + req.params.id) }) app.get("/c/:id", function(req, res) { res.redirect('/comments/' + req.params.id) }) -app.get("/u/:id", function(req, res) { res.redirect('/profile/' + req.params.id) }) -app.get("/p/:id", function(req, res) { res.redirect('/profile/' + req.params.id) }) // API AND HTML -app.get("/profile/:id", function(req, res) { app.run.profile(app, req, res) }) +app.get("/u/:id", function(req, res) { app.run.profile(app, req, res) }) app.get("/:id", function(req, res) { app.run.level(app, req, res) }) // MISC - - app.get("/assets/sizecheck.js", function(req, res) { res.sendFile(__dirname + "/misc/sizecheck.js") }) app.get("/icon/:text", function(req, res) { app.run.icon(app, req, res) }) app.get('/api/icons', function(req, res) { diff --git a/misc/gdpsConfig.js b/misc/gdpsConfig.js index c38cc43..1612234 100644 --- a/misc/gdpsConfig.js +++ b/misc/gdpsConfig.js @@ -4,6 +4,14 @@ module.exports = { + endpoint: "http://boomlings.com/database/", // Server endpoint to send requests to + + params: { // Always send this stuff to the servers + secret: 'Wmfd2893gb7', + gameVersion: '21', + binaryVersion: '35', + }, + base64descriptions: true, // Are level descriptions encoded in Base64? xorPasswords: true, // Are level passwords XOR encrypted? timestampSuffix: " ago", // Suffix to add after timestamps, if any.