From 53b24047e7f92ea85ca67babf0f37b2710eac401 Mon Sep 17 00:00:00 2001 From: ibratabian17 Date: Sun, 20 Oct 2024 17:04:22 +0700 Subject: [PATCH] Improve Account Ticket gen --- core/route/account.js | 438 ++++++++++++++++++++------------------ core/route/ubiservices.js | 9 +- 2 files changed, 241 insertions(+), 206 deletions(-) diff --git a/core/route/account.js b/core/route/account.js index 2ce5380..f0b02ff 100644 --- a/core/route/account.js +++ b/core/route/account.js @@ -72,6 +72,22 @@ function addUser(profileId, userProfile) { const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); saveUserData(dataFilePath, decryptedData); } +// Add a new user +function addUserId(profileId, userId) { + if (decryptedData[profileId]) { + decryptedData[profileId].userId = userId; + const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); + saveUserData(dataFilePath, decryptedData); + } else { + console.log(`[ACC] User ${profileId} not found`) + } +} + +function updateUserTicket(profileId, Ticket) { + decryptedData[profileId.ticket] = Ticket; + const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); + saveUserData(dataFilePath, decryptedData); +} // Helper function to read the leaderboard function readLeaderboard(isDotw = false) { @@ -150,235 +166,251 @@ if (!decryptedData) { loadUserData(dataFilePath); } -// Initialize routes -exports.initroute = (app) => { +module.exports = { + loadUserData, + addUser, + addUserId, + updateUserTicket, + cachedLeaderboard, + cachedDotw, + initroute: (app) => { - // Endpoint to get profiles based on profileIds - app.get("/profile/v2/profiles", async (req, res) => { - const ticket = req.header("Authorization"); - const profileIds = req.query.profileIds.split(','); - const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); + // Endpoint to get profiles based on profileIds + app.get("/profile/v2/profiles", async (req, res) => { + const ticket = req.header("Authorization"); + const profileIds = req.query.profileIds.split(','); + const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); - // Load user data if not already loaded - if (!decryptedData) { - loadUserData(dataFilePath); - } - - const responseProfiles = await Promise.all(profileIds.map(async (profileId) => { - let userProfile = decryptedData[profileId]; - - // If the profile is found in the local data - if (userProfile && userProfile.name) { - console.log(`[ACC] Account Found For: `, profileId); - return { ...userProfile, ip: req.clientIp, ticket: '', profileId }; - } else { - // If the profile is not found locally, fetch from external source - console.log(`[ACC] Asking Official Server For: `, profileId); - const url = `https://prod.just-dance.com/profile/v2/profiles?profileIds=${encodeURIComponent(profileId)}`; - try { - const profileResponse = await axios.get(url, { - headers: { - 'Host': 'prod.just-dance.com', - 'User-Agent': req.headers['user-agent'], - 'Accept': req.headers['accept'] || '/', - 'Accept-Language': 'en-us,en', - 'Authorization': req.headers['authorization'] , - 'X-SkuId': req.headers['x-skuid'], - } - }); - - // Assume the external response contains the profile as `profileData` - const profileData = profileResponse.data[0]; // Adjust according to the actual response format - if (profileData) { - console.log(`[ACC] Account Saved to the server: `, profileId); - const defaultProfile = { ...profileData, ip: req.clientIp, ticket: ticket }; - - // Add the fetched profile to local storage - addUser(profileId, defaultProfile); - - defaultProfile.ticket = '' - - return defaultProfile; - } - } catch (error) { - console.error(`[ACC] Error fetching profile for ${profileId}:`, error.message); - addUser(profileId, { ip: req.clientIp, ticket: ticket }); - return { - "profileId": profileId, - "isExisting": false - }; // If fetch fails, return an empty profile object - } + // Load user data if not already loaded + if (!decryptedData) { + loadUserData(dataFilePath); } - })); - res.send(responseProfiles); - }); + const responseProfiles = await Promise.all(profileIds.map(async (profileId) => { + let userProfile = decryptedData[profileId]; + // If the profile is found in the local data + if (userProfile && userProfile.name) { + console.log(`[ACC] Account Found For: `, profileId); + if (!findUserFromTicket(ticket)) { + decryptedData[profileId].ticket = ticket; + console.log('[ACC] Updated Ticket For ', userProfile.name) + } + return { ...userProfile, ip: req.clientIp, ticket: '', profileId }; + } else { + // If the profile is not found locally, fetch from external source + console.log(`[ACC] Asking Official Server For: `, profileId); + const url = `https://prod.just-dance.com/profile/v2/profiles?profileIds=${encodeURIComponent(profileId)}`; + try { + const profileResponse = await axios.get(url, { + headers: { + 'Host': 'prod.just-dance.com', + 'User-Agent': req.headers['user-agent'], + 'Accept': req.headers['accept'] || '/', + 'Accept-Language': 'en-us,en', + 'Authorization': req.headers['authorization'], + 'X-SkuId': req.headers['x-skuid'], + } + }); - app.post("/profile/v2/profiles", (req, res) => { - const ticket = req.header("Authorization"); - const content = req.body; - content.ticket = ticket; - const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); + // Assume the external response contains the profile as `profileData` + const profileData = profileResponse.data[0]; // Adjust according to the actual response format + if (profileData) { + console.log(`[ACC] Account Saved to the server: `, profileId); + const defaultProfile = { ...profileData, ip: req.clientIp, ticket: ticket }; - // Load user data if not already loaded - if (!decryptedData) { - loadUserData(dataFilePath); - } + // Add the fetched profile to local storage + addUser(profileId, defaultProfile); - // Find matching profile by name or ticket - const matchedProfileId = Object.keys(decryptedData).find(profileId => { - const userProfile = decryptedData[profileId]; - return userProfile.name === content.name || userProfile.ticket === ticket; + defaultProfile.ticket = '' + + return defaultProfile; + } + } catch (error) { + console.error(`[ACC] Error fetching profile for ${profileId}:`, error.message); + addUser(profileId, { ip: req.clientIp, ticket: ticket }); + return { + "profileId": profileId, + "isExisting": false + }; // If fetch fails, return an empty profile object + } + } + })); + + res.send(responseProfiles); }); - if (matchedProfileId) { - const userProfile = decryptedData[matchedProfileId]; - if (!matchedProfileId.name && userProfile.name) { - console.log('[ACC] New User Registered: ', userProfile.name) - } + app.post("/profile/v2/profiles", (req, res) => { + try { + const ticket = req.header("Authorization"); + const content = req.body; + content.ticket = ticket; + const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); - // Merge new content into existing user profile, overriding or adding properties - Object.assign(userProfile, content); - - // Save updated user profile data - decryptedData[matchedProfileId] = userProfile; - saveUserData(dataFilePath, decryptedData); - - // Regenerate Leaderboard List - const leaderboardlist = generateLeaderboard(decryptedData) - saveLeaderboard(leaderboardlist, false); - - res.send(decryptedData[matchedProfileId]); - } else { - console.error("[ACC] Can't Find UUID: ", matchedProfileId); - res.status(404).send("Profile not found."); - } - }); - - - app.post("/profile/v2/map-ended", async (req, res) => { - const ticket = req.header("Authorization"); - const SkuId = req.header("X-SkuId") || "jd2019"; - const clientIp = req.ip; - - try { - const mapList = req.body; - var leaderboard = readLeaderboard(true); // Load the current leaderboard data - - for (let song of mapList) { - updateMostPlayed(song.mapName); - - // Initialize the map in the leaderboard if it doesn't exist - if (!leaderboard[song.mapName]) { - console.log(`${JSON.stringify(leaderboard)} doesnt exist`) - leaderboard[song.mapName] = []; + // Load user data if not already loaded + if (!decryptedData) { + loadUserData(dataFilePath); } - // Find the user profile - const profile = findUserFromTicket(ticket); - if (!profile) { - console.log('[DOTW] Unable to find the Profile') - return res.send('1'); - } - const currentProfile = decryptedData[profile] - if (!currentProfile) { - console.log('[DOTW] Unable to find Pid: ', currentProfile) - return res.send('1'); - } + // Find matching profile by name or ticket + const matchedProfileId = Object.keys(decryptedData).find(profileId => { + const userProfile = decryptedData[profileId]; + return userProfile.name === content.name || userProfile.ticket === ticket; + }); - // Check if an entry for this profileId already exists - const currentScores = leaderboard[song.mapName]; - const existingEntryIndex = currentScores.findIndex(entry => entry.profileId === profile); + if (matchedProfileId) { + const userProfile = decryptedData[matchedProfileId]; - if (existingEntryIndex !== -1) { - // Entry exists for this profile, update if the new score is higher - if ((currentScores[existingEntryIndex].score < song.score) && song.score <= 13334) { - currentScores[existingEntryIndex].score = song.score; - currentScores[existingEntryIndex].weekOptain = getWeekNumber() - console.log(`[DOTW] Updated score dotw list on map ${song.mapName}`); - } else { - return res.send('1'); // Do nothing if the new score is lower + if (!matchedProfileId.name && userProfile.name) { + console.log('[ACC] New User Registered: ', userProfile.name) } + + // Merge new content into existing user profile, overriding or adding properties + Object.assign(userProfile, content); + + // Save updated user profile data + decryptedData[matchedProfileId] = userProfile; + console.error("[ACC] Updated User ", matchedProfileId); + saveUserData(dataFilePath, decryptedData); + + // Regenerate Leaderboard List + const leaderboardlist = generateLeaderboard(decryptedData) + saveLeaderboard(leaderboardlist, false); + + res.send(decryptedData[matchedProfileId]); } else { - // No existing entry for this profile, add a new one - const newScoreEntry = { - __class: "DancerOfTheWeek", - profileId: profile, - score: song.score, - gameVersion: SkuId.split('-')[0] || "jd2019", - rank: currentProfile.rank, - name: currentProfile.name, - avatar: currentProfile.avatar, - country: currentProfile.country, - platformId: currentProfile.platformId, - alias: currentProfile.alias, - aliasGender: currentProfile.aliasGender, - jdPoints: currentProfile.jdPoints, - portraitBorder: currentProfile.portraitBorder, - weekOptain: getWeekNumber() - } - - currentScores.push(newScoreEntry); - leaderboard[song.mapName] = currentScores - console.log(`[DOTW] Added new score for ${currentProfile.name} on map ${song.mapName}`); + console.error("[ACC] Can't Find UUID: ", matchedProfileId); + res.status(404).send("Profile not found."); } + } catch (err) { + console.log(err) } + }); - // Save the updated leaderboard back to the file - saveLeaderboard(leaderboard, true); - res.send(''); - } catch (error) { - console.log(error); - res.status(200).send(''); // Keep sending response even in case of error - } - }); - - // Delete favorite map - app.delete("/profile/v2/favorites/maps/:MapName", async (req, res) => { - try { - const MapName = req.params.MapName; + app.post("/profile/v2/map-ended", async (req, res) => { const ticket = req.header("Authorization"); - const SkuId = req.header("X-SkuId"); + const SkuId = req.header("X-SkuId") || "jd2019"; + const clientIp = req.ip; - const response = await axios.delete( - `${prodwsurl}/profile/v2/favorites/maps/${MapName}`, { - headers: { - "X-SkuId": SkuId, - Authorization: ticket, - }, - }); + try { + const mapList = req.body; + var leaderboard = readLeaderboard(true); // Load the current leaderboard data - res.send(response.data); - } catch (error) { - res.status(500).send(error.message); - } - }); + for (let song of mapList) { + updateMostPlayed(song.mapName); - // Get profile sessions - app.get("/v3/profiles/sessions", async (req, res) => { - try { - const ticket = req.header("Authorization"); - const appid = req.header("Ubi-AppId"); + // Initialize the map in the leaderboard if it doesn't exist + if (!leaderboard[song.mapName]) { + console.log(`${JSON.stringify(leaderboard)} doesnt exist`) + leaderboard[song.mapName] = []; + } - const response = await axios.get(`${ubiwsurl}/v3/profiles/sessions`, { - headers: { - "Content-Type": "application/json", - "Ubi-AppId": appid, - Authorization: ticket, - }, - }); + // Find the user profile + const profile = findUserFromTicket(ticket); + if (!profile) { + console.log('[DOTW] Unable to find the Profile') + return res.send('1'); + } + const currentProfile = decryptedData[profile] + if (!currentProfile) { + console.log('[DOTW] Unable to find Pid: ', currentProfile) + return res.send('1'); + } - res.send(response.data); - } catch (error) { - res.status(500).send(error.message); - } - }); + // Check if an entry for this profileId already exists + const currentScores = leaderboard[song.mapName]; + const existingEntryIndex = currentScores.findIndex(entry => entry.profileId === profile); - // Endpoint to filter players - app.post("/profile/v2/filter-players", (req, res) => { - res.send(["00000000-0000-0000-0000-000000000000"]); - }); -} + if (existingEntryIndex !== -1) { + // Entry exists for this profile, update if the new score is higher + if ((currentScores[existingEntryIndex].score < song.score) && song.score <= 13334) { + currentScores[existingEntryIndex].score = song.score; + currentScores[existingEntryIndex].weekOptain = getWeekNumber() + console.log(`[DOTW] Updated score dotw list on map ${song.mapName}`); + } else { + return res.send('1'); // Do nothing if the new score is lower + } + } else { + // No existing entry for this profile, add a new one + const newScoreEntry = { + __class: "DancerOfTheWeek", + profileId: profile, + score: song.score, + gameVersion: SkuId.split('-')[0] || "jd2019", + rank: currentProfile.rank, + name: currentProfile.name, + avatar: currentProfile.avatar, + country: currentProfile.country, + platformId: currentProfile.platformId, + alias: currentProfile.alias, + aliasGender: currentProfile.aliasGender, + jdPoints: currentProfile.jdPoints, + portraitBorder: currentProfile.portraitBorder, + weekOptain: getWeekNumber() + } + + currentScores.push(newScoreEntry); + leaderboard[song.mapName] = currentScores + console.log(`[DOTW] Added new score for ${currentProfile.name} on map ${song.mapName}`); + } + } + + // Save the updated leaderboard back to the file + saveLeaderboard(leaderboard, true); + res.send(''); + + } catch (error) { + console.log(error); + res.status(200).send(''); // Keep sending response even in case of error + } + }); + + // Delete favorite map + app.delete("/profile/v2/favorites/maps/:MapName", async (req, res) => { + try { + const MapName = req.params.MapName; + const ticket = req.header("Authorization"); + const SkuId = req.header("X-SkuId"); + + const response = await axios.delete( + `${prodwsurl}/profile/v2/favorites/maps/${MapName}`, { + headers: { + "X-SkuId": SkuId, + Authorization: ticket, + }, + }); + + res.send(response.data); + } catch (error) { + res.status(500).send(error.message); + } + }); + + // Get profile sessions + app.get("/v3/profiles/sessions", async (req, res) => { + try { + const ticket = req.header("Authorization"); + const appid = req.header("Ubi-AppId"); + + const response = await axios.get(`${ubiwsurl}/v3/profiles/sessions`, { + headers: { + "Content-Type": "application/json", + "Ubi-AppId": appid, + Authorization: ticket, + }, + }); + + res.send(response.data); + } catch (error) { + res.status(500).send(error.message); + } + }); + + // Endpoint to filter players + app.post("/profile/v2/filter-players", (req, res) => { + res.send(["00000000-0000-0000-0000-000000000000"]); + }); + } +}; \ No newline at end of file diff --git a/core/route/ubiservices.js b/core/route/ubiservices.js index cb0cc65..359f00d 100644 --- a/core/route/ubiservices.js +++ b/core/route/ubiservices.js @@ -8,8 +8,9 @@ const core = { generateCoopCarousel: require('../carousel/carousel').generateCoopCarousel, updateMostPlayed: require('../carousel/carousel').updateMostPlayed, signer: require('../lib/signUrl'), - ipResolver: require('../lib/ipResolver') + ipResolver: require('../lib/ipResolver'), }; +const { addUserId, updateUserTicket } = require('./account'); const settings = require('../../settings.json'); const cachedTicket = {}; const ipCache = {}; // Cache untuk menyimpan ticket berdasarkan IP @@ -41,7 +42,7 @@ const getCountryFromIp = (ip) => 'US'; const generateFalseTicket = () => { const start = "ew0KIC"; const end = "KfQ=="; - const middleLength = 40; + const middleLength = 60; const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let middle = ''; @@ -79,6 +80,8 @@ exports.initroute = (app, express, server) => { const response = await axios.post(`${prodwsurl}/v3/profiles/sessions`, req.body, { headers }); res.send(response.data); + addUserId(response.data.profileId, response.data.userId) + updateUserTicket(response.data.profileId, `Ubi_v1 ${response.data.ticket}`) console.log("[ACC] Using Official Ticket"); } catch (error) { console.log("[ACC] Error fetching from Ubisoft services", error.message); @@ -114,7 +117,7 @@ exports.initroute = (app, express, server) => { serverTime: now.toISOString(), sessionId, sessionKey: "TqCz5+J0w9e8qpLp/PLr9BCfAc30hKlEJbN0Xr+mbZa=", - rememberMeTicket: null + rememberMeTicket: null, }; // Cache the session based on the IP