Improve Account Ticket gen

This commit is contained in:
ibratabian17
2024-10-20 17:04:22 +07:00
parent c57d708198
commit 53b24047e7
2 changed files with 241 additions and 206 deletions

View File

@@ -72,6 +72,22 @@ function addUser(profileId, userProfile) {
const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`);
saveUserData(dataFilePath, decryptedData); 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 // Helper function to read the leaderboard
function readLeaderboard(isDotw = false) { function readLeaderboard(isDotw = false) {
@@ -150,235 +166,251 @@ if (!decryptedData) {
loadUserData(dataFilePath); loadUserData(dataFilePath);
} }
// Initialize routes module.exports = {
exports.initroute = (app) => { loadUserData,
addUser,
addUserId,
updateUserTicket,
cachedLeaderboard,
cachedDotw,
initroute: (app) => {
// Endpoint to get profiles based on profileIds // Endpoint to get profiles based on profileIds
app.get("/profile/v2/profiles", async (req, res) => { app.get("/profile/v2/profiles", async (req, res) => {
const ticket = req.header("Authorization"); const ticket = req.header("Authorization");
const profileIds = req.query.profileIds.split(','); const profileIds = req.query.profileIds.split(',');
const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`);
// Load user data if not already loaded // Load user data if not already loaded
if (!decryptedData) { if (!decryptedData) {
loadUserData(dataFilePath); 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
}
} }
}));
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) => { // Assume the external response contains the profile as `profileData`
const ticket = req.header("Authorization"); const profileData = profileResponse.data[0]; // Adjust according to the actual response format
const content = req.body; if (profileData) {
content.ticket = ticket; console.log(`[ACC] Account Saved to the server: `, profileId);
const dataFilePath = path.join(getSavefilePath(), `/account/profiles/user.json`); const defaultProfile = { ...profileData, ip: req.clientIp, ticket: ticket };
// Load user data if not already loaded // Add the fetched profile to local storage
if (!decryptedData) { addUser(profileId, defaultProfile);
loadUserData(dataFilePath);
}
// Find matching profile by name or ticket defaultProfile.ticket = ''
const matchedProfileId = Object.keys(decryptedData).find(profileId => {
const userProfile = decryptedData[profileId]; return defaultProfile;
return userProfile.name === content.name || userProfile.ticket === ticket; }
} 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) { app.post("/profile/v2/profiles", (req, res) => {
console.log('[ACC] New User Registered: ', userProfile.name) 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 // Load user data if not already loaded
Object.assign(userProfile, content); if (!decryptedData) {
loadUserData(dataFilePath);
// 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] = [];
} }
// Find the user profile // Find matching profile by name or ticket
const profile = findUserFromTicket(ticket); const matchedProfileId = Object.keys(decryptedData).find(profileId => {
if (!profile) { const userProfile = decryptedData[profileId];
console.log('[DOTW] Unable to find the Profile') return userProfile.name === content.name || userProfile.ticket === ticket;
return res.send('1'); });
}
const currentProfile = decryptedData[profile]
if (!currentProfile) {
console.log('[DOTW] Unable to find Pid: ', currentProfile)
return res.send('1');
}
// Check if an entry for this profileId already exists if (matchedProfileId) {
const currentScores = leaderboard[song.mapName]; const userProfile = decryptedData[matchedProfileId];
const existingEntryIndex = currentScores.findIndex(entry => entry.profileId === profile);
if (existingEntryIndex !== -1) { if (!matchedProfileId.name && userProfile.name) {
// Entry exists for this profile, update if the new score is higher console.log('[ACC] New User Registered: ', userProfile.name)
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
} }
// 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 { } else {
// No existing entry for this profile, add a new one console.error("[ACC] Can't Find UUID: ", matchedProfileId);
const newScoreEntry = { res.status(404).send("Profile not found.");
__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}`);
} }
} catch (err) {
console.log(err)
} }
});
// Save the updated leaderboard back to the file
saveLeaderboard(leaderboard, true);
res.send('');
} catch (error) { app.post("/profile/v2/map-ended", async (req, res) => {
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 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( try {
`${prodwsurl}/profile/v2/favorites/maps/${MapName}`, { const mapList = req.body;
headers: { var leaderboard = readLeaderboard(true); // Load the current leaderboard data
"X-SkuId": SkuId,
Authorization: ticket,
},
});
res.send(response.data); for (let song of mapList) {
} catch (error) { updateMostPlayed(song.mapName);
res.status(500).send(error.message);
}
});
// Get profile sessions // Initialize the map in the leaderboard if it doesn't exist
app.get("/v3/profiles/sessions", async (req, res) => { if (!leaderboard[song.mapName]) {
try { console.log(`${JSON.stringify(leaderboard)} doesnt exist`)
const ticket = req.header("Authorization"); leaderboard[song.mapName] = [];
const appid = req.header("Ubi-AppId"); }
const response = await axios.get(`${ubiwsurl}/v3/profiles/sessions`, { // Find the user profile
headers: { const profile = findUserFromTicket(ticket);
"Content-Type": "application/json", if (!profile) {
"Ubi-AppId": appid, console.log('[DOTW] Unable to find the Profile')
Authorization: ticket, 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); // Check if an entry for this profileId already exists
} catch (error) { const currentScores = leaderboard[song.mapName];
res.status(500).send(error.message); const existingEntryIndex = currentScores.findIndex(entry => entry.profileId === profile);
}
});
// Endpoint to filter players if (existingEntryIndex !== -1) {
app.post("/profile/v2/filter-players", (req, res) => { // Entry exists for this profile, update if the new score is higher
res.send(["00000000-0000-0000-0000-000000000000"]); 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"]);
});
}
};

View File

@@ -8,8 +8,9 @@ const core = {
generateCoopCarousel: require('../carousel/carousel').generateCoopCarousel, generateCoopCarousel: require('../carousel/carousel').generateCoopCarousel,
updateMostPlayed: require('../carousel/carousel').updateMostPlayed, updateMostPlayed: require('../carousel/carousel').updateMostPlayed,
signer: require('../lib/signUrl'), signer: require('../lib/signUrl'),
ipResolver: require('../lib/ipResolver') ipResolver: require('../lib/ipResolver'),
}; };
const { addUserId, updateUserTicket } = require('./account');
const settings = require('../../settings.json'); const settings = require('../../settings.json');
const cachedTicket = {}; const cachedTicket = {};
const ipCache = {}; // Cache untuk menyimpan ticket berdasarkan IP const ipCache = {}; // Cache untuk menyimpan ticket berdasarkan IP
@@ -41,7 +42,7 @@ const getCountryFromIp = (ip) => 'US';
const generateFalseTicket = () => { const generateFalseTicket = () => {
const start = "ew0KIC"; const start = "ew0KIC";
const end = "KfQ=="; const end = "KfQ==";
const middleLength = 40; const middleLength = 60;
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let middle = ''; let middle = '';
@@ -79,6 +80,8 @@ exports.initroute = (app, express, server) => {
const response = await axios.post(`${prodwsurl}/v3/profiles/sessions`, req.body, { headers }); const response = await axios.post(`${prodwsurl}/v3/profiles/sessions`, req.body, { headers });
res.send(response.data); 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"); console.log("[ACC] Using Official Ticket");
} catch (error) { } catch (error) {
console.log("[ACC] Error fetching from Ubisoft services", error.message); console.log("[ACC] Error fetching from Ubisoft services", error.message);
@@ -114,7 +117,7 @@ exports.initroute = (app, express, server) => {
serverTime: now.toISOString(), serverTime: now.toISOString(),
sessionId, sessionId,
sessionKey: "TqCz5+J0w9e8qpLp/PLr9BCfAc30hKlEJbN0Xr+mbZa=", sessionKey: "TqCz5+J0w9e8qpLp/PLr9BCfAc30hKlEJbN0Xr+mbZa=",
rememberMeTicket: null rememberMeTicket: null,
}; };
// Cache the session based on the IP // Cache the session based on the IP