Skip to content

Instantly share code, notes, and snippets.

@Windowsfreak
Created February 13, 2026 14:57
Show Gist options
  • Select an option

  • Save Windowsfreak/0f4b0b727120d6a408a68a832e5cc7b6 to your computer and use it in GitHub Desktop.

Select an option

Save Windowsfreak/0f4b0b727120d6a408a68a832e5cc7b6 to your computer and use it in GitHub Desktop.
Aurum-Partnerstatistik-Export
(async function () {
class AurumCryptor {
#password;
#iterations;
#encoder;
#decoder;
constructor(password, iterations = 150000) {
if (!password) {
throw new Error("Password is required for key derivation");
}
this.#password = password;
this.#iterations = iterations;
this.#encoder = new TextEncoder();
this.#decoder = new TextDecoder();
}
async deriveKey(salt) {
const baseKey = await window.crypto.subtle.importKey(
"raw",
this.#encoder.encode(this.#password),
"PBKDF2",
false,
["deriveKey"]
);
return window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: this.#iterations,
hash: "SHA-256"
},
baseKey,
{
name: "AES-GCM",
length: 256
},
false,
["encrypt", "decrypt"]
);
}
async decode(encryptedBase64) {
const encryptedBytes = Uint8Array.from(atob(encryptedBase64), (char) => char.charCodeAt(0));
const salt = encryptedBytes.slice(0, 16);
const iv = encryptedBytes.slice(16, 28);
const ciphertext = encryptedBytes.slice(28);
const aesKey = await this.deriveKey(salt);
const decryptedBytes = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv
},
aesKey,
ciphertext
);
return this.#decoder.decode(decryptedBytes);
}
}
const cryptor = new AurumCryptor("default-password");
async function buildPartnerTree() {
console.log("Starting data extraction...");
const token = localStorage.getItem("token");
if (!token) {
console.error("No token found in localStorage. Please ensure you are logged in.");
return;
}
const headers = {
"Accept": "application/json",
"Authorization": `Bearer ${token}`
};
const delay = ms => new Promise(res => setTimeout(res, ms));
const backoffs = [10, 20, 40, 80, 120, 240, 360, 480, 600];
async function fetchAndDecrypt(url, pageInfo = "") {
let attempt = 0;
while (attempt <= backoffs.length) {
const resp = await fetch(url, { headers });
if (resp.status === 429 && attempt < backoffs.length) {
const waitSeconds = backoffs[attempt];
console.warn(`Rate limited (429). Waiting ${waitSeconds}s... (Attempt ${attempt + 1})`);
await delay(waitSeconds * 1000);
attempt++;
continue;
}
if (!resp.ok) {
throw new Error(`Fetch ${url} ${pageInfo} failed (status ${resp.status}) after ${attempt} retries`);
}
const raw = await resp.json();
if (raw.encrypted) {
const decryptedStr = await cryptor.decode(raw.encrypted);
return JSON.parse(decryptedStr);
}
return raw;
}
}
function parseInvest(val) {
if (!val) return 0;
const cleaned = String(val).replace(/\s/g, '');
return parseFloat(cleaned) || 0;
}
async function getReferralsRecursive(prettyId) {
const partners = [];
const limit = 15;
let page = 1;
let total = 0;
do {
const url = `https://api.aurum.foundation/partners/statistics?limit=${limit}&page=${page}&prettyId=${prettyId}&search=`;
const data = await fetchAndDecrypt(url, `page ${page}`);
total = data.total || 0;
if (data.referrals && Array.isArray(data.referrals)) {
for (const p of data.referrals) {
const node = {
id: p.prettyId,
name: p.name,
rank: (p.rankId || 1) - 1,
invest: parseInvest(p.investmentsAmount),
partners: []
};
if (p.referralsCount > 0) {
console.log(`Fetching referrals for ${p.name} (${p.prettyId})...`);
node.partners = await getReferralsRecursive(p.prettyId);
}
partners.push(node);
}
}
page++;
} while (partners.length < total);
return partners;
}
const rankNames = ["Nova", "Voyager", "Vanguard", "Vanguard Pro", "Nexus", "Oracle", "Prime", "Elite", "Magnat", "Mythos", "Legend"];
function getCsvTree(root) {
const lines = ["id,name,rank,invest,parent,depth"];
function recurse(node, parentId = "", depth = 0) {
const rankName = rankNames[node.rank] || rankNames[0];
lines.push(`${node.id},${node.name},${rankName},${node.invest},"${parentId}",${depth}`);
if (node.partners && node.partners.length > 0) {
for (const p of node.partners) {
recurse(p, node.id, depth + 1);
}
}
}
recurse(root);
return lines.join("\n");
}
try {
const rootData = await fetchAndDecrypt('https://api.aurum.foundation/');
const user = rootData.user;
const affStats = rootData.affiliateStats || {};
const resultTree = {
id: user.prettyId,
name: `${user.personal.name} ${user.personal.surname}`.trim(),
rank: (affStats.referralRankId || 1) - 1,
invest: parseInvest(affStats.investAmount),
partners: []
};
resultTree.partners = await getReferralsRecursive("");
console.log("Tree build complete!");
const section = document.getElementsByTagName("section")[0];
const jsonResult = JSON.stringify(resultTree, null, 2);
const csvResult = getCsvTree(resultTree);
if (section) {
section.innerHTML = `
<div style="width: 100%; height: 100%; min-height: 90vh; display: flex; flex-direction: column; gap: 20px;">
<textarea id="result-json" style="flex: 1; width: 100%; height: 300px; font-family: 'Courier New', monospace; font-size: 14px; padding: 15px; border: 1px solid #ccc; box-sizing: border-box; background: #f9f9f9;">${jsonResult}</textarea>
<textarea id="result-csv" style="flex: 1; width: 100%; height: 300px; font-family: 'Courier New', monospace; font-size: 14px; padding: 15px; border: 1px solid #ccc; box-sizing: border-box; background: #f9f9f9;">${csvResult}</textarea>
</div>`;
} else {
console.log("JSON Result:", jsonResult);
console.log("CSV Result:", csvResult);
}
} catch (error) {
console.error("Error building tree:", error);
}
}
buildPartnerTree();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment