mirror of
https://github.com/ibratabian17/OpenParty.git
synced 2026-01-15 14:22:54 -03:00
Improve Account Ticket gen
This commit is contained in:
@@ -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"]);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user