diff --git a/app.js b/app.js
index a1977a9..79c8a03 100644
--- a/app.js
+++ b/app.js
@@ -772,6 +772,9 @@ app.post('/api/user', async (req, res) => {
case 'friendsList':
data = await fetchWithTimeout(() => API.Me.friendsList());
break;
+ case 'userInfo':
+ data = await fetchWithTimeout(() => API.Me.userInfo());
+ break;
// case "settings":
// data = await fetchWithTimeout(() =>
// API.Me.settings(username, platform)
@@ -807,6 +810,105 @@ app.post('/api/user', async (req, res) => {
}
});
+// API endpoint for CDN-related API calls
+app.post('/api/cdn', async (req, res) => {
+ logger.debug('Received request for /api/cdn');
+ logger.debug(
+ `Request IP: ${
+ req.headers['x-forwarded-for'] || req.ip || req.connection.remoteAddress
+ }`
+ );
+ logger.debug(
+ `Request JSON: ${JSON.stringify({
+ cdnCall: req.body.cdnCall,
+ })}`
+ );
+
+ try {
+ let { ssoToken, cdnCall } = req.body;
+
+ /*
+ logger.debug(
+ `Request details - User Call: ${cdnCall}`
+ );
+
+ logger.debug("=== USER DATA REQUEST ===");
+ logger.debug(`CDN Call: ${cdnCall}`);
+ logger.debug("========================="); */
+
+ const defaultToken = demoTracker.getDefaultSsoToken();
+ if (!ssoToken && defaultToken) {
+ ssoToken = defaultToken;
+ logger.info('Using default SSO token for demo mode');
+ } else if (!ssoToken) {
+ return res.status(200).json({
+ status: 'error',
+ message: 'SSO Token is required',
+ timestamp: global.Utils.toIsoString(new Date()),
+ });
+ }
+
+ try {
+ await ensureLogin(ssoToken);
+ } catch (loginError) {
+ return res.status(200).json({
+ status: 'error',
+ error_type: 'LoginError',
+ message: 'SSO token login failed',
+ details: loginError.message || 'Unknown login error',
+ timestamp: global.Utils.toIsoString(new Date()),
+ });
+ }
+
+ // Create a wrapped function for each API call to handle timeout
+ const fetchWithTimeout = async (apiFn) => {
+ return Promise.race([
+ apiFn(),
+ timeoutPromise(30000), // 30 second timeout
+ ]);
+ };
+
+ try {
+ logger.debug(`Attempting to fetch CDN data for ${cdnCall}`);
+ let data;
+
+ // Fetch user data based on cdnCall
+ switch (cdnCall) {
+ case 'accolades':
+ data = await fetchWithTimeout(() => API.CDN.accolades());
+ break;
+ case 'allCDNData':
+ data = await fetchWithTimeout(() => API.CDN.allCDNData());
+ break;
+
+ default:
+ return res.status(200).json({
+ status: 'error',
+ message: 'Invalid user API call selected',
+ timestamp: global.Utils.toIsoString(new Date()),
+ });
+ }
+
+ demoTracker.incrementDemoCounter(req, ssoToken);
+
+ return res.json({
+ // status: "success",
+ data: data,
+ timestamp: global.Utils.toIsoString(new Date()),
+ });
+ } catch (apiError) {
+ return handleApiError(apiError, res);
+ }
+ } catch (serverError) {
+ return res.status(200).json({
+ status: 'server_error',
+ message: 'The server encountered an unexpected error',
+ error_details: serverError.message || 'Unknown server error',
+ timestamp: global.Utils.toIsoString(new Date()),
+ });
+ }
+});
+
// API endpoint for fuzzy search
app.post('/api/search', async (req, res) => {
logger.debug('Received request for /api/search');
diff --git a/src/index.html b/src/index.html
index 199586e..8e3e690 100644
--- a/src/index.html
+++ b/src/index.html
@@ -68,6 +68,7 @@
+
+
+
+
+
+
+
+
+
Authentication Setup
+
Obtaining Your SSO Token
+
+ -
+ Log in to
+ Call of Duty
+
+ - Open developer tools (F12 or right-click → Inspect)
+ -
+ Navigate to: Application → Storage →
+ Cookies → https://profile.callofduty.com
+
+ - Copy the value of
ACT_SSO_COOKIE
+ - Paste this value into SSO Token
+
+
+
Changing Account API Privacy Settings
+
+ -
+ Log in to
+ Call of Duty
+
+ - Navigate to the Privacy & Security tab
+ -
+ Scroll down to the Game Data and Profile Privacy section
+
+ -
+ Set the following options to "ALL":
+
+ - Game Tag Searchable
+ - Game Play Data
+
+
+
+
+
+
diff --git a/src/js/frontend.js b/src/js/frontend.js
index 1481237..31f313e 100644
--- a/src/js/frontend.js
+++ b/src/js/frontend.js
@@ -272,6 +272,9 @@ function triggerActiveTabButton() {
case 'user':
document.getElementById('fetchUserInfo').click();
break;
+ case 'cdn':
+ document.getElementById('fetchCDNData').click();
+ break;
case 'other':
document.getElementById('fuzzySearch').click();
break;
@@ -799,6 +802,22 @@ document.getElementById('fetchUserInfo').addEventListener('click', async () => {
});
});
+// Fetch CDN Data
+document.getElementById('fetchCDNData').addEventListener('click', async () => {
+ const ssoToken = document.getElementById('ssoToken').value.trim();
+ const cdnCall = document.getElementById('cdnCall').value;
+
+ const sanitize = document.getElementById('sanitizeOption').checked;
+ const replaceKeys = document.getElementById('replaceKeysOption').checked;
+
+ await window.backendAPI.fetchData('/api/cdn', {
+ ssoToken,
+ cdnCall,
+ sanitize,
+ replaceKeys,
+ });
+});
+
// Fuzzy search
document.getElementById('fuzzySearch').addEventListener('click', async () => {
const username = document.getElementById('searchUsername').value.trim();
diff --git a/src/js/index.ts b/src/js/index.ts
index 4771b2b..afc6898 100644
--- a/src/js/index.ts
+++ b/src/js/index.ts
@@ -1589,8 +1589,22 @@ const CDN = new DB();
const Misc = new ALT();
export {
- CDN, ColdWar, disableDebugMode, enableDebugMode, friendActions, login, Me, Misc, ModernWarfare,
+ CDN,
+ ColdWar,
+ disableDebugMode,
+ enableDebugMode,
+ friendActions,
+ login,
+ Me,
+ Misc,
+ ModernWarfare,
ModernWarfare2,
- ModernWarfare3, platforms, Store, telescopeLogin, Vanguard, Warzone, Warzone2, WarzoneMobile
+ ModernWarfare3,
+ platforms,
+ Store,
+ telescopeLogin,
+ Vanguard,
+ Warzone,
+ Warzone2,
+ WarzoneMobile,
};
-
diff --git a/src/js/localStorage.js b/src/js/localStorage.js
index d1db4ac..6798fa8 100644
--- a/src/js/localStorage.js
+++ b/src/js/localStorage.js
@@ -5,7 +5,7 @@ document.addEventListener('DOMContentLoaded', function () {
{ id: 'username', key: 'cod_username' },
{ id: 'platform', key: 'cod_platform' },
{ id: 'game', key: 'cod_game' },
- { id: 'apiCall', key: 'cod_apiCall' },
+ { id: 'userCall', key: 'cod_userCall' },
// Matches tab
{ id: 'matchUsername', key: 'cod_matchUsername' },
diff --git a/src/js/test.js b/src/js/test.js
index 2c41378..e4f50a3 100644
--- a/src/js/test.js
+++ b/src/js/test.js
@@ -9,8 +9,8 @@ import {
} from './index.js';
import fs from 'fs';
-// Me { communityMapDataForMapMode(game, platform, mode, mapID, gamemode), userInfo() };
-// CDN { accolades(), allCDNData() };
+// Me { communityMapDataForMapMode(game, platform, mode, mapID, gamemode) };
+
// ModernWarfare: { bundleInfo(game, platform, lookupType, gamertag), matchHeatMap(game, platform, matchID), bpProg(game, platform, lookupType, gamertag) };
// ColdWar: { bundleInfo(game, platform, lookupType, gamertag), matchHeatMap(game, platform, matchID), bpProg(game, platform, lookupType, gamertag) };
// Vanguard: { bundleInfo(game, platform, lookupType, gamertag), matchHeatMap(game, platform, matchID), bpProg(game, platform, lookupType, gamertag) };